fog-opennebula 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +32 -0
  3. data/CONTRIBUTORS.md +4 -0
  4. data/Gemfile +9 -0
  5. data/LICENSE.md +20 -0
  6. data/README.md +95 -0
  7. data/Rakefile +118 -0
  8. data/fog-opennebula.gemspec +35 -0
  9. data/lib/fog/bin/opennebula.rb +32 -0
  10. data/lib/fog/opennebula.rb +30 -0
  11. data/lib/fog/opennebula/compute.rb +136 -0
  12. data/lib/fog/opennebula/models/compute/flavor.rb +190 -0
  13. data/lib/fog/opennebula/models/compute/flavors.rb +46 -0
  14. data/lib/fog/opennebula/models/compute/group.rb +28 -0
  15. data/lib/fog/opennebula/models/compute/groups.rb +38 -0
  16. data/lib/fog/opennebula/models/compute/interface.rb +39 -0
  17. data/lib/fog/opennebula/models/compute/interfaces.rb +20 -0
  18. data/lib/fog/opennebula/models/compute/network.rb +48 -0
  19. data/lib/fog/opennebula/models/compute/networks.rb +42 -0
  20. data/lib/fog/opennebula/models/compute/server.rb +85 -0
  21. data/lib/fog/opennebula/models/compute/servers.rb +33 -0
  22. data/lib/fog/opennebula/requests/compute/OpenNebulaVNC.rb +314 -0
  23. data/lib/fog/opennebula/requests/compute/get_vnc_console.rb +58 -0
  24. data/lib/fog/opennebula/requests/compute/image_pool.rb +33 -0
  25. data/lib/fog/opennebula/requests/compute/list_groups.rb +87 -0
  26. data/lib/fog/opennebula/requests/compute/list_networks.rb +79 -0
  27. data/lib/fog/opennebula/requests/compute/list_vms.rb +79 -0
  28. data/lib/fog/opennebula/requests/compute/template_pool.rb +120 -0
  29. data/lib/fog/opennebula/requests/compute/vm_allocate.rb +97 -0
  30. data/lib/fog/opennebula/requests/compute/vm_destroy.rb +39 -0
  31. data/lib/fog/opennebula/requests/compute/vm_disk_snapshot.rb +33 -0
  32. data/lib/fog/opennebula/requests/compute/vm_resume.rb +35 -0
  33. data/lib/fog/opennebula/requests/compute/vm_shutdown.rb +22 -0
  34. data/lib/fog/opennebula/requests/compute/vm_stop.rb +21 -0
  35. data/lib/fog/opennebula/requests/compute/vm_suspend.rb +38 -0
  36. data/lib/fog/opennebula/version.rb +9 -0
  37. data/tests/opennebula/compute_tests.rb +15 -0
  38. data/tests/opennebula/models/compute/flavor_tests.rb +34 -0
  39. data/tests/opennebula/models/compute/flavors_tests.rb +15 -0
  40. data/tests/opennebula/models/compute/group_tests.rb +25 -0
  41. data/tests/opennebula/models/compute/groups_tests.rb +14 -0
  42. data/tests/opennebula/models/compute/network_tests.rb +24 -0
  43. data/tests/opennebula/models/compute/networks_tests.rb +14 -0
  44. data/tests/opennebula/requests/compute/vm_allocate_tests.rb +70 -0
  45. data/tests/opennebula/requests/compute/vm_disk_snapshot_test.rb +44 -0
  46. data/tests/opennebula/requests/compute/vm_suspend_resume_tests.rb +45 -0
  47. metadata +243 -0
