tools-cf-plugin 2.4.0 → 3.0.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.
@@ -0,0 +1,145 @@
1
+ require "cf/cli"
2
+ require "nats/client"
3
+ require "set"
4
+
5
+ module CFTools
6
+ class AppPlacement < CF::App::Base
7
+ def precondition; end
8
+
9
+ desc "Show placement of running applications."
10
+ group :admin
11
+ input :host, :alias => "-h", :default => "127.0.0.1",
12
+ :desc => "NATS server address"
13
+ input :port, :alias => "-P", :default => 4222, :type => :integer,
14
+ :desc => "NATS server port"
15
+ input :user, :alias => "-u", :default => "nats",
16
+ :desc => "NATS server user"
17
+ input :password, :alias => "-p", :default => "nats",
18
+ :desc => "NATS server password"
19
+ input :time, :alias => "-t", :default => 12,
20
+ :desc => "Seconds to watch heartbeats"
21
+ input :zeros, :alias => "-z", :default => false,
22
+ :desc => "If set, include zero-value DEAs in output"
23
+ def app_placement
24
+ host = input[:host]
25
+ port = input[:port]
26
+ user = input[:user]
27
+ pass = input[:password]
28
+
29
+ render_apps(
30
+ "nats://#{user}:#{pass}@#{host}:#{port}",
31
+ input[:time]
32
+ )
33
+ end
34
+
35
+ private
36
+ def apps
37
+ @apps ||= {}
38
+ end
39
+
40
+ def known_app_ids
41
+ @known_app_ids ||= Set.new
42
+ end
43
+
44
+ def known_dea_ids
45
+ @known_dea_ids ||= Set.new
46
+ end
47
+
48
+ def render_zeros?
49
+ !!input[:zeros]
50
+ end
51
+
52
+ def render_apps(uri, seconds_to_watch, options = {})
53
+ NATS.start(:uri => uri) do
54
+ NATS.subscribe("dea.heartbeat") do |msg|
55
+ payload = JSON.parse(msg)
56
+ dea_id = payload["dea"].to_i
57
+ register_heartbeat(dea_id, payload["droplets"])
58
+ end
59
+
60
+ EM.add_timer(seconds_to_watch) do
61
+ NATS.stop
62
+ end
63
+ end
64
+
65
+ fill_in_zeros
66
+ render_table
67
+ rescue NATS::ServerError => e
68
+ if e.to_s =~ /connection dropped/i
69
+ line c("dropped by server; reconnecting...", :error)
70
+ retry
71
+ else
72
+ raise
73
+ end
74
+ end
75
+
76
+ def register_heartbeat(dea_id, droplets)
77
+ known_dea_ids << dea_id
78
+ app_id_to_num_instances = Hash.new(0)
79
+ droplets.each do |droplet|
80
+ next unless droplet["state"] == "RUNNING"
81
+ app_id = droplet["droplet"]
82
+ app_id_to_num_instances[app_id] += 1
83
+
84
+ known_app_ids << app_id
85
+ end
86
+
87
+ app_id_to_num_instances.each do |app_id, num_instances|
88
+ apps[app_id] ||= {}
89
+ apps[app_id][dea_id] = num_instances
90
+ end
91
+ end
92
+
93
+ def fill_in_zeros
94
+ known_app_ids.each do |app_id|
95
+ known_dea_ids.each do |dea_id|
96
+ apps[app_id][dea_id] ||= 0
97
+ end
98
+ end
99
+ end
100
+
101
+ def render_table
102
+ print("%-36s placement\n" % "guid")
103
+ apps.each do |app_id, dea_id_to_num_instances|
104
+ render_app(app_id, dea_id_to_num_instances)
105
+ end
106
+
107
+ render_total
108
+ end
109
+
110
+ def render_app(app_id, dea_id_to_num_instances)
111
+ total_instances = 0
112
+ placements = []
113
+ 0.upto(known_dea_ids.max) do |dea_id|
114
+ if dea_id_to_num_instances.has_key?(dea_id)
115
+ num_instances = dea_id_to_num_instances[dea_id]
116
+ total_instances += num_instances
117
+ placements << "#{dea_id}:#{num_instances}" if num_instances > 0 || render_zeros?
118
+ else
119
+ placements << "#{dea_id}:?" if render_zeros?
120
+ end
121
+ end
122
+
123
+ print("%-36s %s T:%s\n" % [app_id, placements.join(" "), total_instances])
124
+ end
125
+
126
+ def render_total
127
+ totals = []
128
+ grand_total = 0
129
+ 0.upto(known_dea_ids.max) do |dea_id|
130
+ if known_dea_ids.include?(dea_id)
131
+ total_for_dea = 0
132
+
133
+ apps.each do |app_id, dea_id_to_num_instances|
134
+ total_for_dea += dea_id_to_num_instances[dea_id]
135
+ end
136
+ totals << "#{dea_id}:#{total_for_dea}"
137
+ grand_total += total_for_dea
138
+ else
139
+ totals << "#{dea_id}:?" if render_zeros?
140
+ end
141
+ end
142
+ print("%-36s %s T:%s\n" % ["total", totals.join(" "), grand_total])
143
+ end
144
+ end
145
+ end
@@ -1,5 +1,6 @@
1
1
  require "tools-cf-plugin/watch"
