Skip to content

Commit d83c017

Browse files
committed
Initial commit
0 parents  commit d83c017

11 files changed

+303
-0
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.vs
2+
bin
3+
obj
4+
*.user

DockerClient.cs

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Diagnostics;
4+
using System.Text;
5+
6+
namespace StackDeployCheck
7+
{
8+
class DockerClient
9+
{
10+
private StackState currentStackState;
11+
public StackState GetCurrentState(string stackName)
12+
{
13+
currentStackState = new StackState()
14+
{
15+
StackName = stackName
16+
};
17+
18+
GetStackTasks(stackName);
19+
20+
return currentStackState;
21+
}
22+
23+
public void GetStackTasks(string stackName)
24+
{
25+
var formatString = "{{.ID}} {{.Name}} {{.Image}} {{.Node}} {{.DesiredState}} [{{.CurrentState}}] [{{.Error}}]";
26+
ProcessStartInfo processStartInfo = new ProcessStartInfo("docker", $"stack ps {stackName} --no-trunc --format \"{formatString}\"")
27+
{
28+
RedirectStandardError = true,
29+
RedirectStandardOutput = true,
30+
RedirectStandardInput = true,
31+
UseShellExecute = false,
32+
CreateNoWindow = true
33+
};
34+
using (Process process = new Process()
35+
{
36+
StartInfo = processStartInfo,
37+
EnableRaisingEvents = true
38+
})
39+
{
40+
process.OutputDataReceived += Process_OutputDataReceived;
41+
process.ErrorDataReceived += Process_ErrorDataReceived;
42+
//process.Exited += Process_Exited;
43+
process.Start();
44+
process.BeginOutputReadLine();
45+
process.BeginErrorReadLine();
46+
//process.WaitForExit(waitTimeout);
47+
process.WaitForExit();
48+
}
49+
}
50+
51+
52+
private void Process_ErrorDataReceived(object sender, DataReceivedEventArgs e)
53+
{
54+
if (!String.IsNullOrEmpty(e.Data))
55+
{
56+
Console.Error.WriteLineAsync($"ERROR: {e.Data}");
57+
}
58+
}
59+
60+
private void Process_OutputDataReceived(object sender, DataReceivedEventArgs e)
61+
{
62+
if (e.Data == String.Empty
63+
|| e.Data == null)
64+
{
65+
return;
66+
}
67+
//if (e.Data.StartsWith("ID "))
68+
//{
69+
// //headerLine = e.Data;
70+
// return;
71+
//}
72+
string currentLine = e.Data;
73+
74+
var currentStart = currentLine.IndexOf("[") + 1;
75+
var currentEnd = currentLine.IndexOf("]");
76+
var errorStart = currentLine.IndexOf("[", currentEnd) + 1;
77+
var errorEnd = currentLine.LastIndexOf("]");
78+
79+
var taskElements = e.Data.Split(" ");
80+
var dockerTask = new DockerTask()
81+
{
82+
Id = taskElements[0],
83+
Name = taskElements[1],
84+
Image = taskElements[2],
85+
Node = taskElements[3],
86+
DesiredState = taskElements[4],
87+
CurrentState = currentLine.Substring(currentStart, currentEnd - currentStart),
88+
Error = currentLine.Substring(errorStart, errorEnd - errorStart)
89+
};
90+
91+
if (dockerTask.DesiredState == "Ready"
92+
|| dockerTask.DesiredState == "Running")
93+
{
94+
dockerTask.IsCurrent = true;
95+
}
96+
currentStackState.Tasks.Add(dockerTask);
97+
98+
//Console.Error.WriteLineAsync($"OUT: {e.Data}");
99+
//Console.Out.WriteLine(dockerTask.Id);
100+
//Console.Out.WriteLine($"{dockerTask.IsCurrent} {dockerTask.Name}");
101+
//Console.Out.WriteLine(dockerTask.Image);
102+
//Console.Out.WriteLine(dockerTask.Node);
103+
//Console.Out.WriteLine(dockerTask.DesiredState);
104+
//Console.Out.WriteLine(dockerTask.CurrentState);
105+
//Console.Out.WriteLine(dockerTask.Error);
106+
//Console.Out.WriteLine("");
107+
}
108+
}
109+
}

DockerTask.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
namespace StackDeployCheck
6+
{
7+
public class DockerTask
8+
{
9+
public string Id { get; internal set; }
10+
public string Name { get; internal set; }
11+
12+
public bool IsCurrent { get; internal set; }
13+
public string Image { get; internal set; }
14+
public string Node { get; internal set; }
15+
public string DesiredState { get; internal set; }
16+
public string CurrentState { get; internal set; }
17+
public string Error { get; internal set; }
18+
}
19+
}

