chef-provisioning-opennebula 0.3.4

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 (41) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +201 -0
  3. data/README.md +532 -0
  4. data/Rakefile +6 -0
  5. data/lib/chef/provider/one_image.rb +244 -0
  6. data/lib/chef/provider/one_template.rb +95 -0
  7. data/lib/chef/provider/one_user.rb +105 -0
  8. data/lib/chef/provider/one_vnet.rb +122 -0
  9. data/lib/chef/provider/one_vnet_lease.rb +133 -0
  10. data/lib/chef/provisioning/driver_init/opennebula.rb +17 -0
  11. data/lib/chef/provisioning/opennebula_driver.rb +18 -0
  12. data/lib/chef/provisioning/opennebula_driver/credentials.rb +105 -0
  13. data/lib/chef/provisioning/opennebula_driver/driver.rb +572 -0
  14. data/lib/chef/provisioning/opennebula_driver/one_lib.rb +352 -0
  15. data/lib/chef/provisioning/opennebula_driver/resources.rb +20 -0
  16. data/lib/chef/provisioning/opennebula_driver/version.rb +30 -0
  17. data/lib/chef/resource/one_image.rb +65 -0
  18. data/lib/chef/resource/one_template.rb +46 -0
  19. data/lib/chef/resource/one_user.rb +50 -0
  20. data/lib/chef/resource/one_vnet.rb +51 -0
  21. data/lib/chef/resource/one_vnet_lease.rb +46 -0
  22. data/spec/integration/test_all_integration_spec.rb +102 -0
  23. data/spec/recipes/attach_back_one_vm_spec.rb +20 -0
  24. data/spec/recipes/attach_back_two_vm_spec.rb +20 -0
  25. data/spec/recipes/attach_one_image_spec.rb +20 -0
  26. data/spec/recipes/converge_back_one_vm_spec.rb +19 -0
  27. data/spec/recipes/converge_back_two_vm_spec.rb +19 -0
  28. data/spec/recipes/converge_bootstrap_vm_spec.rb +34 -0
  29. data/spec/recipes/create_back_one_vm_spec.rb +20 -0
  30. data/spec/recipes/create_back_two_vm_spec.rb +20 -0
  31. data/spec/recipes/create_bootstrap_vm_spec.rb +34 -0
  32. data/spec/recipes/create_one_image_spec.rb +21 -0
  33. data/spec/recipes/create_one_template_spec.rb +52 -0
  34. data/spec/recipes/delete_all_spec.rb +47 -0
  35. data/spec/recipes/driver_options_spec.rb +70 -0
  36. data/spec/recipes/instantiate_one_template_spec.rb +35 -0
  37. data/spec/recipes/snapshot_one_image_spec.rb +21 -0
  38. data/spec/recipes/snapshot_two_image_spec.rb +21 -0
  39. data/spec/spec_helper.rb +35 -0
  40. data/spec/support/opennebula_support.rb +64 -0
  41. metadata +168 -0
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require 'bundler'
2
+ require 'bundler/gem_tasks'
3
+
4
+ task :spec do
5
+ require File.expand_path('spec/run')
6
+ end
@@ -0,0 +1,244 @@
1
+ # Copyright 2015, BlackBerry, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ #
16
+ # Implementation of Provider class.
17
+ #
18
+ class Chef
19
+ #
20
+ # Implementation of Provider class.
21
+ #
22
+ class Provider
23
+ #
24
+ # Implementation of Provider class.
25
+ #
26
+ class OneImage < Chef::Provider::LWRPBase
27
+ use_inline_resources
28
+
29
+ provides :one_image
30
+
31
+ attr_reader :image
32
+
33
+ def whyrun_supported?
34
+ true
35
+ end
36
+
37
+ def load_current_resource
38
+ end
39
+
40
+ def action_handler
41
+ @action_handler ||= Chef::Provisioning::ChefProviderActionHandler.new(self)
42
+ end
43
+
44
+ def exists?
45
+ new_driver = driver
46
+ @image = new_driver.one.get_resource('img', :name => new_resource.name)
47
+ !@image.nil?
48
+ end
49
+
50
+ action :allocate do
51
+ if exists?
52
+ action_handler.report_progress "image '#{new_resource.name}' already exists - nothing to do"
53
+ else
54
+ fail "'size' must be specified" unless new_resource.size
55
+ fail "'datastore_id' must be specified" unless new_resource.datastore_id
56
+
57
+ action_handler.perform_action "allocated image '#{new_resource.name}'" do
58
+ @image = new_driver.one.allocate_img(
59
+ new_resource.name,
60
+ new_resource.size,
61
+ new_resource.datastore_id,
62
+ new_resource.type || 'OS',
63
+ new_resource.fs_type || 'ext2',
64
+ new_resource.img_driver || 'qcow2',
65
+ new_resource.prefix || 'vd',
66
+ new_resource.persistent || false)
67
+ Chef::Log.info("Image '#{new_resource.name}' allocate in initial state #{@image.state_str}")
68
+ @new_resource.updated_by_last_action(true)
69
+ end
70
+ end
71
+ @image
72
+ end
73
+
74
+ action :create do
75
+ @image = action_allocate
76
+ case @image.state_str
77
+ when 'INIT', 'LOCKED'
78
+ action_handler.perform_action "wait for image '#{new_resource.name}' to be READY" do
79
+ current_driver.one.wait_for_img(new_resource.name, @image.id)
80
+ @new_resource.updated_by_last_action(true)
81
+ end
82
+ when 'READY', 'USED', 'USED_PERS'
83
+ action_handler.report_progress "image '#{new_resource.name}' is already in #{@image.state_str} state - nothing to do"
84
+ else
85
+ fail "Image #{new_resource.name} is in unexpected state '#{@image.state_str}'"
86
+ end
87
+ end
88
+
89
+ action :destroy do
90
+ if exists?
91
+ action_handler.perform_action "deleted image '#{new_resource.name}'" do
92
+ rc = @image.delete
93
+ fail "Failed to delete image '#{new_resource.name}' : #{rc.message}" if OpenNebula.is_error?(rc)
94
+ until new_driver.one.get_resource('img', :name => new_resource.name).nil?
95
+ Chef::Log.debug("Waiting for delete image to finish...")
96
+ sleep 1
97
+ end
98
+ @new_resource.updated_by_last_action(true)
99
+ end
100
+ else
101
+ action_handler.report_progress "image '#{new_resource.name}' does not exist - nothing to do"
102
+ end
103
+ end
104
+
105
+ action :attach do
106
+ fail "Missing attribute 'machine_id'" unless new_resource.machine_id
107
+ fail "Failed to attach disk - image '#{new_resource.name}' does not exist" unless exists?
108
+
109
+ vm = new_driver.one.get_resource('vm', new_resource.machine_id.is_a?(Integer) ? :id : :name => new_resource.machine_id)
110
+ fail "Failed to attach disk - VM '#{new_resource.machine}' does not exist" if vm.nil?
111
+ action_handler.perform_action "attached disk #{new_resource.name} to #{vm.name}" do
112
+ disk_hash = @image.to_hash
113
+ disk_tpl = "DISK = [ "
114
+ disk_tpl << " IMAGE = #{disk_hash['IMAGE']['NAME']}, IMAGE_UNAME = #{disk_hash['IMAGE']['UNAME']}"
115
+ disk_tpl << ", TARGET = #{new_resource.target}" if new_resource.target
116
+ disk_tpl << ", DEV_PREFIX = #{new_resource.prefix}" if new_resource.prefix
117
+ disk_tpl << ", CACHE = #{new_resource.cache}" if new_resource.cache
118
+ disk_tpl << "]"
119
+
120
+ disk_id = new_driver.one.get_disk_id(vm, disk_hash['IMAGE']['NAME'])
121
+ if !disk_id.nil?
122
+ action_handler.report_progress "disk is already attached" unless disk_id.nil?
123
+ elsif disk_id.nil?
124
+ action_handler.report_progress "disk not attached, attaching..."
125
+ rc = vm.disk_attach(disk_tpl)
126
+ new_driver.one.wait_for_vm(vm.id)
127
+ fail "Failed to attach disk to VM '#{vm.name}': #{rc.message}" if OpenNebula.is_error?(rc)
128
+ @new_resource.updated_by_last_action(true)
129
+ end
130
+ end
131
+ end
132
+
133
+ action :snapshot do
134
+ fail "Missing attribute 'machine_id'" unless new_resource.machine_id
135
+ fail "snapshot '#{new_resource.name}' already exists" if exists?
136
+ vm = new_driver.one.get_resource('vm', new_resource.machine_id.is_a?(Integer) ? :id : :name => new_resource.machine_id)
137
+ fail "Failed to create snapshot - VM '#{new_resource.machine_id}' does not exist" if vm.nil?
138
+ action_handler.perform_action "created snapshot from '#{new_resource.machine_id}'" do
139
+ disk_id = new_resource.disk_id.is_a?(Integer) ? new_resource.disk_id : new_driver.one.get_disk_id(vm, new_resource.disk_id)
140
+ fail "No disk '#{new_resource.disk_id}' found on '#{vm.name}'" if disk_id.nil?
141
+
142
+ @image = vm.disk_snapshot(disk_id, new_resource.name, "", true)
143
+ fail "Failed to create snapshot '#{new_resource.name}': #{@image.message}" if OpenNebula.is_error?(@image)
144
+
145
+ @image = new_driver.one.wait_for_img(new_resource.name, @image)
146
+ if new_resource.persistent
147
+ action_handler.report_progress "make image '#{new_resource.name}' persistent"
148
+ @image.persistent
149
+ end
150
+ @new_resource.updated_by_last_action(true)
151
+ end
152
+ end
153
+
154
+ action :upload do
155
+ fail "'datastore_id' is required" unless new_resource.datastore_id
156
+ fail "'image_file' is required" unless new_resource.image_file
157
+ fail "image_file #{new_resource.image_file} does not exist" unless ::File.exist? new_resource.image_file
158
+
159
+ file_url = "http://#{node['ipaddress']}/#{::File.basename(@new_resource.image_file)}"
160
+ description = @new_resource.description || "#{@new_resource.name} image"
161
+ image_driver = @new_resource.img_driver || 'qcow2'
162
+
163
+ if exists?
164
+ if @image.name == @new_resource.name &&
165
+ @image['PATH'] == file_url &&
166
+ @image['TEMPLATE/DRIVER'] == image_driver &&
167
+ @image['TEMPLATE/DESCRIPTION'] == description &&
168
+ @image['DATASTORE_ID'] == @new_resource.datastore_id.to_s
169
+ action_handler.report_progress("image '#{@new_resource.name}' (ID: #{@image.id}) already exists - nothing to do")
170
+ else
171
+ fail "image '#{new_resource.name}' already exists, but it is not the same image"
172
+ end
173
+ else
174
+ action_handler.perform_action "upload image '#{@new_resource.image_file}'" do
175
+ begin
176
+ pid = Process.spawn("sudo python -m SimpleHTTPServer 80", :chdir => ::File.dirname(@new_resource.image_file), STDOUT => "/dev/null", STDERR => "/dev/null", :pgroup => true)
177
+ fail "Failed to start 'SimpleHTTPServer'" if pid.nil?
178
+ new_driver.one.upload_img(
179
+ @new_resource.name,
180
+ @new_resource.datastore_id,
181
+ file_url,
182
+ image_driver,
183
+ description,
184
+ @new_resource.type,
185
+ @new_resource.prefix,
186
+ @new_resource.persistent,
187
+ @new_resource.public,
188
+ @new_resource.target,
189
+ @new_resource.disk_type,
190
+ @new_resource.source,
191
+ @new_resource.size,
192
+ @new_resource.fs_type)
193
+
194
+ @new_resource.updated_by_last_action(true)
195
+ ensure
196
+ system("sudo kill -9 -#{pid}")
197
+ end
198
+ end
199
+ end
200
+ end
201
+
202
+ action :download do
203
+ new_driver = driver
204
+
205
+ action_handler.perform_action "downloaded image '#{@new_resource.image_file}" do
206
+ download_url = ENV['ONE_DOWNLOAD'] || @new_resource.download_url
207
+ fail %('download_url' is a required attribute.
208
+ You can get the value for 'download_url' by loging into your OpenNebula CLI
209
+ and reading the ONE_DOWNLOAD environment variable) if download_url.nil?
210
+ # You can get the value for 'download_url' by loging into your OpenNebula CLI and reading the ONE_DOWNLOAD environment variable" if download_url.nil?
211
+ image = new_driver.one.get_resource('img', !@new_resource.image_id.nil? ? { :id => @new_resource.image_id } : { :name => @new_resource.name })
212
+ fail "Image 'NAME: #{@new_resource.name}/ID: #{@new_resource.image_id}' does not exist" if image.nil?
213
+ local_path = @new_resource.image_file || ::File.join(Chef::Config[:file_cache_path], "#{@new_resource.name}.qcow2")
214
+ fail "Will not overwrite an existing file: #{local_path}" if ::File.exist?(local_path)
215
+ command = "curl -o #{local_path} #{download_url}/#{::File.basename(::File.dirname(image['SOURCE']))}/#{::File.basename(image['SOURCE'])}"
216
+ rc = system(command)
217
+ fail rc if rc.nil?
218
+ fail "ERROR: #{rc}" unless rc
219
+ system("chmod 777 #{local_path}")
220
+ Chef::Log.info("Image downloaded from OpenNebula to: #{local_path}")
221
+ @new_resource.updated_by_last_action(true)
222
+ end
223
+ end
224
+
225
+ protected
226
+
227
+ def driver
228
+ if current_driver && current_driver.driver_url != new_driver.driver_url
229
+ fail "Cannot move '#{machine_spec.name}' from #{current_driver.driver_url} to #{new_driver.driver_url}: machine moving is not supported. Destroy and recreate."
230
+ end
231
+ fail "Driver not specified for one_image #{new_resource.name}" unless new_driver
232
+ new_driver
233
+ end
234
+
235
+ def new_driver
236
+ run_context.chef_provisioning.driver_for(new_resource.driver)
237
+ end
238
+
239
+ def current_driver
240
+ run_context.chef_provisioning.driver_for(run_context.chef_provisioning.current_driver) if run_context.chef_provisioning.current_driver
241
+ end
242
+ end
243
+ end
244
+ end
@@ -0,0 +1,95 @@
1
+ # Copyright 2015, BlackBerry, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ #
16
+ # Implementation of Provider class.
17
+ #
18
+ class Chef
19
+ #
20
+ # Implementation of Provider class.
21
+ #
22
+ class Provider
23
+ #
24
+ # Implementation of Provider class.
25
+ #
26
+ class OneTemplate < Chef::Provider::LWRPBase
27
+ use_inline_resources
28
+
29
+ provides :one_template
30
+
31
+ attr_reader :template
32
+
33
+ def whyrun_supported?
34
+ true
35
+ end
36
+
37
+ def load_current_resource
38
+ end
39
+
40
+ def action_handler
41
+ @action_handler ||= Chef::Provisioning::ChefProviderActionHandler.new(self)
42
+ end
43
+
44
+ def exists?
45
+ new_driver = driver
46
+ @template = new_driver.one.get_resource('tpl', :name => new_resource.name)
47
+ !@template.nil?
48
+ end
49
+
50
+ action :create do
51
+ if exists?
52
+ action_handler.report_progress "template '#{new_resource.name}' already exists - nothing to do"
53
+ else
54
+ fail "Missing attribute 'template_file' or 'template'" if !new_resource.template_file && !new_resource.template
55
+ action_handler.perform_action "create template '#{new_resource.name}'" do
56
+ template_str = File.read(new_resource.template_file) if new_resource.template_file
57
+ template_str = new_driver.one.create_template(new_resource.template) if new_resource.template
58
+ template_str << "\nNAME=\"#{new_resource.name}\""
59
+ @template = new_driver.one.allocate_template(template_str)
60
+ @new_resource.updated_by_last_action(true)
61
+ end
62
+ end
63
+ end
64
+
65
+ action :delete do
66
+ if !exists?
67
+ action_handler.report_progress "template '#{new_resource.name}' does not exists - nothing to do"
68
+ else
69
+ action_handler.perform_action "delete template '#{new_resource.name}'" do
70
+ @template.delete
71
+ @new_resource.updated_by_last_action(true)
72
+ end
73
+ end
74
+ end
75
+
76
+ protected
77
+
78
+ def driver
79
+ if current_driver && current_driver.driver_url != new_driver.driver_url
80
+ fail "Cannot move '#{machine_spec.name}' from #{current_driver.driver_url} to #{new_driver.driver_url}: machine moving is not supported. Destroy and recreate."
81
+ end
82
+ fail "Driver not specified for one_image #{new_resource.name}" unless new_driver
83
+ new_driver
84
+ end
85
+
86
+ def new_driver
87
+ run_context.chef_provisioning.driver_for(new_resource.driver)
88
+ end
89
+
90
+ def current_driver
91
+ run_context.chef_provisioning.driver_for(run_context.chef_provisioning.current_driver) if run_context.chef_provisioning.current_driver
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,105 @@
1
+ # Copyright 2015, BlackBerry, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ #
16
+ # Implementation of Provider class.
17
+ #
18
+ class Chef
19
+ #
20
+ # Implementation of Provider class.
21
+ #
22
+ class Provider
23
+ #
24
+ # Implementation of Provider class.
25
+ #
26
+ class OneUser < Chef::Provider::LWRPBase
27
+ use_inline_resources
28
+
29
+ provides :one_user
30
+
31
+ attr_reader :current_user
32
+
33
+ def action_handler
34
+ @action_handler ||= Chef::Provisioning::ChefProviderActionHandler.new(self)
35
+ end
36
+
37
+ def exists?(filter)
38
+ new_driver = driver
39
+ @current_user = new_driver.one.get_resource('user', filter)
40
+ Chef::Log.debug("user '#{filter}' exists: #{!@current_user.nil?}")
41
+ !@current_user.nil?
42
+ end
43
+
44
+ action :create do
45
+ fail "Missing attribute 'password'" unless @new_resource.password
46
+
47
+ if exists?(:name => @new_resource.name)
48
+ action_handler.report_progress "user '#{@new_resource.name}' already exists - nothing to do"
49
+ else
50
+ action_handler.perform_action "create user '#{@new_resource.name}'" do
51
+ user = OpenNebula::User.new(OpenNebula::User.build_xml, @client)
52
+ rc = user.allocate(@new_resource.name, @new_resource.password) unless OpenNebula.is_error?(user)
53
+ Chef::Log.debug(template_str)
54
+ fail "failed to create vnet '#{@new_resource.name}': #{vnet.message}" if OpenNebula.is_error?(rc)
55
+ @new_resource.updated_by_last_action(true)
56
+ end
57
+ end
58
+ end
59
+
60
+ action :delete do
61
+ if exists?(:id => @new_resource.user_id, :name => @new_resource.name)
62
+ action_handler.perform_action "deleted user '#{new_resource.name}' (#{@current_user.id})" do
63
+ rc = @current_user.delete
64
+ fail "failed to delete user '#{@new_resource.name}': #{rc.message}" if OpenNebula.is_error?(rc)
65
+ @new_resource.updated_by_last_action(true)
66
+ end
67
+ else
68
+ action_handler.report_progress "user '#{new_resource.name}' does not exists - nothing to do"
69
+ end
70
+ end
71
+
72
+ action :update do
73
+ if exists?(:id => @new_resource.user_id, :name => @new_resource.name)
74
+ fail "':template' or ':template_file' attribute missing" if !@new_resource.template && !@new_resource.template_file
75
+ # hash = @current_user.to_hash
76
+ tpl = new_driver.one.create_template(@new_resource.template) if @new_resource.template
77
+ tpl = ::File.read(@new_resource.template_file) if @new_resource.template_file
78
+
79
+ rc = @current_user.update(tpl, true)
80
+ fail "failed to update user '#{@new_resource.name}': #{rc.message}" if OpenNebula.is_error?(rc)
81
+ else
82
+ fail "user '#{new_resource.name}' does not exists"
83
+ end
84
+ end
85
+
86
+ protected
87
+
88
+ def driver
89
+ if current_driver && current_driver.driver_url != new_driver.driver_url
90
+ fail "Cannot move '#{machine_spec.name}' from #{current_driver.driver_url} to #{new_driver.driver_url}: machine moving is not supported. Destroy and recreate."
91
+ end
92
+ fail "Driver not specified for one_image #{new_resource.name}" unless new_driver
93
+ new_driver
94
+ end
95
+
96
+ def new_driver
97
+ run_context.chef_provisioning.driver_for(new_resource.driver)
98
+ end
99
+
100
+ def current_driver
101
+ run_context.chef_provisioning.driver_for(run_context.chef_provisioning.current_driver) if run_context.chef_provisioning.current_driver
102
+ end
103
+ end
104
+ end
105
+ end