vagrant-tart 0.0.4 → 0.0.6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3e9661a2803897b09b1601b13b608e24ea19a5f95db89c760f3c04e6a1b18c41
4
- data.tar.gz: fd5723f36984a597846413d9fe14438dd8386116357faff32d212ba6ca265c8e
3
+ metadata.gz: e0f4e5c9e706e7f97e6abfb4a14b15477e34f8519f90940e93918bbc9f766485
4
+ data.tar.gz: 61048e9ab2d365476cae641b2d5757bf61ee90d665871a86cd0dc17ce34ec12e
5
5
  SHA512:
6
- metadata.gz: 942cb301b228455fac8369be172bd5c9be38cf4b4ed91fe7eac0b0af46a15ff9235ecb3e9601de039aafb0836ec493b4e417c46748da4b79058fb8957f762d53
7
- data.tar.gz: 53d7dba4e76a42d9ea51f76cfacb5306db38397e13102ab18123c2b1bc129d65775f09cafa030981d21f2fb16b21c42ef445e5eb8f07feddb433a81605938f75
6
+ metadata.gz: 92a51146a0d799256bef1adea44b0d018d77ca6f7e0d343922f0537a4eef6c32540dc942237aede874289b6d0df447de499397d890adccfd25fbfec6fbc59616
7
+ data.tar.gz: 106b2e9c056910a45d290cf977dfa3395cfd766f249f7b1054b4000b297bf275d88860fddb81d68121410dd1e01ec4fdb197816a697def4e9063addb65a1abdf
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2024 Laurent Etiemble
3
+ Copyright (c) 2024-2025 Laurent Etiemble
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -32,7 +32,7 @@ module VagrantPlugins
32
32
  env[:ui].output(I18n.t("vagrant_tart.messages.instance_configured", name: name))
33
33
 
34
34
  env[:ui].output(I18n.t("vagrant_tart.messages.starting_instance", name: name))
35
- driver.run(name, config.gui, config.suspendable?, config.volumes)
35
+ driver.run(name, config)
36
36
  env[:ui].output(I18n.t("vagrant_tart.messages.instance_started", name: name))
37
37
 
38
38
  @app.call(env)
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "i18n"
4
+
5
+ module VagrantPlugins
6
+ module Tart
7
+ module Action
8
+ # Action block to connect to the VNC server exposed by the VM.
9
+ class VNCConnect
10
+ def initialize(app, _env)
11
+ @app = app
12
+ end
13
+
14
+ def call(env)
15
+ machine = env[:machine]
16
+ config = machine.provider_config
17
+ driver = machine.provider.driver
18
+ name = config.name
19
+
20
+ list = driver.list
21
+ return @app.call(env) unless list.any?(name)
22
+
23
+ instance = driver.get(name)
24
+ return @app.call(env) if instance.nil? || instance.vagrant_state != :running
25
+
26
+ # Grab the VNC info from the machine or the environment
27
+ info = env[:vnc_info]
28
+ info ||= env[:machine].ssh_info
29
+
30
+ env[:ui].output(I18n.t("vagrant_tart.messages.connecting_to_vnc", name: name))
31
+ driver.vnc_connect(info)
32
+
33
+ @app.call(env)
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -21,6 +21,7 @@ module VagrantPlugins
21
21
  autoload :StartInstance, action_root.join("start_instance")
22
22
  autoload :StopInstance, action_root.join("stop_instance")
23
23
  autoload :SuspendInstance, action_root.join("suspend_instance")
24
+ autoload :VNCConnect, action_root.join("vnc_connect")
24
25
 
25
26
  # Vargrant action "destroy".
26
27
  def self.action_destroy
@@ -161,6 +162,23 @@ module VagrantPlugins
161
162
  end
162
163
  end
163
164
 
165
+ # Vagrant action "vnc_connect".
166
+ def self.action_vnc_connect
167
+ Vagrant::Action::Builder.new.tap do |b|
168
+ b.use ConfigValidate
169
+
170
+ b.use Call, IsState, :not_created do |env, b1|
171
+ raise Errors::InstanceNotCreatedError if env[:result]
172
+
173
+ b1.use Call, IsState, :running do |env2, b2|
174
+ raise Errors::InstanceNotRunningError unless env2[:result]
175
+
176
+ b2.use VNCConnect
177
+ end
178
+ end
179
+ end
180
+ end
181
+
164
182
  # Retrieves the state of the virtual machine.
