vagrant-unbundled 2.2.10.0 → 2.2.14.0

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.
Files changed (83) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +60 -0
  3. data/Gemfile +1 -1
  4. data/README.md +4 -44
  5. data/RELEASE.md +1 -1
  6. data/contrib/zsh/_vagrant +3 -1
  7. data/contrib/zsh/generate_zsh_completion.rb +2 -3
  8. data/lib/vagrant.rb +0 -4
  9. data/lib/vagrant/action/builder.rb +6 -15
  10. data/lib/vagrant/action/builtin/box_add.rb +5 -1
  11. data/lib/vagrant/action/builtin/cloud_init_setup.rb +10 -15
  12. data/lib/vagrant/action/builtin/synced_folders.rb +8 -2
  13. data/lib/vagrant/action/runner.rb +1 -1
  14. data/lib/vagrant/box.rb +8 -2
  15. data/lib/vagrant/box_collection.rb +1 -1
  16. data/lib/vagrant/bundler.rb +43 -16
  17. data/lib/vagrant/machine.rb +8 -5
  18. data/lib/vagrant/machine_index.rb +1 -0
  19. data/lib/vagrant/plugin/v2/command.rb +2 -1
  20. data/lib/vagrant/shared_helpers.rb +8 -0
  21. data/lib/vagrant/util/downloader.rb +3 -2
  22. data/lib/vagrant/util/is_port_open.rb +1 -1
  23. data/lib/vagrant/util/mime.rb +92 -0
  24. data/lib/vagrant/util/platform.rb +2 -1
  25. data/lib/vagrant/util/template_renderer.rb +2 -2
  26. data/lib/vagrant/util/uploader.rb +7 -4
  27. data/plugins/commands/cap/command.rb +5 -1
  28. data/plugins/commands/cloud/auth/login.rb +20 -23
  29. data/plugins/commands/cloud/auth/logout.rb +2 -10
  30. data/plugins/commands/cloud/auth/middleware/add_downloader_authentication.rb +57 -0
  31. data/plugins/commands/cloud/auth/whoami.rb +18 -20
  32. data/plugins/commands/cloud/box/create.rb +33 -29
  33. data/plugins/commands/cloud/box/delete.rb +30 -24
  34. data/plugins/commands/cloud/box/show.rb +41 -31
  35. data/plugins/commands/cloud/box/update.rb +34 -26
  36. data/plugins/commands/cloud/client/client.rb +50 -81
  37. data/plugins/commands/cloud/list.rb +3 -4
  38. data/plugins/commands/cloud/locales/en.yml +9 -9
  39. data/plugins/commands/cloud/plugin.rb +10 -0
  40. data/plugins/commands/cloud/provider/create.rb +38 -28
  41. data/plugins/commands/cloud/provider/delete.rb +39 -29
  42. data/plugins/commands/cloud/provider/update.rb +37 -28
  43. data/plugins/commands/cloud/provider/upload.rb +44 -34
  44. data/plugins/commands/cloud/publish.rb +185 -108
  45. data/plugins/commands/cloud/search.rb +34 -21
  46. data/plugins/commands/cloud/util.rb +266 -162
  47. data/plugins/commands/cloud/version/create.rb +33 -28
  48. data/plugins/commands/cloud/version/delete.rb +35 -28
  49. data/plugins/commands/cloud/version/release.rb +35 -29
  50. data/plugins/commands/cloud/version/revoke.rb +36 -29
  51. data/plugins/commands/cloud/version/update.rb +29 -25
  52. data/plugins/commands/login/plugin.rb +0 -13
  53. data/plugins/guests/arch/cap/smb.rb +1 -1
  54. data/plugins/guests/darwin/cap/darwin_version.rb +40 -0
  55. data/plugins/guests/darwin/cap/mount_smb_shared_folder.rb +1 -1
  56. data/plugins/guests/darwin/cap/mount_vmware_shared_folder.rb +12 -2
  57. data/plugins/guests/darwin/plugin.rb +10 -0
  58. data/plugins/guests/debian/cap/change_host_name.rb +8 -7
  59. data/plugins/guests/linux/cap/mount_smb_shared_folder.rb +16 -41
  60. data/plugins/guests/linux/cap/mount_virtualbox_shared_folder.rb +6 -0
  61. data/plugins/guests/linux/cap/persist_mount_shared_folder.rb +18 -5
  62. data/plugins/guests/linux/cap/reboot.rb +10 -5
  63. data/plugins/guests/redhat/cap/change_host_name.rb +6 -2
  64. data/plugins/guests/suse/cap/change_host_name.rb +32 -11
  65. data/plugins/guests/windows/cap/reboot.rb +8 -4
  66. data/plugins/kernel_v2/config/cloud_init.rb +7 -0
  67. data/plugins/kernel_v2/config/disk.rb +1 -1
  68. data/plugins/kernel_v2/config/vm.rb +5 -4
  69. data/plugins/providers/hyperv/action.rb +1 -1
  70. data/plugins/providers/virtualbox/cap/mount_options.rb +1 -1
  71. data/plugins/providers/virtualbox/model/storage_controller_array.rb +4 -6
  72. data/plugins/providers/virtualbox/provider.rb +2 -1
  73. data/plugins/synced_folders/smb/cap/mount_options.rb +21 -1
  74. data/plugins/synced_folders/smb/plugin.rb +10 -0
  75. data/scripts/website_push_www.sh +1 -1
  76. data/vagrant.gemspec +5 -6
  77. data/version.txt +1 -1
  78. metadata +1202 -1595
  79. data/plugins/commands/login/client.rb +0 -253
  80. data/plugins/commands/login/command.rb +0 -137
  81. data/plugins/commands/login/errors.rb +0 -24
  82. data/plugins/commands/login/locales/en.yml +0 -49
  83. data/scripts/website_push_docs.sh +0 -40