2
2
  require "tools-cf-plugin/shell"
3
+ require "tools-cf-plugin/app-placement"
3
4
  require "tools-cf-plugin/dea-ads"
4
5
  require "tools-cf-plugin/dea-apps"
5
6
  require "tools-cf-plugin/tunnel/tunnel-nats"
@@ -63,12 +63,55 @@ module CFTools
63
63
  end
64
64
 
65
65
  def tunnel_to(address, remote_port, gateway)
66
- user, host = gateway.split("@", 2)
67
- Net::SSH::Gateway.new(host, user).open(address, remote_port)
66
+ local_port = grab_ephemeral_port
67
+
68
+ Process.spawn("ssh -o StrictHostKeyChecking=no -N -L #{local_port}:#{address}:#{remote_port} #{gateway}")
69
+
70
+ wait_for_port_open(local_port)
71
+
72
+ local_port
73
+ end
74
+
75
+ def current_deployment(director)
76
+ deployments =
77
+ with_progress("Getting deployments") do
78
+ director.list_deployments
79
+ end
80
+
81
+ fail "No deployments." if deployments.empty?
82
+
83
+ cf_deployments = deployments.select do |d|
84
+ d["releases"].any? { |r| ["cf-release", "cf"].include?(r["name"]) }
85
+ end
86
+
87
+ return cf_deployments.first if cf_deployments.size == 1
88
+
89
+ ask("Which deployment?",
90
+ :choices => deployments,
91
+ :display => proc { |x| x["name"] })
68
92
  end
69
93
 
70
94
  private
71
95
 
96
+ def grab_ephemeral_port
97
+ socket = TCPServer.new('0.0.0.0', 0)
98
+
99
+ socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, true)
100
+
101
+ Socket.do_not_reverse_lookup = true
102
+
103
+ port = socket.addr[1]
104
+ socket.close
105
+
106
+ port
107
+ end
108
+
109
+ def wait_for_port_open(port)
110
+ Timeout.timeout(10) do
111
+ sleep 0.5 until address_reachable?("127.0.0.1", port)
112
+ end
113
+ end
114
+
72
115
  def address_reachable?(host, port)
73
116
  Timeout.timeout(1) do
74
117
  TCPSocket.new(host, port).close
@@ -92,17 +135,12 @@ module CFTools
92
135
  auth
93
136
  end
94
137
 
95
- def current_deployment(director)
96
- deployments = director.list_deployments
97
-
98
- deployments.find do |d|
99
- d["releases"].any? { |r| r["name"] == "cf-release" }
100
- end
101
- end
102
-
103
138
  def current_deployment_manifest(director)