Program.cs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
using System;
2+
using System.Diagnostics;
3+
using System.Timers;
4+
5+
namespace StackDeployCheck
6+
{
7+
class Program
8+
{
9+
static int Main(string[] args)
10+
{
11+
if (args.Length < 1)
12+
{
13+
Console.Error.WriteLine("dotnet stack-deploy-check {stackName} [waitTimeout]");
14+
return -1;
15+
}
16+
17+
var stackName = args[0];
18+
int timeout = 10000;
19+
if (args.Length > 1)
20+
{
21+
if (!int.TryParse(args[1], out timeout))
22+
{
23+
Console.Error.WriteLine("ERROR: Invalid timeout!");
24+
return -2;
25+
}
26+
timeout = timeout * 1000;
27+
}
28+
29+
Timer timer = new Timer(timeout);
30+
timer.Elapsed += Timer_Elapsed;
31+
timer.Start();
32+
33+
var stackChecker = new StackChecker()
34+
{
35+
StackName = stackName
36+
};
37+
stackChecker.AwaitDesiredStates();
38+
Console.Out.WriteLine("All stack tasks are running");
39+
40+
return 0;
41+
}
42+
43+
private static void Timer_Elapsed(object sender, ElapsedEventArgs e)
44+
{
45+
Console.Error.WriteLine("ERROR: Timed out waiting for desired state!");
46+
Environment.Exit(-3);
47+
}
48+
49+
}
50+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<!--
3+
https://go.microsoft.com/fwlink/?LinkID=208121.
4+
-->
5+
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
6+
<PropertyGroup>
7+
<PublishProtocol>FileSystem</PublishProtocol>
8+
<Configuration>Release</Configuration>
9+
<Platform>Any CPU</Platform>
10+
<TargetFramework>netcoreapp2.2</TargetFramework>
11+
<PublishDir>bin\Release\netcoreapp2.2\publish\</PublishDir>
12+
<SelfContained>false</SelfContained>
13+
<_IsPortable>true</_IsPortable>
14+
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
15+
</PropertyGroup>
16+
</Project>

Properties/launchSettings.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"profiles": {
3+
"stack-deploy-check": {
4+
"commandName": "Project",
5+
"commandLineArgs": "vsts"
6+
}
7+
}
8+
}

StackChecker.cs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
using System.Threading;
5+
6+
namespace StackDeployCheck
7+
{
8+
class StackChecker
9+
{
10+
public string StackName { get; set; }
11+
//public List<TaskState> DesiredStates { get; set; }
12+
13+
public bool AwaitDesiredStates()
14+
{
15+
var dockerClient = new DockerClient();
16+
while (true)
17+
{
18+
Console.Out.WriteLine($"Checking stack {StackName} for desired state...");
19+
var stackState = dockerClient.GetCurrentState(StackName);
20+
21+
var allTasksComplete = true;
22+
foreach (var task in stackState.Tasks)
23+
{
24+
if (!task.IsCurrent) continue;
25+
if (!task.CurrentState.StartsWith("Running"))
26+
{
27+
allTasksComplete = false;
28+
}
29+
Console.Out.WriteLine($"Task: {task.Name} State: {task.CurrentState} Image: {task.Image} Error: {task.Error}");
30+
}
31+
if (allTasksComplete)
32+
{
33+
return true;
34+
}
35+
Thread.Sleep(1000);
36+
}
37+
}
38+
}
39+
}

StackState.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using System.Collections.Generic;
2+
3+
namespace StackDeployCheck
4+
{
5+
public class StackState
6+
{
7+
public string StackName { get; set; }
8+
9+
public List<DockerTask> Tasks { get; set; }
10+
11+
public StackState()
12+
{
13+
Tasks = new List<DockerTask>();
14+
}
15+
}
16+
}

stack-deploy-check.csproj

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>netcoreapp2.2</TargetFramework>
6+
<RootNamespace>StackDeployCheck</RootNamespace>
7+
<Authors>NickHeap</Authors>
8+
<Company />
9+
</PropertyGroup>
10+
11+
</Project>

stack-deploy-check.csproj.user

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<PropertyGroup>
4+
<_LastSelectedProfileId>D:\workspaces\nickheap2\stack-deploy-check\Properties\PublishProfiles\FolderProfile.pubxml</_LastSelectedProfileId>
5+
</PropertyGroup>
6+
</Project>

stack-deploy-check.sln

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio Version 16
4+
VisualStudioVersion = 16.0.28803.352
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "stack-deploy-check", "stack-deploy-check.csproj", "{5BBA30D5-8776-49C9-89ED-7F6137FA0B80}"
7+
EndProject
8+
Global
9+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
10+
Debug|Any CPU = Debug|Any CPU
11+
Release|Any CPU = Release|Any CPU
12+
EndGlobalSection
13+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
14+
{5BBA30D5-8776-49C9-89ED-7F6137FA0B80}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15+
{5BBA30D5-8776-49C9-89ED-7F6137FA0B80}.Debug|Any CPU.Build.0 = Debug|Any CPU
16+
{5BBA30D5-8776-49C9-89ED-7F6137FA0B80}.Release|Any CPU.ActiveCfg = Release|Any CPU
17+
{5BBA30D5-8776-49C9-89ED-7F6137FA0B80}.Release|Any CPU.Build.0 = Release|Any CPU
18+
EndGlobalSection
19+
GlobalSection(SolutionProperties) = preSolution
20+
HideSolutionNode = FALSE
21+
EndGlobalSection
22+
GlobalSection(ExtensibilityGlobals) = postSolution
23+
SolutionGuid = {0F144E46-8ACD-463E-9208-6EA1C17A3FF1}
24+
EndGlobalSection
25+
EndGlobal

0 commit comments

Comments
 (0)