@@ -231,15 +231,18 @@ module Vagrant
231
231
  # @param [Proc] callable
232
232
  # @param [Hash] extra_env Extra env for the action env.
233
233
  # @return [Hash] The resulting env
234
- def action_raw(name, callable, extra_env=nil)
234
+ def action_raw(name, callable, extra_env={})
235
+ if !extra_env.is_a?(Hash)
236
+ extra_env = {}
237
+ end
238
+
235
239
  # Run the action with the action runner on the environment
236
- env = {
240
+ env = {ui: @ui}.merge(extra_env).merge(
237
241
  raw_action_name: name,
238
242
  action_name: "machine_action_#{name}".to_sym,
239
243
  machine: self,
240
- machine_action: name,
241
- ui: @ui,
242
- }.merge(extra_env || {})
244
+ machine_action: name
245
+ )
243
246
  @env.action_runner.run(callable, env)
244
247
  end
245
248
 
@@ -263,6 +263,7 @@ module Vagrant
263
263
  #
264
264
  # @return [Hash]
265
265
  def find_by_prefix(prefix)
266
+ return if !prefix
266
267
  @machines.each do |uuid, data|
267
268
  return data.merge("id" => uuid) if uuid.start_with?(prefix)
268
269
  end
@@ -230,7 +230,8 @@ module Vagrant
230
230
  color_index = 0
231
231
 
232
232
  machines.each do |machine|
233
- if machine.state && machine.state.id != :not_created && !@env.machine_index.include?(machine.index_uuid)
233
+ if (machine.state && machine.state.id != :not_created &&
234
+ !machine.index_uuid.nil? && !@env.machine_index.include?(machine.index_uuid))
234
235
  machine.recover_machine(machine.state.id)
235
236
  end
236
237
 
@@ -125,6 +125,14 @@ module Vagrant
125
125
  Gem::Version.new(Vagrant::VERSION).prerelease?
126
126
  end
127
127
 
128
+ # This returns true/false if the Vagrant should allow prerelease
129
+ # versions when resolving plugin dependency constraints
130
+ #
131
+ # @return [Boolean]
132
+ def self.allow_prerelease_dependencies?
133
+ !!ENV["VAGRANT_ALLOW_PRERELEASE"]
134
+ end
135
+
128
136
  # This allows control over dependency resolution when installing
129
137
  # plugins into vagrant. When true, dependency libraries that Vagrant
130
138
  # core relies upon will be hard constraints.
@@ -29,8 +29,9 @@ module Vagrant
29
29
  "vagrantup.com".freeze
30
30
  ].freeze
31
31
 
32
- attr_reader :source
32
+ attr_accessor :source
33
33
  attr_reader :destination