104
139
  deployment = current_deployment(director)
105
- YAML.load(director.get_deployment(deployment["name"])["manifest"])
140
+
141
+ with_progress("Downloading #{c(deployment["name"], :name)} manifest") do
142
+ YAML.load(director.get_deployment(deployment["name"])["manifest"])
143
+ end
106
144
  end
107
145
 
108
146
  def save_auth(director, auth)
@@ -31,10 +31,7 @@ module CFTools::Tunnel
31
31
 
32
32
  line "Director: #{director.director_uri}"
33
33
 
34
- manifest =
35
- with_progress("Downloading deployment manifest") do
36
- current_deployment_manifest(director)
37
- end
34
+ manifest = current_deployment_manifest(director)
38
35
 
39
36
  nats = manifest["properties"]["nats"]
40
37
 
@@ -8,10 +8,13 @@ require "tools-cf-plugin/tunnel/stream_location"
8
8
  module CFTools::Tunnel
9
9
  class WatchLogs < Base
10
10
  LOGS = {
11
- "cloud_controller" => ["cloud_controller_ng/cloud_controller_ng.log"],
12
- "dea_next" => ["dea_next/dea_next.log"],
13
- "health_manager" => ["health_manager_next/health_manager_next.log"],
14
- "router" => ["gorouter/gorouter.log"]
11
+ "api_z1" => ["cloud_controller_ng/cloud_controller_ng.log"],
12
+ "api_z2" => ["cloud_controller_ng/cloud_controller_ng.log"],
13
+ "runner_z1" => ["dea_next/dea_next.log"],
14
+ "runner_z2" => ["dea_next/dea_next.log"],
15
+ "hm_z1" => ["health_manager_next/health_manager_next.log"],
16
+ "router_z1" => ["gorouter/gorouter.log"],
17
+ "router_z2" => ["gorouter/gorouter.log"],
15
18
  }
16
19
 
17
20
  # colorize if told to; don't check if output is tty
@@ -31,10 +34,7 @@ module CFTools::Tunnel
31
34
 
32
35
  director = connected_director(director_host, gateway)
33
36
 
34
- deployment =
35
- with_progress("Getting deployment info") do
36
- current_deployment(director)
37
- end
37
+ deployment = current_deployment(director)
38
38
 
39
39
  locations =
40
40
  with_progress("Finding logs for #{c(deployment["name"], :name)}") do
@@ -1,3 +1,3 @@
1
1
  module CFTools
2
- VERSION = "2.4.0".freeze
2
+ VERSION = "3.0.0".freeze
3
3
  end
@@ -439,7 +439,11 @@ module CFTools
439
439
  end
440
440
 
441
441
  def pretty_version(guid)
442
- guid.split("-").first
442
+ if guid
443
+ guid.split("-").first
444
+ else
445
+ d("none")
446
+ end
443
447
  end
444
448
 
445
449
  def pretty_app(guid)
