Last active
October 28, 2018 06:50
-
-
Save tintoy/70fb3b900fa914fc57d9bff3b9035191 to your computer and use it in GitHub Desktop.
OctoGrok
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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