@@ -0,0 +1,85 @@
1
+ require 'fog/compute/models/server'
2
+
3
+ module Fog
4
+
5
+ module Compute
6
+
7
+ class OpenNebula
8
+
9
+ class Server < Fog::Compute::Server
10
+
11
+ identity :id
12
+ attribute :template_str
13
+ attribute :name
14
+ attribute :uuid
15
+ attribute :state
16
+ attribute :status
17
+ attribute :ip
18
+ attribute :mac
19
+ attribute :vcpu
20
+ attribute :cpu
21
+ attribute :memory
22
+ attribute :user
23
+ attribute :gid
24
+ attribute :group
25
+ attribute :onevm_object
26
+ attribute :flavor
27
+
28
+ def save
29
+ merge_attributes(service.vm_allocate(attributes))
30
+ end
31
+
32
+ def vm_ip_address
33
+ ip
34
+ end
35
+
36
+ def private_ip_address
37
+ ip
38
+ end
39
+
40
+ def public_ip_address
41
+ ip
42
+ end
43
+
44
+ def vm_mac_address
45
+ mac
46
+ end
47
+
48
+ def start
49
+ service.vm_resume(id) if status == 4
50
+ true
51
+ end
52
+
53
+ def stop
54
+ Fog::Logger.warning("stop VM: ID:#{id}")
55
+ service.vm_stop(id)
56
+ end
57
+
58
+ def suspend
59
+ service.vm_suspend(id)
60
+ end
61
+
62
+ def resume
63
+ service.vm_resume(id)
64
+ end
65
+
66
+ def destroy
67
+ service.vm_destroy(id)
68
+ end
69
+
70
+ def ready?
71
+ (status == 3)
72
+ end
73
+
74
+ def console_output
75
+ requires :id
76
+ service.get_vnc_console(id, 'vnc', onevm_object)
77
+ end
78
+
79
+ end
80
+
81
+ end
82
+
83
+ end
84
+
85
+ end
@@ -0,0 +1,33 @@
1
+ require 'fog/core/collection'
2
+ require 'fog/opennebula/models/compute/server'
3
+
4
+ module Fog
5
+
6
+ module Compute
7
+
8
+ class OpenNebula
9
+
10
+ class Servers < Fog::Collection
11
+
12
+ model Fog::Compute::OpenNebula::Server
13
+
14
+ def all(filter = {})
15
+ load(service.list_vms(filter))
16
+ end
17
+
18
+ def get(id)
19
+ data = service.list_vms(:id => id)
20
+ new data.first unless data.empty?
21
+ end
22
+
23
+ def shutdown(id)
24
+ service.vm_shutdown(id)
25
+ end
26
+
27
+ end
28
+
29
+ end
30
+
31
+ end
32
+
33
+ end
@@ -0,0 +1,314 @@
1
+ #
2
+ # This class provides support for launching and stopping a websockify proxy
3
+ #
4
+
5
+ require 'rubygems'
6
+ require 'json'
7
+ require 'opennebula'
8
+
9
+ # if !ONE_LOCATION
10
+ NOVNC_LOCK_FILE = '/var/lock/.novnc.lock'.freeze
11
+ # else
12
+ # NOVNC_LOCK_FILE= ONE_LOCATION + "/var/.novnc.lock"
13
+ # end
14
+
15
+ TOKEN_EXPIRE_SECONDS = 4
16
+
17
+ VNC_STATES = [
18
+ # 0, #LCM_INIT
19
+ # 1, #PROLOG
20
+ # 2, #BOOT
21
+ '3', # RUNNING
22
+ '4', # MIGRATE
23
+ # 5, #SAVE_STOP
24
+ # 6, #SAVE_SUSPEND
25
+ # 7, #SAVE_MIGRATE
26
+ # 8, #PROLOG_MIGRATE
27
+ # 9, #PROLOG_RESUME
28
+ # 10, #EPILOG_STOP
29
+ # 11, #EPILOG
30
+ '12', # SHUTDOWN
31
+ '13', # CANCEL
32
+ # 14, #FAILURE
33
+ # 15, #CLEANUP_RESUBMIT
34
+ '16', # UNKNOWN
35
+ '17', # HOTPLUG
36
+ '18', # SHUTDOWN_POWEROFF
37
+ # 19, #BOOT_UNKNOWN
38
+ # 20, #BOOT_POWEROFF
39
+ # 21, #BOOT_SUSPENDED
40
+ # 22, #BOOT_STOPPED
41
+ # 23, #CLEANUP_DELETE
42
+ '24', # HOTPLUG_SNAPSHOT
43
+ '25', # HOTPLUG_NIC
44
+ '26', # HOTPLUG_SAVEAS
45
+ '27', # HOTPLUG_SAVEAS_POWEROFF
46
+ '28', # HOTPLUG_SAVEAS_SUSPENDED
47
+ '29' # SHUTDOWN_UNDEPLOY
48
+ # 30, #EPILOG_UNDEPLOY
49
+ # 31, #PROLOG_UNDEPLOY
50
+ # 32 #BOOT_UNDEPLOY
51
+ ].freeze
52
+
53
+ VAR_LOCATION = Dir.pwd + '/extras/noVNC'
54
+ SHARE_LOCATION = Dir.pwd + '/extras/noVNC'
55
+ class OpenNebulaVNC
56
+
57
+ attr_reader :proxy_port
58
+
59
+ def initialize(config, logger, options = {})
60
+ opts = { :json_errors => true,
61
+ :token_folder_name => 'sunstone_vnc_tokens' }.merge(options)
62
+
63
+ @pipe = nil
64
+ @token_folder = File.join(VAR_LOCATION, opts[:token_folder_name])
65
+ @proxy_path = File.join(SHARE_LOCATION, 'websockify/websocketproxy.py')
66
+ @proxy_port = config[:vnc_proxy_port]
67
+
68
+ @proxy_ipv6 = config[:vnc_proxy_ipv6]
69
+
70
+ @wss = config[:vnc_proxy_support_wss]
71
+
72
+ @lock_file = NOVNC_LOCK_FILE
73
+
74
+ if (@wss == 'yes') || (@wss == 'only') || (@wss == true)
75
+ @enable_wss = true
76
+ @cert = config[:vnc_proxy_cert]
77
+ @key = config[:vnc_proxy_key]
78
+ else
79
+ @enable_wss = false
80
+ end
81
+ @options = opts
82
+ @logger = logger
83
+ end
84
+
85
+ def start
86
+ if is_running?
87
+ message = 'VNC server already running'
88
+ STDERR.puts message
89
+ @logger.info message
90
+ return false
91
+ end
92
+
93
+ create_token_dir
94
+
95
+ proxy_options = "--target-config=#{@token_folder} "
96
+
97
+ if @enable_wss
98
+ proxy_options << " --cert #{@cert}"
99
+ proxy_options << " --key #{@key}" if @key && !@key.empty?
100
+ proxy_options << ' --ssl-only' if @wss == 'only'
101
+ end
102
+
103
+ proxy_options << ' -6' if @proxy_ipv6
104
+
105
+ cmd = "python #{@proxy_path} #{proxy_options} #{@proxy_port}"
106
+
107
+ begin
108
+ @logger.info { "Starting VNC proxy: #{cmd}" }
109
+ pid = start_daemon(cmd, VNC_LOG)
110
+ rescue Exception => e
111
+ @logger.error e.message
112
+ return false
113
+ end
114
+
115
+ File.open(@lock_file, 'w') do |f|
116
+ f.write(pid.to_s)
117
+ end
118
+
119
+ sleep 1
120
+
121
+ unless is_running?
122
+ message = 'Error starting VNC proxy'
123
+ STDERR.puts message
124
+ @logger.error message
125
+ File.delete(@lock_file) if File.exist?(@lock_file)
126
+
127
+ return false
128
+ end
129
+
130
+ STDOUT.puts 'VNC proxy started'
131
+
132
+ true
133
+ end
134
+
135
+ def proxy(vm_resource)
136
+ # Check configurations and VM attributes
137
+ # if !is_running?
138
+ # return error(400, "VNC Proxy is not running")
139
+ # end
140
+
141
+ unless VNC_STATES.include?(vm_resource['LCM_STATE'])
142
+ return error(400, "Wrong state (#{vm_resource['LCM_STATE']}) to open a VNC session")
143
+ end
144
+
145
+ if vm_resource['TEMPLATE/GRAPHICS/TYPE'].nil? ||
146
+ !vm_resource['TEMPLATE/GRAPHICS/TYPE'].casecmp('vnc').zero?
147
+ return error(400, 'VM has no VNC configured')
148
+ end
149
+
150
+ # Proxy data
151
+ host = vm_resource['HISTORY_RECORDS/HISTORY[last()]/HOSTNAME']
152
+ vnc_port = vm_resource['TEMPLATE/GRAPHICS/PORT']
153
+ vnc_pw = vm_resource['TEMPLATE/GRAPHICS/PASSWD']
154
+
155
+ # Generate token random_str: host:port
156
+ random_str = rand(36**20).to_s(36) # random string a-z0-9 length 20
157
+ token = "#{random_str}: #{host}:#{vnc_port}"
158
+ token_file = 'one-' + vm_resource['ID']
159
+
160
+ # Create token file
161
+
162
+ begin
163
+ f = File.open(File.join(@token_folder, token_file), 'w')
164
+ f.write(token)
165
+ f.close
166
+ rescue Exception => e
167
+ # @logger.error e.message
168
+ return error(500, 'Cannot create VNC proxy token')
169
+ end
170
+
171
+ info = {
172
+ :proxy_port => '29876',
173
+ :password => vnc_pw,
174
+ :token => random_str,
175
+ :vm_name => vm_resource['NAME']
176
+ }
177
+
178
+ [200, info]
179
+ end
180
+
181
+ # Delete proxy token file
182
+ def delete_token(filename)
183
+ File.delete(File.join(@token_folder, filename))
184
+ rescue StandardError => e
185
+ @logger.error "Error deleting token file for VM #{vm_id}"
186
+ @logger.error e.message
187
+ end
188
+
189
+ def stop(force = false)
190
+ pid = get_pid
191
+
192
+ if pid
193
+ @logger.info 'Killing VNC proxy'
194
+
195
+ force ? signal = 'KILL' : signal = 'TERM'
196
+ Process.kill(signal, pid)
197
+
198
+ sleep 1
199
+
200
+ begin
201
+ Process.getpgid(pid)
202
+
203
+ Process.kill('KILL', pid)
204
+ rescue StandardError
205
+ end
206
+
207
+ if is_running?
208
+ message = 'VNC server is still running'
209
+ STDERR.puts message
210
+ logger.error message
211
+ return false
212
+ end
213
+
214
+ delete_token_dir
215
+ else
216
+ message = 'VNC server is not running'
217
+ @logger.info message
218
+ STDERR.puts message
219
+ end
220
+ true
221
+ end
222
+
223
+ def status
224
+ if is_running?
225
+ STDOUT.puts 'VNC is running'
226
+ true
227
+ else
228
+ STDOUT.puts 'VNC is NOT running'
229
+ false
230
+ end
231
+ end
232
+
233
+ private
234
+
235
+ def error(code, msg)
236
+ if @options[:json_errors]
237
+ [code, OpenNebula::Error.new(msg).to_json]
238
+ else
239
+ [code, msg]
240
+ end
241
+ end
242
+
243
+ def create_token_dir
244
+ delete_token_dir
245
+ begin
246
+ Dir.mkdir(@token_folder) unless File.exist?(@token_folder)
247
+ rescue Exception => e
248
+ @logger.error 'Cannot create token folder'
249
+ @logger.error e.message
250
+ end
251
+ end
252
+
253
+ def delete_token_dir
254
+ if File.exist?(@token_folder)
255
+ begin
256
+ Dir.glob("#{@token_folder}/*").each do |file|
257
+ File.delete(file)
258
+ end
259
+ rescue StandardError => e
260
+ @logger.error 'Error deleting token folder'
261
+ @logger.error e.message
262
+ end
263
+ end
264
+ end
265
+
266
+ def is_running?
267
+ if File.exist?(@lock_file)
268
+ pid = File.read(@lock_file).strip
269
+
270
+ return pid.to_i if system("ps #{pid} 1> /dev/null")
271
+
272
+ @logger.info 'Deleting stale lock file'
273
+ File.delete(@lock_file)
274
+ end
275
+
276
+ false
277
+ end
278
+ alias get_pid is_running?
279
+
280
+ if RUBY_VERSION < '1.9'
281
+ def spawn(*args)
282
+ fork do
283
+ command = args[0..-2]
284
+
285
+ # Close stdin and point out and err to log file
286
+ $stdin.close
287
+ $stdout.reopen(VNC_LOG, 'a')
288
+ $stderr.reopen(VNC_LOG, 'a')
289
+
290
+ # Detach process from the parent
291
+ Process.setsid
292
+
293
+ exec(*command)
294
+ end
295
+ end
296
+ end
297
+
298
+ def start_daemon(cmd, log)
299
+ options = {
300
+ :pgroup => true,
301
+ :in => :close,
302
+ [:out, :err] => [log, 'a'],
303
+ :close_others => true
304
+ }
305
+
306
+ params = cmd.split(' ') + [options]
307
+ pid = spawn(*params)
308
+
309
+ Process.detach(pid)
310
+
311
+ pid
312
+ end
313
+
314
+ end
@@ -0,0 +1,58 @@
1
+ require File.expand_path('OpenNebulaVNC', __dir__)
2
+ module Fog
3
+
4
+ module Compute
5
+
6
+ class OpenNebula
7
+
8
+ class Mock
9
+
10
+ # Get a vnc console for an instance.
11
+ #
12
+ # === Parameters
13
+ # * server_id <~String> - The ID of the server.
14
+ # * console_type <~String> - Type of vnc console to get ('novnc' or 'xvpvnc').
15
+ # === Returns
16
+ # * response <~Excon::Response>:
17
+ # * body <~Hash>:
18
+ # * url <~String>
19
+ # * type <~String>
20
+ def get_vnc_console(_server_id, _console_type)
21
+ body = {
22
+ :type => 'novnc',
23
+ :proxy_port => '29876',
24
+ :password => 'null',
25
+ :token => '3n32dtwpsdj5jkug3b4w',
26
+ :proxy_host => 'example.com'
27
+ }
28
+ end
29
+
30
+ end
31
+
32
+ class Real
33
+
34
+ def get_vnc_console(_server_id, _console_type, onevm_object)
35
+ logger = Fog::Logger.new
36
+ $conf = { 'vnc_proxy_port' => '29876', 'vnc_proxy_ipv6' => '',
37
+ 'vnc_proxy_support_wss' => '', 'vnc_proxy_cert' => '',
38
+ 'vnc_proxy_key' => '' }
39
+ $vnc = OpenNebulaVNC.new($conf, logger)
40
+ ret = startvnc(onevm_object, $vnc)
41
+
42
+ response = Excon::Response.new
43
+ response.status = ret[0]
44
+ response.body = ret[1]
45
+ response
46
+ end
47
+
48
+ def startvnc(onevm_object, vnc)
49
+ vnc.proxy(onevm_object)
50
+ end
51
+
52
+ end
53
+
54
+ end
55
+
56
+ end
57
+
58
+ end