virtualmaster 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +6 -0
- data/Gemfile +4 -0
- data/README.mdown +55 -0
- data/Rakefile +1 -0
- data/bin/virtualmaster +22 -0
- data/lib/vmaster.rb +9 -0
- data/lib/vmaster/cli.rb +32 -0
- data/lib/vmaster/config_command.rb +50 -0
- data/lib/vmaster/helpers.rb +71 -0
- data/lib/vmaster/server_commands.rb +163 -0
- data/lib/vmaster/version.rb +3 -0
- data/spec/commands_spec.rb +17 -0
- data/spec/spec_helper.rb +13 -0
- data/virtualmaster.gemspec +31 -0
- metadata +117 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.mdown
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
# VirtualMaster command line interface
|
2
|
+
|
3
|
+
Proof of concept of VirtualMaster command line interface
|
4
|
+
|
5
|
+
# virtualmaster config
|
6
|
+
Running virtualmaster for first time.
|
7
|
+
Setting up environment.
|
8
|
+
|
9
|
+
Your API credentials are available from http://www.virtualmaster.cz/en/api#settings
|
10
|
+
|
11
|
+
Enter your API username:
|
12
|
+
Enter your API password:
|
13
|
+
|
14
|
+
Settings stored within ~/.virtualmaster
|
15
|
+
|
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
|
+
|
21
|
+
Default password 'AdVc:PBi8&7L'.
|
22
|
+
|
23
|
+
# virtualmaster instances
|
24
|
+
+-------+---------+----------------+
|
25
|
+
| name | state | ip_address |
|
26
|
+
+-------+---------+----------------+
|
27
|
+
| demo1 | RUNNING | 195.140.253.88 |
|
28
|
+
+-------+---------+----------------+
|
29
|
+
|
30
|
+
## Install
|
31
|
+
|
32
|
+
The current version of `virtualmaster` command line interface should work with Ruby 1.8.7+.
|
33
|
+
|
34
|
+
## Automatically install SSH keys
|
35
|
+
|
36
|
+
VirtualMaster CLI can install your SSH keys to a remote machine automatically using `--copy-id` switch.
|
37
|
+
|
38
|
+
|
39
|
+
virtualmaster create demo1 --image ubuntu_lucid --copy-id
|
40
|
+
Using image 'ubuntu_lucid' with ID 124
|
41
|
+
Creating 'micro' instance (512 MB memory/10 GB storage)
|
42
|
+
Instance launch request accepted. Instance ID 45387
|
43
|
+
|
44
|
+
Default password 'vBK7i!kK'
|
45
|
+
Waiting for instance............
|
46
|
+
Loading identity file
|
47
|
+
|
48
|
+
Instance ready!
|
49
|
+
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
|
+
|
53
|
+
## More information
|
54
|
+
|
55
|
+
Additional topics are available in [the wiki](https://github.com/Virtualmaster/virtualmaster-cli/wiki).
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/virtualmaster
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'vmaster'
|
5
|
+
rescue LoadError
|
6
|
+
vmaster_path = File.expand_path('../../lib', __FILE__)
|
7
|
+
|
8
|
+
$:.unshift(vmaster_path)
|
9
|
+
|
10
|
+
require 'vmaster'
|
11
|
+
end
|
12
|
+
|
13
|
+
program :name, "virtualmaster"
|
14
|
+
program :version, VirtualMaster::VERSION
|
15
|
+
program :description, "VirtualMaster command line interface"
|
16
|
+
program :help_formatter, :compact
|
17
|
+
|
18
|
+
default_command :help
|
19
|
+
|
20
|
+
VirtualMaster::CLI.run do
|
21
|
+
end
|
22
|
+
|
data/lib/vmaster.rb
ADDED
data/lib/vmaster/cli.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'deltacloud'
|
3
|
+
|
4
|
+
module VirtualMaster
|
5
|
+
class CLI
|
6
|
+
@@api = nil
|
7
|
+
@@config = nil
|
8
|
+
|
9
|
+
def self.run
|
10
|
+
# load config
|
11
|
+
config_file = File.join(ENV["HOME"], ".virtualmaster")
|
12
|
+
if File.exists? config_file
|
13
|
+
config = YAML::load(File.open(config_file))
|
14
|
+
|
15
|
+
@@config = config.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
|
16
|
+
|
17
|
+
@@api = DeltaCloud.new(@@config[:username], @@config[:password], VirtualMaster::DEFAULT_URL)
|
18
|
+
end
|
19
|
+
|
20
|
+
yield
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.api
|
24
|
+
abort "No configuration available! Please run 'virtualmaster config' first!" unless @@api
|
25
|
+
@@api
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.config
|
29
|
+
@@config
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
|
4
|
+
command :config do |c|
|
5
|
+
c.description = "Configure VirtualMaster API username and password"
|
6
|
+
|
7
|
+
c.option '--username NAME', String, 'API username'
|
8
|
+
c.option '--password PASSWD', String, 'API password'
|
9
|
+
|
10
|
+
c.action do |args, options|
|
11
|
+
config_file = File.join(ENV['HOME'], VirtualMaster::CONFIG_FILE)
|
12
|
+
if File.exists?(config_file)
|
13
|
+
abort "Default configuration file already exists: #{config_file}"
|
14
|
+
else
|
15
|
+
say "Running virtualmaster for first time"
|
16
|
+
end
|
17
|
+
|
18
|
+
unless options.username && options.password
|
19
|
+
say "\n"
|
20
|
+
say "Your API credentials are available from http://www.virtualmaster.cz/en/api#settings"
|
21
|
+
say "\n"
|
22
|
+
end
|
23
|
+
|
24
|
+
options.username = ask("Enter API username:") unless options.username
|
25
|
+
options.password = password("Enter API password:", "*") unless options.password
|
26
|
+
|
27
|
+
# verify and store credentials
|
28
|
+
begin
|
29
|
+
api = DeltaCloud.new(options.username, options.password, VirtualMaster::DEFAULT_URL)
|
30
|
+
|
31
|
+
config = {
|
32
|
+
'username' => options.username,
|
33
|
+
'password' => options.password,
|
34
|
+
'default_image' => VirtualMaster::DEFAULT_IMAGE,
|
35
|
+
'images' => VirtualMaster::IMAGES
|
36
|
+
}
|
37
|
+
|
38
|
+
File.open(config_file, 'w') do |f|
|
39
|
+
f.puts YAML.dump(config)
|
40
|
+
end
|
41
|
+
|
42
|
+
say "Setting stored under #{config_file}"
|
43
|
+
rescue DeltaCloud::API::BackendError => e
|
44
|
+
say "Unable to connect to VirtualMaster API: #{e.message}"
|
45
|
+
rescue Exception => e
|
46
|
+
say "Unable to configure environment: #{e.message}"
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module VirtualMaster
|
2
|
+
|
3
|
+
CONFIG_FILE = ".virtualmaster"
|
4
|
+
DEFAULT_URL = "https://www.virtualmaster.cz/services/deltacloud"
|
5
|
+
|
6
|
+
DEFAULT_IMAGE = 124
|
7
|
+
DEFAULT_PROFILE = "micro"
|
8
|
+
|
9
|
+
# pre-defined list of images
|
10
|
+
IMAGES = {
|
11
|
+
:ubuntu_lucid => 124,
|
12
|
+
:debian_squeeze => 1741,
|
13
|
+
:centos_6 => 1743
|
14
|
+
}
|
15
|
+
|
16
|
+
PROFILES = {
|
17
|
+
:nano => {
|
18
|
+
:memory => 256,
|
19
|
+
:storage => 3840
|
20
|
+
},
|
21
|
+
:micro => {
|
22
|
+
:memory => 512,
|
23
|
+
:storage => 6144
|
24
|
+
},
|
25
|
+
:milli => {
|
26
|
+
:memory => 1024,
|
27
|
+
:storage => 20480,
|
28
|
+
},
|
29
|
+
:small => {
|
30
|
+
:memory => 2048,
|
31
|
+
:storage => 30720
|
32
|
+
},
|
33
|
+
:medium => {
|
34
|
+
:memory => 4096,
|
35
|
+
:storage => 40960
|
36
|
+
}
|
37
|
+
#:large => {
|
38
|
+
# :memory => 8192,
|
39
|
+
# :storage => 8192
|
40
|
+
#}
|
41
|
+
}
|
42
|
+
|
43
|
+
|
44
|
+
module Helpers
|
45
|
+
def self.get_instances
|
46
|
+
VirtualMaster::CLI.api.instances
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.get_instance(name)
|
50
|
+
get_instances.each do |instance|
|
51
|
+
return instance if instance.name == name
|
52
|
+
end
|
53
|
+
|
54
|
+
nil
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.get_hw_profile(memory, storage)
|
58
|
+
api = VirtualMaster::CLI.api
|
59
|
+
|
60
|
+
profile_list = api.hardware_profiles.reject { |p| p.memory.value.to_i != memory && p.storage.value.to_i != storage }
|
61
|
+
|
62
|
+
profile_list.first
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.create_instance(name, image_id, profile_id)
|
66
|
+
api = VirtualMaster::CLI.api
|
67
|
+
|
68
|
+
api.create_instance(image_id, :name => name, :hwp_id => profile_id)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,163 @@
|
|
1
|
+
require 'terminal-table'
|
2
|
+
require 'net/ssh'
|
3
|
+
require 'logger'
|
4
|
+
require "base64"
|
5
|
+
require 'openssl'
|
6
|
+
|
7
|
+
log = Logger.new(STDOUT)
|
8
|
+
log.level = Logger::WARN
|
9
|
+
|
10
|
+
# SSH copy id
|
11
|
+
# FIXME how to select the right key
|
12
|
+
|
13
|
+
command :create do |c|
|
14
|
+
c.description = "Launch new server instance"
|
15
|
+
c.option '--image TEMPLATE', String, 'instance template to use'
|
16
|
+
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
|
+
c.option '--wait', 'wait for instance to become operational'
|
20
|
+
c.action do |args, options|
|
21
|
+
# default values
|
22
|
+
options.default :identity => File.join(ENV['HOME'], '.ssh/id_rsa')
|
23
|
+
|
24
|
+
name = args.shift || abort('Server name required')
|
25
|
+
|
26
|
+
# verify server name
|
27
|
+
abort("Virtual server with name #{name} already exists!") if VirtualMaster::Helpers.get_instance(name)
|
28
|
+
|
29
|
+
# image
|
30
|
+
image_name = nil
|
31
|
+
image_id = VirtualMaster::CLI.config[:default_image] || VirtualHost::DEFAULT_IMAGE
|
32
|
+
|
33
|
+
if options.image
|
34
|
+
image_name = options.image
|
35
|
+
|
36
|
+
if image_name.match /^id:/
|
37
|
+
# use image_id directly
|
38
|
+
image_id = image_name[3..-1].to_i
|
39
|
+
|
40
|
+
image_name = nil
|
41
|
+
else
|
42
|
+
# lookup predefined images
|
43
|
+
image_id = VirtualMaster::CLI.config[:images][image_name.to_sym]
|
44
|
+
|
45
|
+
abort "Image '#{image_name}' not recognized!" unless image_id
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
say image_name ? "Using image '#{image_name}' with ID #{image_id}" : "Using image with ID #{image_id}"
|
50
|
+
|
51
|
+
# instance hardware profile
|
52
|
+
profile_name = options.profile || VirtualMaster::DEFAULT_PROFILE
|
53
|
+
|
54
|
+
profile = VirtualMaster::PROFILES[profile_name.to_sym]
|
55
|
+
abort "Image name '#{options.profile}' not recognized!" unless profile
|
56
|
+
|
57
|
+
hwp = VirtualMaster::Helpers.get_hw_profile(profile[:memory], profile[:storage])
|
58
|
+
abort "Internal error: hardware profile not available" unless hwp
|
59
|
+
|
60
|
+
say "Creating '#{profile_name}' instance (#{profile[:memory]} MB memory/#{profile[:storage]/1024} GB storage)"
|
61
|
+
|
62
|
+
instance = VirtualMaster::Helpers.create_instance(name, image_id, hwp.id)
|
63
|
+
|
64
|
+
# TODO handle exceptions (invalid image/profile, limits, etc.)
|
65
|
+
|
66
|
+
say "Instance launch request accepted. Instance ID #{instance.id}"
|
67
|
+
|
68
|
+
# FIXME authentication is missrepresented within Ruby object
|
69
|
+
password = instance.authentication[:username]
|
70
|
+
say "\n"
|
71
|
+
say "Default password '#{password}'"
|
72
|
+
|
73
|
+
# copy-id implies waiting for instance to become operational
|
74
|
+
if options.wait || options.copy_id
|
75
|
+
print 'Waiting for instance'
|
76
|
+
|
77
|
+
while (instance = VirtualMaster::Helpers.get_instance(name)).state != "RUNNING" do
|
78
|
+
print '.'
|
79
|
+
|
80
|
+
sleep(5)
|
81
|
+
end
|
82
|
+
|
83
|
+
puts
|
84
|
+
|
85
|
+
# copy ssh id
|
86
|
+
if options.copy_id
|
87
|
+
authorized_key = nil
|
88
|
+
|
89
|
+
abort "Specified identity file #{options.identity} doesn't exists!" unless File.exist?(options.identity)
|
90
|
+
|
91
|
+
say "Loading identity file\n"
|
92
|
+
key = OpenSSL::PKey::RSA.new File.read options.identity
|
93
|
+
|
94
|
+
# build authorized key output string
|
95
|
+
authtype = key.class.to_s.split('::').last.downcase
|
96
|
+
b64pub = ::Base64.encode64(key.to_blob).strip.gsub(/[\r\n]/, '')
|
97
|
+
authorized_key = "ssh-%s %s\n" % [authtype, b64pub] # => ssh-rsa AAAAB3NzaC1...=
|
98
|
+
|
99
|
+
Net::SSH.start(instance.public_addresses.first[:address], 'root', :password => password) do |ssh|
|
100
|
+
# TODO exception handling
|
101
|
+
output = ssh.exec!("mkdir ~/.ssh")
|
102
|
+
output = ssh.exec!("echo '#{authorized_key}' >>~/.ssh/authorized_keys")
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
puts
|
107
|
+
puts "Instance ready!"
|
108
|
+
puts "Try to login using `ssh root@#{instance.public_addresses.first[:address]}'"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
command :list do |c|
|
114
|
+
c.description = "List all running servers"
|
115
|
+
c.action do |args, options|
|
116
|
+
instances = []
|
117
|
+
|
118
|
+
VirtualMaster::Helpers.get_instances.each do |instance|
|
119
|
+
unless instance.public_addresses.first.nil?
|
120
|
+
ip_address = instance.public_addresses.first[:address]
|
121
|
+
else
|
122
|
+
ip_address = "(not assigned)"
|
123
|
+
end
|
124
|
+
|
125
|
+
instances << [instance.name, instance.state, ip_address]
|
126
|
+
end
|
127
|
+
|
128
|
+
abort "No instances found" if instances.empty?
|
129
|
+
|
130
|
+
table = Terminal::Table.new :headings => ['name','state','ip_address'], :rows => instances
|
131
|
+
puts table
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def instance_action(action, args)
|
136
|
+
name = args.shift || abort('server name required')
|
137
|
+
|
138
|
+
instance = VirtualMaster::Helpers.get_instance(name)
|
139
|
+
instance.send("#{action}!")
|
140
|
+
end
|
141
|
+
|
142
|
+
%w{start reboot stop shutdown destroy}.each do |cmd|
|
143
|
+
command cmd do |c|
|
144
|
+
c.syntax = "virtualmaster #{c.name} SERVER"
|
145
|
+
|
146
|
+
case c.name
|
147
|
+
when "start"
|
148
|
+
c.description = "Start server (when stopped)"
|
149
|
+
when "reboot"
|
150
|
+
c.description = "Reboot server"
|
151
|
+
when "stop"
|
152
|
+
c.description = "Stop server"
|
153
|
+
when "shutdown"
|
154
|
+
c.description = "Shutdown server (ACPI)"
|
155
|
+
when "destroy"
|
156
|
+
c.description = "Remove server"
|
157
|
+
end
|
158
|
+
|
159
|
+
c.action do |args, options|
|
160
|
+
instance_action(c.name, args)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "VirtualMaster commands" do
|
4
|
+
before :each do
|
5
|
+
@runner = Commander::Runner.instance
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should have command :config" do
|
9
|
+
@runner.commands.should have_key('config')
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should have command server commands" do
|
13
|
+
%w{create list start reboot stop shutdown destroy}.each do |cmd|
|
14
|
+
@runner.commands.should have_key(cmd)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
$:.unshift File.dirname(__FILE__) + '/../lib'
|
2
|
+
|
3
|
+
require 'vmaster'
|
4
|
+
|
5
|
+
program :name, "virtualmaster"
|
6
|
+
program :version, VirtualMaster::VERSION
|
7
|
+
program :description, "VirtualMaster command line interface"
|
8
|
+
program :help_formatter, :compact
|
9
|
+
|
10
|
+
default_command :test
|
11
|
+
|
12
|
+
command :test do |c|
|
13
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "vmaster/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "virtualmaster"
|
7
|
+
s.version = VirtualMaster::VERSION
|
8
|
+
s.authors = ["Radim Marek"]
|
9
|
+
s.email = ["radim@laststation.net"]
|
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.}
|
13
|
+
|
14
|
+
s.rubyforge_project = "vmaster"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
# specify any dependencies here; for example:
|
22
|
+
# s.add_development_dependency "rspec"
|
23
|
+
# s.add_runtime_dependency "rest-client"
|
24
|
+
|
25
|
+
s.add_dependency "commander", "~> 4.1.2"
|
26
|
+
s.add_dependency "deltacloud-client", "~> 0.5.0"
|
27
|
+
s.add_dependency "terminal-table", "~> 1.4.4"
|
28
|
+
s.add_dependency "net-ssh", "~> 2.3.0"
|
29
|
+
|
30
|
+
s.add_development_dependency "rspec", "~> 2"
|
31
|
+
end
|
metadata
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: virtualmaster
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.3
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Radim Marek
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-03-13 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: commander
|
16
|
+
requirement: &70220237000360 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 4.1.2
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70220237000360
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: deltacloud-client
|
27
|
+
requirement: &70220236995660 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ~>
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 0.5.0
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70220236995660
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: terminal-table
|
38
|
+
requirement: &70220236993960 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ~>
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 1.4.4
|
44
|
+
type: :runtime
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *70220236993960
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: net-ssh
|
49
|
+
requirement: &70220236992760 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 2.3.0
|
55
|
+
type: :runtime
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *70220236992760
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: rspec
|
60
|
+
requirement: &70220236991620 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ~>
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '2'
|
66
|
+
type: :development
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *70220236991620
|
69
|
+
description: Command line interface to VirtualMaster. Control your virtual infrastructure.
|
70
|
+
email:
|
71
|
+
- radim@laststation.net
|
72
|
+
executables:
|
73
|
+
- virtualmaster
|
74
|
+
extensions: []
|
75
|
+
extra_rdoc_files: []
|
76
|
+
files:
|
77
|
+
- .gitignore
|
78
|
+
- Gemfile
|
79
|
+
- README.mdown
|
80
|
+
- Rakefile
|
81
|
+
- bin/virtualmaster
|
82
|
+
- lib/vmaster.rb
|
83
|
+
- lib/vmaster/cli.rb
|
84
|
+
- lib/vmaster/config_command.rb
|
85
|
+
- lib/vmaster/helpers.rb
|
86
|
+
- lib/vmaster/server_commands.rb
|
87
|
+
- lib/vmaster/version.rb
|
88
|
+
- spec/commands_spec.rb
|
89
|
+
- spec/spec_helper.rb
|
90
|
+
- virtualmaster.gemspec
|
91
|
+
homepage: https://github.com/virtualmaster/virtualmaster-cli
|
92
|
+
licenses: []
|
93
|
+
post_install_message:
|
94
|
+
rdoc_options: []
|
95
|
+
require_paths:
|
96
|
+
- lib
|
97
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
98
|
+
none: false
|
99
|
+
requirements:
|
100
|
+
- - ! '>='
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '0'
|
103
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
104
|
+
none: false
|
105
|
+
requirements:
|
106
|
+
- - ! '>='
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: '0'
|
109
|
+
requirements: []
|
110
|
+
rubyforge_project: vmaster
|
111
|
+
rubygems_version: 1.8.11
|
112
|
+
signing_key:
|
113
|
+
specification_version: 3
|
114
|
+
summary: Command line interface to VirtualMaster
|
115
|
+
test_files:
|
116
|
+
- spec/commands_spec.rb
|
117
|
+
- spec/spec_helper.rb
|