fog-opennebula 0.0.1

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.
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