novafizz 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. data/bin/novawhiz +119 -0
  2. data/bin/nw +119 -0
  3. data/lib/novawhiz.rb +247 -0
  4. 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: []