165
183
  def self.action_get_state
166
184
  Vagrant::Action::Builder.new.tap do |b|
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "i18n"
4
+ require "vagrant/util/ansi_escape_code_remover"
5
+
6
+ module VagrantPlugins
7
+ module Tart
8
+ module Command
9
+ # Command block to open a VNC connection to a virtual machine.
10
+ class VNC < Vagrant.plugin("2", :command)
11
+ def self.synopsis
12
+ "connects to machine via VNC"
13
+ end
14
+
15
+ def execute
16
+ options = {}
17
+
18
+ opts = OptionParser.new do |o|
19
+ o.banner = "Usage: vagrant vnc [options] [name|id] [-- extra args]"
20
+ o.separator ""
21
+ o.separator "Options:"
22
+ o.separator ""
23
+
24
+ o.on("-u", "--username USERNAME", "The username to use for the VNC connection.") do |u|
25
+ options[:username] = u
26
+ end
27
+
28
+ o.on("-p", "--password PASSWORD", "The password to use for the VNC connection.") do |p|
29
+ options[:password] = p
30
+ end
31
+ end
32
+
33
+ # Parse out the extra args to send to the RDP client, which
34
+ # is everything after the "--"
35
+ split_index = @argv.index("--")
36
+ if split_index
37
+ options[:extra_args] = @argv.drop(split_index + 1)
38
+ @argv = @argv.take(split_index)
39
+ end
40
+
41
+ # Parse the options and return if we don't have any target.
42
+ argv = parse_options(opts)
43
+ return unless argv
44
+
45
+ with_target_vms(argv, single_target: true) do |machine|
46
+ vnc_info = get_vnc_info(machine, options)
47
+
48
+ machine.ui.detail("Address: #{vnc_info[:host]}") if vnc_info[:host]
49
+ machine.ui.detail("Username: #{vnc_info[:username]}") if vnc_info[:username]
50
+
51
+ machine.action(:vnc_connect, vnc_info: vnc_info)
52
+ end
53
+
54
+ 0
55
+ end
56
+
57
+ def get_vnc_info(machine, options = {})
58
+ vnc_info = {}
59
+
60
+ ssh_info = machine.ssh_info
61
+ unless ssh_info.nil?
62
+ vnc_info[:host] = ssh_info[:host]
63
+ if options[:username]
64
+ vnc_info[:username] = options[:username]
65
+ vnc_info[:password] = options[:password] || nil
66
+ else
67
+ vnc_info[:username] = ssh_info[:username]
68
+ vnc_info[:password] = ssh_info[:password]
69
+ end
70
+ end
71
+ vnc_info[:extra_args] ||= options[:extra_args]
72
+
73
+ vnc_info
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -23,6 +23,10 @@ module VagrantPlugins
23
23
 
24
24
  # @return [Boolean] Show a GUI window on boot, or run headless
25
25
  attr_accessor :gui
26
+ # @return [Boolean] Whether the audio of the machine passes through the host
27
+ attr_accessor :audio
28
+ # @return [Boolean] Whether the machine and the host share the clipboard
29
+ attr_accessor :clipboard
26
30
  # @return [Integer] Number of CPUs
27
31
  attr_accessor :cpus
28
32
  # @return [Integer] Memory size in MB
@@ -33,6 +37,14 @@ module VagrantPlugins
33
37
  attr_accessor :display
34
38
  # @return [Boolean] Whether the machine is suspendable
35
39
  attr_accessor :suspendable
40
+ # @return [Boolean] Whether the machine expose a VNC server (screen sharing)
41
+ attr_accessor :vnc
42
+ # @return [Boolean] Whether the machine expose a VNC server (virtualization framework)
43
+ attr_accessor :vnc_experimental
44
+ # @return [String] The IP resolver to use (default to 'dhcp')
45
+ attr_accessor :ip_resolver
46
+ # @return [Array<String>] Extra arguments to pass to the tart run command
47
+ attr_accessor :extra_run_args
36
48
 
37
49
  # @return [Array<String>] List of volumes to mount
38
50
  attr_accessor :volumes
