novafizz 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/novawhiz +119 -0
- data/bin/nw +119 -0
- data/lib/novawhiz.rb +247 -0
- metadata +106 -0
data/bin/novawhiz
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'main'
|
3
|
+
require 'novawhiz'
|
4
|
+
|
5
|
+
Main do
|
6
|
+
|
7
|
+
def creds
|
8
|
+
{
|
9
|
+
# for use with openstack
|
10
|
+
:username => ENV['OS_USERNAME'],
|
11
|
+
:password => ENV['OS_PASSWORD'],
|
12
|
+
:authtenant => ENV['OS_TENANT_NAME'],
|
13
|
+
:auth_url => ENV['OS_AUTH_URL'],
|
14
|
+
:region => ENV['OS_REGION_NAME'],
|
15
|
+
|
16
|
+
## for use with hpfog
|
17
|
+
#:provider => ENV['PROVIDER'],
|
18
|
+
#:hp_account_id => ENV['HP_ACCOUNT_ID'],
|
19
|
+
#:hp_secret_key => ENV['HP_SECRET_KEY'],
|
20
|
+
#:hp_auth_uri => ENV['HP_AUTH_URI'],
|
21
|
+
#:hp_tenant_id => ENV['HP_TENANT_ID'],
|
22
|
+
#:hp_avl_zone => ENV['HP_AVL_ZONE']
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
def run
|
27
|
+
STDERR.puts "must specify a subcommand. see `#{$0} help`"
|
28
|
+
exit 1
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
mode 'boot' do
|
33
|
+
argument('name') { 'node name to ssh into' }
|
34
|
+
def run
|
35
|
+
args = params.to_options
|
36
|
+
opts[:name] = args['name']
|
37
|
+
opts[:flavor] ||= 'standard.xsmall'
|
38
|
+
opts[:image] ||= /Ubuntu Precise/
|
39
|
+
opts[:sec_groups] ||= ['default']
|
40
|
+
opts[:key_name] ||= 'default'
|
41
|
+
opts[:region] ||= 'az-2.region-a.geo-1'
|
42
|
+
raise 'no name provided' if !opts[:name] or opts[:name].empty?
|
43
|
+
nw = NovaWhiz.new creds
|
44
|
+
nw.cleanup opts[:name]
|
45
|
+
node = nw.boot opts
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
mode 'ssh' do
|
51
|
+
argument('name') { 'node name to ssh into' }
|
52
|
+
|
53
|
+
def run
|
54
|
+
opts = params.to_options
|
55
|
+
nw = NovaWhiz.new creds
|
56
|
+
node = nw.server_by_name opts['name']
|
57
|
+
key_path = File.expand_path('~/.ssh/hpcloud-keys/' + creds[:region] +'/'+ node.key_name)
|
58
|
+
exec "ssh -i #{key_path} #{nw.default_user node}@#{node.accessipv4} -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
mode 'run' do
|
64
|
+
argument('name') { 'node name to ssh into' }
|
65
|
+
argument('cmd') { 'cmd to execute on remote host' }
|
66
|
+
|
67
|
+
def run
|
68
|
+
opts = params.to_options
|
69
|
+
|
70
|
+
res = Net::SSH::Simple.sync do
|
71
|
+
nw = NovaWhiz.new creds
|
72
|
+
node = nw.server_by_name opts['name']
|
73
|
+
raise "VM with name '#{opts['name']}' could not found" if node == nil
|
74
|
+
|
75
|
+
key = nw.get_key(opts['name'])
|
76
|
+
command_in = opts['cmd'] +"\n"
|
77
|
+
|
78
|
+
ssh(node.accessipv4,
|
79
|
+
'/bin/sh',
|
80
|
+
:user => 'ubuntu',
|
81
|
+
:key_data => [key],
|
82
|
+
:timeout => 3600,
|
83
|
+
:global_known_hosts_file => ['/dev/null'],
|
84
|
+
:user_known_hosts_file => ['/dev/null']) do |e,c,d|
|
85
|
+
case e
|
86
|
+
when :start
|
87
|
+
c.send_data(command_in)
|
88
|
+
c.eof!
|
89
|
+
when :stdout
|
90
|
+
# read the input line-wise (it *will* arrive fragmented!)
|
91
|
+
(@buf ||= '') << d
|
92
|
+
while line = @buf.slice!(/(.*)\r?\n/)
|
93
|
+
yield line.chomp if block_given?
|
94
|
+
end
|
95
|
+
when :stderr
|
96
|
+
(@buf ||= '') << d
|
97
|
+
while line = @buf.slice!(/(.*)\r?\n/)
|
98
|
+
yield line.chomp if block_given?
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
if res.exit_code != 0
|
104
|
+
raise "command #{opts['cmd']} failed on XXXX:\n#{res.stdout}\n#{res.stderr}"
|
105
|
+
end
|
106
|
+
STDOUT.puts res.stdout
|
107
|
+
res
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
|
112
|
+
#mode 'test' do
|
113
|
+
# def run
|
114
|
+
# nw = NovaWhiz.new creds
|
115
|
+
# nw.fog_test_method
|
116
|
+
# end
|
117
|
+
#end
|
118
|
+
|
119
|
+
end
|
data/bin/nw
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'main'
|
3
|
+
require 'novawhiz'
|
4
|
+
|
5
|
+
Main do
|
6
|
+
|
7
|
+
def creds
|
8
|
+
{
|
9
|
+
# for use with openstack
|
10
|
+
:username => ENV['OS_USERNAME'],
|
11
|
+
:password => ENV['OS_PASSWORD'],
|
12
|
+
:authtenant => ENV['OS_TENANT_NAME'],
|
13
|
+
:auth_url => ENV['OS_AUTH_URL'],
|
14
|
+
:region => ENV['OS_REGION_NAME'],
|
15
|
+
|
16
|
+
## for use with hpfog
|
17
|
+
#:provider => ENV['PROVIDER'],
|
18
|
+
#:hp_account_id => ENV['HP_ACCOUNT_ID'],
|
19
|
+
#:hp_secret_key => ENV['HP_SECRET_KEY'],
|
20
|
+
#:hp_auth_uri => ENV['HP_AUTH_URI'],
|
21
|
+
#:hp_tenant_id => ENV['HP_TENANT_ID'],
|
22
|
+
#:hp_avl_zone => ENV['HP_AVL_ZONE']
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
def run
|
27
|
+
STDERR.puts "must specify a subcommand. see `#{$0} help`"
|
28
|
+
exit 1
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
mode 'boot' do
|
33
|
+
argument('name') { 'node name to ssh into' }
|
34
|
+
def run
|
35
|
+
args = params.to_options
|
36
|
+
opts[:name] = args['name']
|
37
|
+
opts[:flavor] ||= 'standard.xsmall'
|
38
|
+
opts[:image] ||= /Ubuntu Precise/
|
39
|
+
opts[:sec_groups] ||= ['default']
|
40
|
+
opts[:key_name] ||= 'default'
|
41
|
+
opts[:region] ||= 'az-2.region-a.geo-1'
|
42
|
+
raise 'no name provided' if !opts[:name] or opts[:name].empty?
|
43
|
+
nw = NovaWhiz.new creds
|
44
|
+
nw.cleanup opts[:name]
|
45
|
+
node = nw.boot opts
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
mode 'ssh' do
|
51
|
+
argument('name') { 'node name to ssh into' }
|
52
|
+
|
53
|
+
def run
|
54
|
+
opts = params.to_options
|
55
|
+
nw = NovaWhiz.new creds
|
56
|
+
node = nw.server_by_name opts['name']
|
57
|
+
key_path = File.expand_path('~/.ssh/hpcloud-keys/' + creds[:region] +'/'+ node.key_name)
|
58
|
+
exec "ssh -i #{key_path} #{nw.default_user node}@#{node.accessipv4} -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
mode 'run' do
|
64
|
+
argument('name') { 'node name to ssh into' }
|
65
|
+
argument('cmd') { 'cmd to execute on remote host' }
|
66
|
+
|
67
|
+
def run
|
68
|
+
opts = params.to_options
|
69
|
+
|
70
|
+
res = Net::SSH::Simple.sync do
|
71
|
+
nw = NovaWhiz.new creds
|
72
|
+
node = nw.server_by_name opts['name']
|
73
|
+
raise "VM with name '#{opts['name']}' could not found" if node == nil
|
74
|
+
|
75
|
+
key = nw.get_key(opts['name'])
|
76
|
+
command_in = opts['cmd'] +"\n"
|
77
|
+
|
78
|
+
ssh(node.accessipv4,
|
79
|
+
'/bin/sh',
|
80
|
+
:user => 'ubuntu',
|
81
|
+
:key_data => [key],
|
82
|
+
:timeout => 3600,
|
83
|
+
:global_known_hosts_file => ['/dev/null'],
|
84
|
+
:user_known_hosts_file => ['/dev/null']) do |e,c,d|
|
85
|
+
case e
|
86
|
+
when :start
|
87
|
+
c.send_data(command_in)
|
88
|
+
c.eof!
|
89
|
+
when :stdout
|
90
|
+
# read the input line-wise (it *will* arrive fragmented!)
|
91
|
+
(@buf ||= '') << d
|
92
|
+
while line = @buf.slice!(/(.*)\r?\n/)
|
93
|
+
yield line.chomp if block_given?
|
94
|
+
end
|
95
|
+
when :stderr
|
96
|
+
(@buf ||= '') << d
|
97
|
+
while line = @buf.slice!(/(.*)\r?\n/)
|
98
|
+
yield line.chomp if block_given?
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
if res.exit_code != 0
|
104
|
+
raise "command #{opts['cmd']} failed on XXXX:\n#{res.stdout}\n#{res.stderr}"
|
105
|
+
end
|
106
|
+
STDOUT.puts res.stdout
|
107
|
+
res
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
|
112
|
+
#mode 'test' do
|
113
|
+
# def run
|
114
|
+
# nw = NovaWhiz.new creds
|
115
|
+
# nw.fog_test_method
|
116
|
+
# end
|
117
|
+
#end
|
118
|
+
|
119
|
+
end
|
data/lib/novawhiz.rb
ADDED
@@ -0,0 +1,247 @@
|
|
1
|
+
require 'openstack'
|
2
|
+
require 'net/ssh/simple'
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
class NovaWhiz
|
6
|
+
|
7
|
+
attr_accessor :os
|
8
|
+
|
9
|
+
def initialize(opts)
|
10
|
+
@os = OpenStack::Connection.create(
|
11
|
+
:username => opts[:username],
|
12
|
+
:api_key => opts[:password],
|
13
|
+
:authtenant => opts[:authtenant],
|
14
|
+
:auth_url => opts[:auth_url],
|
15
|
+
:region => opts[:region],
|
16
|
+
:service_type => "compute")
|
17
|
+
|
18
|
+
#@fog = Fog::Compute.new(
|
19
|
+
# :provider => opts[:provider],
|
20
|
+
# :hp_account_id => opts[:hp_account_id],
|
21
|
+
# :hp_secret_key => opts[:hp_secret_key],
|
22
|
+
# :hp_auth_uri => opts[:hp_auth_uri],
|
23
|
+
# :hp_tenant_id => opts[:hp_tenant_id],
|
24
|
+
# :hp_avl_zone => opts[:hp_avl_zone])
|
25
|
+
end
|
26
|
+
|
27
|
+
## fog methods
|
28
|
+
#
|
29
|
+
#def fog_test_method()
|
30
|
+
#
|
31
|
+
# servers = @fog.servers
|
32
|
+
# servers.size # returns no. of servers
|
33
|
+
# # display servers in a tabular format
|
34
|
+
# @fog.servers.table([:id, :name, :state, :created_at])
|
35
|
+
# @fog.addresses.table([:id, :ip, :fixed_ip, :instance_id])
|
36
|
+
#
|
37
|
+
# floatip_id = address_by_ip("15.185.164.224")
|
38
|
+
#
|
39
|
+
#end
|
40
|
+
#
|
41
|
+
#def assign_floating_ip(server_name,ip)
|
42
|
+
#
|
43
|
+
# address = address_by_ip(ip)
|
44
|
+
# server = server_by_name(server_name)
|
45
|
+
# address.server = server
|
46
|
+
# address.instance_id
|
47
|
+
#
|
48
|
+
#end
|
49
|
+
#
|
50
|
+
#def server_by_name(name)
|
51
|
+
# @fog.server.each do |s|
|
52
|
+
# return s if s.name == name
|
53
|
+
# end
|
54
|
+
# raise "Could not find server with name: #{name}"
|
55
|
+
#end
|
56
|
+
#
|
57
|
+
#def address_by_ip(ip)
|
58
|
+
# @fog.addresses.each do |f|
|
59
|
+
# return f if f.ip == ip
|
60
|
+
# end
|
61
|
+
# raise "Could not find id of floating IP: #{ip}"
|
62
|
+
#end
|
63
|
+
#
|
64
|
+
#def address_by_instance_id(instance_id)
|
65
|
+
# @fog.addresses.each do |f|
|
66
|
+
# return f if f.instance_id == instance_id
|
67
|
+
# end
|
68
|
+
# raise "Could not find ID of floating IP using instance ID: #{instance_id}"
|
69
|
+
#end
|
70
|
+
## end fog methods
|
71
|
+
|
72
|
+
|
73
|
+
def flavor_id(name)
|
74
|
+
flavors = @os.flavors.select { |f| f[:name] == name }
|
75
|
+
raise "ambiguous/unknown flavor: #{name}" unless flavors.length == 1
|
76
|
+
flavors.first[:id]
|
77
|
+
end
|
78
|
+
|
79
|
+
def image_id(reg)
|
80
|
+
images = @os.images.select { |i| i[:name] =~ reg }
|
81
|
+
raise "ambiguous/unknown image: #{reg} : #{images.inspect}" unless images.length >= 1
|
82
|
+
images.first[:id]
|
83
|
+
end
|
84
|
+
|
85
|
+
def replace_period_with_dash(name)
|
86
|
+
# bugbug - handle hp cloud bug where key names with two "." can't be deleted.
|
87
|
+
# when writing and reading keys, convert "." to "-".
|
88
|
+
# remove this code when this openstack bug is fixed
|
89
|
+
nameclean = name.gsub(".","-")
|
90
|
+
return nameclean
|
91
|
+
end
|
92
|
+
|
93
|
+
def new_key(name)
|
94
|
+
key = @os.create_keypair :name => replace_period_with_dash(name)
|
95
|
+
key
|
96
|
+
end
|
97
|
+
|
98
|
+
def get_key(key_name, key_dir = File.expand_path('~/.ssh/hpcloud-keys/az-2.region-a.geo-1/'))
|
99
|
+
key = ""
|
100
|
+
File.open(key_dir + "/" + replace_period_with_dash(key_name), 'r') do |f|
|
101
|
+
while line = f.gets
|
102
|
+
key+=line
|
103
|
+
end
|
104
|
+
end
|
105
|
+
return key
|
106
|
+
end
|
107
|
+
|
108
|
+
def write_key(key, key_dir = File.expand_path('~/.ssh/hpcloud-keys/az-2.region-a.geo-1/'))
|
109
|
+
begin
|
110
|
+
FileUtils.mkdir_p(key_dir) unless File.exists?(key_dir)
|
111
|
+
keyfile_path = key_dir + "/" + key[:name]
|
112
|
+
File.open(keyfile_path, "w") do |f|
|
113
|
+
f.write(key[:private_key])
|
114
|
+
f.close
|
115
|
+
end
|
116
|
+
File.chmod(0600,keyfile_path)
|
117
|
+
rescue
|
118
|
+
raise "Error with writing key at: #{keyfile_path}"
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def public_ip(server)
|
123
|
+
server.accessipv4
|
124
|
+
end
|
125
|
+
|
126
|
+
def wait(timeout, interval=10)
|
127
|
+
while timeout > 0 do
|
128
|
+
return if yield
|
129
|
+
sleep interval
|
130
|
+
timeout -= interval
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def server_by_name(name)
|
135
|
+
@os.servers.each do |s|
|
136
|
+
return @os.server(s[:id]) if s[:name] == name
|
137
|
+
end
|
138
|
+
nil
|
139
|
+
end
|
140
|
+
|
141
|
+
def server_list()
|
142
|
+
return @os.servers
|
143
|
+
end
|
144
|
+
|
145
|
+
def keypair_name(server)
|
146
|
+
server.key_name
|
147
|
+
end
|
148
|
+
|
149
|
+
def default_user(node)
|
150
|
+
'ubuntu'
|
151
|
+
end
|
152
|
+
|
153
|
+
def cleanup(name)
|
154
|
+
if server_exists name
|
155
|
+
delete_if_exists(name)
|
156
|
+
end
|
157
|
+
|
158
|
+
if keypair_exists name
|
159
|
+
delete_keypair_if_exists(name)
|
160
|
+
end
|
161
|
+
|
162
|
+
#TODO: need consistent way of deciding that cleanup is complete. sleep for now.
|
163
|
+
sleep(20)
|
164
|
+
end
|
165
|
+
|
166
|
+
def keypair_exists(name)
|
167
|
+
kp_names = @os.keypairs.values.map { |v| v[:name] }
|
168
|
+
return true if kp_names.include? name
|
169
|
+
end
|
170
|
+
|
171
|
+
def server_exists(name)
|
172
|
+
s = server_by_name name
|
173
|
+
return true if s
|
174
|
+
end
|
175
|
+
|
176
|
+
def delete_keypair_if_exists(name)
|
177
|
+
@os.delete_keypair name if keypair_exists name
|
178
|
+
end
|
179
|
+
|
180
|
+
def delete_if_exists(name)
|
181
|
+
s = server_by_name name
|
182
|
+
s.delete! if s
|
183
|
+
end
|
184
|
+
|
185
|
+
def run_command(creds, cmd)
|
186
|
+
res = Net::SSH::Simple.sync do
|
187
|
+
ssh(creds[:ip], '/bin/sh', :user => creds[:user], :key_data => [creds[:key]], :timeout => 3600, :global_known_hosts_file => ['/dev/null'], :user_known_hosts_file => ['/dev/null']) do |e,c,d|
|
188
|
+
case e
|
189
|
+
when :start
|
190
|
+
c.send_data "#{cmd}\n"
|
191
|
+
c.eof!
|
192
|
+
when :stdout
|
193
|
+
# read the input line-wise (it *will* arrive fragmented!)
|
194
|
+
(@buf ||= '') << d
|
195
|
+
while line = @buf.slice!(/(.*)\r?\n/)
|
196
|
+
yield line.chomp if block_given?
|
197
|
+
end
|
198
|
+
when :stderr
|
199
|
+
(@buf ||= '') << d
|
200
|
+
while line = @buf.slice!(/(.*)\r?\n/)
|
201
|
+
yield line.chomp if block_given?
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
if res.exit_code != 0
|
207
|
+
raise "command #{cmd} failed on #{creds[:ip]}:\n#{res.stdout}\n#{res.stderr}"
|
208
|
+
end
|
209
|
+
res
|
210
|
+
end
|
211
|
+
|
212
|
+
# boot an instance and return creds
|
213
|
+
def boot(opts)
|
214
|
+
opts[:flavor] ||= 'standard.xsmall'
|
215
|
+
opts[:image] ||= /Ubuntu Precise/
|
216
|
+
opts[:sec_groups] ||= ['default']
|
217
|
+
opts[:key_name] ||= 'default'
|
218
|
+
opts[:region] ||= 'az-2.region-a.geo-1'
|
219
|
+
|
220
|
+
raise 'no name provided' if !opts[:name] or opts[:name].empty?
|
221
|
+
|
222
|
+
cleanup opts[:name]
|
223
|
+
private_key = new_key opts[:name]
|
224
|
+
write_key(private_key, File.expand_path('~/.ssh/hpcloud-keys/' + opts[:region] + '/'))
|
225
|
+
|
226
|
+
server = @os.create_server(
|
227
|
+
:imageRef => image_id(opts[:image]),
|
228
|
+
:flavorRef => flavor_id(opts[:flavor]),
|
229
|
+
:key_name => private_key[:name],
|
230
|
+
:security_groups => opts[:sec_groups],
|
231
|
+
:name => opts[:name])
|
232
|
+
|
233
|
+
wait(300) do
|
234
|
+
server = @os.server(server.id)
|
235
|
+
raise 'error booting vm' if server.status == 'ERROR'
|
236
|
+
server.status == 'ACTIVE'
|
237
|
+
end
|
238
|
+
sleep 60
|
239
|
+
|
240
|
+
{
|
241
|
+
:ip => public_ip(server),
|
242
|
+
:user => 'ubuntu',
|
243
|
+
:key => private_key[:private_key]
|
244
|
+
}
|
245
|
+
end
|
246
|
+
|
247
|
+
end
|
metadata
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: novafizz
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.0.8
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- tim miller
|
9
|
+
- matty rhoades
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2012-09-11 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: openstack
|
17
|
+
version_requirements: !ruby/object:Gem::Requirement
|
18
|
+
requirements:
|
19
|
+
- - ">="
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: !binary |-
|
22
|
+
MA==
|
23
|
+
none: false
|
24
|
+
requirement: !ruby/object:Gem::Requirement
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
version: !binary |-
|
29
|
+
MA==
|
30
|
+
none: false
|
31
|
+
prerelease: false
|
32
|
+
type: :runtime
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: net-ssh-simple
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: !binary |-
|
40
|
+
MA==
|
41
|
+
none: false
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: !binary |-
|
47
|
+
MA==
|
48
|
+
none: false
|
49
|
+
prerelease: false
|
50
|
+
type: :runtime
|
51
|
+
- !ruby/object:Gem::Dependency
|
52
|
+
name: main
|
53
|
+
version_requirements: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: !binary |-
|
58
|
+
MA==
|
59
|
+
none: false
|
60
|
+
requirement: !ruby/object:Gem::Requirement
|
61
|
+
requirements:
|
62
|
+
- - ">="
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: !binary |-
|
65
|
+
MA==
|
66
|
+
none: false
|
67
|
+
prerelease: false
|
68
|
+
type: :runtime
|
69
|
+
description: library and command line tool for simplifying openstack nova operations
|
70
|
+
email: none@example.com
|
71
|
+
executables:
|
72
|
+
- novawhiz
|
73
|
+
- nw
|
74
|
+
extensions: []
|
75
|
+
extra_rdoc_files: []
|
76
|
+
files:
|
77
|
+
- lib/novawhiz.rb
|
78
|
+
- bin/novawhiz
|
79
|
+
- bin/nw
|
80
|
+
homepage: http://rubygems.org/gems/novawhiz
|
81
|
+
licenses: []
|
82
|
+
post_install_message:
|
83
|
+
rdoc_options: []
|
84
|
+
require_paths:
|
85
|
+
- lib
|
86
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: !binary |-
|
91
|
+
MA==
|
92
|
+
none: false
|
93
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: !binary |-
|
98
|
+
MA==
|
99
|
+
none: false
|
100
|
+
requirements: []
|
101
|
+
rubyforge_project:
|
102
|
+
rubygems_version: 1.8.24
|
103
|
+
signing_key:
|
104
|
+
specification_version: 3
|
105
|
+
summary: simplify nova operations
|
106
|
+
test_files: []
|