1
1
using System ;
2
2
using System . Collections . Generic ;
3
3
using System . Diagnostics ;
4
+ using System . Linq ;
4
5
using System . Text ;
5
6
6
7
namespace StackDeployCheck
@@ -16,14 +17,32 @@ public StackState GetCurrentState(string stackName)
16
17
} ;
17
18
18
19
GetStackTasks ( stackName ) ;
20
+ GetStackServices ( stackName ) ;
21
+
22
+ foreach ( var service in currentStackState . Services )
23
+ {
24
+ GetServiceStates ( service . Name ) ;
25
+ }
26
+
19
27
20
28
return currentStackState ;
21
29
}
22
30
23
- public void GetStackTasks ( string stackName )
31
+ private void GetServiceStates ( string serviceName )
24
32
{
25
- var formatString = "{{.ID}} {{.Name}} {{.Image}} {{.Node}} {{.DesiredState}} [{{.CurrentState}}] [{{.Error}}]" ;
26
- ProcessStartInfo processStartInfo = new ProcessStartInfo ( "docker" , $ "stack ps { stackName } --no-trunc --format \" { formatString } \" ")
33
+ var formatString = "{{.Spec.Name}} " +
34
+ "{{if not .UpdateStatus}}" +
35
+ "NotUpdated" +
36
+ "{{else}}" +
37
+ "{{if eq .UpdateStatus.State \\ \" rollback_started\\ \" }}" +
38
+ "RollbackStarted" +
39
+ "{{else if eq .UpdateStatus.State \\ \" rollback_completed\\ \" }}" +
40
+ "RollbackCompleted" +
41
+ "{{else}}" +
42
+ "{{.UpdateStatus.State}}" +
43
+ "{{end}}" +
44
+ "{{end}}" ;
45
+ ProcessStartInfo processStartInfo = new ProcessStartInfo ( "docker" , $ "service inspect { serviceName } --format \" { formatString } \" ")
27
46
{
28
47
RedirectStandardError = true ,
29
48
RedirectStandardOutput = true ,
@@ -37,7 +56,7 @@ public void GetStackTasks(string stackName)
37
56
EnableRaisingEvents = true
38
57
} )
39
58
{
40
- process . OutputDataReceived += Process_OutputDataReceived ;
59
+ process . OutputDataReceived += Process_OutputServiceStateDataReceived ;
41
60
process . ErrorDataReceived += Process_ErrorDataReceived ;
42
61
//process.Exited += Process_Exited;
43
62
process . Start ( ) ;
@@ -48,53 +67,139 @@ public void GetStackTasks(string stackName)
48
67
}
49
68
}
50
69
70
+ private void Process_OutputServiceStateDataReceived ( object sender , DataReceivedEventArgs e )
71
+ {
72
+ if ( e . Data == String . Empty
73
+ || e . Data == null )
74
+ {
75
+ return ;
76
+ }
77
+
78
+ string currentLine = e . Data ;
51
79
52
- private void Process_ErrorDataReceived ( object sender , DataReceivedEventArgs e )
80
+ if ( currentLine . StartsWith ( "Status: Template parsing error" , StringComparison . InvariantCultureIgnoreCase ) )
81
+ {
82
+ return ;
83
+ }
84
+
85
+ var serviceStateElements = currentLine . Split ( " " ) ;
86
+ if ( serviceStateElements . Length < 2 )
87
+ {
88
+ return ;
89
+ }
90
+
91
+ // "{{.Spec.Name}} {{.UpdateStatus.State}} {{.UpdateStatus.CompletedAt}} {{.UpdateStatus.Message}}";
92
+
93
+ string name = serviceStateElements [ 0 ] ;
94
+ string state = serviceStateElements [ 1 ] ;
95
+
96
+ if ( state . Equals ( "completed_rollback" ) )
97
+ {
98
+ state = "RolledBack" ;
99
+ }
100
+
101
+ var service = currentStackState . Services . FirstOrDefault < DockerService > ( ds => ds . Name == name ) ;
102
+ if ( service != null )
103
+ {
104
+ UpdateState updateState ;
105
+ if ( Enum . TryParse < UpdateState > ( state , true , out updateState ) )
106
+ {
107
+ service . UpdateState = updateState ;
108
+ }
109
+ else
110
+ {
111
+ Console . Error . WriteLine ( $ "ERROR: unable to parse service update state { state } ") ;
112
+ service . UpdateState = UpdateState . Unknown ;
113
+ }
114
+ }
115
+ }
116
+
117
+ public void GetStackTasks ( string stackName )
53
118
{
54
- if ( ! String . IsNullOrEmpty ( e . Data ) )
119
+ var formatString = "{{.ID}}{{\\ \" \\ x00\\ \" }}{{.Name}}{{\\ \" \\ x00\\ \" }}{{.Image}}{{\\ \" \\ x00\\ \" }}{{.Node}}{{\\ \" \\ x00\\ \" }}{{.DesiredState}}{{\\ \" \\ x00\\ \" }}{{.CurrentState}}{{\\ \" \\ x00\\ \" }}{{.Error}}" ;
120
+ ProcessStartInfo processStartInfo = new ProcessStartInfo ( "docker" , $ "stack ps { stackName } --no-trunc --format \" { formatString } \" ")
121
+ {
122
+ RedirectStandardError = true ,
123
+ RedirectStandardOutput = true ,
124
+ RedirectStandardInput = true ,
125
+ UseShellExecute = false ,
126
+ CreateNoWindow = true
127
+ } ;
128
+ using ( Process process = new Process ( )
129
+ {
130
+ StartInfo = processStartInfo ,
131
+ EnableRaisingEvents = true
132
+ } )
55
133
{
56
- Console . Error . WriteLineAsync ( $ "ERROR: { e . Data } ") ;
134
+ process . OutputDataReceived += Process_OutputTasksDataReceived ;
135
+ process . ErrorDataReceived += Process_ErrorDataReceived ;
136
+ //process.Exited += Process_Exited;
137
+ process . Start ( ) ;
138
+ process . BeginOutputReadLine ( ) ;
139
+ process . BeginErrorReadLine ( ) ;
140
+ //process.WaitForExit(waitTimeout);
141
+ process . WaitForExit ( ) ;
57
142
}
58
143
}
59
144
60
- private void Process_OutputDataReceived ( object sender , DataReceivedEventArgs e )
145
+ private void Process_OutputTasksDataReceived ( object sender , DataReceivedEventArgs e )
61
146
{
62
147
if ( e . Data == String . Empty
63
148
|| e . Data == null )
64
149
{
65
150
return ;
66
151
}
67
- //if (e.Data.StartsWith("ID "))
68
- //{
69
- // //headerLine = e.Data;
70
- // return;
71
- //}
72
- string currentLine = e . Data ;
73
152
74
- var currentStart = currentLine . IndexOf ( "[" ) + 1 ;
75
- var currentEnd = currentLine . IndexOf ( "]" ) ;
76
- var errorStart = currentLine . IndexOf ( "[" , currentEnd ) + 1 ;
77
- var errorEnd = currentLine . LastIndexOf ( "]" ) ;
153
+ var taskElements = e . Data . Split ( '\x00 ' ) ;
154
+ if ( taskElements . Length < 7 )
155
+ {
156
+ return ;
157
+ }
78
158
79
- var taskElements = e . Data . Split ( " " ) ;
80
159
var dockerTask = new DockerTask ( )
81
160
{
82
161
Id = taskElements [ 0 ] ,
83
162
Name = taskElements [ 1 ] ,
84
163
Image = taskElements [ 2 ] ,
85
164
Node = taskElements [ 3 ] ,
86
- DesiredState = taskElements [ 4 ] ,
87
- CurrentState = currentLine . Substring ( currentStart , currentEnd - currentStart ) ,
88
- Error = currentLine . Substring ( errorStart , errorEnd - errorStart )
165
+ Error = taskElements [ 6 ]
89
166
} ;
167
+ dockerTask . SetDesiredState ( taskElements [ 4 ] ) ;
168
+ dockerTask . SetCurrentState ( taskElements [ 5 ] ) ;
90
169
91
- if ( dockerTask . DesiredState == "Ready"
92
- || dockerTask . DesiredState == "Running" )
93
- {
94
- dockerTask . IsCurrent = true ;
95
- }
96
170
currentStackState . Tasks . Add ( dockerTask ) ;
97
171
172
+ //if (e.Data.StartsWith("ID "))
173
+ //{
174
+ // //headerLine = e.Data;
175
+ // return;
176
+ //}
177
+ //string currentLine = e.Data;
178
+
179
+ //var currentStart = currentLine.IndexOf("[") + 1;
180
+ //var currentEnd = currentLine.IndexOf("]");
181
+ //var errorStart = currentLine.IndexOf("[", currentEnd) + 1;
182
+ //var errorEnd = currentLine.LastIndexOf("]");
183
+
184
+ //var taskElements = e.Data.Split(" ");
185
+ //if (taskElements.Length < 5)
186
+ //{
187
+ // return;
188
+ //}
189
+
190
+ //var dockerTask = new DockerTask()
191
+ //{
192
+ // Id = taskElements[0],
193
+ // Name = taskElements[1],
194
+ // Image = taskElements[2],
195
+ // Node = taskElements[3],
196
+ // Error = currentLine.Substring(errorStart, errorEnd - errorStart)
197
+ //};
198
+ //dockerTask.SetDesiredState(taskElements[4]);
199
+ //dockerTask.SetCurrentState(currentLine.Substring(currentStart, currentEnd - currentStart));
200
+
201
+ //currentStackState.Tasks.Add(dockerTask);
202
+
98
203
//Console.Error.WriteLineAsync($"OUT: {e.Data}");
99
204
//Console.Out.WriteLine(dockerTask.Id);
100
205
//Console.Out.WriteLine($"{dockerTask.IsCurrent} {dockerTask.Name}");
@@ -103,7 +208,77 @@ private void Process_OutputDataReceived(object sender, DataReceivedEventArgs e)
103
208
//Console.Out.WriteLine(dockerTask.DesiredState);
104
209
//Console.Out.WriteLine(dockerTask.CurrentState);
105
210
//Console.Out.WriteLine(dockerTask.Error);
106
- //Console.Out.WriteLine("");
211
+ //Console.Out.WriteLine("--------------------------------------------------");
212
+ }
213
+ public void GetStackServices ( string stackName )
214
+ {
215
+ var formatString = "{{.ID}}{{\\ \" \\ x00\\ \" }}{{.Name}}{{\\ \" \\ x00\\ \" }}{{.Mode}}{{\\ \" \\ x00\\ \" }}{{.Replicas}}{{\\ \" \\ x00\\ \" }}{{.Image}}{{\\ \" \\ x00\\ \" }}{{.Ports}}" ;
216
+ ProcessStartInfo processStartInfo = new ProcessStartInfo ( "docker" , $ "stack services { stackName } --format \" { formatString } \" ")
217
+ {
218
+ RedirectStandardError = true ,
219
+ RedirectStandardOutput = true ,
220
+ RedirectStandardInput = true ,
221
+ UseShellExecute = false ,
222
+ CreateNoWindow = true
223
+ } ;
224
+ using ( Process process = new Process ( )
225
+ {
226
+ StartInfo = processStartInfo ,
227
+ EnableRaisingEvents = true
228
+ } )
229
+ {
230
+ process . OutputDataReceived += Process_OutputServicesDataReceived ;
231
+ process . ErrorDataReceived += Process_ErrorDataReceived ;
232
+ //process.Exited += Process_Exited;
233
+ process . Start ( ) ;
234
+ process . BeginOutputReadLine ( ) ;
235
+ process . BeginErrorReadLine ( ) ;
236
+ //process.WaitForExit(waitTimeout);
237
+ process . WaitForExit ( ) ;
238
+ }
239
+
240
+ //
107
241
}
242
+
243
+ private void Process_OutputServicesDataReceived ( object sender , DataReceivedEventArgs e )
244
+ {
245
+ if ( e . Data == String . Empty
246
+ || e . Data == null )
247
+ {
248
+ return ;
249
+ }
250
+ string currentLine = e . Data ;
251
+ var serviceElements = currentLine . Split ( "\x00 " ) ;
252
+ if ( serviceElements . Length < 6 )
253
+ {
254
+ return ;
255
+ }
256
+
257
+ var dockerService = new DockerService ( )
258
+ {
259
+ Id = serviceElements [ 0 ] ,
260
+ Name = serviceElements [ 1 ] ,
261
+ Mode = serviceElements [ 2 ] ,
262
+ Image = serviceElements [ 4 ] ,
263
+ Ports = serviceElements [ 5 ]
264
+ } ;
265
+ dockerService . SetReplicas ( serviceElements [ 3 ] ) ;
266
+ currentStackState . Services . Add ( dockerService ) ;
267
+ }
268
+ private void Process_ErrorDataReceived ( object sender , DataReceivedEventArgs e )
269
+ {
270
+ if ( ! String . IsNullOrEmpty ( e . Data ) )
271
+ {
272
+ // don't log if no tasks found
273
+ if ( e . Data . StartsWith ( "nothing found in stack" , StringComparison . InvariantCultureIgnoreCase )
274
+ || e . Data . StartsWith ( "Status: Template parsing error: template: :1:30: executing" , StringComparison . InvariantCultureIgnoreCase ) )
275
+ {
276
+ return ;
277
+ }
278
+ Console . Out . WriteLineAsync ( $ "ERROR FROM DOCKER: { e . Data } ") ;
279
+ }
280
+ }
281
+
282
+
108
283
}
109
284
}
0 commit comments