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.
- 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:
|