vagrant-tart 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +36 -0
- data/lib/vagrant-tart/action/create_instance.rb +42 -0
- data/lib/vagrant-tart/action/delete_instance.rb +36 -0
- data/lib/vagrant-tart/action/forward_ports.rb +25 -0
- data/lib/vagrant-tart/action/get_state.rb +32 -0
- data/lib/vagrant-tart/action/login.rb +43 -0
- data/lib/vagrant-tart/action/pull_image.rb +40 -0
- data/lib/vagrant-tart/action/start_instance.rb +44 -0
- data/lib/vagrant-tart/action/stop_instance.rb +35 -0
- data/lib/vagrant-tart/action/suspend_instance.rb +36 -0
- data/lib/vagrant-tart/action.rb +181 -0
- data/lib/vagrant-tart/config.rb +126 -0
- data/lib/vagrant-tart/errors.rb +42 -0
- data/lib/vagrant-tart/model/get_result.rb +52 -0
- data/lib/vagrant-tart/model/list_result.rb +76 -0
- data/lib/vagrant-tart/model/tart_disk.rb +77 -0
- data/lib/vagrant-tart/plugin.rb +47 -0
- data/lib/vagrant-tart/provider.rb +97 -0
- data/lib/vagrant-tart/scripts/login.sh +9 -0
- data/lib/vagrant-tart/scripts/run.sh +17 -0
- data/lib/vagrant-tart/synced_folder.rb +97 -0
- data/lib/vagrant-tart/util/driver.rb +185 -0
- data/lib/vagrant-tart/version.rb +9 -0
- data/lib/vagrant-tart.rb +20 -0
- data/locales/en.yml +74 -0
- metadata +74 -0
@@ -0,0 +1,126 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "etc"
|
4
|
+
require "i18n"
|
5
|
+
require "vagrant"
|
6
|
+
|
7
|
+
module VagrantPlugins
|
8
|
+
module Tart
|
9
|
+
# Holds the configuration for the Tart provider.
|
10
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
11
|
+
class Config < Vagrant.plugin("2", :config)
|
12
|
+
# @return [String] The image registry
|
13
|
+
attr_accessor :registry
|
14
|
+
# @return [String] The image registry username
|
15
|
+
attr_accessor :username
|
16
|
+
# @return [String] The image registry password
|
17
|
+
attr_accessor :password
|
18
|
+
|
19
|
+
# @return [String] The image source
|
20
|
+
attr_accessor :image
|
21
|
+
# @return [String] The name
|
22
|
+
attr_accessor :name
|
23
|
+
|
24
|
+
# @return [Integer] Number of CPUs
|
25
|
+
attr_accessor :cpu
|
26
|
+
# @return [Integer] Memory size in MB
|
27
|
+
attr_accessor :memory
|
28
|
+
# @return [Integer] Disk storage size in GB
|
29
|
+
attr_accessor :disk
|
30
|
+
# @return [Boolean] Show a GUI window on boot, or run headless
|
31
|
+
attr_accessor :gui
|
32
|
+
# @return [String] Display screen resolution
|
33
|
+
attr_accessor :display
|
34
|
+
# @return [Boolean] Whether the machine is suspendable
|
35
|
+
attr_accessor :suspendable
|
36
|
+
|
37
|
+
# @return [Array<String>] List of volumes to mount
|
38
|
+
attr_accessor :volumes
|
39
|
+
|
40
|
+
# Initialize the configuration with unset values
|
41
|
+
def initialize
|
42
|
+
super
|
43
|
+
|
44
|
+
@registry = UNSET_VALUE
|
45
|
+
@username = UNSET_VALUE
|
46
|
+
@password = UNSET_VALUE
|
47
|
+
|
48
|
+
@image = UNSET_VALUE
|
49
|
+
@name = UNSET_VALUE
|
50
|
+
|
51
|
+
@cpu = UNSET_VALUE
|
52
|
+
@memory = UNSET_VALUE
|
53
|
+
@disk = UNSET_VALUE
|
54
|
+
@gui = UNSET_VALUE
|
55
|
+
@display = UNSET_VALUE
|
56
|
+
@suspendable = UNSET_VALUE
|
57
|
+
|
58
|
+
@volumes = []
|
59
|
+
end
|
60
|
+
|
61
|
+
# Make sure the configuration has defined all the necessary values
|
62
|
+
def finalize!
|
63
|
+
@registry = nil if @registry == UNSET_VALUE
|
64
|
+
@username = nil if @username == UNSET_VALUE
|
65
|
+
@password = nil if @password == UNSET_VALUE
|
66
|
+
|
67
|
+
@image = nil if @image == UNSET_VALUE
|
68
|
+
@name = nil if @name == UNSET_VALUE
|
69
|
+
|
70
|
+
@cpu = 1 if @cpu == UNSET_VALUE
|
71
|
+
@memory = 1024 if @memory == UNSET_VALUE
|
72
|
+
@disk = 10 if @disk == UNSET_VALUE
|
73
|
+
@gui = false if @gui == UNSET_VALUE
|
74
|
+
@display = "1024x768" if @display == UNSET_VALUE
|
75
|
+
@suspendable = false if @suspendable == UNSET_VALUE
|
76
|
+
end
|
77
|
+
|
78
|
+
# Validate the configuration
|
79
|
+
def validate(_machine)
|
80
|
+
errors = _detected_errors
|
81
|
+
|
82
|
+
# Sanity checks for the registry
|
83
|
+
unless @registry.nil?
|
84
|
+
errors << I18n.t("vagrant_tart.config.username_required") if @username.nil? || @username.empty?
|
85
|
+
errors << I18n.t("vagrant_tart.config.password_required") if @password.nil? || @password.empty?
|
86
|
+
end
|
87
|
+
|
88
|
+
# Sanity checks for the image and the name
|
89
|
+
errors << I18n.t("vagrant_tart.config.image_required") if @image.nil? || @image.empty?
|
90
|
+
errors << I18n.t("vagrant_tart.config.name_required") if @name.nil? || @name.empty?
|
91
|
+
|
92
|
+
# Check that the GUI flag is a valid boolean
|
93
|
+
errors << I18n.t("vagrant_tart.config.gui_invalid") unless @gui == true || @gui == false
|
94
|
+
|
95
|
+
# Check that CPU is a valid number and between 1 and the maximum available CPUs
|
96
|
+
max_cpus = Etc.nprocessors
|
97
|
+
unless (@cpu.is_a? Integer) && @cpu >= 1 && @cpu <= max_cpus
|
98
|
+
errors << I18n.t("vagrant_tart.config.cpu_invalid", max_cpus: max_cpus)
|
99
|
+
end
|
100
|
+
|
101
|
+
# Check that memory is a valid number and between 1 and the maximum available memory
|
102
|
+
max_memory = `sysctl -n hw.memsize`.to_i / 1024 / 1024
|
103
|
+
unless (@memory.is_a? Integer) && @memory >= 1 && @memory <= max_memory
|
104
|
+
errors << I18n.t("vagrant_tart.config.memory_invalid", max_memory: max_memory)
|
105
|
+
end
|
106
|
+
|
107
|
+
# Check that disk is a valid number and greater than 1
|
108
|
+
errors << I18n.t("vagrant_tart.config.disk_invalid") unless (@disk.is_a? Integer) && @disk >= 1
|
109
|
+
|
110
|
+
# Check that the display resolution is a valid string conforming to the format "WIDTHxHEIGHT"
|
111
|
+
errors << I18n.t("vagrant_tart.config.display_invalid") unless @display.match?(/^\d+x\d+$/)
|
112
|
+
|
113
|
+
{ "Tart Provider" => errors }
|
114
|
+
end
|
115
|
+
|
116
|
+
def suspendable?
|
117
|
+
@suspendable
|
118
|
+
end
|
119
|
+
|
120
|
+
def use_registry?
|
121
|
+
!@registry.nil? && !@username.nil? && !@password.nil?
|
122
|
+
end
|
123
|
+
end
|
124
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module Tart
|
5
|
+
module Errors
|
6
|
+
# The base class for all plugin errors.
|
7
|
+
class TartError < Vagrant::Errors::VagrantError
|
8
|
+
error_namespace("vagrant_tart.errors")
|
9
|
+
end
|
10
|
+
|
11
|
+
# This error is raised if the platform is not MacOS.
|
12
|
+
class MacOSRequired < TartError
|
13
|
+
error_key(:macos_required)
|
14
|
+
end
|
15
|
+
|
16
|
+
# This error is raised if the Tart binary is not found.
|
17
|
+
class TartRequired < TartError
|
18
|
+
error_key(:tart_required)
|
19
|
+
end
|
20
|
+
|
21
|
+
# This error is raised if a Tart command fails.
|
22
|
+
class CommandError < TartError
|
23
|
+
error_key(:command_error)
|
24
|
+
end
|
25
|
+
|
26
|
+
# This error is raised if the virutal machine is not created.
|
27
|
+
class InstanceNotCreatedError < TartError
|
28
|
+
error_key(:instance_not_created)
|
29
|
+
end
|
30
|
+
|
31
|
+
# This error is raised if the virtual machine is not running.
|
32
|
+
class InstanceNotRunningError < TartError
|
33
|
+
error_key(:instance_not_running)
|
34
|
+
end
|
35
|
+
|
36
|
+
# This error is raised if the synced folder are not for Tart.
|
37
|
+
class SyncedFolderNonTart < TartError
|
38
|
+
error_key(:synced_folder_not_tart)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module Tart
|
5
|
+
module Model
|
6
|
+
# Represents the result of a Tart 'get' operation.
|
7
|
+
class GetResult
|
8
|
+
# @return [Integer] The number of CPUs of the machine.
|
9
|
+
attr_accessor :cpu
|
10
|
+
# @return [Integer] The size of the machine's disk.
|
11
|
+
attr_accessor :disk
|
12
|
+
# @return [Boolean] Whether the machine is running.
|
13
|
+
attr_accessor :running
|
14
|
+
# @return [Integer] The memory of the machine.
|
15
|
+
attr_accessor :memory
|
16
|
+
# @return [String] The operating system of the machine.
|
17
|
+
attr_accessor :os
|
18
|
+
# @return [String] The size of the machine.
|
19
|
+
attr_accessor :size
|
20
|
+
# @return [String] The state of the machine.
|
21
|
+
attr_accessor :state
|
22
|
+
# @return [String] The size of the display
|
23
|
+
attr_accessor :display
|
24
|
+
|
25
|
+
# Initialize the result from raw data.
|
26
|
+
# @param [Hash] data The raw data.
|
27
|
+
def initialize(data)
|
28
|
+
@cpu = data["CPU"]
|
29
|
+
@disk = data["Disk"]
|
30
|
+
@running = data["Running"]
|
31
|
+
@memory = data["Memory"]
|
32
|
+
@os = data["OS"]
|
33
|
+
@size = data["Size"]
|
34
|
+
@state = data["State"]
|
35
|
+
@display = data["Display"]
|
36
|
+
end
|
37
|
+
|
38
|
+
# Returns the state of the machine using Vagrant symbols.
|
39
|
+
def vagrant_state
|
40
|
+
case @state
|
41
|
+
when "running"
|
42
|
+
:running
|
43
|
+
when "stopped", "suspended"
|
44
|
+
:stopped
|
45
|
+
else
|
46
|
+
:host_state_unknown
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module Tart
|
5
|
+
module Model
|
6
|
+
# Represents the result of a Tart 'list' operation.
|
7
|
+
class ListResult
|
8
|
+
# @return [Array<ListResultItem>] The list of machines.
|
9
|
+
attr_accessor :machines
|
10
|
+
|
11
|
+
# Initialize the result from raw data.
|
12
|
+
# @param [Array<Hash>] data The raw data.
|
13
|
+
def initialize(data)
|
14
|
+
@machines = []
|
15
|
+
data.each do |machine|
|
16
|
+
item = ListResultItem.new(machine)
|
17
|
+
@machines << item
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Checks if a machine with the given name exists.
|
22
|
+
# @param [String] name The name of the machine.
|
23
|
+
# @return [Boolean]
|
24
|
+
def any?(name)
|
25
|
+
@machines.any? { |i| i.name == name }
|
26
|
+
end
|
27
|
+
|
28
|
+
# Finds a machine with the given name.
|
29
|
+
# @param [String] name The name of the machine.
|
30
|
+
# @return [ListResultItem]
|
31
|
+
def find(name)
|
32
|
+
@machines.find { |i| i.name == name }
|
33
|
+
end
|
34
|
+
|
35
|
+
# Represents an item in the list result.
|
36
|
+
class ListResultItem
|
37
|
+
# @return [Integer] The size of the machine's disk.
|
38
|
+
attr_accessor :disk
|
39
|
+
# @return [String] The name of the machine.
|
40
|
+
attr_accessor :name
|
41
|
+
# @return [Boolean] Whether the machine is running.
|
42
|
+
attr_accessor :running
|
43
|
+
# @return [Integer] The size of the machine's image.
|
44
|
+
attr_accessor :size
|
45
|
+
# @return [String] The source of the machine (local or oci).
|
46
|
+
attr_accessor :source
|
47
|
+
# @return [String] The state of the machine.
|
48
|
+
attr_accessor :state
|
49
|
+
|
50
|
+
# Initialize the result from raw data.
|
51
|
+
# @param [Hash] data The raw data.
|
52
|
+
def initialize(data)
|
53
|
+
@disk = data["Disk"]
|
54
|
+
@name = data["Name"]
|
55
|
+
@running = data["Running"]
|
56
|
+
@size = data["Size"]
|
57
|
+
@source = data["Source"]
|
58
|
+
@state = data["State"]
|
59
|
+
end
|
60
|
+
|
61
|
+
# Returns the state of the machine using Vagrant symbols.
|
62
|
+
def vagrant_state
|
63
|
+
case @state
|
64
|
+
when "running"
|
65
|
+
:running
|
66
|
+
when "stopped", "suspended"
|
67
|
+
:stopped
|
68
|
+
else
|
69
|
+
:host_state_unknown
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module VagrantPlugins
|
4
|
+
module Tart
|
5
|
+
module Model
|
6
|
+
# Represents a synced folder for the Tart provider.
|
7
|
+
class TartDisk
|
8
|
+
# The default tag for auto-mounted folders.
|
9
|
+
AUTO_MOUNT ||= "com.apple.virtio-fs.automount" # rubocop:disable Lint/OrAssignmentToConstant
|
10
|
+
# The default path for auto-mounted folders on Darwin.
|
11
|
+
DARWIN_SHARED_FILES ||= "/Volumes/My Shared Files" # rubocop:disable Lint/OrAssignmentToConstant
|
12
|
+
|
13
|
+
# The path on the host machine.
|
14
|
+
attr_accessor :host_path
|
15
|
+
# The path on the guest machine.
|
16
|
+
attr_accessor :guest_path
|
17
|
+
# The mode of the folder (either "ro" or "rw"). Default is "rw".
|
18
|
+
attr_accessor :mode
|
19
|
+
# The tag of the folder.
|
20
|
+
attr_accessor :tag
|
21
|
+
# The prefix of the folder.
|
22
|
+
attr_accessor :prefix
|
23
|
+
|
24
|
+
# Initialize the folder from configuration data.
|
25
|
+
# @param [Hash] data The configuration data.
|
26
|
+
def initialize(data)
|
27
|
+
@host_path = data[:hostpath]
|
28
|
+
@guest_path = data[:guestpath]
|
29
|
+
parse_mount_options(data[:mount_options] || [])
|
30
|
+
end
|
31
|
+
|
32
|
+
# Check if the disk is auto-mounted.
|
33
|
+
def automount?
|
34
|
+
@tag == AUTO_MOUNT
|
35
|
+
end
|
36
|
+
|
37
|
+
# Convert the disk to a Tart command line option.
|
38
|
+
def to_tart_disk
|
39
|
+
# Create options
|
40
|
+
options = []
|
41
|
+
options << "ro" if @mode == "ro"
|
42
|
+
options << "tag=#{tag}" if @tag
|
43
|
+
|
44
|
+
result = @host_path.to_s
|
45
|
+
if @guest_path.start_with?(DARWIN_SHARED_FILES)
|
46
|
+
prefix = @guest_path[DARWIN_SHARED_FILES.length + 1..]
|
47
|
+
result = "#{prefix}:#{result}" if prefix
|
48
|
+
end
|
49
|
+
result += ":#{options.join(",")}" if options.any?
|
50
|
+
result
|
51
|
+
end
|
52
|
+
|
53
|
+
# Convert the disk to a human readable string.
|
54
|
+
def to_s
|
55
|
+
"#{@host_path} -> #{@guest_path} (mode=#{@mode || "rw"}, tag=#{@tag || "none"})"
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
# Parse the mount options.
|
61
|
+
def parse_mount_options(mount_options)
|
62
|
+
# Mode option
|
63
|
+
mode = mount_options.find { |option| option.start_with?("mode=") }
|
64
|
+
@mode = mode.split("=")[1] if mode
|
65
|
+
|
66
|
+
# Tag option
|
67
|
+
tag = mount_options.find { |option| option.start_with?("tag=") }
|
68
|
+
@tag = if tag
|
69
|
+
tag.split("=")[1]
|
70
|
+
else
|
71
|
+
AUTO_MOUNT
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Check if the Vagrant gem is available
|
4
|
+
begin
|
5
|
+
require "vagrant"
|
6
|
+
rescue LoadError
|
7
|
+
raise "The Vagrant Tart plugin must be run within Vagrant."
|
8
|
+
end
|
9
|
+
|
10
|
+
# Make sure no one is attempting to install this plugin into an early Vagrant version.
|
11
|
+
raise "The Vagrant Tart plugin is only compatible with Vagrant 2.3 or higher" if Vagrant::VERSION < "2.3.0"
|
12
|
+
|
13
|
+
module VagrantPlugins
|
14
|
+
module Tart
|
15
|
+
# Provides the capabilities to manage Tart virtual machines.
|
16
|
+
class Plugin < Vagrant.plugin("2")
|
17
|
+
name "tart"
|
18
|
+
description "Allows Vagrant to manage Tart virtual machines."
|
19
|
+
|
20
|
+
# Register the configuration.
|
21
|
+
config(:tart, :provider) do
|
22
|
+
require_relative "config"
|
23
|
+
Config
|
24
|
+
end
|
25
|
+
|
26
|
+
# Register the provider.
|
27
|
+
provider(:tart, box_optional: true, parallel: true) do
|
28
|
+
setup_i18n
|
29
|
+
|
30
|
+
require_relative "provider"
|
31
|
+
Provider
|
32
|
+
end
|
33
|
+
|
34
|
+
# Register the synced folder implementation.
|
35
|
+
synced_folder(:tart) do
|
36
|
+
require_relative "synced_folder"
|
37
|
+
SyncedFolder
|
38
|
+
end
|
39
|
+
|
40
|
+
# Load the translation files
|
41
|
+
def self.setup_i18n
|
42
|
+
I18n.load_path << File.expand_path("locales/en.yml", Tart.source_root)
|
43
|
+
I18n.reload!
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "log4r"
|
4
|
+
require_relative "util/driver"
|
5
|
+
|
6
|
+
module VagrantPlugins
|
7
|
+
module Tart
|
8
|
+
# Provider that is responsible for managing the virtual machine and exposing it to Vagrant.
|
9
|
+
class Provider < Vagrant.plugin("2", :provider)
|
10
|
+
# The associated driver
|
11
|
+
attr_reader :driver
|
12
|
+
|
13
|
+
# Initialize the provider with the given machine.
|
14
|
+
def initialize(machine)
|
15
|
+
super
|
16
|
+
@logger = Log4r::Logger.new("vagrant::provider::tart")
|
17
|
+
@machine = machine
|
18
|
+
@driver = Util::Driver.new
|
19
|
+
end
|
20
|
+
|
21
|
+
# Check if the provider can be used.
|
22
|
+
# rubocop:disable Style/OptionalBooleanParameter
|
23
|
+
def self.usable?(raise_error = false)
|
24
|
+
raise Errors::MacOSRequired unless Vagrant::Util::Platform.darwin?
|
25
|
+
|
26
|
+
tart_present = Vagrant::Util::Which.which("tart")
|
27
|
+
raise Errors::TartRequired unless tart_present
|
28
|
+
|
29
|
+
true
|
30
|
+
rescue Errors::TartError
|
31
|
+
raise if raise_error
|
32
|
+
|
33
|
+
false
|
34
|
+
end
|
35
|
+
# rubocop:enable Style/OptionalBooleanParameter
|
36
|
+
|
37
|
+
# Execute the action with the given name.
|
38
|
+
def action(name)
|
39
|
+
action_method = "action_#{name}"
|
40
|
+
return Action.send(action_method) if Action.respond_to?(action_method)
|
41
|
+
|
42
|
+
nil
|
43
|
+
end
|
44
|
+
|
45
|
+
# Return the state of the virtual machine.
|
46
|
+
def state
|
47
|
+
@logger.info("Getting state '#{@machine.id}'")
|
48
|
+
|
49
|
+
state_id = nil
|
50
|
+
state_id = :not_created unless @machine.id
|
51
|
+
|
52
|
+
unless state_id
|
53
|
+
env = @machine.action(:get_state)
|
54
|
+
state_id = env[:machine_state_id]
|
55
|
+
end
|
56
|
+
|
57
|
+
# Get the short and long description
|
58
|
+
short = state_id.to_s
|
59
|
+
long = ""
|
60
|
+
|
61
|
+
# If we're not created, then specify the special ID flag
|
62
|
+
state_id = Vagrant::MachineState::NOT_CREATED_ID if state_id == :not_created
|
63
|
+
|
64
|
+
Vagrant::MachineState.new(state_id, short, long)
|
65
|
+
end
|
66
|
+
|
67
|
+
# Return the SSH info for the virtual machine.
|
68
|
+
def ssh_info
|
69
|
+
# We can only SSH into a running machine
|
70
|
+
return nil if state.id != :running
|
71
|
+
|
72
|
+
# Retrieve the IP address
|
73
|
+
instance_ip = nil
|
74
|
+
begin
|
75
|
+
instance_ip = @driver.ip(@machine.provider_config.name)
|
76
|
+
rescue Errors::CommandError
|
77
|
+
@logger.warn("Failed to read guest IP #{$ERROR_INFO}")
|
78
|
+
end
|
79
|
+
|
80
|
+
return nil if instance_ip.nil?
|
81
|
+
|
82
|
+
@logger.info("IP: #{instance_ip}")
|
83
|
+
|
84
|
+
# Return the information
|
85
|
+
{
|
86
|
+
host: instance_ip,
|
87
|
+
port: 22
|
88
|
+
}
|
89
|
+
end
|
90
|
+
|
91
|
+
def to_s
|
92
|
+
id = @machine.id.nil? ? "nil" : @machine.id
|
93
|
+
"Tart[#{id}]"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env zsh
|
2
|
+
set -eo pipefail
|
3
|
+
|
4
|
+
# Run the virtual machine in the background with the arguments passed to the script
|
5
|
+
nohup tart run "$@" &
|
6
|
+
|
7
|
+
# Save the PID of the virtual machine
|
8
|
+
TART_VM_PID=$!
|
9
|
+
|
10
|
+
# Give the process 3 seconds to start.
|
11
|
+
sleep 3
|
12
|
+
|
13
|
+
# If the process is not alive, then exit with an error message
|
14
|
+
if ! ps -p $TART_VM_PID > /dev/null; then
|
15
|
+
echo "Failed to start the virtual machine." 1>&2
|
16
|
+
exit 1
|
17
|
+
fi
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "log4r"
|
4
|
+
require "vagrant/util/platform"
|
5
|
+
require_relative "model/tart_disk"
|
6
|
+
|
7
|
+
module VagrantPlugins
|
8
|
+
module Tart
|
9
|
+
# Manages the synced folders for the Tart provider.
|
10
|
+
class SyncedFolder < Vagrant.plugin("2", :synced_folder)
|
11
|
+
def initialize(*args)
|
12
|
+
super
|
13
|
+
@logger = Log4r::Logger.new("vagrant::provider::tart")
|
14
|
+
@disks = []
|
15
|
+
end
|
16
|
+
|
17
|
+
# rubocop:disable Style/OptionalBooleanParameter
|
18
|
+
def usable?(machine, raise_errors = false)
|
19
|
+
# These synced folders only work if the provider if Tart
|
20
|
+
if machine.provider_name != :tart
|
21
|
+
raise Errors::SyncedFolderNonTart, provider: machine.provider_name.to_s if raise_errors
|
22
|
+
|
23
|
+
return false
|
24
|
+
end
|
25
|
+
|
26
|
+
true
|
27
|
+
end
|
28
|
+
# rubocop:enable Style/OptionalBooleanParameter
|
29
|
+
|
30
|
+
def prepare(machine, folders, _opts)
|
31
|
+
@logger.info("Preparing synced folders for Tart provider.")
|
32
|
+
|
33
|
+
# Get the shared folder options
|
34
|
+
folders.each_value do |data|
|
35
|
+
disk = Model::TartDisk.new(data)
|
36
|
+
@disks << disk
|
37
|
+
end
|
38
|
+
|
39
|
+
# Add the synced folders to the configuration
|
40
|
+
@disks.each do |disk|
|
41
|
+
machine.ui.output("Adding disk '#{disk}'.")
|
42
|
+
machine.provider_config.volumes << disk.to_tart_disk
|
43
|
+
end
|
44
|
+
|
45
|
+
@logger.info("#{@disks.size} synced folders added to the configuration.")
|
46
|
+
end
|
47
|
+
|
48
|
+
def enable(machine, _folders, _opts)
|
49
|
+
darwin = machine.guest.capability?(:darwin_version)
|
50
|
+
|
51
|
+
@disks.each do |disk|
|
52
|
+
enable_disk(machine, disk, darwin)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def disable(_machine, _folders, _opts)
|
57
|
+
# Do nothing
|
58
|
+
end
|
59
|
+
|
60
|
+
def cleanup(_machine, _opts)
|
61
|
+
@disks.clear
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def enable_disk(machine, disk, darwin)
|
67
|
+
machine.ui.output("Mounting disk '#{disk.host_path}' -> '#{disk.guest_path}'...")
|
68
|
+
if darwin
|
69
|
+
enable_disk_darwin(machine, disk)
|
70
|
+
else
|
71
|
+
enable_disk_linux(machine, disk)
|
72
|
+
end
|
73
|
+
machine.ui.success("Disk mounted.")
|
74
|
+
end
|
75
|
+
|
76
|
+
def enable_disk_darwin(machine, disk)
|
77
|
+
# Create the guest path if it doesn't exist
|
78
|
+
machine.communicate.sudo("mkdir -p #{disk.guest_path}") unless disk.automount?
|
79
|
+
|
80
|
+
return if disk.automount? || machine.communicate.test("mount | grep #{disk.guest_path}")
|
81
|
+
|
82
|
+
# Mount the disk
|
83
|
+
machine.communicate.sudo("mount_virtiofs #{disk.tag} #{disk.guest_path}")
|
84
|
+
end
|
85
|
+
|
86
|
+
def enable_disk_linux(machine, disk)
|
87
|
+
# Create the guest path if it doesn't exist
|
88
|
+
machine.communicate.sudo("mkdir -p #{disk.guest_path}")
|
89
|
+
|
90
|
+
return if machine.communicate.test("mountpoint -q #{disk.guest_path}")
|
91
|
+
|
92
|
+
# Mount the disk
|
93
|
+
machine.communicate.sudo("mount -t virtiofs #{disk.tag} #{disk.guest_path}")
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|