@@ -0,0 +1,164 @@
1
+ require "spec_helper"
2
+
3
+ describe CFTools::AppPlacement do
4
+ let(:client) { fake_client :apps => [app1, app2, app3] }
5
+
6
+ let(:app1) do
7
+ fake :app, :name => "myapp1", :guid => "myappguid-1",
8
+ :memory => 128, :total_instances => 2
9
+ end
10
+
11
+ let(:app2) do
12
+ fake :app, :name => "myapp2", :guid => "myappguid-2",
13
+ :memory => 256, :total_instances => 2
14
+ end
15
+
16
+ let(:app3) do
17
+ fake :app, :name => "myapp3", :guid => "myappguid-3",
18
+ :memory => 1024, :total_instances => 4
19
+ end
20
+
21
+ before { stub_client }
22
+
23
+ before do
24
+ NATS.stub(:start).and_yield
25
+ EM.stub(:add_timer).and_yield
26
+ end
27
+
28
+ let(:dea1_heartbeat) { <<PAYLOAD }
29
+ {
30
+ "prod": false,
31
+ "dea": "1-3b293b726167fbc895af5a7927c0973a",
32
+ "droplets": [
33
+ {
34
+ "state_timestamp": 1369251231.3436642,
35
+ "state": "RUNNING",
36
+ "index": 0,
37
+ "instance": "app1-instance2",
38
+ "version": "5c0e0e10-8384-4a35-915e-872fe91ffb95",
39
+ "droplet": "#{app1.guid}",
40
+ "cc_partition": "default"
41
+ }
42
+ ]
43
+ }
44
+ PAYLOAD
45
+
46
+ let(:dea2_heartbeat) { <<PAYLOAD }
47
+ {
48
+ "prod": false,
49
+ "dea": "2-4b293b726167fbc895af5a7927c0973a",
50
+ "droplets": [
51
+ {
52
+ "state_timestamp": 1369251231.3436642,
53
+ "state": "RUNNING",
54
+ "index": 0,
55
+ "instance": "app1-instance1",
56
+ "version": "5c0e0e10-8384-4a35-915e-872fe91ffb95",
57
+ "droplet": "#{app1.guid}",
58
+ "cc_partition": "default"
59
+ },
60
+ {
61
+ "state_timestamp": 1369251231.3436642,
62
+ "state": "CRASHED",
63
+ "index": 1,
64
+ "instance": "app2-dead-isntance",
65
+ "version": "deadbeef-8384-4a35-915e-872fe91ffb95",
66
+ "droplet": "#{app2.guid}",
67
+ "cc_partition": "default"
68
+ },
69
+ {
70
+ "state_timestamp": 1369251231.3436642,
71
+ "state": "RUNNING",
72
+ "index": 1,
73
+ "instance": "app2-instance1",
74
+ "version": "deadbeef-8384-4a35-915e-872fe91ffb95",
75
+ "droplet": "#{app2.guid}",
76
+ "cc_partition": "default"
77
+ },
78
+ {
79
+ "state_timestamp": 1369251231.3436642,
80
+ "state": "RUNNING",
81
+ "index": 1,
82
+ "instance": "app2-instance2",
83
+ "version": "deadbeef-8384-4a35-915e-872fe91ffb95",
84
+ "droplet": "#{app2.guid}",
85
+ "cc_partition": "default"
86
+ },
87
+ {
88
+ "state_timestamp": 1369251225.2800167,
89
+ "state": "RUNNING",
90
+ "index": 0,
91
+ "instance": "app3-instance1",
92
+ "version": "bdc3b7d7-5a55-455d-ac66-ba82a9ad43e7",
93
+ "droplet": "#{app3.guid}",
94
+ "cc_partition": "default"
95
+ },
96
+ {
97
+ "state_timestamp": 1369251225.2800167,
98
+ "state": "RUNNING",
99
+ "index": 0,
100
+ "instance": "app3-instance2",
101
+ "version": "bdc3b7d7-5a55-455d-ac66-ba82a9ad43e7",
102
+ "droplet": "#{app3.guid}",
103
+ "cc_partition": "default"
104
+ },
105
+ {
106
+ "state_timestamp": 1369251225.2800167,
107
+ "state": "RUNNING",
108
+ "index": 0,
109
+ "instance": "app3-instance3",
110
+ "version": "bdc3b7d7-5a55-455d-ac66-ba82a9ad43e7",
111
+ "droplet": "#{app3.guid}",
112
+ "cc_partition": "default"
113
+ },
114
+ {
115
+ "state_timestamp": 1369251225.2800167,
116
+ "state": "RUNNING",
117
+ "index": 0,
118
+ "instance": "app3-instance4",
119
+ "version": "bdc3b7d7-5a55-455d-ac66-ba82a9ad43e7",
120
+ "droplet": "#{app3.guid}",
121
+ "cc_partition": "default"
122
+ }
123
+ ]
124
+ }
125
+ PAYLOAD
126
+
127
+ before do
128
+ NATS.stub(:subscribe) do |&callback|
129
+ callback.call(dea2_heartbeat)
130
+ callback.call(dea1_heartbeat)
131
+ callback.call(dea2_heartbeat) # old dea2_heartbeat should be discarded
132
+ end
133
+ end
134
+
135
+ it "outputs the list of guids and placements, without zeros by default" do
136
+ cf %W[app-placement]
137
+ expect(output).to say(%r{guid\s+placement})
138
+ expect(output).to say(%r{myappguid-1\s+1:1\s+2:1\s+T:2\D})
139
+ expect(output).to say(%r{myappguid-2\s+2:2\s+T:2\D})
140
+ expect(output).to say(%r{myappguid-3\s+2:4\s+T:4\D})
141
+ expect(output).to say(%r{total \s+1:1\s+2:7\s+T:8\D})
142
+ end
143
+
144
+ it "outputs the list of guids and placements, with a zero if requested" do
145
+ cf %W[app-placement -z]
146
+ expect(output).to say(%r{guid\s+placement})
147
+ expect(output).to say(%r{myappguid-1\s+0:\?\s+1:1\s+2:1\s+T:2\D})
148
+ expect(output).to say(%r{myappguid-2\s+0:\?\s+1:0\s+2:2\s+T:2\D})
149
+ expect(output).to say(%r{myappguid-3\s+0:\?\s+1:0\s+2:4\s+T:4\D})
150
+ expect(output).to say(%r{total \s+0:\?\s+1:1\s+2:7\s+T:8\D})
151
+ end
152
+
153
+ describe "observation time" do
154
+ it "defaults to 12 seconds (slightly longer than a single heartbeat interval)" do
155
+ EM.should_receive(:add_timer).with(12)
156
+ cf %W[app-placement]
157
+ end
158
+
159
+ it "can be overridden" do
160
+ EM.should_receive(:add_timer).with(3)
161
+ cf %W[app-placement --time 3]
162
+ end
163
+ end
164
+ end
@@ -63,20 +63,84 @@ module CFTools::Tunnel
63
63
  describe "#tunnel_to" do