@@ -49,11 +61,17 @@ module VagrantPlugins
49
61
  @name = UNSET_VALUE
50
62
 
51
63
  @gui = UNSET_VALUE
64
+ @audio = UNSET_VALUE
65
+ @clipboard = UNSET_VALUE
52
66
  @cpus = UNSET_VALUE
53
67
  @memory = UNSET_VALUE
54
68
  @disk = UNSET_VALUE
55
69
  @display = UNSET_VALUE
56
70
  @suspendable = UNSET_VALUE
71
+ @vnc = UNSET_VALUE
72
+ @vnc_experimental = UNSET_VALUE
73
+ @ip_resolver = UNSET_VALUE
74
+ @extra_run_args = UNSET_VALUE
57
75
 
58
76
  @volumes = []
59
77
  end
@@ -68,11 +86,17 @@ module VagrantPlugins
68
86
  @name = nil if @name == UNSET_VALUE
69
87
 
70
88
  @gui = false if @gui == UNSET_VALUE
89
+ @audio = false if @audio == UNSET_VALUE
90
+ @clipboard = false if @clipboard == UNSET_VALUE
71
91
  @cpus = 1 if @cpus == UNSET_VALUE
72
92
  @memory = 1024 if @memory == UNSET_VALUE
73
93
  @disk = 10 if @disk == UNSET_VALUE
74
94
  @display = "1024x768" if @display == UNSET_VALUE
75
95
  @suspendable = false if @suspendable == UNSET_VALUE
96
+ @vnc = false if @vnc == UNSET_VALUE
97
+ @vnc_experimental = false if @vnc_experimental == UNSET_VALUE
98
+ @ip_resolver = "dhcp" if @ip_resolver == UNSET_VALUE
99
+ @extra_run_args = [] if @extra_run_args == UNSET_VALUE
76
100
  end
77
101
 
78
102
  # Validate the configuration
@@ -86,6 +110,12 @@ module VagrantPlugins
86
110
  # Check that the GUI flag is a valid boolean
87
111
  errors << I18n.t("vagrant_tart.config.gui_invalid") unless @gui == true || @gui == false
88
112
 
113
+ # Check that the audio flag is a valid boolean
114
+ errors << I18n.t("vagrant_tart.config.audio_invalid") unless @audio == true || @audio == false
115
+
116
+ # Check that the clipboard flag is a valid boolean
117
+ errors << I18n.t("vagrant_tart.config.clipboard_invalid") unless @clipboard == true || @clipboard == false
118
+
89
119
  # Check that CPUs is a valid number and between 1 and the maximum available CPUs
90
120
  max_cpus = Etc.nprocessors
91
121
  unless (@cpus.is_a? Integer) && @cpus >= 1 && @cpus <= max_cpus
@@ -107,6 +137,23 @@ module VagrantPlugins
107
137
  # Check that the suspendable flag is a valid boolean
108
138
  errors << I18n.t("vagrant_tart.config.suspendable_invalid") unless @suspendable == true || @suspendable == false
109
139
 
140
+ # Check that the VNC flag is a valid boolean
141
+ errors << I18n.t("vagrant_tart.config.vnc_invalid") unless @vnc == true || @vnc == false
142
+
143
+ # Check that the VNC experimental flag is a valid boolean
144
+ unless @vnc_experimental == true || @vnc_experimental == false
145
+ errors << I18n.t("vagrant_tart.config.vnc_experimental_invalid")
146
+ end
147
+
148
+ # Check that the VNC and VNC experimental flags are not both true
149
+ errors << I18n.t("vagrant_tart.config.vnc_exclusive") if @vnc == true && @vnc_experimental == true
150
+
151
+ # Check that the IP resolver is a valid string (either 'dhcp' or 'arp')
152
+ errors << I18n.t("vagrant_tart.config.ip_resolver_invalid") unless %w[dhcp arp].include? @ip_resolver
153
+
154
+ # Check that the extra run arguments is an array of strings
155
+ errors << I18n.t("vagrant_tart.config.extra_run_args_invalid") unless @extra_run_args.is_a? Array
156
+
110
157
  { "Tart Provider" => errors }
111
158
  end
112
159
 
@@ -36,6 +36,12 @@ module VagrantPlugins
36
36
  SyncedFolder
