Class: VagrantPlugins::ProviderLibvirt::Driver

Inherits:
Object
  • Object
show all
Defined in:
lib/vagrant-libvirt/driver.rb

Instance Method Summary collapse

Constructor Details

#initialize(machine) ⇒ Driver

Returns a new instance of Driver.



21
22
23
24
# File 'lib/vagrant-libvirt/driver.rb', line 21

def initialize(machine)
  @logger = Log4r::Logger.new('vagrant_libvirt::driver')
  @machine = machine
end

Instance Method Details

#attach_device(xml) ⇒ Object



243
244
245
# File 'lib/vagrant-libvirt/driver.rb', line 243

def attach_device(xml)
  get_libvirt_domain.attach_device(xml)
end

#connectionObject



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/vagrant-libvirt/driver.rb', line 26

def connection
  # If already connected to Libvirt, just use it and don't connect
  # again.
  return @connection if @connection

  # Get config options for Libvirt provider.
  config = @machine.provider_config
  uri = config.uri

  # Setup command for retrieving IP address for newly created machine
  # with some MAC address. Get it from dnsmasq leases table
  ip_command = %q( awk "/$mac/ {print \$1}" /proc/net/arp )

  conn_attr = {
    provider: 'libvirt',
    libvirt_uri: uri,
    libvirt_ip_command: ip_command,
  }
  conn_attr[:libvirt_username] = config.username if config.username
  conn_attr[:libvirt_password] = config.password if config.password

  @logger.info("Connecting to Libvirt (#{uri}) ...")
  begin
    @connection = Fog::Compute.new(conn_attr)
  rescue Fog::Errors::Error => e
    raise Errors::FogLibvirtConnectionError,
          error_message: e.message
  end

  @connection
end

#create_new_snapshot(snapshot_name) ⇒ Object



132
133
134
135
136
137
138
139
140
141
142
# File 'lib/vagrant-libvirt/driver.rb', line 132

def create_new_snapshot(snapshot_name)
  snapshot_desc = <<-EOF
  <domainsnapshot>
    <name>#{snapshot_name}</name>
    <description>Snapshot for vagrant sandbox</description>
  </domainsnapshot>
  EOF
  get_libvirt_domain().snapshot_create_xml(snapshot_desc)
rescue Fog::Errors::Error => e
  raise Errors::SnapshotCreationError, error_message: e.message
end

#create_snapshot(snapshot_name) ⇒ Object



144
145
146
147
148
149
150
# File 'lib/vagrant-libvirt/driver.rb', line 144

def create_snapshot(snapshot_name)
  begin
    delete_snapshot(snapshot_name)
  rescue Errors::SnapshotDeletionError
  end
  create_new_snapshot(snapshot_name)
end

#created?Boolean

Returns:

  • (Boolean)


69
70
71
72
# File 'lib/vagrant-libvirt/driver.rb', line 69

def created?
  domain = get_domain()
  !domain.nil?
end

#delete_snapshot(snapshot_name) ⇒ Object



126
127
128
129
130
# File 'lib/vagrant-libvirt/driver.rb', line 126

def delete_snapshot(snapshot_name)
  get_snapshot_if_exists(snapshot_name).delete
rescue Errors::SnapshotMissing => e
  raise Errors::SnapshotDeletionError, error_message: e.message
end

#detach_device(xml) ⇒ Object



247
248
249
# File 'lib/vagrant-libvirt/driver.rb', line 247

def detach_device(xml)
  get_libvirt_domain.detach_device(xml)
end

#get_domainObject



187
188
189
190
191
192
193
194
195
196
197
198
# File 'lib/vagrant-libvirt/driver.rb', line 187

def get_domain
  begin
    domain = connection.servers.get(@machine.id)
  rescue Libvirt::RetrieveError => e
    raise e unless e.libvirt_code == ProviderLibvirt::Util::ErrorCodes::VIR_ERR_NO_DOMAIN

    @logger.debug("machine #{@machine.name} domain not found #{e}.")
    return nil
  end

  domain
end

#get_ipaddress(domain = nil) ⇒ Object



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/vagrant-libvirt/driver.rb', line 74

def get_ipaddress(domain=nil)
  # Find the machine
  domain = get_domain() if domain.nil?

  if domain.nil?
    # The machine can't be found
    return nil
  end

  # attempt to get ip address from qemu agent
  if @machine.provider_config.qemu_use_agent == true
    @logger.info('Get IP via qemu agent')
    return get_ipaddress_from_qemu_agent(@machine.config.vm.boot_timeout, domain)
  end

  return get_ipaddress_from_system domain.mac if @machine.provider_config.qemu_use_session

  # Get IP address from dhcp leases table
  begin
    ip_address = get_ipaddress_from_domain(domain)
  rescue Fog::Errors::TimeoutError
    @logger.info("Timeout at waiting for an ip address for machine #{@machine.name}")

    raise
  end

  unless ip_address
    @logger.info("No arp table entry found for machine #{@machine.name}")
    return nil
  end

  ip_address