64
64
  let(:gateway) { double }
65
65
 
66
- before { gateway.stub(:open) }
66
+ before { Process.stub(:spawn) }
67
+
68
+ before { subject.stub(:wait_for_port_open) }
67
69
 
68
70
  it "creates a gateway using the given user/host" do
69
- expect(Net::SSH::Gateway).to receive(:new).with("ghost", "guser") { gateway }
70
- subject.tunnel_to("1.2.3.4", 1234, "guser@ghost")
71
- end
71
+ subject.stub(:grab_ephemeral_port => 5678)
72
+
73
+ expect(Process).to receive(:spawn).with(
74
+ "ssh -o StrictHostKeyChecking=no -N -L 5678:1.2.3.4:1234 guser@ghost")
75
+
76
+ expect(subject).to receive(:wait_for_port_open).with(5678)
72
77
 
73
- it "opens a local tunnel and returns its port" do
74
- Net::SSH::Gateway.stub(:new).with("ghost", "guser") { gateway }
75
- expect(gateway).to receive(:open).with("1.2.3.4", 1234) { 5678 }
76
78
  expect(subject.tunnel_to("1.2.3.4", 1234, "guser@ghost")).to eq(5678)
77
79
  end
78
80
  end
79
81
 
82
+ describe "#current_deployment" do
83
+ let(:director) { double }
84
+
85
+ before { director.stub(:list_deployments => deployments) }
86
+
87
+ let(:cf_deployment) do
88
+ { "name" => "a", "releases" => [{ "name" => "cf" }] }
89
+ end
90
+
91
+ let(:cf_release_deployment) do
92
+ { "name" => "b", "releases" => [{ "name" => "cf-release" }] }
93
+ end
94
+
95
+ let(:other_deployment) do
96
+ { "name" => "b", "releases" => [{ "name" => "some-release" }] }
97
+ end
98
+
99
+ context "when there are no deployments" do
100
+ let(:deployments) { [] }
101
+
102
+ it "fails" do
103
+ expect {
104
+ subject.current_deployment(director)
105
+ }.to raise_error(/no deployments/i)
106
+ end
107
+ end
108
+
109
+ context "when there is one deployment with release name 'cf'" do
110
+ let(:deployments) { [cf_deployment] }
111
+
112
+ it "returns that deployment" do
113
+ expect(subject.current_deployment(director)).to eq(cf_deployment)
114
+ end
115
+ end
116
+
117
+ context "when there is one deployment with release name 'cf-release'" do
118
+ let(:deployments) { [cf_release_deployment] }
119
+
120
+ it "returns that deployment" do
121
+ expect(subject.current_deployment(director)).to eq(cf_release_deployment)
122
+ end
123
+ end
124
+
125
+ context "when there are multiple deployments" do
126
+ let(:deployments) { [cf_deployment, cf_release_deployment, other_deployment] }
127
+
128
+ it "asks which deployment to use" do
129
+ called = false
130
+
131
+ should_ask("Which deployment?", anything) do |_, opts|
132
+ called = true
133
+ expect(opts[:choices]).to eq(deployments)
134
+ expect(opts[:display].call(deployments.first)).to eq("a")
135
+ cf_release_deployment
136
+ end
137
+
138
+ expect(subject.current_deployment(director)).to eq(cf_release_deployment)
139
+ expect(called).to be_true
140
+ end
141
+ end
142
+ end
143
+
80
144
  describe "#authenticate_with_director" do
81
145
  let(:director) { double }
82
146
 
@@ -9,9 +9,9 @@ module CFTools::Tunnel
9
9
  let(:stream) { double }
10
10
 
11
11
  let(:vms) do
12
- [ { "ips" => ["1.2.3.4"], "job_name" => "cloud_controller", "index" => 0 },
13
- { "ips" => ["1.2.3.5"], "job_name" => "dea_next", "index" => 0 },
14
- { "ips" => ["1.2.3.6"], "job_name" => "dea_next", "index" => 1 }
12
+ [ { "ips" => ["1.2.3.4"], "job_name" => "api_z1", "index" => 0 },
13
+ { "ips" => ["1.2.3.5"], "job_name" => "runner_z1", "index" => 0 },
14
+ { "ips" => ["1.2.3.6"], "job_name" => "runner_z1", "index" => 1 }
15
15
  ]
16
16
  end
17
17
 
@@ -72,9 +72,9 @@ module CFTools::Tunnel
72
72
  context "when there are jobs to log" do
73
73
  it "streams their locations" do
74
74
  expect(stream).to receive(:stream).with(hash_including(
75
- ["cloud_controller", 0] => anything,
76
- ["dea_next", 0] => anything,
77
- ["dea_next", 1] => anything))
75
+ ["api_z1", 0] => anything,
76
+ ["runner_z1", 0] => anything,
77
+ ["runner_z1", 1] => anything))
78
78
 
79
79
  cf %W[watch-logs some-director.com]
80
80
  end
@@ -85,17 +85,17 @@ module CFTools::Tunnel
85
85
  entry3_time = Time.new(2011, 06, 21, 1, 2, 5)
86
86
 
