mamiya 0.0.1.alpha24 → 0.0.1.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +24 -18
  3. data/example/config.agent.rb +3 -0
  4. data/example/config.rb +27 -0
  5. data/example/deploy.rb +19 -11
  6. data/lib/mamiya/agent.rb +38 -2
  7. data/lib/mamiya/agent/actions.rb +4 -0
  8. data/lib/mamiya/agent/tasks/clean.rb +35 -0
  9. data/lib/mamiya/agent/tasks/notifyable.rb +4 -1
  10. data/lib/mamiya/agent/tasks/prepare.rb +2 -0
  11. data/lib/mamiya/agent/tasks/switch.rb +123 -0
  12. data/lib/mamiya/cli.rb +1 -20
  13. data/lib/mamiya/cli/client.rb +225 -3
  14. data/lib/mamiya/configuration.rb +18 -0
  15. data/lib/mamiya/master/agent_monitor.rb +19 -4
  16. data/lib/mamiya/master/agent_monitor_handlers.rb +10 -0
  17. data/lib/mamiya/master/application_status.rb +72 -0
  18. data/lib/mamiya/master/package_status.rb +178 -0
  19. data/lib/mamiya/master/web.rb +48 -44
  20. data/lib/mamiya/steps/build.rb +1 -1
  21. data/lib/mamiya/steps/prepare.rb +1 -1
  22. data/lib/mamiya/steps/switch.rb +2 -1
  23. data/lib/mamiya/storages/filesystem.rb +1 -1
  24. data/lib/mamiya/storages/mock.rb +1 -1
  25. data/lib/mamiya/storages/s3.rb +1 -1
  26. data/lib/mamiya/storages/s3_proxy.rb +1 -1
  27. data/lib/mamiya/version.rb +1 -1
  28. data/spec/agent/actions_spec.rb +26 -1
  29. data/spec/agent/tasks/clean_spec.rb +88 -2
  30. data/spec/agent/tasks/notifyable_spec.rb +3 -3
  31. data/spec/agent/tasks/switch_spec.rb +176 -0
  32. data/spec/agent_spec.rb +142 -1
  33. data/spec/configuration_spec.rb +23 -0
  34. data/spec/master/agent_monitor_spec.rb +128 -38
  35. data/spec/master/application_status_spec.rb +171 -0
  36. data/spec/master/package_status_spec.rb +560 -0
  37. data/spec/master/web_spec.rb +116 -1
  38. data/spec/steps/build_spec.rb +1 -1
  39. data/spec/steps/prepare_spec.rb +6 -1
  40. data/spec/steps/switch_spec.rb +6 -2
  41. data/spec/storages/filesystem_spec.rb +2 -21
  42. data/spec/storages/s3_proxy_spec.rb +2 -22
  43. data/spec/storages/s3_spec.rb +2 -20
  44. metadata +11 -2
