virtualmaster 0.0.7 → 0.1.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/.gitignore CHANGED
@@ -1,6 +1,5 @@
1
1
  *.gem
2
2
  .bundle
3
- Gemfile.lock
4
3
  pkg/*
5
4
  vendor/bundle
6
5
  vendor/cache
@@ -0,0 +1,40 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ virtualmaster (0.1.0)
5
+ commander (~> 4.1.2)
6
+ deltacloud-client (~> 0.5.0)
7
+ net-ssh (~> 2.3.0)
8
+ terminal-table (~> 1.4.4)
9
+
10
+ GEM
11
+ remote: http://rubygems.org/
12
+ specs:
13
+ commander (4.1.2)
14
+ highline (~> 1.6.11)
15
+ deltacloud-client (0.5.0)
16
+ nokogiri (>= 1.4.3)
17
+ rest-client (>= 1.6.1)
18
+ diff-lcs (1.1.3)
19
+ highline (1.6.11)
20
+ mime-types (1.18)
21
+ net-ssh (2.3.0)
22
+ nokogiri (1.5.2)
23
+ rest-client (1.6.7)
24
+ mime-types (>= 1.16)
25
+ rspec (2.9.0)
26
+ rspec-core (~> 2.9.0)
27
+ rspec-expectations (~> 2.9.0)
28
+ rspec-mocks (~> 2.9.0)
29
+ rspec-core (2.9.0)
30
+ rspec-expectations (2.9.1)
31
+ diff-lcs (~> 1.1.3)
32
+ rspec-mocks (2.9.0)
33
+ terminal-table (1.4.5)
34
+
35
+ PLATFORMS
36
+ ruby
37
+
38
+ DEPENDENCIES
39
+ rspec (~> 2)
40
+ virtualmaster!
@@ -1,6 +1,7 @@
1
- # VirtualMaster command line interface
1
+ # Virtualmaster command line interface
2
2
 
3
- Proof of concept of VirtualMaster command line interface
3
+
4
+ Proof of concept of Virtualmaster command line interface
4
5
 
5
6
  # virtualmaster config
6
7
  Running virtualmaster for first time.
@@ -13,13 +14,18 @@ Proof of concept of VirtualMaster command line interface
13
14
 
14
15
  Settings stored within ~/.virtualmaster
15
16
 
16
- # virtualmaster create demo1 --image lucid
17
- Using image 'lucid' with id (999).
18
- Creating 'micro' instance (512 MB memory/5 GB storage).
19
- Instance launch request accepted (instance id 44444).
20
-
17
+ # virtualmaster create demo1 --image ubuntu_lucid
18
+ Using image 'ubuntu_lucid' with ID 124
19
+ Creating 'micro' instance (512 MB memory/10 GB storage)
20
+ Instance launch request accepted. Instance ID 47135
21
+
21
22
  Default password 'AdVc:PBi8&7L'.
22
23
 
24
+ Waiting for instance................
25
+ Instance ready.
26
+
27
+ Try to login using `ssh root@80.79.29.246'
28
+
23
29
  # virtualmaster instances
24
30
  +-------+---------+----------------+
25
31
  | name | state | ip_address |
@@ -33,22 +39,21 @@ The current version of `virtualmaster` command line interface should work with R
33
39
 
34
40
  ## Automatically install SSH keys
35
41
 
36
- VirtualMaster CLI can install your SSH keys to a remote machine automatically using `--copy-id` switch.
42
+ Virtualmaster CLI can install your SSH keys to a remote machine automatically using `--identity IDENTITY_FILE` command-line option.
37
43
 
38
-
39
- virtualmaster create demo1 --image ubuntu_lucid --copy-id
44
+ virtualmaster create demo1 --image ubuntu_lucid --identity ~/.ssh/id_rsa
40
45
  Using image 'ubuntu_lucid' with ID 124
41
46
  Creating 'micro' instance (512 MB memory/10 GB storage)
42
47
  Instance launch request accepted. Instance ID 45387
43
48
 
44
49
  Default password 'vBK7i!kK'
50
+
45
51
  Waiting for instance............
46
- Loading identity file
52
+ Instance ready.
53
+
54
+ Loading identity file /Users/virtualmaster/.ssh/id_rsa
47
55
 
48
- Instance ready!
49
56
  Try to login using `ssh root@195.140.253.130'
50
-
51
- If you want to specify other key (ie. not ~/.ssh/id\_rsa) use option `--identity IDENTITY_FILE`.
52
57
 
53
58
  ## Instance size
54
59
 
@@ -12,19 +12,24 @@ end
12
12
 
13
13
  program :name, "virtualmaster"
14
14
  program :version, VirtualMaster::VERSION
15
- program :description, "VirtualMaster command line interface"
15
+ program :description, "Virtualmaster command line interface"
16
16
  program :help_formatter, :compact
17
17
 
18
18
  default_command :help
19
19
 
20
20
  VirtualMaster::CLI.run do
21
- end
21
+ # load callback
22
+ callback_files = File.join(File.dirname(__FILE__), "../lib/vmaster/callbacks/*.rb")
23
+ Dir.glob(callback_files).each do |f|
24
+ VirtualMaster::Callbacks.load_file(f)
25
+ end
22
26
 
23
- include Commander::UI
24
- include Commander::UI::AskForClass
25
- include Commander::Delegates
27
+ # TODO find callbacks in other rubygems
26
28
 
27
- $terminal.wrap_at = HighLine::SystemExtensions.terminal_size.first - 5 rescue 80 if $stdin.tty?
29
+ # include commands
30
+ require 'vmaster/config_command'
31
+ require 'vmaster/server_commands'
32
+ end
28
33
 
29
34
  Commander::Runner.instance.run!
30
35
 
@@ -4,6 +4,7 @@ require "vmaster/version"
4
4
  require "vmaster/helpers"
5
5
  require "vmaster/cli"
6
6
  require "vmaster/request"
7
+ require "vmaster/callbacks"
7
8
 
8
9
  require 'commander'
9
10
  require 'commander/delegates'
@@ -17,9 +18,3 @@ include Commander::UI::AskForClass
17
18
  include Commander::Delegates
18
19
 
19
20
  $terminal.wrap_at = HighLine::SystemExtensions.terminal_size.first - 5 rescue 80 if $stdin.tty?
20
-
21
-
22
- # include commands
23
- require 'vmaster/config_command'
24
- require 'vmaster/server_commands'
25
-
@@ -0,0 +1,92 @@
1
+ # encoding: utf-8
2
+
3
+ def callback(name, &block)
4
+ cb = VirtualMaster::Callbacks::Callback.new(name, &block)
5
+
6
+ VirtualMaster::CLI.callbacks << cb
7
+ end
8
+
9
+ module VirtualMaster
10
+ module Callbacks
11
+
12
+ class Callback
13
+ attr_reader :name
14
+
15
+ def initialize(name, &block)
16
+ @name = name
17
+ @blocks = {}
18
+ @option = nil
19
+
20
+ instance_eval &block
21
+ end
22
+
23
+ def before(event, &block)
24
+ store_callback(event, :before, &block)
25
+ end
26
+
27
+ def after(event, &block)
28
+ store_callback(event, :after, &block)
29
+ end
30
+
31
+ #
32
+ # command line options provide configuration
33
+ #
34
+ # TODO support for multiple options
35
+ #
36
+ def option(name, type, description)
37
+ @option = {
38
+ :name => name,
39
+ :type => type,
40
+ :description => description
41
+ }
42
+ end
43
+
44
+ def fire(event, phase, options, server)
45
+ @blocks[event][phase].call(options, server) if includes?(event, phase) && options[@option[:name]]
46
+ end
47
+
48
+ def to_s
49
+ @blocks.inspect
50
+ end
51
+
52
+ def has_option?
53
+ not @option.nil?
54
+ end
55
+
56
+ def to_option
57
+ arguments = []
58
+
59
+ option_name = "--#{@option[:name]}"
60
+ option_name << " VALUE" if @option[:type]
61
+
62
+ arguments << option_name
63
+ arguments << @option[:type] if @option[:type]
64
+ arguments << @option[:description]
65
+ end
66
+
67
+ private
68
+
69
+ def includes?(event, phase)
70
+ @blocks.include?(event) && @blocks[event].include?(phase)
71
+ end
72
+
73
+ def store_callback(event, phase, &block)
74
+ callbacks = @blocks[event] || {}
75
+
76
+ callbacks[phase] = block
77
+
78
+ @blocks[event] = callbacks
79
+ end
80
+ end
81
+
82
+ def self.load_file(file)
83
+ load file
84
+ end
85
+
86
+ def self.trigger_event(event, phase, options, server = {})
87
+ CLI.callbacks.each do |callback|
88
+ callback.fire(event, phase, options, server)
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,16 @@
1
+ #
2
+ # Demo callback
3
+ #
4
+
5
+ callback :demo do
6
+ option :demo, nil, 'Value to print'
7
+
8
+ after :create do |options, server|
9
+ puts "Hello world"
10
+ end
11
+
12
+ after :shutdown do
13
+ puts "That's all folks!"
14
+ end
15
+ end
16
+
@@ -0,0 +1,36 @@
1
+ #
2
+ # SSH keys callback
3
+ #
4
+
5
+ require 'net/ssh'
6
+ require 'base64'
7
+ require 'openssl'
8
+
9
+ callback :ssh_copy_id do
10
+ option :identity, String, 'Identity file which is going to be copied to target machine'
11
+
12
+ before :create do |options|
13
+ # FIXME requires support for optional values
14
+ options[:identity] ||= File.join(ENV['HOME'], '.ssh/id_rsa')
15
+
16
+ abort "Specified identity file #{options[:identity]} doesn't exist!" unless File.exist?(options[:identity])
17
+ end
18
+
19
+ after :create do |options, server|
20
+ authorized_key = nil
21
+
22
+ say "Loading identity file #{options[:identity]}\n"
23
+ key = OpenSSL::PKey::RSA.new File.read options[:identity]
24
+
25
+ # build authorized key output string
26
+ authtype = key.class.to_s.split('::').last.downcase
27
+ b64pub = ::Base64.encode64(key.to_blob).strip.gsub(/[\r\n]/, '')
28
+ authorized_key = "ssh-%s %s\n" % [authtype, b64pub] # => ssh-rsa AAAAB3NzaC1...=
29
+
30
+ Net::SSH.start(server.public_addresses.first[:address], 'root', :password => options[:password]) do |ssh|
31
+ # TODO exception handling
32
+ output = ssh.exec!("mkdir ~/.ssh")
33
+ output = ssh.exec!("echo '#{authorized_key}' >>~/.ssh/authorized_keys")
34
+ end
35
+ end
36
+ end
@@ -5,6 +5,7 @@ module VirtualMaster
5
5
  class CLI
6
6
  @@api = nil
7
7
  @@config = nil
8
+ @@callbacks = []
8
9
 
9
10
  def self.run
10
11
  # load config
@@ -39,5 +40,10 @@ module VirtualMaster
39
40
  def self.config
40
41
  @@config
41
42
  end
43
+
44
+ def self.callbacks
45
+ @@callbacks
46
+ end
42
47
  end
43
48
  end
49
+
@@ -12,24 +12,32 @@ log.level = Logger::WARN
12
12
 
13
13
  command :create do |c|
14
14
  c.description = "Launch new server instance"
15
+
15
16
  c.option '--image TEMPLATE', String, 'instance template to use'
16
17
  c.option '--profile PROFILE', String, 'instance hardware profile'
17
- c.option '--copy-id', 'install public key on a machine'
18
- c.option '--identity IDENTITY', String, 'SSH identity to use (with --copy-id)'
19
18
  c.option '--zone ZONE', String, 'Availability zone to launch instance i'
20
19
  c.option '--level LEVEL', String, 'Instance level to use (personal, production)'
21
- c.option '--wait', 'wait for instance to become operational'
20
+ c.option '--detached', 'Do not wait for instance to become operational (disables callbacks)'
21
+
22
+ # generate options for callbacks
23
+ VirtualMaster::CLI.callbacks.each do |cb|
24
+ c.send :option, *(cb.to_option)
25
+ end
26
+
22
27
  c.action do |args, options|
23
28
  # default values
24
- options.default :identity => File.join(ENV['HOME'], '.ssh/id_rsa')
25
29
  options.default :zone => "prague-l1"
26
30
  options.default :level => "personal"
31
+ options.default :interactive => true
27
32
 
28
33
  name = args.shift || abort('Server name required')
29
34
 
30
35
  # verify server name
31
36
  abort("Virtual server with name #{name} already exists!") if VirtualMaster::Helpers.get_instance(name)
32
37
 
38
+ # support for non-interactive mode
39
+ options.interactive = false if options.detached
40
+
33
41
  # image
34
42
  image_name = nil
35
43
  image_id = VirtualMaster::CLI.config[:default_image] || VirtualHost::DEFAULT_IMAGE
@@ -66,11 +74,14 @@ command :create do |c|
66
74
  hwp = VirtualMaster::Helpers.get_hw_profile(profile[:memory], profile[:storage])
67
75
  abort "Internal error: hardware profile not available" unless hwp
68
76
 
77
+ # before :create callbacks
78
+ VirtualMaster::Callbacks.trigger_event(:create, :before, options.__hash__, nil)
79
+
69
80
  say "Creating '#{profile_name}' instance (#{profile[:memory]} MB memory/#{profile[:storage]/1024} GB storage)"
70
81
 
71
82
  realm = "#{options.zone}-#{options.level}"
72
83
 
73
- instance = VirtualMaster::Helpers.create_instance(name, image_id, hwp.id, realm)
84
+ instance = VirtualMaster::Helpers.create_instance(name, image_id, hwp.id, realm) if options.interactive
74
85
 
75
86
  # TODO handle exceptions (invalid image/profile, limits, etc.)
76
87
 
@@ -78,11 +89,14 @@ command :create do |c|
78
89
 
79
90
  # FIXME authentication is missrepresented within Ruby object
80
91
  password = instance.authentication[:username]
81
- say "\n"
92
+ puts
82
93
  say "Default password '#{password}'"
94
+ puts
95
+
96
+ options.password = password
83
97
 
84
98
  # copy-id implies waiting for instance to become operational
85
- if options.wait || options.copy_id
99
+ if options.interactive
86
100
  print 'Waiting for instance'
87
101
 
88
102
  while (instance = VirtualMaster::Helpers.get_instance(name)).state != "RUNNING" do
@@ -92,30 +106,12 @@ command :create do |c|
92
106
  end
93
107
 
94
108
  puts
109
+ puts "Instance ready."
110
+
111
+ # TODO consistent naming (instance vs server)
112
+ VirtualMaster::Callbacks.trigger_event(:create, :after, options.__hash__, instance)
95
113
 
96
- # copy ssh id
97
- if options.copy_id
98
- authorized_key = nil
99
-
100
- abort "Specified identity file #{options.identity} doesn't exists!" unless File.exist?(options.identity)
101
-
102
- say "Loading identity file\n"
103
- key = OpenSSL::PKey::RSA.new File.read options.identity
104
-
105
- # build authorized key output string
106
- authtype = key.class.to_s.split('::').last.downcase
107
- b64pub = ::Base64.encode64(key.to_blob).strip.gsub(/[\r\n]/, '')
108
- authorized_key = "ssh-%s %s\n" % [authtype, b64pub] # => ssh-rsa AAAAB3NzaC1...=
109
-
110
- Net::SSH.start(instance.public_addresses.first[:address], 'root', :password => password) do |ssh|
111
- # TODO exception handling
112
- output = ssh.exec!("mkdir ~/.ssh")
113
- output = ssh.exec!("echo '#{authorized_key}' >>~/.ssh/authorized_keys")
114
- end
115
- end
116
-
117
114
  puts
118
- puts "Instance ready!"
119
115
  puts "Try to login using `ssh root@#{instance.public_addresses.first[:address]}'"
120
116
  end
121
117
  end
@@ -1,3 +1,3 @@
1
1
  module VirtualMaster
2
- VERSION = "0.0.7"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -4,7 +4,7 @@ require 'vmaster'
4
4
 
5
5
  program :name, "virtualmaster"
6
6
  program :version, VirtualMaster::VERSION
7
- program :description, "VirtualMaster command line interface"
7
+ program :description, "Virtualmaster command line interface"
8
8
  program :help_formatter, :compact
9
9
 
10
10
  default_command :test
@@ -8,8 +8,8 @@ Gem::Specification.new do |s|
8
8
  s.authors = ["Radim Marek"]
9
9
  s.email = ["radim@laststation.net"]
10
10
  s.homepage = "https://github.com/virtualmaster/virtualmaster-cli"
11
- s.summary = %q{Command line interface to VirtualMaster}
12
- s.description = %q{Command line interface to VirtualMaster. Control your virtual infrastructure.}
11
+ s.summary = %q{Command line interface to Virtualmaster}
12
+ s.description = %q{Command line interface to Virtualmaster. Control your virtual infrastructure.}
13
13
 
14
14
  s.rubyforge_project = "vmaster"
15
15
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: virtualmaster
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.7
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-04-06 00:00:00.000000000 Z
12
+ date: 2012-04-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: commander
16
- requirement: &70327968586800 !ruby/object:Gem::Requirement
16
+ requirement: &70096844415120 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 4.1.2
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70327968586800
24
+ version_requirements: *70096844415120
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: deltacloud-client
27
- requirement: &70327968586300 !ruby/object:Gem::Requirement
27
+ requirement: &70096844414580 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: 0.5.0
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *70327968586300
35
+ version_requirements: *70096844414580
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: terminal-table
38
- requirement: &70327967699220 !ruby/object:Gem::Requirement
38
+ requirement: &70096844414100 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ~>
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: 1.4.4
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *70327967699220
46
+ version_requirements: *70096844414100
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: net-ssh
49
- requirement: &70327967698520 !ruby/object:Gem::Requirement
49
+ requirement: &70096844413440 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ~>
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: 2.3.0
55
55
  type: :runtime
56
56
  prerelease: false
57
- version_requirements: *70327967698520
57
+ version_requirements: *70096844413440
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: rspec
60
- requirement: &70327967697440 !ruby/object:Gem::Requirement
60
+ requirement: &70096844412820 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ~>
@@ -65,8 +65,8 @@ dependencies:
65
65
  version: '2'
66
66
  type: :development
67
67
  prerelease: false
68
- version_requirements: *70327967697440
69
- description: Command line interface to VirtualMaster. Control your virtual infrastructure.
68
+ version_requirements: *70096844412820
69
+ description: Command line interface to Virtualmaster. Control your virtual infrastructure.
70
70
  email:
71
71
  - radim@laststation.net
72
72
  executables:
@@ -76,10 +76,14 @@ extra_rdoc_files: []
76
76
  files:
77
77
  - .gitignore
78
78
  - Gemfile
79
+ - Gemfile.lock
79
80
  - README.mdown
80
81
  - Rakefile
81
82
  - bin/virtualmaster
82
83
  - lib/vmaster.rb
84
+ - lib/vmaster/callbacks.rb
85
+ - lib/vmaster/callbacks/demo_callback.rb
86
+ - lib/vmaster/callbacks/ssh_keys_callback.rb
83
87
  - lib/vmaster/cli.rb
84
88
  - lib/vmaster/config_command.rb
85
89
  - lib/vmaster/helpers.rb
@@ -112,7 +116,7 @@ rubyforge_project: vmaster
112
116
  rubygems_version: 1.8.11
113
117
  signing_key:
114
118
  specification_version: 3
115
- summary: Command line interface to VirtualMaster
119
+ summary: Command line interface to Virtualmaster
116
120
  test_files:
117
121
  - spec/commands_spec.rb
118
122
  - spec/spec_helper.rb