From d0ebba1f6630cab57d19dd0c7f0aec3d542cdda4 Mon Sep 17 00:00:00 2001 From: Manisha Singhal Date: Wed, 18 Oct 2023 15:17:49 +0200 Subject: [PATCH] fixup! feat: Add Cloudinit support using iso image (#294) (#298) --- app/helpers/proxmox_vm_cloudinit_helper.rb | 68 +++++++++++++++------- 1 file changed, 47 insertions(+), 21 deletions(-) diff --git a/app/helpers/proxmox_vm_cloudinit_helper.rb b/app/helpers/proxmox_vm_cloudinit_helper.rb index afdceb87f..b241ad0ea 100644 --- a/app/helpers/proxmox_vm_cloudinit_helper.rb +++ b/app/helpers/proxmox_vm_cloudinit_helper.rb @@ -42,38 +42,42 @@ def parse_server_cloudinit(args) cloudinit_h end - def create_cloudinit_iso(vm_name, configs) - ssh = Fog::SSH.new(URI.parse(fog_credentials[:proxmox_url]).host, fog_credentials[:proxmox_username].split('@')[0], { password: fog_credentials[:proxmox_password] }) + def create_cloudinit_iso(vm_name, configs, ssh) + iso = File.join(default_iso_path, "#{vm_name.tr('.', '_')}_cloudinit.iso") files = [] wd = create_temp_directory(ssh) + configs.each do |config| - begin - ssh.run([%({echo "#{config[1]}" >> "#{wd}/#{config[0]}"})]) - rescue ::Foreman::Exception => e - logger.error("Error writing to the file #{config[0]}: #{e}") - raise e + config_file = ssh.run(%(echo "#{config[1]}" >> "#{wd}/#{config[0]}")) + unless config_file.first.status.zero? + delete_temp_dir(ssh, wd) + raise ::Foreman::Exception, "Failed to create file #{config[0]}: #{config_file.first.stdout}" end files.append(File.join(wd, config[0])) end - raise Foreman::Exception, N_('ISO build failed') unless ssh.run(generate_iso_command(vm_name, files)) - delete_config_files(wd) + generated_iso = ssh.run(generate_iso_command(iso, files)) + unless generated_iso.first.status.zero? + delete_temp_dir(ssh, wd) + raise Foreman::Exception, N_("ISO build failed: #{generated_iso.first.stdout}") + end + delete_temp_dir(ssh, wd) iso end - def generate_iso_command(vm_name, files) - iso = File.join(default_iso_path, "#{vm_name}_cloudinit.iso") - arguments = ["genisoimage", "-output #{iso}", '-volid', 'cidata', '-joliet', '-rock'] - logger.warn("iso image generation args: #{arguments}") - arguments.concat(files).join(' ') + def generate_iso_command(iso_file, config_files) + arguments = ["genisoimage", "-output #{iso_file}", '-volid', 'cidata', '-joliet', '-rock'] + iso_command = arguments.concat(config_files).join(' ') + logger.debug("iso image generation args: #{iso_command}") + iso_command end def create_temp_directory(ssh) - res = ssh.run([%({mktemp -d})]) + res = ssh.run("mktemp -d") raise ::Foreman::Exception, "Could not create working directory to store cloudinit config data: #{res.first.stdout}." unless res.first.status.zero? res.first.stdout.chomp end - def delete_config_files(working_dir) + def delete_temp_dir(ssh, working_dir) ssh.run("rm -rf #{working_dir}") rescue Foreman::Exception => e logger.warn("Could not delete directory for config files: #{e}. Please delete it manually at #{working_dir}") @@ -83,12 +87,13 @@ def parse_cloudinit_config(args) filenames = ["meta-data"] config_data = ["instance-id: #{args[:name]}"] user_data = args.delete(:user_data) - return args if user_data == '' + check_template_format(user_data) + ssh = vm_ssh if user_data.include?('#network-config') && user_data.include?('#cloud-config') config_data.concat(user_data.split('#network-config')) - filenames.append(['user-data', 'network-config']) + filenames.concat(['user-data', 'network-config']) elsif user_data.include?('#network-config') && !user_data.include?('#cloud-config') config_data.append(user_data.split('#network-config')[1]) filenames.append("network-config") @@ -98,11 +103,11 @@ def parse_cloudinit_config(args) end return args if config_data.length == 1 - configs = filenames.zip(config_data).to_h - iso = create_cloudinit_iso(args[:name], configs) - args.merge(attach_cloudinit_iso(args[:node_id], iso)) + iso = create_cloudinit_iso(args[:name], configs, ssh) + args[:config_attributes]&.merge!(update_boot_order(args[:image_id])) + args.merge!(attach_cloudinit_iso(args[:node_id], iso)) end def attach_cloudinit_iso(node, iso) @@ -114,4 +119,25 @@ def attach_cloudinit_iso(node, iso) def default_iso_path "/var/lib/vz/template/iso" end + + def update_boot_order(image_id) + vm = find_vm_by_uuid(image_id) + return if vm.disks.nil? + disks = vm.disks.map { |disk| disk.split(":")[0] }.join(";") + { boot: "order=" + disks } + end + + def vm_ssh + ssh = Fog::SSH.new(URI.parse(fog_credentials[:proxmox_url]).host, fog_credentials[:proxmox_username].split('@')[0], { password: fog_credentials[:proxmox_password] }) + ssh.run('ls') # test if ssh is successful + ssh + rescue StandardError => e + raise ::Foreman::Exception, "Unable to ssh into proxmox server: #{e}" + end + + def check_template_format(user_data) + YAML.safe_load(user_data) + rescue StandardError => e + raise ::Foreman::Exception, "'User data kind' template provided could not be loaded, please check the format: #{e}" + end end