tools-cf-plugin 2.4.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: