tools-cf-plugin 2.1.1 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -44,9 +44,6 @@ module CFTools::Tunnel
44
44
  tunnel_to(nats["address"], nats["port"], gateway)
45
45
  end
46
46
 
47
- line "port: #{nport}"
48
- line "creds: #{nats}"
49
-
50
47
  with_progress("Logging in as admin user") do
51
48
  login_as_admin(manifest)
52
49
  end
@@ -1,3 +1,3 @@
1
1
  module CFTools
2
- VERSION = "2.1.1".freeze
2
+ VERSION = "2.2.0".freeze
3
3
  end
@@ -3,17 +3,18 @@ require "nats/client"
3
3
 
4
4
  module CFTools
5
5
  class Watch < CF::App::Base
6
- def precondition
7
- check_target
8
- end
6
+ def precondition; end
9
7
 
10
8
  REPLY_PREFIX = "`- reply to "
11
9
  COLUMN_WIDTH = 30
12
10
 
13
11
  desc "Watch messages going over NATS relevant to an application"
14
12
  group :admin
15
- input :app, :argument => :optional, :from_given => by_name(:app),
13
+ input :app, :argument => :optional, :from_given => by_name(:apps),
16
14
  :desc => "Application to watch"
15
+ input :subjects, :aliases => %w[-s --subject],
16
+ :from_given => proc { |s| s.split(",") },
17
+ :desc => "NATS subject to subscribe to"
17
18
  input :host, :alias => "-h", :default => "127.0.0.1",
18
19
  :desc => "NATS server address"
19
20
  input :port, :alias => "-P", :default => 4222, :type => :integer,
@@ -23,11 +24,12 @@ module CFTools
23
24
  input :password, :alias => "-p", :default => "nats",
24
25
  :desc => "NATS server password"
25
26
  def watch
26
- app = input[:app]
27
+ app = get_app(input[:app])
27
28
  host = input[:host]
28
29
  port = input[:port]
29
30
  user = input[:user]
30
31
  pass = input[:password]
32
+ subjects = input[:subjects] || [">"]
31
33
 
32
34
  @requests = {}
33
35
  @seen_apps = {}
@@ -35,7 +37,7 @@ module CFTools
35
37
 
36
38
  $stdout.sync = true
37
39
 
38
- watching_nats("nats://#{user}:#{pass}@#{host}:#{port}") do |msg, reply, sub|
40
+ watching_nats("nats://#{user}:#{pass}@#{host}:#{port}", subjects) do |msg, reply, sub|
39
41
  begin
40
42
  if @requests.include?(sub)
41
43
  process_response(sub, reply, msg, app)
@@ -65,7 +67,7 @@ module CFTools
65
67
  def process_message(sub, reply, msg, app)
66
68
  register_request(sub, reply) if reply
67
69
 
68
- payload = JSON.parse(msg) # rescue msg
70
+ payload = JSON.parse(msg) rescue msg
69
71
 
70
72
  case sub
71
73
  when "dea.advertise"
@@ -81,7 +83,6 @@ module CFTools
81
83
  when "router.start"
82
84
  sub, payload = pretty_router_start(sub, payload)
83
85
  when "router.register"
84
- return if !app && payload.has_key?("dea")
85
86
  sub, payload = pretty_register(sub, payload)
86
87
  when "router.unregister"
87
88
  sub, payload = pretty_unregister(sub, payload)
@@ -101,8 +102,10 @@ module CFTools
101
102
  sub, payload = pretty_healthmanager_health(sub, payload)
102
103
  when "dea.shutdown"
103
104
  sub, payload = pretty_dea_shutdown(sub, payload)
104
- when /^cloudcontrollers\.hm\.requests\.\w+$/
105
- sub, payload = process_cloudcontrollers_hm_request(payload)
105
+ when "health.start"
106
+ sub, payload = pretty_health_start(sub, payload)
107
+ when "health.stop"
108
+ sub, payload = pretty_health_stop(sub, payload)
106
109
  when /^([^.]+)\.announce$/
107
110
  sub, payload = pretty_service_announcement(sub, payload)
108
111
  when "vcap.component.announce"
@@ -168,13 +171,13 @@ module CFTools
168
171
  [ c(sub, :bad),
169
172
  [ "app: #{pretty_app(payload["droplet"])}",
170
173
  "reason: #{payload["reason"]}",
171
- "index: #{payload["index"]}"
174
+ "index: #{payload["index"]}",
175
+ "version: #{pretty_version(payload["version"])}"
172
176
  ].join(", ")
173
177
  ]