34
+ attr_accessor :headers
34
35
 
35
36
  def initialize(source, destination, options=nil)
36
37
  options ||= {}
@@ -58,7 +59,7 @@ module Vagrant
58
59
  @ca_cert = options[:ca_cert]
59
60
  @ca_path = options[:ca_path]
60
61
  @continue = options[:continue]
61
- @headers = options[:headers]
62
+ @headers = Array(options[:headers])
62
63
  @insecure = options[:insecure]
63
64
  @ui = options[:ui]
64
65
  @client_cert = options[:client_cert]
@@ -17,7 +17,7 @@ module Vagrant
17
17
  Socket.tcp(host, port, connect_timeout: 0.1).close
18
18
  true
19
19
  rescue Errno::ETIMEDOUT, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, \
20
- Errno::ENETUNREACH, Errno::EACCES, Errno::ENOTCONN
20
+ Errno::ENETUNREACH, Errno::EACCES, Errno::ENOTCONN, Errno::EALREADY
21
21
  false
22
22
  end
23
23
  end
@@ -0,0 +1,92 @@
1
+ require 'mime/types'
2
+ require 'securerandom'
3
+
4
+ module Vagrant
5
+ module Util
6
+ module Mime
7
+ class Multipart
8
+
9
+ # @return [Array<String>] collection of content part of the multipart mime
10
+ attr_accessor :content
11
+
12
+ # @return [String] type of the content
13
+ attr_accessor :content_type
14
+
15
+ # @return [Hash] headers for the mime
16
+ attr_accessor :headers
17
+
18
+ # @param [String] (optional) mime content type
19
+ # @param [String] (optional) mime version
20
+ def initialize(content_type="multipart/mixed")
21
+ @content_id = "#{Time.now.to_i}@#{SecureRandom.alphanumeric(24)}.local"
22
+ @boundary = "Boundary_#{SecureRandom.alphanumeric(24)}"
23
+ @content_type = MIME::Types[content_type].first
24
+ @content = []
25
+ @headers = {
26
+ "Content-ID"=> "<#{@content_id}>",
27
+ "Content-Type"=> "#{content_type}; boundary=#{@boundary}",
28
+ }
29
+ end
30
+
31
+ # Add an entry to the multipart mime
32
+ #
33
+ # @param entry to add
34
+ def add(entry)
35
+ content << entry
36
+ end
37
+
38
+ # Output MimeEntity as a string
39
+ #
40
+ # @return [String] mime data
41
+ def to_s
42
+ output_string = ""
43
+ headers.each do |k, v|
44
+ output_string += "#{k}: #{v}\n"
45
+ end
46
+ output_string += "\n--#{@boundary}\n"
47
+ @content.each do |entry|
48
+ output_string += entry.to_s
49
+ output_string += "\n--#{@boundary}\n"
50
+ end
51
+ output_string
52
+ end
53
+ end
54
+
55
+ class Entity
56
+
57
+ # @return [String] entity content
58
+ attr_reader :content
59
+
60
+ # @return [String] type of the entity content
61
+ attr_reader :content_type
62
+
63
+ # @return [String] content disposition
64
+ attr_accessor :disposition
65
+
66
+ # @param [String] entity content
67
+ # @param [String] type of the entity content
68
+ def initialize(content, content_type)
69
+ if !MIME::Types.include?(content_type)
70
+ MIME::Types.add(MIME::Type.new(content_type))
71
+ end
72
+ @content = content
73
+ @content_type = MIME::Types[content_type].first
74
+ @content_id = "#{Time.now.to_i}@#{SecureRandom.alphanumeric(24)}.local"
75
+ end
76
+
77
+ # Output MimeEntity as a string
78
+ #
79
+ # @return [String] mime data
80
+ def to_s
81
+ output_string = "Content-ID: <#{@content_id}>\n"
82
+ output_string += "Content-Type: #{@content_type}\n"
83
+ if disposition
84
+ output_string += "Content-Disposition: #{@disposition}\n"
85
+ end
86
+ output_string += "\n#{content}"
87
+ output_string
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
@@ -554,6 +554,7 @@ module Vagrant
554
554
  # Get list of local mount paths that are DrvFs file systems
555
555
  #
556
556
  # @return [Array<String>]
557
+ # @todo(chrisroberts): Constantize types for check
557
558
  def wsl_drvfs_mounts
558
559
  if !defined?(@_wsl_drvfs_mounts)
559
560
  @_wsl_drvfs_mounts = []
@@ -561,7 +562,7 @@ module Vagrant
561
562
  result = Util::Subprocess.execute("mount")
562
563
  result.stdout.each_line do |line|
563
564
  info = line.match(MOUNT_PATTERN)
564
- if info && info[:type] == "drvfs"
565
+ if info && (info[:type] == "drvfs" || info[:type] == "9p")
565
566
  @_wsl_drvfs_mounts << info[:mount]
566
567
  end
567
568
  end
@@ -1,7 +1,7 @@
1
1
  require 'ostruct'
2
2
  require "pathname"
3
3
 
4
- require 'erubis'
4
+ require 'erubi'
5
5
 
6
6
  module Vagrant
7
7
  module Util
@@ -73,7 +73,7 @@ module Vagrant
73
73
  #
74
74
  # @return [String]
75
75
  def render_string
76
- Erubis::Eruby.new(template, trim: true).result(binding)
76
+ binding.eval(Erubi::Engine.new(template, trim: true).src)
77
77
  end
78
78
 
79
79
  # Returns the full path to the template, taking into account the gem directory
@@ -13,9 +13,11 @@ module Vagrant
13
13
  # a hand-rolled Ruby library, so we defer to its expertise.
14
14
  class Uploader
15
15
 
16
- # @param [String] destination - valid URL to upload file to
17
- # @param [String] file - location of file to upload on disk
18
- # @param [Hash] options
16
+ # @param [String] destination Valid URL to upload file to
17
+ # @param [String] file Location of file to upload on disk
18
+ # @param [Hash] options
19
+ # @option options [Vagrant::UI] :ui UI interface for output
20
+ # @option options [String, Symbol] :method Request method for upload
19
21
  def initialize(destination, file, options=nil)
20
22
  options ||= {}
21
23
  @logger = Log4r::Logger.new("vagrant::util::uploader")
@@ -27,6 +29,7 @@ module Vagrant
27
29
  if !@request_method
28
30
  @request_method = "PUT"
29
31
  end
32
+ @request_method = @request_method.to_s.upcase
30
33
  end
31
34
 
32
35
  def upload!
@@ -51,7 +54,7 @@ module Vagrant
51
54
  protected
52
55
 
53
56
  def build_options
54
- options = [@destination, "--request", @request_method, "--upload-file", @file]
57
+ options = [@destination, "--request", @request_method, "--upload-file", @file, "--fail"]
55
58
  return options
56
59
  end
57
60
 
@@ -27,6 +27,10 @@ module VagrantPlugins
27
27
  o.on("--check", "Only checks for a capability, does not execute") do |f|
28
28
  options[:check] = f
29
29
  end
30
+
31
+ o.on("-t", "--target=TARGET", "Target guest to run against (if applicable)") do |t|
32
+ options[:target] = t
33
+ end
30
34
  end
31
35
 
32
36
  # Parse the options
@@ -45,7 +49,7 @@ module VagrantPlugins
45
49
  if type == :host
46
50
  cap_host = @env.host
47
51
  else
48
- with_target_vms([]) do |vm|
52
+ with_target_vms(options[:target] || []) do |vm|
49
53
  cap_host = case type
50
54
  when :provider
51
55
  vm.provider
@@ -5,6 +5,8 @@ module VagrantPlugins
5
5
  module AuthCommand
6
6
  module Command
7
7
  class Login < Vagrant.plugin("2", :command)
8
+ include Util
9
+
8
10
  def execute
9
11
  options = {}
10
12
 
@@ -16,15 +18,10 @@ module VagrantPlugins
16
18
  o.on("-c", "--check", "Checks if currently logged in") do |c|
17
19
  options[:check] = c
18
20
  end
19
-
20
21
  o.on("-d", "--description DESCRIPTION", String, "Set description for the Vagrant Cloud token") do |d|
21
22
  options[:description] = d
22
23
  end
23
24
 
24
- o.on("-k", "--logout", "Logout from Vagrant Cloud") do |k|
25
- options[:logout] = k
26
- end
27
-
28
25
  o.on("-t", "--token TOKEN", String, "Set the Vagrant Cloud token") do |t|
29
26
  options[:token] = t
30
27
  end
@@ -37,26 +34,32 @@ module VagrantPlugins
37
34
  # Parse the options
38
35
  argv = parse_options(opts)
39
36
  return if !argv
37
+ if !argv.empty?
38
+ raise Vagrant::Errors::CLIInvalidUsage,
39
+ help: opts.help.chomp
40
+ end
40
41
 
41
- @client = Client.new(@env)
42
- @client.username_or_email = options[:login]
42
+ client = Client.new(@env)
43
+ client.username_or_email = options[:login]
43
44
 
44
45
  # Determine what task we're actually taking based on flags
45
46
  if options[:check]
46
- return execute_check
47
- elsif options[:logout]
48
- return execute_logout
47
+ return execute_check(client)
49
48
  elsif options[:token]
50
- return execute_token(options[:token])
49
+ return execute_token(client, options[:token])
51
50
  else
52
- @client = VagrantPlugins::CloudCommand::Util.client_login(@env, options)
51
+ if client.logged_in?
52
+ @env.ui.success(I18n.t("cloud_command.check_logged_in"))
53
+ else
54
+ client_login(@env, options.slice(:login, :description))
55
+ end
53
56
  end
54
57
 
55
58
  0
56
59
  end
57
60
 
58
- def execute_check
59
- if @client.logged_in?
61
+ def execute_check(client)
62
+ if client.logged_in?
60
63
  @env.ui.success(I18n.t("cloud_command.check_logged_in"))
61
64
  return 0
62
65
  else
@@ -65,17 +68,11 @@ module VagrantPlugins
65
68
  end
66
69
  end
67
70
 
68
- def execute_logout
69
- @client.clear_token
70
- @env.ui.success(I18n.t("cloud_command.logged_out"))
71
- return 0
72
- end
73
-
74
- def execute_token(token)
75
- @client.store_token(token)
71
+ def execute_token(client, token)
72
+ client.store_token(token)
76
73
  @env.ui.success(I18n.t("cloud_command.token_saved"))
77
74
 
78
- if @client.logged_in?
75
+ if client.logged_in?
79
76
  @env.ui.success(I18n.t("cloud_command.check_logged_in"))
80
77
  return 0
81
78
  else
@@ -9,15 +9,9 @@ module VagrantPlugins
9
9
  options = {}
10
10
 
11
11
  opts = OptionParser.new do |o|
12
- o.banner = "Usage: vagrant cloud auth logout [options]"
12
+ o.banner = "Usage: vagrant cloud auth logout"
13
13
  o.separator ""
14
14
  o.separator "Log out of Vagrant Cloud"
15
- o.separator ""
16
- o.separator "Options:"
17
- o.separator ""
18
- o.on("-u", "--username USERNAME_OR_EMAIL", String, "Vagrant Cloud username or email address") do |l|
19
- options[:login] = l
20
- end
21
15
  end
22
16
 
23
17
  # Parse the options
@@ -28,9 +22,7 @@ module VagrantPlugins
28
22
  help: opts.help.chomp
29
23
  end
30
24
 
31
- # Initializes client and deletes token on disk
32
- @client = VagrantPlugins::CloudCommand::Util.client_login(@env, options[:username])
33
-
25
+ @client = Client.new(@env)
34
26
  @client.clear_token
35
27
  @env.ui.success(I18n.t("cloud_command.logged_out"))
36
28
  return 0