37
37
  end
38
38
 
39
+ # Register the custom VNC command.
40
+ command("vnc", primary: false) do
41
+ require_relative "command/vnc"
42
+ Command::VNC
43
+ end
44
+
39
45
  # Load the translation files
40
46
  def self.setup_i18n
41
47
  I18n.load_path << File.expand_path("locales/en.yml", Tart.source_root)
@@ -72,7 +72,7 @@ module VagrantPlugins
72
72
  # Retrieve the IP address
73
73
  instance_ip = nil
74
74
  begin
75
- instance_ip = @driver.ip(@machine.provider_config.name)
75
+ instance_ip = @driver.ip(@machine.provider_config.name, @machine.provider_config.ip_resolver)
76
76
  rescue Errors::CommandError
77
77
  @logger.warn("Failed to read guest IP #{$ERROR_INFO}")
78
78
  end
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env zsh
2
+ set -eo pipefail
3
+
4
+ # Open a VNC connection to the virtual machine
5
+ nohup open $1 &
@@ -26,6 +26,27 @@ module VagrantPlugins
26
26
  execute(*cmd, &block)
27
27
  end
28
28
 
29
+ # Trigger a VNC connection to the machine.
30
+ # @param info [Hash] The information to connect to the machine
31
+ def vnc_connect(info)
32
+ machine_ip = info[:host]
33
+ username = info[:username]
34
+ password = info[:password]
35
+
36
+ auth = if username && password
37
+ "#{username}:#{password}@"
38
+ elsif username
39
+ "#{username}@"
40
+ else
41
+ ""
42
+ end
43
+ target = "vnc://#{auth}#{machine_ip}"
44
+
45
+ script_path = @script_path.join("open.sh")
46
+ cmd = [script_path.to_s, target]
47
+ execute(*cmd)
48
+ end
49
+
29
50
  # Execute the 'create' command.
30
51
  # @param name [String] The name of the machine
31
52
  def delete(name)
@@ -46,8 +67,8 @@ module VagrantPlugins
46
67
  # Execute the 'ip' commanda and returns the IP address of the machine.
47
68
  # @param name [String] The name of the machine
48
69
  # @return [String] The IP address of the machine
49
- def ip(name)
50
- cmd = ["tart", "ip", name]
70
+ def ip(name, ip_resolver)
71
+ cmd = ["tart", "ip", "--resolver", ip_resolver, name]
51
72
  result = execute(*cmd)
52
73
  result.strip
53
74
  end
@@ -88,13 +109,23 @@ module VagrantPlugins
88
109
 
89
110
  # Execute the 'run' command by calling an accessory script.
90
111
  # @param name [String] The name of the machine
91
- def run(name, use_gui, suspend, volumes)
112
+ # @param options [Hash] The options to pass to the command
113
+ # @param options.use_gui [Boolean] Whether to use the GUI
114
+ # @param options.suspend [Boolean] Whether the machine is suspendable
115
+ # @param options.volumes [Array<String>] The volumes to mount
116
+ def run(name, config)
92
117
  script_path = @script_path.join("run.sh")
93
118
 
94
119
  cmd = [script_path.to_s, name]
95
- cmd << "--no-graphics" unless use_gui
96
- cmd << "--suspendable" if suspend
97
- volumes.each do |volume|
120
+ cmd << "--no-graphics" unless config.gui
121
+ cmd << "--no-audio" unless config.audio
122
+ cmd << "--no-clipboard" unless config.clipboard
123
+ cmd << "--suspendable" if config.suspendable?
124
+ cmd << "--vnc" if config.vnc
125
+ cmd << "--vnc-experimental" if config.vnc_experimental
126
+ cmd.concat(config.extra_run_args)
127
+
128
+ config.volumes.each do |volume|
98
129
  cmd << "--dir=#{volume}"
99
130
  end
100
131
 
@@ -4,6 +4,6 @@ module VagrantPlugins
4
4
  # Top level module for the Tart provider plugin.
5
5
  module Tart
6
6
  # Current version of the Tart provider plugin.
7
- VERSION = "0.0.4"
7
+ VERSION = "0.0.6"
8
8
  end
9
9
  end
data/locales/en.yml CHANGED
@@ -1,22 +1,36 @@
1
1
  en:
2
2
  vagrant_tart:
3
3
  config:
4
+ audio_invalid: |-
5
+ Configuration must specify a valid audio setting (true or false)
6
+ clipboard_invalid: |-
7
+ Configuration must specify a valid clipboard setting (true or false)
4
8
  cpus_invalid: |-
5
9
  Configuration must specify a valid CPUs count (between 1 and %{max_cpus})
6
10
  disk_invalid: |-
7
11
  Configuration must specify a valid disk size (greater than 1 GB)
8
12
  display_invalid: |-
9
13
  Configuration must specify a valid display size (WIDTHxHEIGHT pixels)
14
+ extra_run_args_invalid: |-
15
+ Configuration must specify a valid extra run arguments (array of strings)
10
16
  gui_invalid: |-
11
17
  Configuration must specify a valid GUI setting (true or false)
12
18
  image_required: |-
13
19
  Configuration must specify an image
20
+ ip_resolver_arp_invalid: |-
21
+ Configuration must specify a valid IP resolver ARP setting (true or false)
14
22
  memory_invalid: |-
15
23
  Configuration must specify a valid memory size (between 1 and %{max_memory} MB)
16
24
  name_required: |-
17
25
  Configuration must specify a virtual machine name
18
26
  suspendable_invalid: |-
19
27
  Configuration must specify a valid suspendable setting (true or false)
28
+ vnc_invalid: |-
29
+ Configuration must specify a valid VNC setting (true or false)
30
+ vnc_exclusive: |-
31
+ Configuration must specify either vnc or vnc_experimental setting
32
+ vnc_experimental_invalid: |-
33
+ Configuration must specify a valid VNC experimental setting (true or false)
20
34
 
21
35
  errors:
22
36
  command_error: |-
@@ -39,6 +53,8 @@ en:
39
53
  Cloning instance %{name}...
40
54
  configuring_instance: |-
41
55
  Configuring instance %{name}...
56
+ connecting_to_vnc: |-
57
+ Opening VNC connection to %{name}...
42
58
  deleting_instance: |-
43
59
  Deleting instance %{name}...
44
60
  image_pulled: |-
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vagrant-tart
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Laurent Etiemble
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-06-22 00:00:00.000000000 Z
11
+ date: 2025-02-16 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Allows Vagrant to manage Tart virtual machines.
14
14
  email:
@@ -30,6 +30,8 @@ files:
30
30
  - lib/vagrant-tart/action/start_instance.rb
31
31
  - lib/vagrant-tart/action/stop_instance.rb
32
32
  - lib/vagrant-tart/action/suspend_instance.rb
33
+ - lib/vagrant-tart/action/vnc_connect.rb
34
+ - lib/vagrant-tart/command/vnc.rb
33
35
  - lib/vagrant-tart/config.rb
34
36
  - lib/vagrant-tart/errors.rb
35
37
  - lib/vagrant-tart/model/get_result.rb
@@ -38,6 +40,7 @@ files:
38
40
  - lib/vagrant-tart/plugin.rb
39
41
  - lib/vagrant-tart/provider.rb
40
42
  - lib/vagrant-tart/scripts/login.sh
43
+ - lib/vagrant-tart/scripts/open.sh
41
44
  - lib/vagrant-tart/scripts/run.sh
42
45
  - lib/vagrant-tart/synced_folder.rb
43
46
  - lib/vagrant-tart/util/driver.rb
@@ -52,7 +55,7 @@ metadata:
52
55
  source_code_uri: https://github.com/letiemble/vagrant-tart
53
56
  changelog_uri: https://github.com/letiemble/vagrant-tart/blob/main/CHANGELOG.md
54
57
  rubygems_mfa_required: 'true'
55
- post_install_message:
58
+ post_install_message:
56
59
  rdoc_options: []
57
60
  require_paths:
58
61
  - lib
@@ -67,8 +70,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
67
70
  - !ruby/object:Gem::Version
68
71
  version: '0'
69
72
  requirements: []
70
- rubygems_version: 3.3.27
71
- signing_key:
73
+ rubygems_version: 3.5.11
74
+ signing_key:
72
75
  specification_version: 4
73
76
  summary: Vagrant Tart provider
74
77
  test_files: []