management 1.1 → 1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +9 -1
- data/lib/management.rb +4 -1
- data/lib/management/command.rb +17 -7
- data/lib/management/commands/attach_address.rb +20 -0
- data/lib/management/commands/destroy_servers.rb +27 -0
- data/lib/management/commands/list_addresses.rb +31 -0
- data/lib/management/commands/open_console.rb +16 -0
- data/lib/management/commands/run_script.rb +14 -20
- data/lib/management/commands/start_server.rb +2 -1
- data/lib/management/commands/stop_server.rb +2 -1
- data/lib/management/helper.rb +7 -1
- data/lib/management/interpreter.rb +1 -1
- data/lib/management/version.rb +1 -1
- data/management.gemspec +1 -1
- data/spec/main_spec.rb +44 -9
- metadata +9 -6
- data/lib/management/commands/destroy_server.rb +0 -25
data/README.md
CHANGED
@@ -2,10 +2,18 @@
|
|
2
2
|
|
3
3
|
Minimalist EC2 configuration & deployment tool.
|
4
4
|
|
5
|
-
- Version: **1.
|
5
|
+
- Version: **1.2**
|
6
6
|
|
7
7
|
![build status](https://travis-ci.org/sdegutis/management.svg?branch=master)
|
8
8
|
|
9
|
+
#### Install
|
10
|
+
|
11
|
+
`gem install management`
|
12
|
+
|
13
|
+
#### Intro
|
14
|
+
|
15
|
+
Read [this short blog post](http://sdegutis.github.io/2014/06/09/announcing-management/) for a brief summary of this project.
|
16
|
+
|
9
17
|
#### Usage
|
10
18
|
|
11
19
|
```
|
data/lib/management.rb
CHANGED
@@ -5,8 +5,11 @@ require_relative 'management/helper'
|
|
5
5
|
require_relative 'management/command'
|
6
6
|
require_relative 'management/commands/create_server'
|
7
7
|
require_relative 'management/commands/list_servers'
|
8
|
-
require_relative 'management/commands/
|
8
|
+
require_relative 'management/commands/destroy_servers'
|
9
9
|
require_relative 'management/commands/start_server'
|
10
10
|
require_relative 'management/commands/stop_server'
|
11
11
|
require_relative 'management/commands/run_script'
|
12
12
|
require_relative 'management/commands/ssh_server'
|
13
|
+
require_relative 'management/commands/list_addresses'
|
14
|
+
require_relative 'management/commands/attach_address'
|
15
|
+
require_relative 'management/commands/open_console'
|
data/lib/management/command.rb
CHANGED
@@ -18,23 +18,33 @@ module Management
|
|
18
18
|
self.class.name.split('::').last.
|
19
19
|
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
20
20
|
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
21
|
-
tr(
|
21
|
+
tr('_', '-').
|
22
22
|
downcase
|
23
23
|
end
|
24
24
|
|
25
25
|
def help_string
|
26
26
|
return sprintf("%20s ", self.command_name) + fn.parameters.map do |req, name|
|
27
|
-
name =
|
28
|
-
req
|
27
|
+
name = '<' + name.to_s.sub(/_names?/, '') + '>'
|
28
|
+
case req
|
29
|
+
when :opt then '[' + name + ']'
|
30
|
+
when :rest then name + ' [...]'
|
31
|
+
else name
|
32
|
+
end
|
29
33
|
end.join(' ')
|
30
34
|
end
|
31
35
|
|
36
|
+
def true_arity
|
37
|
+
min = fn.parameters.take_while{|req, name| req == :req}.count
|
38
|
+
max = fn.parameters.count
|
39
|
+
max = Float::INFINITY if max > 0 && fn.parameters.last.first == :rest
|
40
|
+
min..max
|
41
|
+
end
|
42
|
+
|
32
43
|
def call_with(args, error_handler)
|
33
|
-
|
34
|
-
num_req_args = fn.arity
|
44
|
+
arity = self.true_arity
|
35
45
|
|
36
|
-
error_handler.call "not enough arguments" if args.count <
|
37
|
-
error_handler.call "too many arguments" if args.count >
|
46
|
+
error_handler.call "not enough arguments" if args.count < arity.begin
|
47
|
+
error_handler.call "too many arguments" if args.count > arity.end
|
38
48
|
|
39
49
|
fn.call *args
|
40
50
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require_relative '../command'
|
2
|
+
|
3
|
+
module Management
|
4
|
+
|
5
|
+
class AttachAddress < Management::Command
|
6
|
+
|
7
|
+
include Management::Helper
|
8
|
+
|
9
|
+
def run(address_name, server_name)
|
10
|
+
address = get_address(address_name)
|
11
|
+
server = get_server(server_name)
|
12
|
+
|
13
|
+
puts "Attaching #{address_name} to #{server_name}..."
|
14
|
+
address.server = server
|
15
|
+
puts "Done."
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require_relative '../command'
|
2
|
+
|
3
|
+
module Management
|
4
|
+
|
5
|
+
class DestroyServers < Management::Command
|
6
|
+
|
7
|
+
include Management::Helper
|
8
|
+
|
9
|
+
def run(*server_names)
|
10
|
+
servers = server_names.map{|server_name| get_server(server_name)}
|
11
|
+
|
12
|
+
puts "You are about to delete the following servers:"
|
13
|
+
puts ['', *servers.map{ |server| " - #{server.name}" }, '', ''].join("\n")
|
14
|
+
|
15
|
+
print "Are you sure you want to do this? Type 'Yes' to continue, or anything else to abort: "
|
16
|
+
abort "Aborted." if $stdin.gets.chomp != 'Yes'
|
17
|
+
|
18
|
+
servers.each do |server|
|
19
|
+
puts "Destroying #{server.name}..."
|
20
|
+
server.destroy
|
21
|
+
puts "Done."
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require_relative '../command'
|
2
|
+
|
3
|
+
module Management
|
4
|
+
|
5
|
+
class ListAddresses < Management::Command
|
6
|
+
|
7
|
+
include Management::Helper
|
8
|
+
|
9
|
+
def run()
|
10
|
+
servers = live_servers
|
11
|
+
|
12
|
+
cols = [
|
13
|
+
{size: 20, title: "IP", fn: ->(addr){ addr.public_ip } },
|
14
|
+
{size: 20, title: "Server", fn: ->(addr){ s = servers.find{|server| server.id == addr.server_id }; s ? s.name : "n/a" } },
|
15
|
+
{size: 30, title: "Name", fn: ->(addr){ a = config[:addresses].find{|k, v| v == addr.public_ip}; a ? a.first : "n/a" } },
|
16
|
+
{size: 15, title: "Status", fn: ->(addr){ s = servers.find{|server| server.id == addr.server_id }; s ? s.state : "n/a" } },
|
17
|
+
]
|
18
|
+
|
19
|
+
format = cols.map{|c| "%-#{c[:size]}s"}.join(" ") + "\n"
|
20
|
+
|
21
|
+
send :printf, *([format].concat(cols.map{|c|c[:title]}))
|
22
|
+
send :printf, *([format].concat(cols.map{|c|'-' * c[:size]}))
|
23
|
+
|
24
|
+
cloud.addresses.each do |address|
|
25
|
+
send :printf, *([format].concat(cols.map{|c|c[:fn].call address}))
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -24,21 +24,28 @@ module Management
|
|
24
24
|
|
25
25
|
case type.to_sym
|
26
26
|
when :copy
|
27
|
-
|
27
|
+
local_path, remote_path, opts = *data
|
28
|
+
puts "############ Copying #{local_path} -> #{remote_path}"
|
29
|
+
|
30
|
+
copy_file(server, local_path, remote_path, opts)
|
28
31
|
when :run
|
29
|
-
|
30
|
-
|
32
|
+
cmd = data
|
33
|
+
puts "############ Running #{cmd}"
|
31
34
|
|
35
|
+
code = run_remote_command(server, cmd)
|
36
|
+
if code != 0
|
37
|
+
abort "Failed. Exit code: #{code}"
|
38
|
+
end
|
39
|
+
end
|
32
40
|
end
|
33
41
|
|
42
|
+
puts "############ Success!"
|
34
43
|
end
|
35
44
|
|
36
45
|
def copy_file(server, local_path, remote_path, opts = nil)
|
37
46
|
should_template = opts && opts[:template]
|
38
47
|
custom_chown = opts && opts[:chown]
|
39
48
|
|
40
|
-
puts "Copying #{local_path} -> #{remote_path}"
|
41
|
-
|
42
49
|
Dir.mktmpdir('management-file-dir') do |file_tmpdir|
|
43
50
|
|
44
51
|
# copy to the fake "remote" path locally
|
@@ -63,27 +70,14 @@ module Management
|
|
63
70
|
server.copy_file(local_tar_path, remote_tar_path)
|
64
71
|
server.extract_tar(remote_tar_path)
|
65
72
|
server.chown_r(remote_path, custom_chown) if custom_chown
|
66
|
-
|
67
73
|
end
|
68
|
-
|
69
74
|
end
|
70
|
-
|
71
75
|
end
|
72
76
|
|
77
|
+
# returns error code
|
73
78
|
def run_remote_command(server, cmd)
|
74
|
-
puts "Running #{cmd}"
|
75
|
-
|
76
79
|
result = server.ssh("#{cmd}").first
|
77
|
-
|
78
|
-
if result.respond_to?(:status)
|
79
|
-
puts
|
80
|
-
puts "---------------------------"
|
81
|
-
if result.status == 0
|
82
|
-
puts "Success!"
|
83
|
-
else
|
84
|
-
puts "Failed. Exit code: #{result.status}"
|
85
|
-
end
|
86
|
-
end
|
80
|
+
return result.status
|
87
81
|
end
|
88
82
|
|
89
83
|
def missing_local_files(script)
|
data/lib/management/helper.rb
CHANGED
@@ -25,8 +25,14 @@ module Management
|
|
25
25
|
server
|
26
26
|
end
|
27
27
|
|
28
|
+
def get_address(name)
|
29
|
+
addresses = cloud.addresses
|
30
|
+
ip = config[:addresses][name.to_sym] or invalid_selection "Invalid address: #{name}", config[:addresses].map(&:first)
|
31
|
+
addresses.find{|a| a.public_ip == ip} or abort "Could not find an address with the IP #{ip} (#{name})"
|
32
|
+
end
|
33
|
+
|
28
34
|
def live_servers
|
29
|
-
cloud.servers.reject{ |s| s.state == 'terminated' }
|
35
|
+
cloud.servers.reject{ |s| s.state == 'terminated' || s.state == 'shutting-down' }
|
30
36
|
end
|
31
37
|
|
32
38
|
def config
|
@@ -6,7 +6,7 @@ module Management
|
|
6
6
|
commands = Management::Command.all
|
7
7
|
|
8
8
|
parser = OptionParser.new do |opts|
|
9
|
-
opts.banner = "Usage: management [command
|
9
|
+
opts.banner = "Usage: management [command [arg ...]]"
|
10
10
|
opts.separator('')
|
11
11
|
opts.separator('Commands:')
|
12
12
|
commands.each { |command| opts.separator command.help_string }
|
data/lib/management/version.rb
CHANGED
data/management.gemspec
CHANGED
@@ -18,9 +18,9 @@ Gem::Specification.new do |s|
|
|
18
18
|
|
19
19
|
s.add_dependency 'fog'
|
20
20
|
s.add_dependency 'unf' # just to shut up the warnings
|
21
|
+
s.add_dependency 'pry'
|
21
22
|
|
22
23
|
s.add_development_dependency 'rake'
|
23
|
-
s.add_development_dependency 'pry'
|
24
24
|
s.add_development_dependency 'fakefs'
|
25
25
|
s.add_development_dependency 'rspec', '~> 3.0.0'
|
26
26
|
s.add_development_dependency 'guard-rspec'
|
data/spec/main_spec.rb
CHANGED
@@ -40,6 +40,41 @@ describe 'management' do
|
|
40
40
|
|
41
41
|
before { subject.define_singleton_method(:raw_yaml) { YAML.load(SampleConfig) } }
|
42
42
|
|
43
|
+
describe Management::Command do
|
44
|
+
|
45
|
+
describe "true arity" do
|
46
|
+
|
47
|
+
around(:each) { |example| timeout(0.05, &example) }
|
48
|
+
|
49
|
+
it "considers 1 required arg to have 1..1 arity" do
|
50
|
+
subject.define_singleton_method(:run){|x|}
|
51
|
+
expect(subject.true_arity).to eq 1..1
|
52
|
+
end
|
53
|
+
|
54
|
+
it "considers 2 required args to have 2..2 arity" do
|
55
|
+
subject.define_singleton_method(:run){|x, y|}
|
56
|
+
expect(subject.true_arity).to eq 2..2
|
57
|
+
end
|
58
|
+
|
59
|
+
it "considers 2 required args and one optinal arg to have 2..3 arity" do
|
60
|
+
subject.define_singleton_method(:run){|x, y, z = nil|}
|
61
|
+
expect(subject.true_arity).to eq 2..3
|
62
|
+
end
|
63
|
+
|
64
|
+
it "considers 2 required args and a final rest arg to have 2..Float::INFINITY arity" do
|
65
|
+
subject.define_singleton_method(:run){|x, y, *z|}
|
66
|
+
expect(subject.true_arity).to eq 2..Float::INFINITY
|
67
|
+
end
|
68
|
+
|
69
|
+
it "considers 1 required arg, one optional arg, and a final rest arg to have 1..Float::INFINITY arity" do
|
70
|
+
subject.define_singleton_method(:run){|x, y = nil, *z|}
|
71
|
+
expect(subject.true_arity).to eq 1..Float::INFINITY
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
43
78
|
describe Management::Helper do
|
44
79
|
|
45
80
|
subject { Object.new.extend Management::Helper }
|
@@ -217,9 +252,9 @@ describe 'management' do
|
|
217
252
|
|
218
253
|
end
|
219
254
|
|
220
|
-
describe Management::
|
255
|
+
describe Management::DestroyServers do
|
221
256
|
|
222
|
-
let(:server) { double "server" }
|
257
|
+
let(:server) { double "server", name: "server-1" }
|
223
258
|
before { allow(subject).to receive(:get_server).with("server-1").and_return(server) }
|
224
259
|
|
225
260
|
it "destroys the given server if you type 'Yes' verbatim" do
|
@@ -230,13 +265,13 @@ describe 'management' do
|
|
230
265
|
it "does not destroy the given server if you don't type 'Yes' verbatim" do
|
231
266
|
expect(server).not_to receive(:destroy)
|
232
267
|
without_stdout do
|
233
|
-
with_stdin("yes\n") { subject.run("server-1") }
|
234
|
-
with_stdin("Y\n") { subject.run("server-1") }
|
235
|
-
with_stdin("y\n") { subject.run("server-1") }
|
236
|
-
with_stdin("yep\n") { subject.run("server-1") }
|
237
|
-
with_stdin("\n") { subject.run("server-1") }
|
238
|
-
with_stdin("YES\n") { subject.run("server-1") }
|
239
|
-
with_stdin("Yes.\n") { subject.run("server-1") }
|
268
|
+
expect{with_stdin("yes\n" ) { subject.run("server-1") }}.to raise_error SystemExit
|
269
|
+
expect{with_stdin("Y\n" ) { subject.run("server-1") }}.to raise_error SystemExit
|
270
|
+
expect{with_stdin("y\n" ) { subject.run("server-1") }}.to raise_error SystemExit
|
271
|
+
expect{with_stdin("yep\n" ) { subject.run("server-1") }}.to raise_error SystemExit
|
272
|
+
expect{with_stdin("\n" ) { subject.run("server-1") }}.to raise_error SystemExit
|
273
|
+
expect{with_stdin("YES\n" ) { subject.run("server-1") }}.to raise_error SystemExit
|
274
|
+
expect{with_stdin("Yes.\n") { subject.run("server-1") }}.to raise_error SystemExit
|
240
275
|
end
|
241
276
|
end
|
242
277
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: management
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '1.
|
4
|
+
version: '1.2'
|
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: 2014-06-
|
12
|
+
date: 2014-06-12 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: fog
|
@@ -44,14 +44,14 @@ dependencies:
|
|
44
44
|
- !ruby/object:Gem::Version
|
45
45
|
version: '0'
|
46
46
|
- !ruby/object:Gem::Dependency
|
47
|
-
name:
|
47
|
+
name: pry
|
48
48
|
requirement: !ruby/object:Gem::Requirement
|
49
49
|
none: false
|
50
50
|
requirements:
|
51
51
|
- - ! '>='
|
52
52
|
- !ruby/object:Gem::Version
|
53
53
|
version: '0'
|
54
|
-
type: :
|
54
|
+
type: :runtime
|
55
55
|
prerelease: false
|
56
56
|
version_requirements: !ruby/object:Gem::Requirement
|
57
57
|
none: false
|
@@ -60,7 +60,7 @@ dependencies:
|
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '0'
|
62
62
|
- !ruby/object:Gem::Dependency
|
63
|
-
name:
|
63
|
+
name: rake
|
64
64
|
requirement: !ruby/object:Gem::Requirement
|
65
65
|
none: false
|
66
66
|
requirements:
|
@@ -140,9 +140,12 @@ files:
|
|
140
140
|
- lib/ext/fog.rb
|
141
141
|
- lib/management.rb
|
142
142
|
- lib/management/command.rb
|
143
|
+
- lib/management/commands/attach_address.rb
|
143
144
|
- lib/management/commands/create_server.rb
|
144
|
-
- lib/management/commands/
|
145
|
+
- lib/management/commands/destroy_servers.rb
|
146
|
+
- lib/management/commands/list_addresses.rb
|
145
147
|
- lib/management/commands/list_servers.rb
|
148
|
+
- lib/management/commands/open_console.rb
|
146
149
|
- lib/management/commands/run_script.rb
|
147
150
|
- lib/management/commands/ssh_server.rb
|
148
151
|
- lib/management/commands/start_server.rb
|
@@ -1,25 +0,0 @@
|
|
1
|
-
require_relative '../command'
|
2
|
-
|
3
|
-
module Management
|
4
|
-
|
5
|
-
class DestroyServer < Management::Command
|
6
|
-
|
7
|
-
include Management::Helper
|
8
|
-
|
9
|
-
def run(server_name)
|
10
|
-
server = get_server(server_name)
|
11
|
-
|
12
|
-
print "Are you sure you want to do this? Type 'Yes' to continue, or anything else to abort: "
|
13
|
-
answer = $stdin.gets.chomp
|
14
|
-
|
15
|
-
if answer == 'Yes'
|
16
|
-
server.destroy
|
17
|
-
puts "Destroyed."
|
18
|
-
else
|
19
|
-
puts "Aborted."
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
end
|
24
|
-
|
25
|
-
end
|