@@ -0,0 +1,57 @@
1
+ require "cgi"
2
+ require "uri"
3
+
4
+ require "vagrant/util/credential_scrubber"
5
+ require_relative "./add_authentication"
6
+
7
+ require Vagrant.source_root.join("plugins/commands/cloud/client/client")
8
+
9
+ # Similar to AddAuthentication this middleware will add authentication for interacting
10
+ # with Vagrant cloud. It does this by adding Authentication headers to a
11
+ # Vagrant::Util::Downloader object.
12
+ module VagrantPlugins
13
+ module CloudCommand
14
+ class AddDownloaderAuthentication < AddAuthentication
15
+
16
+ @@logger = Log4r::Logger.new("vagrant::clout::add_download_authentication")
17
+
18
+ def call(env)
19
+ client = Client.new(env[:env])
20
+ token = client.token
21
+ Vagrant::Util::CredentialScrubber.sensitive(token)
22
+
23
+ begin
24
+ target_url = URI.parse(env[:downloader].source)
25
+ if target_url.host != TARGET_HOST && REPLACEMENT_HOSTS.include?(target_url.host)
26
+ target_url.host = TARGET_HOST
27
+ env[:downloader].source = target_url.to_s
28
+ end
29
+ rescue URI::Error
30
+ # if there is an error, use current target_url
31
+ end
32
+
33
+ server_uri = URI.parse(Vagrant.server_url.to_s)
34
+ if token && !server_uri.host.to_s.empty?
35
+ if target_url.host == server_uri.host
36
+ if server_uri.host != TARGET_HOST && !self.class.custom_host_notified?
37
+ env[:ui].warn(I18n.t("cloud_command.middleware.authentication.different_target",
38
+ custom_host: server_uri.host, known_host: TARGET_HOST) + "\n")
39
+ sleep CUSTOM_HOST_NOTIFY_WAIT
40
+ self.class.custom_host_notified!
41
+ end
42
+
43
+ if Array(env[:downloader].headers).any? { |h| h.include?("Authorization") }
44
+ @@logger.info("Not adding an authentication header, one already found")
45
+ else
46
+ env[:downloader].headers << "Authorization: Bearer #{token}"
47
+ end
48
+ end
49
+
50
+ env[:downloader]
51
+ end
52
+
53
+ @app.call(env)
54
+ end.freeze
55
+ end
56
+ end
57
+ end
@@ -5,19 +5,15 @@ module VagrantPlugins
5
5
  module AuthCommand
6
6
  module Command
7
7
  class Whoami < Vagrant.plugin("2", :command)
8
+ include Util
9
+
8
10
  def execute
9
11
  options = {}
10
12
 
11
13
  opts = OptionParser.new do |o|
12
- o.banner = "Usage: vagrant cloud auth whoami [options] [token]"
14
+ o.banner = "Usage: vagrant cloud auth whoami [token]"
13
15
  o.separator ""
14
16
  o.separator "Display currently logged in user"
15
- o.separator ""
16
- o.separator "Options:"
17
- o.separator ""
18
- o.on("-u", "--username USERNAME_OR_EMAIL", String, "Vagrant Cloud username or email address") do |l|
19
- options[:login] = l
20
- end
21
17
  end
22
18
 
23
19
  # Parse the options
@@ -28,28 +24,30 @@ module VagrantPlugins
28
24
  help: opts.help.chomp
29
25
  end
30
26
 
31
- @client = VagrantPlugins::CloudCommand::Util.client_login(@env, options[:login])
32
-
33
27
  if argv.first
34
28
  token = argv.first
35
29
  else
36
- token = @client.token
30
+ client = Client.new(@env)
31
+ token = client.token
37
32
  end
38
33
 
39
- whoami(token, options[:username])
34
+ whoami(token)
40
35
  end
41
36
 
42
- def whoami(access_token, username)
43
- server_url = VagrantPlugins::CloudCommand::Util.api_server_url
44
- account = VagrantPlugins::CloudCommand::Util.account(username, access_token, server_url)
45
-
37
+ def whoami(access_token)
38
+ if access_token.to_s.empty?
39
+ @env.ui.error(I18n.t("cloud_command.check_not_logged_in"))
40
+ return 1
41
+ end
46
42
  begin
47
- success = account.validate_token
48
- user = success["user"]["username"]
49
- @env.ui.success("Currently logged in as #{user}")
43
+ account = VagrantCloud::Account.new(
44
+ custom_server: api_server_url,
45
+ access_token: access_token
46
+ )
47
+ @env.ui.success("Currently logged in as #{account.username}")
50
48
  return 0
51
- rescue VagrantCloud::ClientError => e
52
- @env.ui.error(I18n.t("cloud_command.errors.whoami.read_error", org: username))
49
+ rescue VagrantCloud::Error::ClientError => e
50
+ @env.ui.error(I18n.t("cloud_command.errors.whoami.read_error"))
53
51
  @env.ui.error(e)
54
52
  return 1
55
53
  end