management 1.1 → 1.2

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/README.md CHANGED
@@ -2,10 +2,18 @@
2
2
 
3
3
  Minimalist EC2 configuration & deployment tool.
4
4
 
5
- - Version: **1.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/destroy_server'
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'
@@ -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 = "<#{name.to_s.sub('_name', '')}>"
28
- req == :opt ? "[#{name}]" : name
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
- num_all_args = fn.parameters.count
34
- num_req_args = fn.arity
44
+ arity = self.true_arity
35
45
 
36
- error_handler.call "not enough arguments" if args.count < num_req_args
37
- error_handler.call "too many arguments" if args.count > num_all_args
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
@@ -0,0 +1,16 @@
1
+ require_relative '../command'
2
+
3
+ module Management
4
+
5
+ class OpenConsole < Management::Command
6
+
7
+ include Management::Helper
8
+
9
+ def run()
10
+ require 'pry'
11
+ binding.pry
12
+ end
13
+
14
+ end
15
+
16
+ end
@@ -24,21 +24,28 @@ module Management
24
24
 
25
25
  case type.to_sym
26
26
  when :copy
27
- copy_file(server, *data)
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
- run_remote_command(server, data)
30
- end
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)
@@ -8,8 +8,9 @@ module Management
8
8
 
9
9
  def run(server_name)
10
10
  server = get_server(server_name)
11
+ puts "Starting #{server_name}..."
11
12
  server.start
12
- puts "Started #{server_name}."
13
+ puts "Done."
13
14
  end
14
15
 
15
16
  end
@@ -8,8 +8,9 @@ module Management
8
8
 
9
9
  def run(server_name)
10
10
  server = get_server(server_name)
11
+ puts "Stopping #{server_name}..."
11
12
  server.stop
12
- puts "Stopped #{server_name}."
13
+ puts "Done."
13
14
  end
14
15
 
15
16
  end
@@ -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] [args*]"
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 }
@@ -1,3 +1,3 @@
1
1
  module Management
2
- VERSION = "1.1"
2
+ VERSION = "1.2"
3
3
  end
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::DestroyServer do
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.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-09 00:00:00.000000000 Z
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: rake
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: :development
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: pry
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/destroy_server.rb
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