end

#get_snapshot_if_exists(snapshot_name) ⇒ Object

if we can get snapshot description without exception it exists



153
154
155
156
157
158
# File 'lib/vagrant-libvirt/driver.rb', line 153

def get_snapshot_if_exists(snapshot_name)
  snapshot = get_libvirt_domain().lookup_snapshot_by_name(snapshot_name)
  return snapshot if snapshot.xml_desc
rescue Libvirt::RetrieveError => e
  raise Errors::SnapshotMissing, error_message: e.message
end

#host_devicesObject



219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# File 'lib/vagrant-libvirt/driver.rb', line 219

def host_devices
  @host_devices ||= begin
    cmd = []
    unless @machine.provider_config.proxy_command.nil? || @machine.provider_config.proxy_command.empty?
      cmd = ['ssh', @machine.provider_config.host]
      cmd += ['-p', @machine.provider_config.port.to_s] if @machine.provider_config.port
      cmd += ['-l', @machine.provider_config.username] if @machine.provider_config.username
      cmd += ['-i', @machine.provider_config.id_ssh_key_file] if @machine.provider_config.id_ssh_key_file
    end
    ip_cmd = cmd + %W(ip -j link show)

    result = Vagrant::Util::Subprocess.execute(*ip_cmd)
    raise Errors::FogLibvirtConnectionError unless result.exit_code == 0

    info = JSON.parse(result.stdout)

    (
      info.map { |iface| iface['ifname'] } +
      connection.client.list_all_interfaces.map { |iface| iface.name } +
      list_all_networks.map { |net| net.bridge_name }
    ).uniq.reject(&:empty?)
  end
end

#list_all_networksObject



200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
# File 'lib/vagrant-libvirt/driver.rb', line 200

def list_all_networks
  client = if @machine.provider_config.qemu_use_session
             system_connection
          else
            connection.client
          end

  client.list_all_networks.select do |net|
    begin
      net.bridge_name
    rescue Libvirt::Error
      # there does not appear to be a mechanism to determine the type of network, only by
      # querying the attribute and catching the error is it possible to ignore unsupported.
      @logger.debug "Ignoring #{net.name} as it does not support retrieval of bridge_name attribute"
      next
    end
  end
end

#list_snapshotsObject



120
121
122
123
124
# File 'lib/vagrant-libvirt/driver.rb', line 120

def list_snapshots
  get_libvirt_domain().list_snapshots
rescue Fog::Errors::Error => e
  raise Errors::SnapshotListError, error_message: e.message
end

#restore_snapshot(snapshot_name) ⇒ Object



108
109
110
111
112
113
114
115
116
117
118
# File 'lib/vagrant-libvirt/driver.rb', line 108

def restore_snapshot(snapshot_name)
  domain = get_libvirt_domain()
  snapshot = get_snapshot_if_exists(snapshot_name)
  begin
    # 4 is VIR_DOMAIN_SNAPSHOT_REVERT_FORCE
    # needed due to https://bugzilla.redhat.com/show_bug.cgi?id=1006886
    domain.revert_to_snapshot(snapshot, 4)
  rescue Fog::Errors::Error => e
    raise Errors::SnapshotReversionError, error_message: e.message
  end
end

#stateObject



160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
# File 'lib/vagrant-libvirt/driver.rb', line 160

def state
  # may be other error states with initial retreival we can't handle
  begin
    domain = get_domain
  rescue Libvirt::RetrieveError => e
    @logger.debug("Machine #{@machine.id} not found #{e}.")
    return :not_created
  end

  # TODO: terminated no longer appears to be a valid fog state, remove?
  return :not_created if domain.nil?
  return :unknown if domain.state.nil?
  return :not_created if domain.state.to_sym == :terminated

  state = domain.state.tr('-', '_').to_sym
  if state == :running
    begin
      get_ipaddress(domain)
    rescue Fog::Errors::TimeoutError => e
      @logger.debug("Machine #{@machine.id} running but no IP address available: #{e}.")
      return :inaccessible
    end
  end

  state
end

#system_connectionObject



58
59
60
61
62
63
64
65
66
67
# File 'lib/vagrant-libvirt/driver.rb', line 58

def system_connection
  # If already connected to Libvirt, just use it and don't connect
  # again.
  return @system_connection if @system_connection

  config = @machine.provider_config

  @system_connection = Libvirt.open_read_only(config.system_uri)
  @system_connection
end