@@ -0,0 +1,171 @@
1
+ require 'spec_helper'
2
+ require 'mamiya/master/application_status'
3
+
4
+ describe Mamiya::Master::ApplicationStatus do
5
+ let(:application) { 'myapp' }
6
+
7
+ let(:agent_statuses) do
8
+ {}
9
+ end
10
+
11
+ let(:agent_monitor) do
12
+ double('agent_monitor', statuses: agent_statuses)
13
+ end
14
+
15
+ subject(:status) { described_class.new(agent_monitor, application) }
16
+
17
+ describe "#participants" do
18
+ subject { status.participants }
19
+
20
+ let(:agent_statuses) do
21
+ {
22
+ 'agent1' => {
23
+ 'packages' => {'myapp' => [
24
+ ]},
25
+ 'queues' => {'fetch' => {
26
+ 'working' => nil,
27
+ 'queue' => [
28
+ ]
29
+ }}
30
+ },
31
+ 'agent2' => {
32
+ 'prereleases' => {'myapp' => [
33
+ ]},
34
+ 'queues' => {'fetch' => {
35
+ 'working' => nil,
36
+ 'queue' => [
37
+ ]
38
+ }}
39
+ },
40
+ 'agent3' => {
41
+ 'releases' => {'myapp' => [
42
+ ]},
43
+ 'queues' => {'fetch' => {
44
+ 'working' => nil,
45
+ 'queue' => [
46
+ ]
47
+ }}
48
+ },
49
+ 'agent4' => {
50
+ 'queues' => {'fetch' => {
51
+ 'working' => {'app' => 'myapp'},
52
+ 'queue' => [
53
+ ]
54
+ }}
55
+ },
56
+ 'agent5' => {
57
+ 'queues' => {'fetch' => {
58
+ 'working' => nil,
59
+ 'queue' => [
60
+ {'app' => 'myapp'},
61
+ ]
62
+ }}
63
+ },
64
+ 'agent6' => {
65
+ 'currents' => {'myapp' => 'pkg'},
66
+ 'queues' => {'fetch' => {
67
+ 'working' => nil,
68
+ 'queue' => [
69
+ {'app' => 'notmyapp'},
70
+ ]
71
+ }}
72
+ },
73
+ 'agent7' => {
74
+ 'queues' => {'fetch' => {
75
+ 'working' => nil,
76
+ 'queue' => [
77
+ {'app' => 'notmyapp'},
78
+ ]
79
+ }}
80
+ },
81
+ }
82
+ end
83
+
84
+ it "returns participants" do
85
+ expect(subject.keys.sort).to eq %w(agent1 agent2 agent3 agent4 agent5 agent6)
86
+ end
87
+ end
88
+
89
+ describe "#currents" do
90
+ subject { status.currents }
91
+
92
+ let(:agent_statuses) do
93
+ {
94
+ 'agent1' => {
95
+ 'currents' => {'myapp' => 'a'},
96
+ },
97
+ 'agent2' => {
98
+ 'currents' => {'myapp' => 'b'},
99
+ },
100
+ 'agent3' => {
101
+ 'currents' => {'myapp' => 'a'},
102
+ },
103
+ }
104
+ end
105
+
106
+ it { should eq('a' => %w(agent1 agent3), 'b' => %w(agent2)) }
107
+ end
108
+
109
+ describe "#major_current" do
110
+ subject { status.major_current }
111
+
112
+ let(:agent_statuses) do
113
+ {
114
+ 'agent1' => {
115
+ 'currents' => {'myapp' => 'a'},
116
+ },
117
+ 'agent2' => {
118
+ 'currents' => {'myapp' => 'b'},
119
+ },
120
+ 'agent3' => {
121
+ 'currents' => {'myapp' => 'a'},
122
+ },
123
+ }
124
+ end
125
+
126
+ it { should eq 'a' }
127
+ end
128
+
129
+ describe "#common_releases" do
130
+ subject { status.common_releases }
131
+
132
+ let(:agent_statuses) do
133
+ {
134
+ 'agent1' => {
135
+ 'releases' => {'myapp' => %w(a b c)},
136
+ },
137
+ 'agent2' => {
138
+ 'releases' => {'myapp' => %w(b c d e)},
139
+ },
140
+ 'agent3' => {
141
+ 'releases' => {'myapp' => %w(b c e)},
142
+ },
143
+ }
144
+ end
145
+
146
+ it { should eq %w(b c) }
147
+ end
148
+
149
+ describe "#common_previous_release" do
150
+ subject { status.common_previous_release }
151
+
152
+ let(:agent_statuses) do
153
+ {
154
+ 'agent1' => {
155
+ 'currents' => {'myapp' => 'c'},
156
+ 'releases' => {'myapp' => %w(a b c)},
157
+ },
158
+ 'agent2' => {
159
+ 'currents' => {'myapp' => 'c'},
160
+ 'releases' => {'myapp' => %w(b c d e)},
161
+ },
162
+ 'agent3' => {
163
+ 'currents' => {'myapp' => 'b'},
164
+ 'releases' => {'myapp' => %w(b c e)},
165
+ },
166
+ }
167
+ end
168
+
169
+ it { should eq ?b }
170
+ end
171
+ end
@@ -0,0 +1,560 @@
1
+ require 'spec_helper'
2
+ require 'mamiya/master/package_status'
3
+
4
+ describe Mamiya::Master::PackageStatus do
5
+ let(:application) { 'myapp' }
6
+ let(:package) { 'mypackage' }
7
+
8
+ let(:agent_statuses) do
9
+ {}
10
+ end
11
+
12
+ let(:agent_monitor) do
13
+ double('agent_monitor', statuses: agent_statuses)
14
+ end
15
+
16
+ subject(:status) { described_class.new(agent_monitor, application, package) }
17
+
18
+ # TODO: FIXME: Add test to confirm ignoring master node
19
+
20
+ describe "#status" do
21
+ subject { status.status }
22
+
23
+ context "if there's fetching agents" do
24
+ let(:agent_statuses) do
25
+ {
26
+ 'agent1' => {
27
+ 'packages' => {'myapp' => [
28
+ ]},
29
+ 'queues' => {'fetch' => {
30
+ 'working' => {
31
+ 'task' => 'fetch',
32
+ 'app' => 'myapp',
33
+ 'pkg' => 'mypackage'
34
+ },
35
+ 'queue' => [
36
+ ]
37
+ }}
38
+ },
39
+ 'agent2' => {
40
+ 'packages' => {'myapp' => [
41
+ 'mypackage',
42
+ ]},
43
+ 'queues' => {'fetch' => {
44
+ 'working' => nil,
45
+ 'queue' => [
46
+ ]
47
+ }}
48
+ }
49
+ }
50
+ end
51
+
52
+ it { should include(:distributing) }
53
+ it { should include(:partially_distributed) }
54
+ end
55
+
56
+ context "if there's queued agents" do
57
+ let(:agent_statuses) do
58
+ {
59
+ 'agent1' => {
60
+ 'packages' => {'myapp' => [
61
+ ]},
62
+ 'queues' => {'fetch' => {
63
+ 'working' => nil,
64
+ 'queue' => [
65
+ {
66
+ 'task' => 'fetch',
67
+ 'app' => 'myapp',
68
+ 'pkg' => 'mypackage'
69
+ }
70
+ ]
71
+ }}
72
+ },
73
+ 'agent2' => {
74
+ 'packages' => {'myapp' => [
75
+ 'mypackage',
76
+ ]},
77
+ 'queues' => {'fetch' => {
78
+ 'working' => nil,
79
+ 'queue' => [
80
+ ]
81
+ }}
82
+ }
83
+ }
84
+ end
85
+
86
+ it { should include(:distributing) }
87
+ it { should include(:partially_distributed) }
88
+ end
89
+
90
+ context "if any agents have the package" do
91
+ let(:agent_statuses) do
92
+ {
93
+ 'agent1' => {
94
+ 'packages' => {'myapp' => [
95
+ 'mypackage',
96
+ ]},
97
+ 'queues' => {'fetch' => {
98
+ 'working' => nil,
99
+ 'queue' => [
100
+ ]
101
+ }},
102
+ },
103
+ 'agent2' => {
104
+ 'packages' => {'myapp' => [
105
+ ]},
106
+ 'queues' => {'fetch' => {
107
+ 'working' => nil,
108
+ 'queue' => [
109
+ ]
110
+ }}
111
+ }
112
+ }
113
+ end
114
+
115
+ it { should include(:partially_distributed) }
116
+ end
117
+
118
+ context "if all agents have the package" do
119
+ let(:agent_statuses) do
120
+ {
121
+ 'agent1' => {
122
+ 'packages' => {'myapp' => [
123
+ 'mypackage',
124
+ ]},
125
+ 'queues' => {'fetch' => {
126
+ 'working' => nil,
127
+ 'queue' => [
128
+ ]
129
+ }},
130
+ },
131
+ 'agent2' => {
132
+ 'packages' => {'myapp' => [
133
+ 'mypackage',
134
+ ]},
135
+ 'queues' => {'fetch' => {
136
+ 'working' => nil,
137
+ 'queue' => [
138
+ ]
139
+ }}
140
+ }
141
+ }
142
+ end
143
+
144
+ it { should include(:distributed) }
145
+ end
146
+
147
+ context "if no agents relate to the package" do
148
+ let(:agent_statuses) do
149
+ {
150
+ 'agent1' => {
151
+ 'packages' => {'myapp' => [
152
+ ]},
153
+ 'queues' => {'fetch' => {
154
+ 'working' => nil,
155
+ 'queue' => [
156
+ ]
157
+ }},
158
+ },
159
+ 'agent2' => {
160
+ 'packages' => {'myapp' => [
161
+ ]},
162
+ 'queues' => {'fetch' => {
163
+ 'working' => nil,
164
+ 'queue' => [
165
+ ]
166
+ }}
167
+ }
168
+ }
169
+ end
170
+
171
+ it { should eq [:unknown] }
172
+ end
173
+ end
174
+
175
+ describe "#fetch_queued_agents" do
176
+ let(:agent_statuses) do
177
+ {
178
+ 'agent1' => {
179
+ 'packages' => {'myapp' => [
180
+ ]},
181
+ 'queues' => {'fetch' => {
182
+ 'working' => {
183
+ 'task' => 'fetch',
184
+ 'app' => 'myapp',
185
+ 'pkg' => 'anotherpackage',
186
+ },
187
+ 'queue' => [
188
+ {
189
+ 'task' => 'fetch',
190
+ 'app' => 'myapp',
191
+ 'pkg' => 'mypackage',
192
+ }
193
+ ]
194
+ }},
195
+ },
196
+ 'agent2' => {
197
+ 'packages' => {'myapp' => [
198
+ 'mypackage'
199
+ ]},
200
+ 'queues' => {'fetch' => {
201
+ 'working' => nil,
202
+ 'queue' => [
203
+ ]
204
+ }}
205
+ }
206
+ }
207
+ end
208
+
209
+ it "returns queued agents" do
210
+ expect(status.fetch_queued_agents).to eq %w(agent1)
211
+ end
212
+ end
213
+
214
+ describe "#fetching_agents" do
215
+ let(:agent_statuses) do
216
+ {
217
+ 'agent1' => {
218
+ 'packages' => {'myapp' => [
219
+ ]},
220
+ 'queues' => {'fetch' => {
221
+ 'working' => {
222
+ 'task' => 'fetch',
223
+ 'app' => 'myapp',
224
+ 'pkg' => 'mypackage',
225
+ },
226
+ 'queue' => [
227
+ ]
228
+ }},
229
+ },
230
+ 'agent2' => {
231
+ 'packages' => {'myapp' => [
232
+ 'mypackage'
233
+ ]},
234
+ 'queues' => {'fetch' => {
235
+ 'working' => nil,
236
+ 'queue' => [
237
+ ]
238
+ }}
239
+ }
240
+ }
241
+ end
242
+
243
+ it "returns fetching agents" do
244
+ expect(status.fetching_agents).to eq %w(agent1)
245
+ end
246
+ end
247
+
248
+ describe "#fetched_agents" do
249
+ let(:agent_statuses) do
250
+ {
251
+ 'agent1' => {
252
+ 'packages' => {'myapp' => [
253
+ ]},
254
+ 'queues' => {'fetch' => {
255
+ 'working' => {
256
+ 'task' => 'fetch',
257
+ 'app' => 'myapp',
258
+ 'pkg' => 'mypackage',
259
+ },
260
+ 'queue' => [
261
+ ]
262
+ }},
263
+ },
264
+ 'agent2' => {
265
+ 'packages' => {'myapp' => [
266
+ 'mypackage'
267
+ ]},
268
+ 'queues' => {'fetch' => {
269
+ 'working' => nil,
270
+ 'queue' => [
271
+ ]
272
+ }}
273
+ }
274
+ }
275
+ end
276
+
277
+ it "returns fetched agents" do
278
+ expect(status.fetched_agents).to eq %w(agent2)
279
+ end
280
+ end
281
+
282
+ ###
283
+
284
+ describe "#prepare_queued_agents" do
285
+ let(:agent_statuses) do
286
+ {
287
+ 'agent1' => {
288
+ 'packages' => {'myapp' => [
289
+ 'mypackage'
290
+ ]},
291
+ 'queues' => {'prepare' => {
292
+ 'working' => {
293
+ 'task' => 'prepare',
294
+ 'app' => 'myapp',
295
+ 'pkg' => 'anotherpackage',
296
+ },
297
+ 'queue' => [
298
+ {
299
+ 'task' => 'prepare',
300
+ 'app' => 'myapp',
301
+ 'pkg' => 'mypackage',
302
+ }
303
+ ]
304
+ }},
305
+ },
306
+ 'agent2' => {
307
+ 'packages' => {'myapp' => [
308
+ 'mypackage'
309
+ ]},
310
+ 'queues' => {'prepare' => {
311
+ 'working' => nil,
312
+ 'queue' => [
313
+ ]
314
+ }}
315
+ }
316
+ }
317
+ end
318
+
319
+ it "returns queued agents" do
320
+ expect(status.prepare_queued_agents).to eq %w(agent1)
321
+ end
322
+ end
323
+
324
+ describe "#preparing_agents" do
325
+ let(:agent_statuses) do
326
+ {
327
+ 'agent1' => {
328
+ 'packages' => {'myapp' => [
329
+ 'mypackage'
330
+ ]},
331
+ 'queues' => {'prepare' => {
332
+ 'working' => {
333
+ 'task' => 'prepare',
334
+ 'app' => 'myapp',
335
+ 'pkg' => 'mypackage',
336
+ },
337
+ 'queue' => [
338
+ ]
339
+ }},
340
+ },
341
+ 'agent2' => {
342
+ 'packages' => {'myapp' => [
343
+ 'mypackage'
344
+ ]},
345
+ 'queues' => {'prepare' => {
346
+ 'working' => nil,
347
+ 'queue' => [
348
+ ]
349
+ }}
350
+ }
351
+ }
352
+ end
353
+
354
+ it "returns preparing agents" do
355
+ expect(status.preparing_agents).to eq %w(agent1)
356
+ end
357
+ end
358
+
359
+ describe "#prepared_agents" do
360
+ let(:agent_statuses) do
361
+ {
362
+ 'agent1' => {
363
+ 'packages' => {'myapp' => [
364
+ 'mypackage'
365
+ ]},
366
+ 'queues' => {'prepare' => {
367
+ 'working' => {
368
+ 'task' => 'prepare',
369
+ 'app' => 'myapp',
370
+ 'pkg' => 'mypackage',
371
+ },
372
+ 'queue' => [
373
+ ]
374
+ }},
375
+ },
376
+ 'agent2' => {
377
+ 'packages' => {'myapp' => [
378
+ 'mypackage'
379
+ ]},
380
+ 'prereleases' => {'myapp' => [
381
+ 'mypackage'
382
+ ]},
383
+ 'queues' => {'prepare' => {
384
+ 'working' => nil,
385
+ 'queue' => [
386
+ ]
387
+ }}
388
+ }
389
+ }
390
+ end
391
+
392
+ it "returns prepared agents" do
393
+ expect(status.prepared_agents).to eq %w(agent2)
394
+ end
395
+ end
396
+
397
+ ###
398
+
399
+ describe "#switch_queued_agents" do
400
+ let(:agent_statuses) do
401
+ {
402
+ 'agent1' => {
403
+ 'packages' => {'myapp' => [
404
+ 'mypackage'
405
+ ]},
406
+ 'prereleases' => {'myapp' => [
407
+ 'mypackage'
408
+ ]},
409
+ 'queues' => {'switch' => {
410
+ 'working' => {
411
+ 'task' => 'switch',
412
+ 'app' => 'myapp',
413
+ 'pkg' => 'anotherpackage',
414
+ },
415
+ 'queue' => [
416
+ {
417
+ 'task' => 'switch',
418
+ 'app' => 'myapp',
419
+ 'pkg' => 'mypackage',
420
+ }
421
+ ]
422
+ }},
423
+ },
424
+ 'agent2' => {
425
+ 'packages' => {'myapp' => [
426
+ 'mypackage'
427
+ ]},
428
+ 'prereleases' => {'myapp' => [
429
+ 'mypackage'
430
+ ]},
431
+ 'queues' => {'switch' => {
432
+ 'working' => nil,
433
+ 'queue' => [
434
+ ]
435
+ }}
436
+ }
437
+ }
438
+ end
439
+
440
+ it "returns queued agents" do
441
+ expect(status.switch_queued_agents).to eq %w(agent1)
442
+ end
443
+ end
444
+
445
+ describe "#switching_agents" do
446
+ let(:agent_statuses) do
447
+ {
448
+ 'agent1' => {
449
+ 'packages' => {'myapp' => [
450
+ 'mypackage'
451
+ ]},
452
+ 'prereleases' => {'myapp' => [
453
+ 'mypackage'
454
+ ]},
455
+ 'queues' => {'switch' => {
456
+ 'working' => {
457
+ 'task' => 'switch',
458
+ 'app' => 'myapp',
459
+ 'pkg' => 'mypackage',
460
+ },
461
+ 'queue' => [
462
+ ]
463
+ }},
464
+ },
465
+ 'agent2' => {
466
+ 'packages' => {'myapp' => [
467
+ 'mypackage'
468
+ ]},
469
+ 'prereleases' => {'myapp' => [
470
+ 'mypackage'
471
+ ]},
472
+ 'queues' => {'switch' => {
473
+ 'working' => nil,
474
+ 'queue' => [
475
+ ]
476
+ }}
477
+ }
478
+ }
479
+ end
480
+
481
+ it "returns switching agents" do
482
+ expect(status.switching_agents).to eq %w(agent1)
483
+ end
484
+ end
485
+
486
+ describe "#current_agents" do
487
+ let(:agent_statuses) do
488
+ {
489
+ 'agent1' => {
490
+ 'packages' => {'myapp' => [
491
+ 'mypackage'
492
+ ]},
493
+ 'prereleases' => {'myapp' => [
494
+ 'mypackage'
495
+ ]},
496
+ 'currents' => {'myapp' => 'prevpkg'},
497
+ 'queues' => {'switch' => {
498
+ 'working' => {
499
+ 'task' => 'switch',
500
+ 'app' => 'myapp',
501
+ 'pkg' => 'mypackage',
502
+ },
503
+ 'queue' => [
504
+ ]
505
+ }},
506
+ },
507
+ 'agent2' => {
508
+ 'packages' => {'myapp' => [
509
+ 'mypackage'
510
+ ]},
511
+ 'prereleases' => {'myapp' => [
512
+ 'mypackage'
513
+ ]},
514
+ 'currents' => {'myapp' => 'mypackage'},
515
+ 'queues' => {'switch' => {
516
+ 'working' => nil,
517
+ 'queue' => [
518
+ ]
519
+ }}
520
+ }
521
+ }
522
+ end
523
+
524
+ it "returns current agents" do
525
+ expect(status.current_agents).to eq %w(agent2)
526
+ end
527
+ end
528
+
529
+ ###
530
+
531
+ describe "#non_participants" do
532
+ let(:agent_statuses) do
533
+ {
534
+ 'agent1' => {
535
+ 'packages' => {'myapp' => [
536
+ ]},
537
+ 'queues' => {'fetch' => {
538
+ 'working' => nil,
539
+ 'queue' => [
540
+ ]
541
+ }},
542
+ },
543
+ 'agent2' => {
544
+ 'packages' => {'myapp' => [
545
+ 'mypackage'
546
+ ]},
547
+ 'queues' => {'fetch' => {
548
+ 'working' => nil,
549
+ 'queue' => [
550
+ ]
551
+ }}
552
+ }
553
+ }
554
+ end
555
+
556
+ it "returns non participants" do
557
+ expect(status.non_participants).to eq %w(agent1)
558
+ end
559
+ end
560
+ end