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.
- data/lib/tools-cf-plugin/app-placement.rb +145 -0
- data/lib/tools-cf-plugin/plugin.rb +1 -0
- data/lib/tools-cf-plugin/tunnel/base.rb +49 -11
- data/lib/tools-cf-plugin/tunnel/tunnel-nats.rb +1 -4
- data/lib/tools-cf-plugin/tunnel/watch-logs.rb +8 -8
- data/lib/tools-cf-plugin/version.rb +1 -1
- data/lib/tools-cf-plugin/watch.rb +5 -1
- data/spec/app-placement_spec.rb +164 -0
- data/spec/tunnel/base_spec.rb +71 -7
- data/spec/tunnel/watch-logs_spec.rb +14 -14
- metadata +7 -5
@@ -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
|
@@ -63,12 +63,55 @@ module CFTools
|
|
63
63
|
end
|
64
64
|
|
65
65
|
def tunnel_to(address, remote_port, gateway)
|
66
|
-
|
67
|
-
|
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
|
-
|
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
|
-
"
|
12
|
-
"
|
13
|
-
"
|
14
|
-
"
|
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
|
@@ -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
|
data/spec/tunnel/base_spec.rb
CHANGED
@@ -63,20 +63,84 @@ module CFTools::Tunnel
|
|
63
63
|
describe "#tunnel_to" do
|
64
64
|
let(:gateway) { double }
|
65
65
|
|
66
|
-
before {
|
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
|
-
|
70
|
-
|
71
|
-
|
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" => "
|
13
|
-
{ "ips" => ["1.2.3.5"], "job_name" => "
|
14
|
-
{ "ips" => ["1.2.3.6"], "job_name" => "
|
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
|
-
["
|
76
|
-
["
|
77
|
-
["
|
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
|
-
"
|
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
|
-
"
|
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
|
-
"
|
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("
|
107
|
-
expect(output).to say("
|
108
|
-
expect(output).to say("
|
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(["
|
114
|
-
cf %W[watch-logs some-director.com
|
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:
|
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-
|
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.
|
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.
|
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:
|