class Fog::Libvirt::Compute::Server
Constants
- DOMAIN_CLEANUP_REGEXP
-
Locale-friendly removal of non-alpha nums
Attributes
The following attributes are only needed when creating a new vm
TODO: Add depreciation warning
The following attributes are only needed when creating a new vm
TODO: Add depreciation warning
rubocop:enable Metrics
Public Class Methods
Source
# File lib/fog/libvirt/models/compute/server.rb, line 55 def initialize(attributes={} ) @xml = attributes.delete(:xml) verify_boot_order(attributes[:boot_order]) super defaults.merge(attributes) initialize_nics initialize_volumes @user_data = attributes.delete(:user_data) end
Can be created by passing in :xml => “<xml to create domain/server>” or by providing :template_options => {
:name => "", :cpus => 1, :memory_size => 256 , :volume_template }
Calls superclass method
Public Instance Methods
Source
# File lib/fog/libvirt/models/compute/server.rb, line 276 def cloud_init_volume_name "#{name}-cloud-init.iso" end
Source
# File lib/fog/libvirt/models/compute/server.rb, line 267 def create_user_data_iso generate_config_iso(user_data) do |iso| vol = service.volumes.create(:name => cloud_init_volume_name, :capacity => "#{File.size(iso)}b", :allocation => "0G") vol.upload_image(iso) @iso_file = cloud_init_volume_name @iso_dir = File.dirname(vol.path) if vol.path end end
Source
# File lib/fog/libvirt/models/compute/server.rb, line 98 def destroy(options={ :destroy_volumes => false, :flags => ::Libvirt::Domain::UNDEFINE_NVRAM }) poweroff unless stopped? flags = options.fetch(:flags, ::Libvirt::Domain::UNDEFINE_NVRAM) if flags.zero? service.vm_action(uuid, :undefine) else # the test driver doesn't support UNDEFINE_NVRAM if service.uri.driver == 'test' flags ^= ::Libvirt::Domain::UNDEFINE_NVRAM end service.vm_action(uuid, :undefine, flags) end volumes.each { |vol| vol.destroy } if options[:destroy_volumes] true end
Source
# File lib/fog/libvirt/models/compute/server.rb, line 94 def disk_path volumes.first.path if volumes and volumes.first end
Source
# File lib/fog/libvirt/models/compute/server.rb, line 250 def generate_config_iso(user_data, &blk) Dir.mktmpdir('config') do |wd| generate_config_iso_in_dir(wd, user_data, &blk) end end
Source
# File lib/fog/libvirt/models/compute/server.rb, line 256 def generate_config_iso_in_dir(dir_path, user_data, &blk) FileUtils.touch(File.join(dir_path, "meta-data")) File.open(File.join(dir_path, 'user-data'), 'w') { |f| f.write user_data } isofile = Tempfile.new(['init', '.iso']).path unless system("genisoimage -output #{isofile} -volid cidata -joliet -rock #{File.join(dir_path, 'user-data')} #{File.join(dir_path, 'meta-data')}") raise Fog::Errors::Error.new("Couldn't generate cloud-init iso disk with genisoimage.") end blk.call(isofile) end
Source
# File lib/fog/libvirt/models/compute/server.rb, line 120 def poweroff action_status = service.vm_action(uuid, :destroy) reload action_status end
Also aliased as: halt
Source
# File lib/fog/libvirt/models/compute/server.rb, line 163 def private_ip_address ip_address(:private) end
Source
# File lib/fog/libvirt/models/compute/server.rb, line 167 def public_ip_address ip_address(:public) end
Source
# File lib/fog/libvirt/models/compute/server.rb, line 148 def ready? state == "running" end
Source
# File lib/fog/libvirt/models/compute/server.rb, line 114 def reboot action_status = service.vm_action(uuid, :reboot) reload action_status end
Source
# File lib/fog/libvirt/models/compute/server.rb, line 132 def resume action_status = service.vm_action(uuid, :resume) reload action_status end
Source
# File lib/fog/libvirt/models/compute/server.rb, line 68 def save raise Fog::Errors::Error.new('Saving an existing server may create a duplicate') unless new? create_or_clone_volume unless xml or @volumes create_user_data_iso if user_data @xml ||= to_xml self.id = (persistent ? service.define_domain(xml) : service.create_domain(xml)).uuid reload rescue => e raise Fog::Errors::Error.new("Error saving the server: #{e}") end
Source
# File lib/fog/libvirt/models/compute/server.rb, line 195 def scp(local_path, remote_path, upload_options = {}) requires :ssh_ip_address, :username scp_options = {} scp_options[:password] = password unless self.password.nil? scp_options[:key_data] = [private_key] if self.private_key scp_options[:proxy]= ssh_proxy unless self.ssh_proxy.nil? Fog::SCP.new(ssh_ip_address, username, scp_options).upload(local_path, remote_path, upload_options) end
Transfers a file
Source
# File lib/fog/libvirt/models/compute/server.rb, line 207 def setup(credentials = {}) requires :public_key, :ssh_ip_address, :username credentials[:proxy]= ssh_proxy unless ssh_proxy.nil? credentials[:password] = password unless self.password.nil? credentials[:key_data] = [private_key] if self.private_key commands = [ %{mkdir .ssh}, # %{passwd -l #{username}}, #Not sure if we need this here # %{echo "#{Fog::JSON.encode(attributes)}" >> ~/attributes.json} ] if public_key commands << %{echo "#{public_key}" >> ~/.ssh/authorized_keys} end # wait for domain to be ready Timeout::timeout(360) do begin Timeout::timeout(8) do Fog::SSH.new(ssh_ip_address, username, credentials.merge(:timeout => 4)).run('pwd') end rescue Errno::ECONNREFUSED sleep(2) retry rescue Net::SSH::AuthenticationFailed, Timeout::Error retry end end Fog::SSH.new(ssh_ip_address, username, credentials).run(commands) end
Sets up a new key
Source
# File lib/fog/libvirt/models/compute/server.rb, line 126 def shutdown action_status = service.vm_action(uuid, :shutdown) reload action_status end
Also aliased as: stop
Source
# File lib/fog/libvirt/models/compute/server.rb, line 171 def ssh(commands) requires :ssh_ip_address, :username ssh_options={} ssh_options[:password] = password unless password.nil? ssh_options[:proxy]= ssh_proxy unless ssh_proxy.nil? super(commands, ssh_options) end
Calls superclass method
Source
# File lib/fog/libvirt/models/compute/server.rb, line 181 def ssh_proxy begin require 'net/ssh/proxy/command' rescue LoadError Fog::Logger.warning("'net/ssh' missing, please install and try again.") exit(1) end # if this is a direct connection, we don't need a proxy to be set. return nil unless connection.uri.ssh_enabled? user_string= service.uri.user ? "-l #{service.uri.user}" : "" Net::SSH::Proxy::Command.new("ssh #{user_string} #{service.uri.host} nc %h %p") end
Source
# File lib/fog/libvirt/models/compute/server.rb, line 79 def start return true if active? action_status = service.vm_action(uuid, :create) reload action_status end
Source
# File lib/fog/libvirt/models/compute/server.rb, line 144 def stopped? state == "shutoff" end
Source
# File lib/fog/libvirt/models/compute/server.rb, line 138 def suspend action_status = service.vm_action(uuid, :suspend) reload action_status end
Source
# File lib/fog/libvirt/models/compute/server.rb, line 281 def to_xml builder = Nokogiri::XML::Builder.new do |xml| xml.domain(:type => domain_type) do xml.name(name) xml.memory(memory_size) if hugepages xml.memoryBacking do xml.hugepages end end xml.vcpu(cpus) os_tags = {} os_tags[:firmware] = firmware if firmware == 'efi' xml.os(**os_tags) do type = xml.type(os_type, :arch => arch) type[:machine] = "q35" if ["i686", "x86_64"].include?(arch) boot_order.each do |dev| xml.boot(:dev => dev) end loader_attributes&.each do |key, value| xml.loader(key => value) end if firmware == "efi" && firmware_features&.any? xml.firmware do firmware_features.each_pair do |key, value| xml.feature(:name => key, :enabled => value) end end end end xml.features do xml.acpi xml.apic end unless cpu.empty? if cpu.dig(:model, :name) xml.cpu do xml.model(cpu.dig(:model, :name), :fallback => cpu.dig(:model, :fallback) || "allow") end else xml.cpu( :mode => cpu.fetch(:mode, "host-passthrough"), :check => cpu.fetch(:check, "none"), :migratable => cpu.fetch(:migratable, "on") ) end end xml.clock(:offset => "utc") do xml.timer(:name => "rtc", :tickpolicy => "catchup") xml.timer(:name => "pit", :tickpolicy => "delay") xml.timer(:name => "hpet", :present => "no") end xml.devices do ceph_args = read_ceph_args volumes.each_with_index do |volume, index| target_device = "vd#{('a'..'z').to_a[index]}" if ceph_args && volume.pool_name.include?(ceph_args["libvirt_ceph_pool"]) xml.disk(:type => "network", :device => "disk") do xml.driver(:name => "qemu", :type => volume.format_type, :cache => "writeback", :discard => "unmap") xml.source(:protocol => "rbd", :name => volume.path) ceph_args["monitor"]&.split(",")&.each do |monitor| xml.host(:name => monitor, :port => ceph_args["port"]) end xml.auth(:username => ceph_args["auth_username"]) do if ceph_args.key?("auth_uuid") xml.secret(:type => "ceph", :uuid => ceph_args["auth_uuid"]) else xml.secret(:type => "ceph", :usage => ceph_args["auth_usage"]) end end xml.target(:dev => target_device, :bus => ceph_args["bus_type"] == "virtio" ? "virtio" : "scsi") end else is_block = volume.path.start_with?("/dev/") xml.disk(:type => is_block ? "block" : "file", :device => "disk") do xml.driver(:name => "qemu", :type => volume.format_type) if is_block xml.source(:dev => volume.path) else xml.source(:file => volume.path) end xml.target(:dev => target_device, :bus => "virtio") end end end if iso_file xml.disk(:type => "file", :device => "cdrom") do xml.driver(:name => "qemu", :type => "raw") xml.source(:file => "#{iso_dir}/#{iso_file}") xml.target(:dev => "sda", :bus => "scsi") xml.readonly xml.address(:type => "drive", :controller => 0, :bus => 0, :unit => 0) end end nics.each do |nic| xml.interface(:type => nic.type) do xml.mac(:address => nic.mac) if nic.mac if nic.type == "bridge" xml.source(:bridge => nic.bridge) else xml.source(:network => nic.network) end xml.model(:type => nic.model) end end if guest_agent xml.channel(:type => "unix") do xml.target(:type => "virtio", :name => "org.qemu.guest_agent.0") end end xml.rng(:model => "virtio") do xml.backend(virtio_rng[:backend_path], :model => virtio_rng.fetch(:backend_model, "random")) end if arch == "s390x" xml.controller(:type => "scsi", :index => "0", :model => "virtio-scsi") xml.console(:type => "pty") do xml.target(:type => "sclp") end xml.memballoon(:model => "virtio") else xml.serial(:type => "pty") do xml.target(:port => 0) end xml.console(:type => "pty") do xml.target(:port => 0) end xml.input(:type => "tablet", :bus => "usb") xml.input(:type => "mouse", :bus => "ps2") graphics = xml.graphics(:type => display[:type]) if display[:port].empty? graphics.port = display[:port] graphics.autoport = "no" else graphics.port = -1 graphics.autoport = "yes" end graphics.listen = display[:listen] unless display[:listen].empty? graphics.passwd = display[:password] if display[:password] && !display[:password].empty? xml.video do xml.model(video) end end end end end builder.to_xml end
rubocop:disable Metrics
Source
# File lib/fog/libvirt/models/compute/server.rb, line 86 def update_autostart(value) service.update_autostart(uuid, value) end
Source
# File lib/fog/libvirt/models/compute/server.rb, line 239 def update_display attrs = {} service.update_display attrs.merge(:uuid => uuid) reload end
Source
# File lib/fog/libvirt/models/compute/server.rb, line 245 def vnc_port Fog::Logger.deprecation("#{self.class} => #vnc_port is deprecated, use #display[:port] instead [light_black](#{caller.first})[/]") display[:port] end
can’t use deprecate method, as the value is part of the display hash
Source
# File lib/fog/libvirt/models/compute/server.rb, line 158 def volumes # lazy loading of volumes @volumes ||= (@volumes_path || []).map{ |path| service.volumes.all(:path => path).first }.compact end
Private Instance Methods
Source
# File lib/fog/libvirt/models/compute/server.rb, line 475 def addresses(service_arg=service, options={}) ip_address = nil if (nic = self.nics&.first) net = service.networks.all(:name => nic.network).first # Assume the lease expiring last is the current IP address ip_address = net&.dhcp_leases(nic.mac)&.max_by { |lse| lse["expirytime"] }&.dig("ipaddr") end return { :public => [ip_address], :private => [ip_address] } end
This retrieves the ip address of the mac address using dhcp_leases It returns an array of public and private ip addresses Currently only one ip address is returned, but in the future this could be multiple if the server has multiple network interface
Source
# File lib/fog/libvirt/models/compute/server.rb, line 507 def create_or_clone_volume options = {:name => volume_name || default_volume_name} # Check if a disk template was specified if volume_template_name template_volume = service.volumes.all(:name => volume_template_name).first raise Fog::Errors::Error.new("Template #{volume_template_name} not found") unless template_volume begin volume = template_volume.clone("#{options[:name]}") rescue => e raise Fog::Errors::Error.new("Error creating the volume : #{e}") end else # If no template volume was given, let's create our own volume options[:pool_name] = volume_pool_name if volume_pool_name options[:format_type] = volume_format_type if volume_format_type options[:capacity] = volume_capacity if volume_capacity options[:allocation] = volume_allocation if volume_allocation begin volume = service.volumes.create(options) rescue => e raise Fog::Errors::Error.new("Error creating the volume : #{e}") end end @volumes.nil? ? @volumes = [volume] : @volumes << volume end
Source
# File lib/fog/libvirt/models/compute/server.rb, line 576 def default_display {:port => '-1', :listen => '127.0.0.1', :type => 'vnc' } end
Source
# File lib/fog/libvirt/models/compute/server.rb, line 534 def default_iso_dir "/var/lib/libvirt/images" end
Source
# File lib/fog/libvirt/models/compute/server.rb, line 538 def default_volume_name "#{name}.#{volume_format_type || 'img'}" end
Source
# File lib/fog/libvirt/models/compute/server.rb, line 542 def defaults { :persistent => true, :cpus => 1, :memory_size => 256 * 1024, :name => randomized_name, :os_type => "hvm", :arch => "x86_64", :domain_type => "kvm", :autostart => false, :iso_dir => default_iso_dir, :network_interface_type => "network", :network_nat_network => "default", :network_bridge_name => "br0", :boot_order => %w[hd cdrom network], :display => default_display, :cpu => {}, :hugepages => false, :guest_agent => true, :video => {:type => "cirrus", :vram => 9216, :heads => 1}, :virtio_rng => {}, :firmware_features => { "secure-boot" => "no" }, } end
Source
# File lib/fog/libvirt/models/compute/server.rb, line 493 def initialize_nics if nics nics.map! { |nic| nic.is_a?(Hash) ? service.nics.new(nic) : nic } else self.nics = [service.nics.new({:type => network_interface_type, :bridge => network_bridge_name, :network => network_nat_network})] end end
Source
# File lib/fog/libvirt/models/compute/server.rb, line 501 def initialize_volumes if attributes[:volumes] && !attributes[:volumes].empty? @volumes = attributes[:volumes].map { |vol| vol.is_a?(Hash) ? service.volumes.new(vol) : vol } end end
Source
# File lib/fog/libvirt/models/compute/server.rb, line 489 def ip_address(key) addresses[key]&.first end
Source
# File lib/fog/libvirt/models/compute/server.rb, line 456 def read_ceph_args(path = "/etc/foreman/ceph.conf") return unless File.file?(path) args = {} File.readlines(path).each do |line| pair = line.strip.split("=") key = pair[0] value = pair[1] args[key] = value end args end
Source
# File lib/fog/libvirt/models/compute/server.rb, line 567 def verify_boot_order order = [] valid_boot_media = %w[cdrom fd hd network] if order order.each do |b| raise "invalid boot order, possible values are any combination of: #{valid_boot_media.join(', ')}" unless valid_boot_media.include?(b) end end end