Class: Chef::Provisioning::OpenNebulaDriver::OneLib
- Inherits:
-
Object
- Object
- Chef::Provisioning::OpenNebulaDriver::OneLib
- Defined in:
- lib/chef/provisioning/opennebula_driver/one_lib.rb
Overview
Implementation.
Instance Attribute Summary collapse
-
#client ⇒ Object
readonly
Returns the value of attribute client.
-
#version_ge_4_14 ⇒ Object
readonly
Returns the value of attribute version_ge_4_14.
Instance Method Summary collapse
- #allocate_img(img_config) ⇒ Object
- #allocate_template(template_str) ⇒ Object
- #allocate_vm(template) ⇒ Object
- #allocate_vnet(template_str, cluster_id) ⇒ Object
- #chmod_resource(res = nil, octet = nil) ⇒ Object
-
#create_template(t, level = 0) ⇒ Object
This method will create a VM template from parameters provided in the âtâ Hash.
- #get_disk_id(vm, disk_name) ⇒ Object
-
#get_pool(type) ⇒ Object
This function provides a more readable way to return a OpenNebula::*Pool back to a caller.
-
#get_resource(resource_type, filter = {}) ⇒ Object
TODO: Always return an array.
-
#get_template(name, options) ⇒ Object
This will retrieve a VM template from one of the following locations: :template_name - template located in OpenNebula :template_id - template located in OpenNebula :template_file - local file containing the VM template :template - Hash containing equivalent structure as a VM template.
-
#initialize(args) ⇒ OneLib
constructor
A new instance of OneLib.
- #recursive_merge(dest, source) ⇒ Object
- #rename_vm(res, name) ⇒ Object
-
#retry_one(msg = "retry_one", retries = 3, retry_delay = 5, return_nil = false, return_error = false) ⇒ Object
Retry ONE operation.
- #template_from_file(options) ⇒ Object
- #template_from_hash(options) ⇒ Object
- #template_from_one(options) ⇒ Object
- #update_template(template_id, template_str) ⇒ Object
- #upload_img(img_config) ⇒ Object
- #wait_for_img(name, img_id) ⇒ Object
- #wait_for_vm(id, end_state = nil) ⇒ Object
Constructor Details
#initialize(args) ⇒ OneLib
Returns a new instance of OneLib.
51 52 53 54 55 56 57 |
# File 'lib/chef/provisioning/opennebula_driver/one_lib.rb', line 51 def initialize(args) @client = OpenNebula::Client.new(args[:credentials], args[:endpoint], args[:options]) rc = @client.get_version raise OpenNebulaException, rc. if OpenNebula.is_error?(rc) gem_version = Gem.loaded_specs['opennebula'].version.to_s.split('.').map(&:to_i) @version_ge_4_14 = gem_version[0] > 4 || (gem_version[0] == 4 && gem_version[1] >= 14) end |
Instance Attribute Details
#client ⇒ Object (readonly)
Returns the value of attribute client.
49 50 51 |
# File 'lib/chef/provisioning/opennebula_driver/one_lib.rb', line 49 def client @client end |
#version_ge_4_14 ⇒ Object (readonly)
Returns the value of attribute version_ge_4_14.
49 50 51 |
# File 'lib/chef/provisioning/opennebula_driver/one_lib.rb', line 49 def version_ge_4_14 @version_ge_4_14 end |
Instance Method Details
#allocate_img(img_config) ⇒ Object
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 |
# File 'lib/chef/provisioning/opennebula_driver/one_lib.rb', line 251 def allocate_img(img_config) template = <<-EOT NAME = #{img_config[:name]} TYPE = #{img_config[:type]} FSTYPE = #{img_config[:fstype]} SIZE = #{img_config[:size]} PERSISTENT = #{img_config[:persistent] ? 'YES' : 'NO'} DRIVER = #{img_config[:driver]} DEV_PREFIX = #{img_config[:prefix]} EOT img = OpenNebula::Image.new(OpenNebula::Image.build_xml, @client) raise OpenNebulaException, img. if OpenNebula.is_error?(img) rc = img.allocate(template, img_config[:datastore_id]) raise OpenNebulaException, rc. if OpenNebula.is_error?(rc) Chef::Log.debug("Allocated disk image #{img_config[:name]} (#{img.id})") img end |
#allocate_template(template_str) ⇒ Object
317 318 319 320 321 322 |
# File 'lib/chef/provisioning/opennebula_driver/one_lib.rb', line 317 def allocate_template(template_str) tpl = OpenNebula::Template.new(OpenNebula::Template.build_xml, @client) rc = tpl.allocate(template_str) unless OpenNebula.is_error?(tpl) raise OpenNebulaException, rc. if OpenNebula.is_error?(rc) rc end |
#allocate_vm(template) ⇒ Object
160 161 162 163 164 165 166 167 168 |
# File 'lib/chef/provisioning/opennebula_driver/one_lib.rb', line 160 def allocate_vm(template) vm = OpenNebula::VirtualMachine.new(OpenNebula::VirtualMachine.build_xml, @client) raise OpenNebulaException, vm. if OpenNebula.is_error?(vm) Chef::Log.debug(template) rc = vm.allocate(template) raise OpenNebulaException, rc. if OpenNebula.is_error?(rc) vm end |
#allocate_vnet(template_str, cluster_id) ⇒ Object
303 304 305 306 307 308 |
# File 'lib/chef/provisioning/opennebula_driver/one_lib.rb', line 303 def allocate_vnet(template_str, cluster_id) vnet = OpenNebula::Vnet.new(OpenNebula::Vnet.build_xml, @client) rc = vnet.allocate(template_str, cluster_id) unless OpenNebula.is_error?(vnet) raise OpenNebulaException, rc. if OpenNebula.is_error?(rc) vnet end |
#chmod_resource(res = nil, octet = nil) ⇒ Object
246 247 248 249 |
# File 'lib/chef/provisioning/opennebula_driver/one_lib.rb', line 246 def chmod_resource(res = nil, octet = nil) rc = res.chmod_octet(octet) unless res.nil? || octet.nil? raise OpenNebulaException, rc. if OpenNebula.is_error?(rc) end |
#create_template(t, level = 0) ⇒ Object
This method will create a VM template from parameters provided in the âtâ Hash. The hash must have equivalent structure as the VM template.
We considered using OpenNebulaHelper::create_template for this, however it would require a backwards compatibility shim and/or making breaking changes to the API. In particular, our method is more attractive due to the nested nature of our Hash, versus specifying a long string for the :context attribute with embedded newlines. Our strategy provides a way to override specific values, while this is difficult to accomplish with OpenNebulaHelper::create_template.
Current template hash: {
"NAME" => "baz"
"CPU" => "1",
"VCPU" => "1",
"MEMORY" => "512",
"OS" => {
"ARCH" => "x86_64"
},
"GRAPHICS" => {
"LISTEN" => "0.0.0.0",
"TYPE" => "vnc"
},
"CONTEXT" => {
"FOO" => "BAR",
"BAZ" => "QUX"
"HOSTNAME" => "$NAME",
"SSH_PUBLIC_KEY" => "$USER[SSH_PUBLIC_KEY]",
"NETWORK" => "YES"
}
}
Using OpenNebulaHelper::create_template:
:name => 'baz'
:cpu => 1,
:vcpu => 1,
:memory => 512,
:arch => 'x86_64',
:vnc => true,
:context => "FOO=\"BAR\"\nBAZ=\"QUX\"\nHOSTNAME=\"$NAME\"",
:ssh => true,
:net_context => true
455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 |
# File 'lib/chef/provisioning/opennebula_driver/one_lib.rb', line 455 def create_template(t, level = 0) tpl = "" count = t.size index = 1 t.each do |k, v| if v.is_a?(Hash) level.times { tpl << " " } # DISK and NIC is just for backward compatibility # it should be replaced by Array k = 'DISK' if k =~ /^DISK/ k = 'NIC' if k =~ /^NIC/ tpl << "#{k} = [\n" tpl << create_template(v, (level + 1)) (level - 1).times { tpl << " " } tpl << "]\n" elsif v.is_a?(Array) level.times { tpl << " " } v.each do |e| tpl << "#{k} = [\n" tpl << create_template(e, (level + 1)) tpl << "]\n" end else comma = (index < count) && level > 0 level.times { tpl << " " } txt = v.is_a?(String) ? "#{k} = \"#{v.gsub(/(?<!\\)\"/, '\"')}\"" : "#{k} = \"#{v}\"" tpl << txt tpl << (comma ? ",\n" : "\n") index += 1 end end tpl end |
#get_disk_id(vm, disk_name) ⇒ Object
296 297 298 299 300 301 |
# File 'lib/chef/provisioning/opennebula_driver/one_lib.rb', line 296 def get_disk_id(vm, disk_name) fail "VM cannot be nil" if vm.nil? disk_id = nil vm.each('TEMPLATE/DISK') { |disk| disk_id = disk['DISK_ID'].to_i if disk['IMAGE'] == disk_name } disk_id end |
#get_pool(type) ⇒ Object
This function provides a more readable way to return a OpenNebula::*Pool back to a caller. The caller simply needs to pass the pool type in symbol form to us, and we send back the pool. The idea is that passing :template will give us back OpenNebula::TemplatePool, etc. for consistency with the OpenNebula API calls. Note that we are still supporting the old API, while logging a warning that the old format is deprecated. Users should expect the old format to disappear in a future release.
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
# File 'lib/chef/provisioning/opennebula_driver/one_lib.rb', line 68 def get_pool(type) fail "pool type must be specified" if type.nil? key = type.capitalize key = :SecurityGroup if key == :Securitygroup key = :VirtualMachine if key == :Virtualmachine key = :VirtualNetwork if key == :Virtualnetwork if key == :Documentpooljson # Doesn't match the template below return OpenNebula::DocumentPoolJSON.new(@client) end pool_class = Object.const_get("OpenNebula::#{key}Pool") pool_class.new(@client) rescue NameError _get_pool(type.to_s) # This will raise an exception if invalid. end |
#get_resource(resource_type, filter = {}) ⇒ Object
TODO: Always return an array
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
# File 'lib/chef/provisioning/opennebula_driver/one_lib.rb', line 126 def get_resource(resource_type, filter = {}) fail "resource_type must be specified" if resource_type.nil? # Ensure the hash key is correct when searching hash_key = resource_type.to_s.upcase hash_key = 'VMTEMPLATE' if hash_key == 'TPL' || hash_key == 'TEMPLATE' if filter.empty? Chef::Log.warn("get_resource: 'name' or 'id' must be provided") return nil end pool = get_pool(resource_type) if resource_type.to_s != 'user' && filter[:id] && !filter[:id].nil? pool.info!(-2, filter[:id].to_i, filter[:id].to_i) return pool.first end if resource_type.to_s == 'user' pool.info else pool.info!(-2, -1, -1) end resources = [] pool.each do |res| next unless res.name == filter[:name] next if filter[:uname] && res.to_hash[hash_key]['UNAME'] != filter[:uname] resources << res end return nil if resources.empty? return resources[0] if resources.size == 1 resources end |
#get_template(name, options) ⇒ Object
This will retrieve a VM template from one of the following locations:
:template_name - template located in OpenNebula
:template_id - template located in OpenNebula
:template_file - local file containing the VM template
:template - Hash containing equivalent structure as a VM template
348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 |
# File 'lib/chef/provisioning/opennebula_driver/one_lib.rb', line 348 def get_template(name, ) t_hash = nil if ![:template_name].nil? || ![:template_id].nil? t_hash = template_from_one() elsif ![:template_file].nil? t_hash = template_from_file() elsif ![:template].nil? t_hash = template_from_hash() else fail "To create a VM you must specify one of ':template', " \ "':template_id', or ':template_name' option " \ "in ':bootstrap_options'" end fail "Inavlid VM template : #{t_hash}" if t_hash.nil? || t_hash.empty? tpl_updates = [:template_options] || {} if [:user_variables] Chef::Log.warn("':user_variables' will be deprecated in next " \ "version in favour of ':template_options'") recursive_merge(tpl_updates, [:user_variables]) end recursive_merge(t_hash, tpl_updates) unless tpl_updates.empty? if [:enforce_chef_fqdn] Chef::Log.warn(':enforce_chef_fqdn has been deprecated. VM name ' \ 'will be set to the machine resource name.') end # FQDN is the machine resource name, unless overridden by e.g. cloud-init t_hash['NAME'] = name unless t_hash['CONTEXT']['SSH_PUBLIC_KEY'] t_hash['CONTEXT']['SSH_PUBLIC_KEY'] = "$USER[SSH_PUBLIC_KEY]" end tpl = create_template(t_hash) Chef::Log.debug(tpl) tpl end |
#recursive_merge(dest, source) ⇒ Object
324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 |
# File 'lib/chef/provisioning/opennebula_driver/one_lib.rb', line 324 def recursive_merge(dest, source) source.each do |k, v| if source[k].is_a?(Hash) if dest[k].is_a?(Array) dest[k] = v.dup else dest[k] = {} unless dest[k] recursive_merge(dest[k], v) end elsif source[k].is_a?(Array) dest[k] = v.dup else dest[k] = v end end end |
#rename_vm(res, name) ⇒ Object
213 214 215 216 |
# File 'lib/chef/provisioning/opennebula_driver/one_lib.rb', line 213 def rename_vm(res, name) rc = res.rename(name) raise OpenNebulaException, rc. if OpenNebula.is_error?(rc) end |
#retry_one(msg = "retry_one", retries = 3, retry_delay = 5, return_nil = false, return_error = false) ⇒ Object
Retry ONE operation
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
# File 'lib/chef/provisioning/opennebula_driver/one_lib.rb', line 191 def retry_one(msg = "retry_one", retries = 3, retry_delay = 5, return_nil = false, return_error = false) return nil unless block_given? count = 1 rc = nil loop do rc = yield Chef::Log.info(msg) if OpenNebula.is_error?(rc) return rc if return_error elsif rc.nil? return rc if return_nil else return rc end sleep retry_delay break if count == retries count += 1 end Chef::Log.info("FAIL: one_lib.retry_one '#{msg}'") rc end |
#template_from_file(options) ⇒ Object
390 391 392 393 394 395 396 397 398 399 400 401 |
# File 'lib/chef/provisioning/opennebula_driver/one_lib.rb', line 390 def template_from_file() t_hash = nil doc = OpenNebula::CustomObject.new(OpenNebula::CustomObject.build_xml, @client) unless OpenNebula.is_error?(doc) rc = doc.allocate(File.read([:template_file]).to_s) fail "Failed to allocate OpenNebula document: #{rc.}" if OpenNebula.is_error?(rc) doc.info! t_hash = doc.to_hash['DOCUMENT']['TEMPLATE'] doc.delete end t_hash end |
#template_from_hash(options) ⇒ Object
403 404 405 |
# File 'lib/chef/provisioning/opennebula_driver/one_lib.rb', line 403 def template_from_hash() [:template] end |
#template_from_one(options) ⇒ Object
383 384 385 386 387 388 |
# File 'lib/chef/provisioning/opennebula_driver/one_lib.rb', line 383 def template_from_one() t = get_resource(:template, :name => [:template_name]) if [:template_name] t = get_resource(:template, :id => [:template_id]) if [:template_id] fail "Template '#{}' does not exist" if t.nil? t.to_hash["VMTEMPLATE"]["TEMPLATE"] end |
#update_template(template_id, template_str) ⇒ Object
310 311 312 313 314 315 |
# File 'lib/chef/provisioning/opennebula_driver/one_lib.rb', line 310 def update_template(template_id, template_str) template = OpenNebula::Template.new(OpenNebula::Template.build_xml(template_id), @client) rc = template.update(template_str) unless OpenNebula.is_error?(template) raise OpenNebulaException, rc. if OpenNebula.is_error?(rc) rc end |
#upload_img(img_config) ⇒ Object
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 |
# File 'lib/chef/provisioning/opennebula_driver/one_lib.rb', line 218 def upload_img(img_config) template = <<-EOTPL NAME = #{img_config[:name]} PATH = \"#{img_config[:path]}\" DRIVER = #{img_config[:driver]} DESCRIPTION = \"#{img_config[:description]}\" EOTPL template << "TYPE = #{img_config[:type]}\n" unless img_config[:type].nil? template << "DEV_PREFIX = #{img_config[:prefix]}\n" unless img_config[:prefix].nil? template << "TARGET = #{img_config[:target]}\n" unless img_config[:target].nil? template << "DISK_STYPE = #{img_config[:disk_type]}\n" unless img_config[:disk_type].nil? template << "SOURCE = #{img_config[:source]}\n" unless img_config[:source].nil? template << "SIZE = #{img_config[:size]}\n" unless img_config[:size].nil? template << "FSTYPE = #{img_config[:fs_type]}\n" unless img_config[:fs_type].nil? template << "PUBLIC = #{img_config[:public] ? 'YES' : 'NO'}\n" unless img_config[:public].nil? template << "PERSISTENT = #{img_config[:persistent] ? 'YES' : 'NO'}\n" unless img_config[:persistent].nil? Chef::Log.debug("\n#{template}") image = OpenNebula::Image.new(OpenNebula::Image.build_xml, @client) raise OpenNebulaException, image. if OpenNebula.is_error?(image) rc = image.allocate(template, img_config[:datastore_id].to_i) raise OpenNebulaException, rc. if OpenNebula.is_error?(rc) Chef::Log.debug("Waiting for image '#{img_config[:name]}' (#{image.id}) to be ready") wait_for_img(img_config[:name], image.id) chmod_resource(image, img_config[:mode]) end |
#wait_for_img(name, img_id) ⇒ Object
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 |
# File 'lib/chef/provisioning/opennebula_driver/one_lib.rb', line 273 def wait_for_img(name, img_id) cur_state = nil image = nil state = 'INIT' pool = get_pool(:image) retry_one("wait for IMAGE #{img_id} to be ready", 600, 2) do pool.info!(-2, img_id, img_id) pool.each do |img| next unless img.id == img_id cur_state = img.state_str image = img Chef::Log.debug("Image #{img_id} state: '#{cur_state}'") state = cur_state break end (state == 'INIT' || state == 'LOCKED') ? nil : true end fail "Failed to create #{name} image. State = '#{state}'" if state != 'READY' Chef::Log.info("Image #{name} is in READY state") image end |
#wait_for_vm(id, end_state = nil) ⇒ Object
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
# File 'lib/chef/provisioning/opennebula_driver/one_lib.rb', line 170 def wait_for_vm(id, end_state = nil) end_state ||= 'RUNNING' vm = get_resource(:virtualmachine, :id => id) fail "Did not find VM with ID: #{id}" unless vm # Wait up to 10 min for the VM to be ready rc = retry_one("wait for VM #{id} to be ready", 300, 2) do vm.info if vm.lcm_state_str != 'LCM_INIT' short_lcm = OpenNebula::VirtualMachine::SHORT_LCM_STATES[vm.lcm_state_str] fail "'#{vm.name}'' failed. Current state: #{vm.lcm_state_str}" if short_lcm == 'fail' end fail "'#{vm.name}'' failed. Current state: #{vm.state_str}" if vm.state_str == 'FAILED' Chef::Log.info("current state #{vm.name}: '#{vm.lcm_state_str}' short: '#{short_lcm}'") vm.lcm_state_str.casecmp(end_state) == 0 ? true : nil end fail "wait_for_vm timed out: '#{id}'" if rc.nil? vm end |