87
87
  entry1 = LogEntry.new(
88
- "cloud_controller/0",
88
+ "api_z1/0",
89
89
  %Q[{"message":"a","timestamp":#{entry1_time.to_f},"log_level":"info"}],
90
90
  :stdout)
91
91
 
92
92
  entry2 = LogEntry.new(
93
- "dea_next/1",
93
+ "runner_z1/1",
94
94
  %Q[{"message":"b","timestamp":#{entry2_time.to_f},"log_level":"warn","data":{"foo":"bar"}}],
95
95
  :stdout)
96
96
 
97
97
  entry3 = LogEntry.new(
98
- "dea_next/0",
98
+ "runner_z1/0",
99
99
  %Q[{"message":"c","timestamp":#{entry3_time.to_f},"log_level":"error"}],
100
100
  :stdout)
101
101
 
@@ -103,15 +103,15 @@ module CFTools::Tunnel
103
103
 
104
104
  cf %W[watch-logs some-director.com]
105
105
 
106
- expect(output).to say("cloud_controller/0 01:02:03 AM info a \n")
107
- expect(output).to say("dea_next/1 01:02:04 AM warn b {\"foo\"=>\"bar\"}\n")
108
- expect(output).to say("dea_next/0 01:02:05 AM error c \n")
106
+ expect(output).to say("api_z1/0 01:02:03 AM info a \n")
107
+ expect(output).to say("runner_z1/1 01:02:04 AM warn b {\"foo\"=>\"bar\"}\n")
108
+ expect(output).to say("runner_z1/0 01:02:05 AM error c \n")
109
109
  end
110
110
 
111
111
  context "and components were specified" do
112
112
  it "streams their locations" do
113
- expect(stream).to receive(:stream).with(["cloud_controller", 0] => anything)
114
- cf %W[watch-logs some-director.com cloud_controller]
113
+ expect(stream).to receive(:stream).with(["api_z1", 0] => anything)
114
+ cf %W[watch-logs some-director.com api_z1]
115
115
  end
116
116
  end
117
117
  end
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.4.0
4
+ version: 3.0.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-07-09 00:00:00.000000000 Z
12
+ date: 2013-10-08 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: cfoundry
@@ -200,7 +200,7 @@ dependencies:
200
200
  requirements:
201
201
  - - ~>
202
202
  - !ruby/object:Gem::Version
203
- version: 0.1.0
203
+ version: '0.2'
204
204
  type: :development
205
205
  prerelease: false
206
206
  version_requirements: !ruby/object:Gem::Requirement
@@ -208,7 +208,7 @@ dependencies:
208
208
  requirements:
209
209
  - - ~>
210
210
  - !ruby/object:Gem::Version
211
- version: 0.1.0
211
+ version: '0.2'
212
212
  - !ruby/object:Gem::Dependency
213
213
  name: fakefs
214
214
  requirement: !ruby/object:Gem::Requirement
@@ -249,6 +249,7 @@ extensions: []
249
249
  extra_rdoc_files: []
250
250
  files:
251
251
  - Rakefile
252
+ - lib/tools-cf-plugin/app-placement.rb
252
253
  - lib/tools-cf-plugin/dea-ads.rb
253
254
  - lib/tools-cf-plugin/dea-apps.rb
254
255
  - lib/tools-cf-plugin/plugin.rb
@@ -262,6 +263,7 @@ files:
262
263
  - lib/tools-cf-plugin/tunnel/watch-logs.rb
263
264
  - lib/tools-cf-plugin/version.rb
264
265
  - lib/tools-cf-plugin/watch.rb
266
+ - spec/app-placement_spec.rb
265
267
  - spec/dea-ads_spec.rb
266
268
  - spec/dea-apps_spec.rb
267
269
  - spec/fixtures/dea-apps/stats_1.json
@@ -305,6 +307,7 @@ signing_key:
305
307
  specification_version: 3
306
308
  summary: Cloud Foundry tooling commands.
307
309
  test_files:
310
+ - spec/app-placement_spec.rb
308
311
  - spec/dea-ads_spec.rb
309
312
  - spec/dea-apps_spec.rb
310
313
  - spec/fixtures/dea-apps/stats_1.json
@@ -323,4 +326,3 @@ test_files:
323
326
  - spec/tunnel/tunnel-nats_spec.rb
324
327
  - spec/tunnel/watch-logs_spec.rb
325
328
  - spec/watch_spec.rb
326
- has_rdoc: