Class: VagrantPlugins::Utm::Driver::Base

Inherits:
Object
  • Object
show all
Includes:
Vagrant::Util::Retryable
Defined in:
lib/vagrant_utm/driver/base.rb

Overview

Executes commands on the host machine through the AppleScript bridge interface paired with a command line interface.

Direct Known Subclasses

Meta, Version_4_5

Instance Method Summary collapse

Constructor Details

#initializeBase

Returns a new instance of Base.



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/vagrant_utm/driver/base.rb', line 19

def initialize
  @logger = Log4r::Logger.new("vagrant::provider::utm::base")

  # This flag is used to keep track of interrupted state (SIGINT)
  @interrupted = false
  # The path to the scripts directory.
  @script_path = Pathname.new(File.expand_path("../scripts", __dir__))

  # Set 'utmctl' path
  @utmctl_path = Vagrant::Util::Which.which("utmctl")

  # if not found, fall back to /usr/local/bin/utmctl
  @utmctl_path ||= "/Applications/UTM.app/Contents/MacOS/utmctl"
  @logger.info("utmctl path: #{@utmctl_path}")
end

Instance Method Details

#check_qemu_guest_agentBoolean

Checks if the qemu-guest-agent is installed and running in this VM.

Returns:

  • (Boolean)


40
# File 'lib/vagrant_utm/driver/base.rb', line 40

def check_qemu_guest_agent; end

#clear_forwarded_portsObject

Clears the forwarded ports that have been set on the virtual machine.



36
# File 'lib/vagrant_utm/driver/base.rb', line 36

def clear_forwarded_ports; end

#deletevoid

This method returns an undefined value.

Deletes the virtual machine references by this driver.



140
# File 'lib/vagrant_utm/driver/base.rb', line 140

def delete; end

#execute(*command, &block) ⇒ String

Execute the given subcommand for utmctl and return the output. Copied from github.com/hashicorp/vagrant/blob/main/plugins/providers/virtualbox/driver/base.rb.

Parameters:

  • subcommand (String)

    The subcommand to execute.

Returns:

  • (String)

    The output of the command.



252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
# File 'lib/vagrant_utm/driver/base.rb', line 252

def execute(*command, &block) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength,Metrics/PerceivedComplexity
  # Get the options hash if it exists
  opts = {}
  opts = command.pop if command.last.is_a?(Hash)

  tries = 0
  tries = 3 if opts[:retryable]

  # Variable to store our execution result
  r = nil

  retryable(on: Errors::UtmctlError, tries: tries, sleep: 1) do # rubocop:disable Metrics/BlockLength
    # if there is an error with utmctl, this gets set to true
    errored = false

    # Execute the command
    r = raw(*command, &block)

    # If the command was a failure, then raise an exception that is
    # nicely handled by Vagrant.
    if r.exit_code != 0
      if @interrupted
        @logger.info("Exit code != 0, but interrupted. Ignoring.")
      elsif r.exit_code == 126
        # To be consistent with VBoxManage
        raise Errors::UtmctlNotFoundError
      else
        errored = true
      end
    else
      # if utmctl fails but doesn't exit with an error code
      # Handle those cases here

      if r.stderr =~ /Error/
        @logger.info("Error found, assuming error.")
        errored = true
      end

      if r.stderr =~ /OSStatus error/
        @logger.info("OSStatus error found, assuming error.")
        errored = true

      end
    end

    # If there was an error running utmctl, show the error and the output
    if errored
      raise Errors::UtmctlError,
            command: command.inspect,
            stderr: r.stderr,
            stdout: r.stdout
    end
  end

  # Return the output, making sure to replace any Windows-style
  # newlines with Unix-style.
  r.stdout.gsub("\r\n", "\n")
end

#execute_osa_script(command) ⇒ Object

Execute a script using the OSA interface.



173
# File 'lib/vagrant_utm/driver/base.rb', line 173

def execute_osa_script(command); end

#execute_shell(*command, &block) ⇒ Object

Execute a shell command and return the output.



176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
# File 'lib/vagrant_utm/driver/base.rb', line 176

def execute_shell(*command, &block) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength,Metrics/PerceivedComplexity
  # Get the options hash if it exists
  opts = {}
  opts = command.pop if command.last.is_a?(Hash)

  tries = 0
  tries = 3 if opts[:retryable]

  # Variable to store our execution result
  r = nil

  retryable(on: VagrantPlugins::Utm::Errors::CommandError, tries: tries, sleep: 1) do
    # If there is an error with VBoxManage, this gets set to true
    errored = false

    # Execute the command
    r = raw_shell(*command, &block)

    # If the command was a failure, then raise an exception that is
    # nicely handled by Vagrant.
    if r.exit_code != 0
      if @interrupted
        @logger.info("Exit code != 0, but interrupted. Ignoring.")
      else
        errored = true
      end
    end

    if errored
      raise VagrantPlugins::Utm::Errors::CommandError,
            command: command.inspect,
            stderr: r.stderr,
            stdout: r.stdout
    end
  end

  # Return the output, making sure to replace any Windows-style
  # newlines with Unix-style.
  # AppleScript logs are always in stderr, so we return that
  # if there is any output.
  if r.stdout && !r.stdout.empty?
    r.stdout.gsub("\r\n", "\n")
  elsif r.stderr && !r.stderr.empty?
    r.stderr.gsub("\r\n", "\n")
  else
    ""
  end
end

#forward_ports(ports) ⇒ Object

Forwards a set of ports for a VM.

This will not affect any previously set forwarded ports, so be sure to delete those if you need to.

The format of each port hash should be the following:

{
  name: "foo",
  hostport: 8500,
  guestport: 80,
  adapter: 1,
  protocol: "tcp"
}

Note that “adapter” and “protocol” are optional and will default to 1 and “tcp” respectively.

Parameters:

  • ports (Array<Hash>)

    An array of ports to set. See documentation for more information on the format.



62
# File 'lib/vagrant_utm/driver/base.rb', line 62

def forward_ports(ports); end

#haltObject

Halts the virtual machine (pulls the plug).



147
# File 'lib/vagrant_utm/driver/base.rb', line 147

def halt; end

#import(utm_file) ⇒ uuid

Import a virtual machine from a UTM file.

Parameters:

  • utm_file (String)

    The url to the UTM file.

Returns:

  • (uuid)

    The UUID of the imported machine.



118
# File 'lib/vagrant_utm/driver/base.rb', line 118

def import(utm_file); end

#last_uuiduuid

Return UUID of the last VM in the list.

Returns:

  • (uuid)

    The UUID of the VM.



144
# File 'lib/vagrant_utm/driver/base.rb', line 144

def last_uuid; end

#listListResult

Execute the ‘list’ command and returns the list of machines.

Returns:

  • (ListResult)

    The list of machines.



113
# File 'lib/vagrant_utm/driver/base.rb', line 113

def list; end

#random_mac_addressString

Generate a random MAC address.

This method generates a random MAC address because it is difficult to get UTM to generate one through scripting.

Returns:

  • (String)

    The MAC address.



163
164
165
166
167
168
169
170
# File 'lib/vagrant_utm/driver/base.rb', line 163

def random_mac_address
  # Generate 6 random bytes
  bytes = Array.new(6) { rand(256) }
  # Ensure the first byte is local
  bytes[0] = (bytes[0] & 0xFC) | 0x02
  # Convert bytes to MAC address string
  bytes.map { |byte| format("%02X", byte) }.join(":")
end

#raw(*command, &block) ⇒ Object

Executes a utmctl command and returns the raw result object.



312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
# File 'lib/vagrant_utm/driver/base.rb', line 312

def raw(*command, &block)
  int_callback = lambda do
    @interrupted = true

    # We have to execute this in a thread due to trap contexts
    # and locks.
    Thread.new { @logger.info("Interrupted.") }.join
  end

  # Append in the options for subprocess
  # NOTE: We include the LANG env var set to C to prevent command output
  #       from being localized
  command << { notify: i[stdout stderr], env: env_lang }

  Vagrant::Util::Busy.busy(int_callback) do
    Vagrant::Util::Subprocess.execute(@utmctl_path, *command, &block)
  end
rescue Vagrant::Util::Subprocess::LaunchError => e
  raise Vagrant::Errors::UtmLaunchError,
        message: e.to_s
end

#raw_shell(*command, &block) ⇒ Object

Executes a command and returns the raw result object.



226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
# File 'lib/vagrant_utm/driver/base.rb', line 226

def raw_shell(*command, &block)
  int_callback = lambda do
    @interrupted = true

    # We have to execute this in a thread due to trap contexts
    # and locks.
    Thread.new { @logger.info("Interrupted.") }.join
  end

  # Append in the options for subprocess
  # NOTE: We include the LANG env var set to C to prevent command output
  #       from being localized
  command << { notify: i[stdout stderr], env: env_lang }

  Vagrant::Util::Busy.busy(int_callback) do
    Vagrant::Util::Subprocess.execute(*command, &block)
  end
rescue Vagrant::Util::Subprocess::LaunchError => e
  raise Vagrant::Errors::UtmLaunchError,
        message: e.to_s
end

#read_forwarded_ports(uuid = nil) ⇒ Array<Array>

nic, name(hostport), hostport, guestport

Returns:

  • (Array<Array>)

    An array of arrays, each of which contains



74
# File 'lib/vagrant_utm/driver/base.rb', line 74

def read_forwarded_ports(uuid = nil); end

#read_guest_ipArray<String>

Returns the IP addresses of the guest machine. Only supported for VMs with qemu-guest-agent installed.

Returns:

  • (Array<String>)

    The IP addresses of the guest machine.



99
# File 'lib/vagrant_utm/driver/base.rb', line 99

def read_guest_ip; end

#read_network_interfacesHash

Returns a list of network interfaces of the VM.

Returns:

  • (Hash)


104
# File 'lib/vagrant_utm/driver/base.rb', line 104

def read_network_interfaces; end

#read_stateSymbol

Returns the current state of this VM.

Returns:

  • (Symbol)


79
# File 'lib/vagrant_utm/driver/base.rb', line 79

def read_state; end

#read_used_ports(active_only: true) ⇒ Array

Returns a list of all forwarded ports in use by active virtual machines.

Parameters:

  • active_only (Boolean) (defaults to: true)

    If true, only VMs that are running will be checked.

Returns:

  • (Array)


87
# File 'lib/vagrant_utm/driver/base.rb', line 87

def read_used_ports(active_only: true); end

#read_vmsArray<String>

Returns a list of all UUIDs of virtual machines currently known by UTM.

Returns:

  • (Array<String>)


93
# File 'lib/vagrant_utm/driver/base.rb', line 93

def read_vms; end

#set_mac_address(mac) ⇒ Object

Sets the MAC address of the first network adapter.

Parameters:

  • mac (String)

    MAC address without any spaces/hyphens.



109
# File 'lib/vagrant_utm/driver/base.rb', line 109

def set_mac_address(mac); end

#set_name(name) ⇒ void

This method returns an undefined value.

Sets the name of the virtual machine.

Parameters:

  • name (String)

    The new name of the machine.



123
# File 'lib/vagrant_utm/driver/base.rb', line 123

def set_name(name); end

#ssh_port(expected) ⇒ Object

Reads the SSH port of this VM.

Parameters:

  • expected (Integer)

    Expected guest port of SSH.



128
# File 'lib/vagrant_utm/driver/base.rb', line 128

def ssh_port(expected); end

#startvoid

This method returns an undefined value.

Starts the virtual machine referenced by this driver.



132
# File 'lib/vagrant_utm/driver/base.rb', line 132

def start; end

#start_disposablevoid

This method returns an undefined value.

Starts the virtual machine in disposable mode.



136
# File 'lib/vagrant_utm/driver/base.rb', line 136

def start_disposable; end

#suspendObject

Suspend the virtual machine.



150
# File 'lib/vagrant_utm/driver/base.rb', line 150

def suspend; end

#verify!Object

Verifies that the driver is ready to accept work.

This should raise a VagrantError if things are not ready.



155
# File 'lib/vagrant_utm/driver/base.rb', line 155

def verify!; end

#vm_exists?(uuid) ⇒ Boolean

Check if the VM with the given UUID (Name) exists.

Returns:

  • (Boolean)


65
# File 'lib/vagrant_utm/driver/base.rb', line 65

def vm_exists?(uuid); end