174
178
  end
175
179
 
176
180
  def pretty_heartbeat(sub, payload, app)
177
-
178
181
  dea, _ = payload["dea"].split("-", 2)
179
182
 
180
183
  states = Hash.new(0)
@@ -233,7 +236,8 @@ module CFTools
233
236
  [ "app: #{pretty_app(payload["droplet"])}",
234
237
  "dea: #{dea}",
235
238
  "index: #{payload["index"]}",
236
- "uris: #{list(payload["uris"])}"
239
+ "version: #{pretty_version(payload["version"])}",
240
+ "uris: #{list(Array(payload["uris"]))}"
237
241
  ].join(", ")
238
242
  ]
239
243
  end
@@ -241,6 +245,10 @@ module CFTools
241
245
  def pretty_stop(sub, payload)
242
246
  message = ["app: #{pretty_app(payload["droplet"])}"]
243
247
 
248
+ if (version = payload["version"])
249
+ message << "version: #{pretty_version(version)}"
250
+ end
251
+
244
252
  if (indices = payload["indices"])
245
253
  message << "scaling down indices: #{indices.join(", ")}"
246
254
  elsif (instances = payload["instances"])
@@ -261,10 +269,14 @@ module CFTools
261
269
  end
262
270
 
263
271
  def pretty_find_droplet(sub, payload)
264
- states = payload["states"].collect { |s| c(s.downcase, state_color(s))}
272
+ states = (payload["states"] || []).collect do |s|
273
+ c(s.downcase, state_color(s))
274
+ end
275
+
265
276
  [ d(sub),
266
277
  [ "app: #{pretty_app(payload["droplet"])}",
267
- "querying states: #{states.join(", ")}"
278
+ "version: #{pretty_version(payload["version"])}",
279
+ "querying states: #{list(states)}"
268
280
  ].join(", ")
269
281
  ]
270
282
  end
@@ -273,20 +285,25 @@ module CFTools
273
285
  dea, _ = payload["dea"].split("-", 2)
274
286
  index = payload["index"]
275
287
  state = payload["state"]
276
- time = Time.at(payload["state_timestamp"])
288
+ version = payload["version"]
289
+ since = Time.at(payload["state_timestamp"])
277
290
  [ sub,
278
291
  [ "dea: #{dea}",
279
292
  "index: #{index}",
280
293
  "state: #{c(state.downcase, state_color(state))}",
281
- "since: #{time}"
294
+ "version: #{pretty_version(version)}",
295
+ "since: #{since}"
282
296
  ].join(", ")
283
297
  ]
284
298
  end
285
299
 
286
300
  def pretty_healthmanager_status(sub, payload)
287
301
  state = payload["state"]
302
+ version = payload["version"]
303
+
288
304
  [ d(sub),
289
305
  [ "app: #{pretty_app(payload["droplet"])}",
306
+ "version: #{pretty_version(version)}",
290
307
  "querying states: #{c(state.downcase, state_color(state))}"
291
308
  ].join(", ")
292
309
  ]
@@ -297,13 +314,17 @@ module CFTools
297
314
  end
298
315
 
299
316
  def pretty_healthmanager_health(sub, payload)
300
- apps = payload["droplets"].collect { |d| pretty_app(d["droplet"]) }
317
+ apps = payload["droplets"].collect do |d|
318
+ "#{pretty_app(d["droplet"])} (#{pretty_version(d["version"])})"
319
+ end
320
+
301
321
  [d(sub), "querying health for: #{list(apps)}"]
302
322
  end
303
323
 
304
324
  def pretty_healthmanager_health_response(sub, payload)
305
325
  [ sub,
306
326
  [ "app: #{pretty_app(payload["droplet"])}",
327
+ "version: #{pretty_version(payload["version"])}",
307
328
  "healthy: #{payload["healthy"]}"
308
329
  ].join(", ")
309
330
  ]
@@ -323,25 +344,23 @@ module CFTools
323
344
  [c(sub, :error), "dea: #{dea}, apps: #{list(apps)}"]
324
345
  end
325
346
 
326
- def process_cloudcontrollers_hm_request(payload)
327
- last_updated = Time.at(payload["last_updated"])
328
-
329
- op = payload["op"]
330
-
331
- message = [
332
- "app: #{pretty_app(payload["droplet"])}",
333
- "operation: #{pretty_hm_op(op)}",
334
- "app last updated: #{last_updated}"
347
+ def pretty_health_start(sub, payload)
348
+ [ c(sub, :good),
349
+ [ "app: #{pretty_app(payload["droplet"])}",
350
+ "version: #{pretty_version(payload["version"])}",
351
+ "indices: #{list(payload["indices"])}",
352
+ "running: #{pretty_running_counts(payload["running"])}"
353
+ ].join(", ")
335
354
  ]
355
+ end
336
356
 
337
- case op
338
- when "STOP"
339
- message << "instances: #{list(payload["instances"])}"
340
- when "START"
341
- message << "indices: #{list(payload["indices"])}"
342
- end
343
-
344
- [c("hm.request", :warning), message.join(", ")]
357
+ def pretty_health_stop(sub, payload)
358
+ [ c(sub, :bad),
359
+ [ "app: #{pretty_app(payload["droplet"])}",
360
+ "instances: #{pretty_instance_breakdown(payload["instances"])}",
361
+ "running: #{pretty_running_counts(payload["running"])}"
362
+ ].join(", ")
363
+ ]
345
364
  end
346
365
 
347
366
  def pretty_service_announcement(sub, payload)
@@ -398,18 +417,25 @@ module CFTools
398
417
  [d(sub), message.join(", ")]
399
418
  end
400
419
 
401
- def pretty_hm_op(op)
402
- case op
403
- when "STOP"
404
- c("stop", :bad)
405
- when "START"
406
- c("start", :good)
407
- else
408
- op
409
- end
420
+ def pretty_running_counts(running)
421
+ running.collect do |ver, num|
422
+ "#{num} x #{pretty_version(ver)}"
423
+ end.join(", ")
424
+ end
425
+
426
+ def pretty_instance_breakdown(instances)
427
+ instances.collect do |inst, ver|
428
+ "#{inst} (#{pretty_version(ver)})"
429
+ end.join(", ")
430
+ end
431
+
432
+ def pretty_version(guid)
433
+ guid.split("-").first
410
434
  end
411
435
 
412
436
  def pretty_app(guid)
437
+ return guid unless client
438
+
413
439
  existing_app =
414
440
  if @seen_apps.key?(guid)
415
441
  @seen_apps[guid]
@@ -419,22 +445,45 @@ module CFTools
419
445
  end
420
446
 
421
447
  if existing_app
422
- #@seen_apps[guid] = existing_app
448
+ @seen_apps[guid] = existing_app
423
449
  c(existing_app.name, :name)
424
450
  else
425
451
  @seen_apps[guid] = nil
426
452
  d("unknown (#{guid})")
427
453
  end
454
+ rescue CFoundry::TargetRefused, CFoundry::InvalidAuthToken
455
+ guid
428
456
  end
429
457
 
430
- def watching_nats(uri, &blk)
458
+ def watching_nats(uri, subjects, &blk)
431
459
  NATS.start(:uri => uri) do
432
- NATS.subscribe(">", &blk)
460
+ subjects.each do |subject|
461
+ NATS.subscribe(subject, &blk)
462
+ end
433
463
  end
434
464
  end
435
465
 
436
466
  def register_request(sub, reply)
437
467
  @requests[reply] = [sub, @request_ticker += 1]
438
468
  end
469
+
470
+ def get_app(apps)
471
+ return unless apps
472
+
473
+ if apps.empty?
474
+ fail "Unknown app '#{input.given[:app]}'."
475
+ elsif apps.size == 1
476
+ apps.first
477
+ else
478
+ disambiguate_app(apps)
479
+ end
480
+ end
481
+
482
+ def disambiguate_app(apps)
483
+ ask("Which application?", :choices => apps,
484
+ :display => proc do |a|
485
+ "#{a.name} (#{a.space.organization.name}/#{a.space.name})"
486
+ end)
487
+ end
439
488
  end
440
489
  end
@@ -33,6 +33,21 @@ describe CFTools::Watch do
33
33
  cf %W[watch]
34
34
  end
35
35
 
36
+ context "when a subject is given" do
37
+ it "subscribes to the given subject on NATS" do
38
+ expect(NATS).to receive(:subscribe).with("some.subject")
39
+ cf %W[watch --subject some.subject]
40
+ end
41
+
42
+ context "when multiple subjects are given" do
43
+ it "subscribes to all of them on NATS" do
44
+ expect(NATS).to receive(:subscribe).with("some.subject")
45
+ expect(NATS).to receive(:subscribe).with("some.other.subject")
46
+ cf %W[watch --subjects some.subject,some.other.subject]
47
+ end
48
+ end
49
+ end
50
+
36
51
  context "when no application is given" do
37
52
  around { |example| Timecop.freeze(&example) }
38
53
 
@@ -104,6 +119,25 @@ describe CFTools::Watch do
104
119
  end
105
120
  end
106
121
 
122
+ context "and multiple apps with the sane name are found" do
123
+ let!(:org1) { fake :organization, :name => "org1" }
124
+ let!(:org2) { fake :organization, :name => "org2" }
125
+ let!(:space1) { fake :space, :name => "space1", :organization => org1 }
126
+ let!(:space2) { fake :space, :name => "space2", :organization => org2 }
127
+ let!(:app1) { fake :app, :name => "myapp", :guid => "myappguid", :space => space1 }
128
+ let!(:app2) { fake :app, :name => "myapp", :guid => "myappguid", :space => space2 }
129
+
130
+ let(:client) { fake_client :apps => [app1, app2] }
131
+
132
+ it "asks to disambiguate" do
133
+ should_ask("Which application?", hash_including(:choices => [app1, app2])) do |_, opts|
134
+ expect(opts[:display].call(app1)).to eq("myapp (org1/space1)")
135
+ end
136
+
137
+ cf %W[watch myapp]
138
+ end
139
+ end
140
+
107
141
  context "and a message containing the app's GUID is seen" do
108
142
  around { |example| Timecop.freeze(&example) }
109
143
 
@@ -146,7 +180,7 @@ PAYLOAD
146
180
  it "pretty-prints the message body" do
147
181
  cf %W[watch]
148
182
 
149
- expect(output).to say("app: myapp, reason: STOPPED, index: 0")
183
+ expect(output).to say("app: myapp, reason: STOPPED, index: 0, version: aaca113b")
150
184
  end
151
185
  end
152
186
 
@@ -172,7 +206,7 @@ PAYLOAD
172
206
  "state": "CRASHED",
173
207
  "index": 1,
174
208
  "instance": "some other app instance",
175
- "version": "5c0e0e10-8384-4a35-915e-872fe91ffb95",
209
+ "version": "deadbeef-8384-4a35-915e-872fe91ffb95",
176
210
  "droplet": "#{app.guid}",
177
211
  "cc_partition": "default"
178
212
  },
@@ -453,10 +487,42 @@ PAYLOAD
453
487
  expect(output).to say("dea.42.start")
454
488
  end
455
489
 
456
- it "prints the uris, host, and port" do
490
+ it "prints the app, dea, index, version, and uris" do
457
491
  cf %W[watch]
458
492
 
459
- expect(output).to say("app: myapp, dea: 42, index: 2, uris: myapp.com")
493
+ expect(output).to say("app: myapp, dea: 42, index: 2, version: ce1da6af, uris: myapp.com")
494
+ end
495
+
496
+ context "when a single uri is given as a string" do
497
+ let(:payload) { <<PAYLOAD }
498
+ {
499
+ "index": 2,
500
+ "debug": null,
501
+ "console": true,
502
+ "env": [],
503
+ "cc_partition": "default",
504
+ "limits": {
505
+ "fds": 16384,
506
+ "disk": 1024,
507
+ "mem": 128
508
+ },
509
+ "services": [],
510
+ "droplet": "#{app.guid}",
511
+ "name": "hello-sinatra",
512
+ "uris": "myapp.com",
513
+ "prod": false,
514
+ "sha1": "9c8f36ee81b535a7d9b4efcd9d629e8cf8a2645f",
515
+ "executableFile": "deprecated",
516
+ "executableUri": "https://a1-cf-app-com-cc-droplets.s3.amazonaws.com/ac/cf/accf1078-e7e1-439a-bd32-77296390c406?AWSAccessKeyId=AKIAIMGCF7E5F6M5RV3A&Signature=1lyIotK3cZ2VUyK3H8YrlT82B8c%3D&Expires=1369259081",
517
+ "version": "ce1da6af-59b1-4fea-9e39-64c19440a671"
518
+ }
519
+ PAYLOAD
520
+
521
+ it "prints the app, dea, index, version, and uris" do
522
+ cf %W[watch]
523
+
524
+ expect(output).to say("app: myapp, dea: 42, index: 2, version: ce1da6af, uris: myapp.com")
525
+ end
460
526
  end
461
527
  end
462
528
 
@@ -497,7 +563,7 @@ PAYLOAD
497
563
  it "prints that it's scaling down, and the affected indices" do
498
564
  cf %W[watch]
499
565
 
500
- expect(output).to say("app: myapp, scaling down indices: 1, 2")
566
+ expect(output).to say("app: myapp, version: ce1da6af, scaling down indices: 1, 2")
501
567
  end
502
568
  end
503
569
 
@@ -568,6 +634,8 @@ PAYLOAD
568
634
  }
569
635
  PAYLOAD
570
636
 
637
+ let(:state_timestamp) { "1369262704.3337305" }
638
+
571
639
  let(:response_payload) { <<PAYLOAD }
572
640
  {
573
641
  "console_port": 61016,
@@ -579,11 +647,11 @@ PAYLOAD
579
647
  ],
580
648
  "dea": "1-c0d2928b36c524153cdc8cfb51d80f75",
581
649
  "droplet": "#{app.guid}",
582
- "version": "c75b3e45-0cf4-403d-a54d-1c0970dca50d",
650
+ "version": "878318bf-0cf4-403d-a54d-1c0970dca50d",
583
651
  "instance": "7cc4f4fe64c7a0fbfaacf71e9e222a35",
584
652
  "index": 0,
585
653
  "state": "RUNNING",
586
- "state_timestamp": 1369262704.3337305,
654
+ "state_timestamp": #{state_timestamp},
587
655
  "file_uri": "http://10.10.17.1:12345/instances"
588
656
  }
589
657
  PAYLOAD
@@ -591,7 +659,22 @@ PAYLOAD
591
659
  it "prints the states being queried" do
592
660
  cf %W[watch]
593
661
 
594
- expect(output).to say("app: myapp, querying states: starting, running")
662
+ expect(output).to say("app: myapp, version: 878318bf, querying states: starting, running")
663
+ end
664
+
665
+ context "when there are no states being queried" do
666
+ let(:payload) { <<PAYLOAD }
667
+ {
668
+ "version": "878318bf-64a0-4055-b79b-46871292ceb8",
669
+ "droplet": "#{app.guid}"
670
+ }
671
+ PAYLOAD
672
+
673
+ it "prints them as 'none'" do
674
+ cf %W[watch]
675
+
676
+ expect(output).to say("app: myapp, version: 878318bf, querying states: none")
677
+ end
595
678
  end
596
679
 
597
680
  context "and we see the response" do
@@ -604,7 +687,7 @@ PAYLOAD
604
687
  it "pretty-prints the response" do
605
688
  cf %W[watch]
606
689
 
607
- expect(output).to say("reply to dea.find.droplet (1)\tdea: 1, index: 0, state: running, since: 2013-05-22 15:45:04 -0700")
690
+ expect(output).to say("reply to dea.find.droplet (1)\tdea: 1, index: 0, state: running, version: 878318bf, since: #{Time.at(state_timestamp.to_f)}")
608
691
  end
609
692
  end
610
693
  end
@@ -632,7 +715,7 @@ PAYLOAD
632
715
  it "prints the states being queried" do
633
716
  cf %W[watch]
634
717
 
635
- expect(output).to say("app: myapp, querying states: flapping")
718
+ expect(output).to say("app: myapp, version: 50512eed, querying states: flapping")
636
719
  end
637
720
 
638
721
  context "and we see the response" do
@@ -661,11 +744,11 @@ PAYLOAD
661
744
  {
662
745
  "droplets": [
663
746
  {
664
- "version": "some-version",
747
+ "version": "deadbeef-foo",
665
748
  "droplet": "#{app.guid}"
666
749
  },
667
750
  {
668
- "version": "some-other-version",
751
+ "version": "beefdead-foo",
669
752
  "droplet": "#{other_app.guid}"
670
753
  }
671
754
  ]
@@ -675,7 +758,7 @@ PAYLOAD
675
758
  let(:response_payload) { <<PAYLOAD }
676
759
  {
677
760
  "healthy": 2,
678
- "version": "some-version",
761
+ "version": "deadbeef-foo",
679
762
  "droplet": "#{app.guid}"
680
763
  }
681
764
  PAYLOAD
@@ -683,7 +766,7 @@ PAYLOAD
683
766
  let(:other_response_payload) { <<PAYLOAD }
684
767
  {
685
768
  "healthy": 3,
686
- "version": "some-version",
769
+ "version": "beefdead-foo",
687
770
  "droplet": "#{other_app.guid}"
688
771
  }
689
772
  PAYLOAD
@@ -693,7 +776,7 @@ PAYLOAD
693
776
  it "prints the apps whose health being queried" do
694
777
  cf %W[watch]
695
778
 
696
- expect(output).to say("querying health for: myapp, otherapp")
779
+ expect(output).to say("querying health for: myapp (deadbeef), otherapp (beefdead)")
697
780
  end
698
781
 
699
782
  context "and we see the response" do
@@ -707,8 +790,8 @@ PAYLOAD
707
790
  it "pretty-prints the response" do
708
791
  cf %W[watch]
709
792
 
710
- expect(output).to say("reply to healthmanager.health (1)\tapp: myapp, healthy: 2")
711
- expect(output).to say("reply to healthmanager.health (1)\tapp: otherapp, healthy: 3")
793
+ expect(output).to say("reply to healthmanager.health (1)\tapp: myapp, version: deadbeef, healthy: 2")
794
+ expect(output).to say("reply to healthmanager.health (1)\tapp: otherapp, version: beefdead, healthy: 3")
712
795
  end
713
796
  end
714
797
  end
@@ -760,58 +843,60 @@ PAYLOAD
760
843
  end
761
844
  end
762
845
 
763
- context "when a message is seen with subject cloudcontrollers.hm.requests.*" do
764
- let(:subject) { "cloudcontrollers.hm.requests.default" }
846
+ context "when a message is seen with subject health.start" do
847
+ let(:subject) { "health.start" }
765
848
 
766
849
  let(:last_updated) { Time.now }
767
850
 
768
- context "and it is a STOP operation" do
769
- let(:payload) { <<PAYLOAD }
851
+ let(:payload) { <<PAYLOAD }
770
852
  {
771
- "instances": [
772
- "some-instance",
773
- "some-other-instance"
853
+ "indices": [
854
+ 1,
855
+ 3
774
856
  ],
857
+ "running": {
858
+ "deadbeef-version": 1,
859
+ "beefdead-version": 2
860
+ },
861
+ "version": "deadbeef-foo",
775
862
  "last_updated": #{last_updated.to_i},
776
- "op": "STOP",
777
863
  "droplet": "#{app.guid}"
778
864
  }
779
865
  PAYLOAD
780
866
 
781
- it "trims the subject" do
782
- cf %W[watch]
867
+ it "prints the operation, last updated timestamp, and instances" do
868
+ cf %W[watch]
783
869
 
784
- expect(output).to say(/\s+hm\.request\s+/)
785
- end
870
+ expect(output).to say(
871
+ "app: myapp, version: deadbeef, indices: 1, 3, running: 1 x deadbeef, 2 x beefdead")
872
+ end
873
+ end
786
874
 
787
- it "prints the operation, last updated timestamp, and instances" do
788
- cf %W[watch]
875
+ context "when a message is seen with subject health.stop" do
876
+ let(:subject) { "health.stop" }
789
877
 
790
- expect(output).to say(
791
- "app: myapp, operation: stop, app last updated: #{last_updated}, instances: some-instance, some-other-instance")
792
- end
793
- end
878
+ let(:last_updated) { Time.now }
794
879
 
795
- context "and it is a START operation" do
796
- let(:payload) { <<PAYLOAD }
880
+ let(:payload) { <<PAYLOAD }
797
881
  {
798
- "indices": [
799
- 1,
800
- 3
801
- ],
802
- "version": "some-version",
882
+ "instances": {
883
+ "some-instance": "deadbeef-version",
884
+ "some-other-instance": "beefdead-version"
885
+ },
886
+ "running": {
887
+ "deadbeef-version": 1,
888
+ "beefdead-version": 2
889
+ },
803
890
  "last_updated": #{last_updated.to_i},
804
- "op": "START",
805
891
  "droplet": "#{app.guid}"
806
892
  }
807
893
  PAYLOAD
808
894
 
809
- it "prints the operation, last updated timestamp, and instances" do
810
- cf %W[watch]
895
+ it "prints the operation, last updated timestamp, and instances" do
896
+ cf %W[watch]
811
897
 
812
- expect(output).to say(
813
- "app: myapp, operation: start, app last updated: #{last_updated}, indices: 1, 3")
814
- end
898
+ expect(output).to say(
899
+ "app: myapp, instances: some-instance (deadbeef), some-other-instance (beefdead), running: 1 x deadbeef, 2 x beefdead")
815
900
  end
816
901
  end
817
902
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tools-cf-plugin
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.1
4
+ version: 2.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-06-24 00:00:00.000000000 Z
12
+ date: 2013-06-26 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: cfoundry
@@ -271,29 +271,29 @@ extensions: []
271
271
  extra_rdoc_files: []
272
272
  files:
273
273
  - Rakefile
274
- - lib/tools-cf-plugin/dea-ads.rb
275
- - lib/tools-cf-plugin/dea-apps.rb
276
274
  - lib/tools-cf-plugin/plugin.rb
277
- - lib/tools-cf-plugin/shell.rb
278
- - lib/tools-cf-plugin/tunnel/base.rb
275
+ - lib/tools-cf-plugin/version.rb
276
+ - lib/tools-cf-plugin/tunnel/watch-logs.rb
279
277
  - lib/tools-cf-plugin/tunnel/log_entry.rb
280
- - lib/tools-cf-plugin/tunnel/multi_line_stream.rb
281
- - lib/tools-cf-plugin/tunnel/stream_location.rb
282
278
  - lib/tools-cf-plugin/tunnel/tunnel-nats.rb
283
- - lib/tools-cf-plugin/tunnel/watch-logs.rb
284
- - lib/tools-cf-plugin/version.rb
279
+ - lib/tools-cf-plugin/tunnel/stream_location.rb
280
+ - lib/tools-cf-plugin/tunnel/base.rb
281
+ - lib/tools-cf-plugin/tunnel/multi_line_stream.rb
285
282
  - lib/tools-cf-plugin/watch.rb
286
- - spec/dea-ads_spec.rb
287
- - spec/dea-apps_spec.rb
283
+ - lib/tools-cf-plugin/dea-apps.rb
284
+ - lib/tools-cf-plugin/shell.rb
285
+ - lib/tools-cf-plugin/dea-ads.rb
288
286
  - spec/shell_spec.rb
287
+ - spec/watch_spec.rb
289
288
  - spec/spec_helper.rb
290
- - spec/tunnel/base_spec.rb
289
+ - spec/dea-apps_spec.rb
290
+ - spec/dea-ads_spec.rb
291
291
  - spec/tunnel/log_entry_spec.rb
292
- - spec/tunnel/multi_line_stream_spec.rb
292
+ - spec/tunnel/watch-logs_spec.rb
293
+ - spec/tunnel/base_spec.rb
293
294
  - spec/tunnel/stream_location_spec.rb
295
+ - spec/tunnel/multi_line_stream_spec.rb
294
296
  - spec/tunnel/tunnel-nats_spec.rb
295
- - spec/tunnel/watch-logs_spec.rb
296
- - spec/watch_spec.rb
297
297
  homepage: http://github.com/cloudfoundry/tools-cf-plugin
298
298
  licenses: []
299
299
  post_install_message:
@@ -319,15 +319,14 @@ signing_key:
319
319
  specification_version: 3
320
320
  summary: Cloud Foundry tooling commands.
321
321
  test_files:
322
- - spec/dea-ads_spec.rb
323
- - spec/dea-apps_spec.rb
324
322
  - spec/shell_spec.rb
323
+ - spec/watch_spec.rb
325
324
  - spec/spec_helper.rb
326
- - spec/tunnel/base_spec.rb
325
+ - spec/dea-apps_spec.rb
326
+ - spec/dea-ads_spec.rb
327
327
  - spec/tunnel/log_entry_spec.rb
328
- - spec/tunnel/multi_line_stream_spec.rb
328
+ - spec/tunnel/watch-logs_spec.rb
329
+ - spec/tunnel/base_spec.rb
329
330
  - spec/tunnel/stream_location_spec.rb
331
+ - spec/tunnel/multi_line_stream_spec.rb
330
332
  - spec/tunnel/tunnel-nats_spec.rb
331
- - spec/tunnel/watch-logs_spec.rb
332
- - spec/watch_spec.rb
333
- has_rdoc: