Skip to content

Instantly share code, notes, and snippets.

@tintoy
Last active October 28, 2018 06:50
Show Gist options
  • Save tintoy/70fb3b900fa914fc57d9bff3b9035191 to your computer and use it in GitHub Desktop.
Save tintoy/70fb3b900fa914fc57d9bff3b9035191 to your computer and use it in GitHub Desktop.
OctoGrok
using Octopus.Client.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
namespace OctoMon
{
public class DeploymentTask
{
public string Id { get; set; }
public string ProjectId { get; set; }
public string ReleaseId { get; set; }
public string EnvironmentId { get; set; }
public string DeploymentId { get; set; }
public string DeploymentProcessId { get; set; }
public string Name { get; set; }
public ActivityElement RootActivity { get; set; }
public List<DeploymentStepTask> Steps { get; } = new List<DeploymentStepTask>();
public override string ToString() => $"[Deployment] {Name}";
public static DeploymentTask From(TaskDetailsResource task, DeploymentResource deployment, DeploymentProcessResource deploymentProcess)
{
if (task == null)
throw new ArgumentNullException(nameof(task));
if (deployment == null)
throw new ArgumentNullException(nameof(deployment));
if (deploymentProcess == null)
throw new ArgumentNullException(nameof(deploymentProcess));
if (task.ActivityLogs.Count != 1)
throw new ArgumentException("Task detail contains more than one root activity.", nameof(task));
ActivityElement rootActivity = task.ActivityLogs[0];
var deploymentTask = new DeploymentTask
{
Id = task.Task.Id,
ProjectId = deployment.ProjectId,
ReleaseId = deployment.ReleaseId,
EnvironmentId = deployment.EnvironmentId,
DeploymentId = deployment.Id,
DeploymentProcessId = deployment.DeploymentProcessId,
RootActivity = rootActivity,
Name = rootActivity.Name
};
deploymentTask.Steps.AddRange(
DeploymentStepTask.From(deploymentTask, deploymentProcess)
);
return deploymentTask;
}
}
public class DeploymentStepTask
{
public static readonly int InvalidStepNumber = -1;
static readonly Regex StepActivityMatcher = new Regex(@"Step (?<StepNumber>\d{1,3}): (?<StepName>.+)");
public DeploymentTask Deployment { get; set; }
public string StepName { get; set; }
public int StepNumber { get; set; }
public string ProcessStepId => ProcessStep?.Id;
public DeploymentStepResource ProcessStep { get; set; }
public ActivityElement StepActivity { get; set; }
public List<DeploymentStepMachineTask> MachineTasks { get; } = new List<DeploymentStepMachineTask>();
public override string ToString() => $"[Step] {StepName}";
public static IEnumerable<DeploymentStepTask> From(DeploymentTask deploymentTask, DeploymentProcessResource deploymentProcess)
{
if (deploymentTask == null)
throw new ArgumentNullException(nameof(deploymentTask));
if (deploymentProcess == null)
throw new ArgumentNullException(nameof(deploymentProcess));
if (deploymentTask.RootActivity == null)
throw new ArgumentException("Deployment task has no root activity.", nameof(deploymentTask));
Dictionary<string, DeploymentStepResource> deploymentProcessSteps = deploymentProcess.Steps.ToDictionary(step => step.Name);
foreach (ActivityElement stepActivity in deploymentTask.RootActivity.Children)
{
var deploymentStep = new DeploymentStepTask
{
Deployment = deploymentTask,
StepActivity = stepActivity,
StepName = stepActivity.Name,
StepNumber = InvalidStepNumber
};
deploymentStep.MachineTasks.AddRange(
DeploymentStepMachineTask.From(deploymentStep)
);
// If we can, attempt to parse out the step number / step name from the step activity's name.
Match match = StepActivityMatcher.Match(stepActivity.Name);
if (match.Success)
{
deploymentStep.StepName = match.Groups["StepName"].Value;
if (Int32.TryParse(match.Groups["StepName"].Value, out int stepNumber))
deploymentStep.StepNumber = stepNumber;
}
if (deploymentProcessSteps.TryGetValue(deploymentStep.StepName, out DeploymentStepResource processStep))
{
deploymentStep.ProcessStepId = processStep.Id;
deploymentStep.ProcessStep = processStep;
}
yield return deploymentStep;
}
}
}
public class DeploymentStepMachineTask
{
public DeploymentStepTask Step { get; set; }
public ActivityElement MachineActivity { get; set; }
public string MachineName { get; set; }
public override string ToString() => $"[Machine] {MachineName}";
public static IEnumerable<DeploymentStepMachineTask> From(DeploymentStepTask deploymentStepTask)
{
if (deploymentStepTask == null)
throw new ArgumentNullException(nameof(deploymentStepTask));
if (deploymentStepTask.StepActivity == null)
throw new ArgumentException("Deployment step task has no step activity.", nameof(deploymentStepTask));
foreach (ActivityElement machineActivity in deploymentStepTask.StepActivity.Children)
{
var deploymentStep = new DeploymentStepMachineTask
{
Step = deploymentStepTask,
MachineActivity = machineActivity,
MachineName = machineActivity.Name
};
yield return deploymentStep;
}
}
}
}
using Octopus.Client;
using Octopus.Client.Model;
using Serilog;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
namespace OctoMon
{
class Program
{
static async Task Main(string[] args)
{
SynchronizationContext.SetSynchronizationContext(
new SynchronizationContext()
);
ConfigureLogging();
const string projectName = "AdamTest";
try
{
Log.Information("Connecting to Octopus...");
OctopusServerEndpoint endpoint = new OctopusServerEndpoint("https://my-octopus-server/",
apiKey: "MY-OCTOPUS-API-KEY"
);
IOctopusAsyncClient client = await OctopusAsyncClient.Create(endpoint);
ProjectResource project = await client.Repository.Projects.FindByName(projectName);
Log.Information("Scanning for tasks...");
List<TaskResource> tasks = await client.Repository.Tasks.FindAll();
Log.Information("{TaskCount} tasks found.", tasks.Count);
IEnumerable<TaskResource> deploymentTasks = tasks.Where(
task => task.Arguments.ContainsKey("DeploymentId")
);
foreach (TaskResource deploymentTask in deploymentTasks.Take(50))
{
DeploymentResource deployment = await client.Repository.Deployments.Get(
(string)deploymentTask.Arguments["DeploymentId"]
);
if (deployment.ProjectId != project.Id)
continue;
TaskDetailsResource deploymentTaskDetails = await client.Repository.Tasks.GetDetails(deploymentTask);
DeploymentProcessResource deploymentProcess = await client.Repository.DeploymentProcesses.Get(deployment.DeploymentProcessId);
DeploymentTask task = DeploymentTask.From(deploymentTaskDetails, deployment, deploymentProcess);
int stepsWithProcessStepCount = task.Steps.Count(
step => step.ProcessStep != null
);
Log.Information("Found {StepsWithProcessStepCount} steps with associated process step for deployment task {TaskName} ({TaskId}).",
stepsWithProcessStepCount,
task.Name,
task.Id
);
DeploymentActionResource action1 = task.Steps[0].ProcessStep.Actions[0];
foreach (var actionProperty in action1.Properties.OrderBy(kvp => kvp.Key))
{
Log.Information(" {ActionType} action {Sensitive}property {PropertyName} = {PropertyValue}",
action1.ActionType.Replace("Octopus.", String.Empty),
actionProperty.Value.IsSensitive ? "sensitive " : String.Empty,
actionProperty.Key,
actionProperty.Value.IsSensitive ? "*********" : actionProperty.Value.Value
);
}
}
}
catch (Exception unexpectedError)
{
Log.Error(unexpectedError, "Unexpected error.");
}
}
static void ConfigureLogging()
{
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Information()
.WriteTo.LiterateConsole(
outputTemplate: "[{Level:u3}] {Message:l}{NewLine}{Exception}"
)
.CreateLogger();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment