vagrant-docker-hosts-manager 0.2.0 → 0.4.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +20 -0
- data/README.md +1 -0
- data/lib/vagrant-docker-hosts-manager/VERSION +1 -1
- data/lib/vagrant-docker-hosts-manager/actions/apply.rb +68 -0
- data/lib/vagrant-docker-hosts-manager/actions/cleanup.rb +34 -0
- data/lib/vagrant-docker-hosts-manager/command.rb +255 -248
- data/lib/vagrant-docker-hosts-manager/config.rb +45 -10
- data/lib/vagrant-docker-hosts-manager/helpers.rb +91 -7
- data/lib/vagrant-docker-hosts-manager/plugin.rb +2 -92
- data/lib/vagrant-docker-hosts-manager/util/docker.rb +10 -11
- data/lib/vagrant-docker-hosts-manager/util/hosts_file.rb +140 -132
- data/lib/vagrant-docker-hosts-manager/util/i18n.rb +20 -12
- data/lib/vagrant-docker-hosts-manager/util/verbose.rb +22 -0
- data/lib/vagrant-docker-hosts-manager/version.rb +7 -5
- data/locales/en.yml +117 -110
- data/locales/fr.yml +118 -111
- metadata +6 -2
|
@@ -10,281 +10,278 @@ module VagrantDockerHostsManager
|
|
|
10
10
|
json: false,
|
|
11
11
|
dry: false,
|
|
12
12
|
lang: nil,
|
|
13
|
-
no_emoji: false
|
|
13
|
+
no_emoji: false,
|
|
14
|
+
yes: false,
|
|
15
|
+
all: false
|
|
14
16
|
}
|
|
15
17
|
|
|
16
|
-
|
|
17
|
-
help_topic = begin
|
|
18
|
-
i = raw_argv.index { |x| x =~ /\A(?:help|--help|-h)\z/ }
|
|
19
|
-
cand = (i && raw_argv[i + 1]) ? raw_argv[i + 1] : nil
|
|
20
|
-
(cand && cand !~ /\A-/) ? cand : nil
|
|
21
|
-
rescue
|
|
22
|
-
nil
|
|
23
|
-
end
|
|
18
|
+
help_topic = extract_help_topic(@argv)
|
|
24
19
|
|
|
25
20
|
parser = OptionParser.new do |o|
|
|
26
21
|
o.banner = "Usage: vagrant hosts <apply|remove|view|help|version> [options]"
|
|
27
22
|
o.on("--json", "Machine-readable JSON output") { opts[:json] = true }
|
|
28
23
|
o.on("--lang LANG", "Force language (en|fr)") { |v| opts[:lang] = v }
|
|
29
24
|
o.on("--no-emoji", "Disable emoji in CLI output") { opts[:no_emoji] = true }
|
|
30
|
-
o.on("-
|
|
25
|
+
o.on("-y", "--yes", "Auto-confirm destructive operations") { opts[:yes] = true }
|
|
26
|
+
o.on("--all", "--prune", "remove: purge ALL managed blocks (every machine, incl. orphans)") { opts[:all] = true }
|
|
31
27
|
end
|
|
32
28
|
|
|
33
29
|
argv = parse_options(parser)
|
|
34
30
|
return 0 unless argv
|
|
35
31
|
|
|
36
32
|
action = argv.shift
|
|
37
|
-
env = @env
|
|
38
33
|
|
|
39
|
-
Util::I18n.setup!(env, forced: opts[:lang])
|
|
34
|
+
Util::I18n.setup!(@env, forced: opts[:lang])
|
|
40
35
|
Util::I18n.set_json_mode(opts[:json])
|
|
41
36
|
ENV["VDHM_DRY_RUN"] = "1" if opts[:dry]
|
|
42
37
|
ENV["VDHM_NO_EMOJI"] = "1" if opts[:no_emoji]
|
|
43
38
|
|
|
39
|
+
dispatch(action, argv, opts, help_topic)
|
|
40
|
+
rescue StandardError => e
|
|
41
|
+
Util::Json.emit(action: "command", status: "error", error: e.message)
|
|
42
|
+
UiHelpers.error(@env.ui, "#{UiHelpers.e(:error, no_emoji: opts[:no_emoji])} #{e.message}") unless opts[:json]
|
|
43
|
+
1
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
private
|
|
47
|
+
|
|
48
|
+
def dispatch(action, argv, opts, help_topic)
|
|
44
49
|
case action
|
|
45
|
-
when nil, "", "help"
|
|
46
|
-
topic
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
when "
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
when nil, "", "help"
|
|
51
|
+
print_help(@env.ui, topic: help_topic || argv.shift, no_emoji: opts[:no_emoji])
|
|
52
|
+
0
|
|
53
|
+
when "version" then cmd_version(opts)
|
|
54
|
+
when "apply" then cmd_apply(argv, opts)
|
|
55
|
+
when "remove" then cmd_remove(argv, opts)
|
|
56
|
+
when "view" then cmd_view(argv, opts)
|
|
57
|
+
else
|
|
58
|
+
print_help(@env.ui, no_emoji: opts[:no_emoji])
|
|
59
|
+
0
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def extract_help_topic(raw_argv)
|
|
64
|
+
i = raw_argv.index { |x| x =~ /\A(?:help|--help|-h)\z/ }
|
|
65
|
+
cand = (i && raw_argv[i + 1]) ? raw_argv[i + 1] : nil
|
|
66
|
+
(cand && cand !~ /\A-/) ? cand : nil
|
|
67
|
+
rescue StandardError
|
|
68
|
+
nil
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def cmd_version(opts)
|
|
72
|
+
if opts[:json]
|
|
73
|
+
Util::Json.emit(action: "version", status: "success", data: { version: VagrantDockerHostsManager::VERSION })
|
|
74
|
+
else
|
|
75
|
+
emoji = UiHelpers.e(:version, no_emoji: opts[:no_emoji])
|
|
76
|
+
line = ::I18n.t("vdhm.log.version_line",
|
|
77
|
+
default: "vagrant-docker-hosts-manager version %{version}",
|
|
78
|
+
version: VagrantDockerHostsManager::VERSION)
|
|
79
|
+
UiHelpers.say(@env.ui, "#{emoji} #{line}")
|
|
80
|
+
end
|
|
81
|
+
0
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def cmd_apply(argv, opts)
|
|
85
|
+
begin
|
|
86
|
+
ip_for_apply, host_for_apply =
|
|
87
|
+
parse_strict_mapping_from_argv!(argv, @env.ui, opts[:no_emoji], json: opts[:json])
|
|
88
|
+
rescue ArgumentError => e
|
|
89
|
+
Util::Json.emit(action: "apply", status: "error", error: e.message) if opts[:json]
|
|
90
|
+
return 1
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
machine = require_target_vm("apply", argv, opts) or return 1
|
|
94
|
+
|
|
95
|
+
if ip_for_apply || host_for_apply
|
|
96
|
+
code = validate_apply_mapping(ip_for_apply, host_for_apply, opts)
|
|
97
|
+
return code if code
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
mid = machine.id || "unknown"
|
|
101
|
+
hoster = Util::HostsFile.new({ machine: machine, ui: @env.ui }, owner_id: mid)
|
|
102
|
+
|
|
103
|
+
entries =
|
|
104
|
+
if ip_for_apply && host_for_apply
|
|
105
|
+
{ host_for_apply => ip_for_apply }
|
|
52
106
|
else
|
|
53
|
-
|
|
54
|
-
line = ::I18n.t("log.version_line",
|
|
55
|
-
default: "vagrant-docker-hosts-manager version %{version}",
|
|
56
|
-
version: VagrantDockerHostsManager::VERSION)
|
|
57
|
-
UiHelpers.say(@env.ui, "#{emoji} #{line}")
|
|
107
|
+
compute_entries(machine, machine.config.docker_hosts)
|
|
58
108
|
end
|
|
109
|
+
|
|
110
|
+
if entries.empty?
|
|
111
|
+
say_info(::I18n.t("vdhm.messages.no_entries", default: "No hosts entries configured."), opts)
|
|
112
|
+
Util::Json.emit(action: "apply", status: "noop", data: { reason: "no entries" })
|
|
59
113
|
return 0
|
|
60
114
|
end
|
|
61
115
|
|
|
62
|
-
|
|
116
|
+
return 0 if opts[:dry] && Util::Json.emit(action: "apply", status: "dry-run", data: { entries: entries })
|
|
63
117
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
parse_strict_mapping_from_argv!(argv, @env.ui, opts[:no_emoji], json: opts[:json])
|
|
69
|
-
rescue ArgumentError => e
|
|
70
|
-
Util::Json.emit(action: "apply", status: "error", error: e.message) if opts[:json]
|
|
71
|
-
return 1
|
|
72
|
-
end
|
|
118
|
+
hoster.apply(entries)
|
|
119
|
+
Util::Json.emit(action: "apply", status: "success", data: { entries: entries })
|
|
120
|
+
0
|
|
121
|
+
end
|
|
73
122
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
123
|
+
def validate_apply_mapping(ip, host, opts)
|
|
124
|
+
unless ip && host
|
|
125
|
+
emit_error(::I18n.t("vdhm.messages.missing_mapping",
|
|
126
|
+
default: "Provide both IP and FQDN (e.g. `vagrant hosts apply 1.2.3.4 example.test`)."), opts)
|
|
127
|
+
return 1
|
|
128
|
+
end
|
|
129
|
+
unless ipv4?(ip)
|
|
130
|
+
emit_error(::I18n.t("vdhm.messages.invalid_ip", default: "Invalid IPv4 address: %{ip}", ip: ip), opts)
|
|
131
|
+
return 1
|
|
132
|
+
end
|
|
133
|
+
unless fqdn?(host)
|
|
134
|
+
emit_error(::I18n.t("vdhm.messages.invalid_host", default: "Invalid host/FQDN: %{host}", host: host), opts)
|
|
135
|
+
return 1
|
|
136
|
+
end
|
|
137
|
+
nil
|
|
138
|
+
end
|
|
88
139
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
UiHelpers.error(@env.ui, "#{UiHelpers.e(:error, no_emoji: opts[:no_emoji])} " +
|
|
92
|
-
::I18n.t("messages.missing_mapping",
|
|
93
|
-
default: "Provide both IP and FQDN (e.g. `vagrant hosts apply 1.2.3.4 example.test`)."))
|
|
94
|
-
return 1
|
|
95
|
-
end
|
|
96
|
-
unless ipv4?(ip_for_apply)
|
|
97
|
-
UiHelpers.error(@env.ui, "#{UiHelpers.e(:error, no_emoji: opts[:no_emoji])} " +
|
|
98
|
-
::I18n.t("messages.invalid_ip", default: "Invalid IPv4 address: %{ip}", ip: ip_for_apply))
|
|
99
|
-
return 1
|
|
100
|
-
end
|
|
101
|
-
unless fqdn?(host_for_apply)
|
|
102
|
-
UiHelpers.error(@env.ui, "#{UiHelpers.e(:error, no_emoji: opts[:no_emoji])} " +
|
|
103
|
-
::I18n.t("messages.invalid_host", default: "Invalid host/FQDN: %{host}", host: host_for_apply))
|
|
104
|
-
return 1
|
|
105
|
-
end
|
|
106
|
-
end
|
|
140
|
+
def cmd_remove(argv, opts)
|
|
141
|
+
return remove_all_owners(opts) if opts[:all]
|
|
107
142
|
|
|
108
|
-
|
|
109
|
-
mid = machine.id || "unknown"
|
|
110
|
-
hoster = Util::HostsFile.new({ machine: machine, ui: @env.ui }, owner_id: mid)
|
|
143
|
+
remove_key = parse_remove_key_from_argv!(argv)
|
|
111
144
|
|
|
112
|
-
|
|
113
|
-
UiHelpers.error(@env.ui, "#{UiHelpers.e(:error, no_emoji: opts[:no_emoji])} " +
|
|
114
|
-
::I18n.t("errors.not_admin",
|
|
115
|
-
default: "Administrator/root privileges required to modify hosts at %{path}.",
|
|
116
|
-
path: hoster.printable_path))
|
|
117
|
-
return 1
|
|
118
|
-
end
|
|
145
|
+
machine = require_target_vm("remove", argv, opts) or return 1
|
|
119
146
|
|
|
120
|
-
|
|
121
|
-
|
|
147
|
+
if remove_key && !(ipv4?(remove_key) || fqdn?(remove_key))
|
|
148
|
+
emit_error(::I18n.t("vdhm.messages.invalid_key", default: "Invalid IP or FQDN: %{key}", key: remove_key), opts)
|
|
149
|
+
UiHelpers.error(@env.ui, " " + ::I18n.t("vdhm.messages.remove_expected_format",
|
|
150
|
+
default: "Expected IPv4 (e.g. 172.28.100.2) or FQDN (e.g. example.test)."))
|
|
151
|
+
Util::Json.emit(action: "remove", status: "error", error: "invalid parameter format") if opts[:json]
|
|
152
|
+
return 1
|
|
153
|
+
end
|
|
122
154
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
::I18n.t("messages.no_entries", default: "No hosts entries configured."))
|
|
126
|
-
Util::Json.emit(action: "apply", status: "noop", data: { reason: "no entries" })
|
|
127
|
-
return 0
|
|
128
|
-
end
|
|
155
|
+
mid = machine.id || "unknown"
|
|
156
|
+
hoster = Util::HostsFile.new({ machine: machine, ui: @env.ui }, owner_id: mid)
|
|
129
157
|
|
|
130
|
-
|
|
158
|
+
return remove_filtered(hoster, remove_key, mid, opts) if remove_key
|
|
131
159
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
return 0
|
|
160
|
+
remove_all(machine, hoster, mid, opts)
|
|
161
|
+
end
|
|
135
162
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
)
|
|
149
|
-
)
|
|
150
|
-
Util::Json.emit(action: "remove", status: "error", error: "No target machine found") if opts[:json]
|
|
151
|
-
return 1
|
|
152
|
-
end
|
|
163
|
+
def remove_filtered(hoster, remove_key, mid, opts)
|
|
164
|
+
return 0 if opts[:dry] && Util::Json.emit(action: "remove", status: "dry-run",
|
|
165
|
+
data: { owner: mid, key: remove_key })
|
|
166
|
+
|
|
167
|
+
removed = if ipv4?(remove_key)
|
|
168
|
+
hoster.remove_entries!(ips: [remove_key], domains: [])
|
|
169
|
+
else
|
|
170
|
+
hoster.remove_entries!(ips: [], domains: [remove_key])
|
|
171
|
+
end
|
|
172
|
+
Util::Json.emit(action: "remove", status: "success", data: { removed: removed, mode: "filtered" })
|
|
173
|
+
0
|
|
174
|
+
end
|
|
153
175
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
176
|
+
def remove_all(machine, hoster, mid, opts)
|
|
177
|
+
return 0 if opts[:dry] && Util::Json.emit(action: "remove", status: "dry-run", data: { owner: mid })
|
|
178
|
+
|
|
179
|
+
vm_label = (machine.name rescue nil) || mid
|
|
180
|
+
unless opts[:yes]
|
|
181
|
+
if opts[:json]
|
|
182
|
+
emit_error(::I18n.t("vdhm.errors.confirmation_required",
|
|
183
|
+
default: "Confirmation required: pass --yes to proceed in --json mode."), opts)
|
|
184
|
+
Util::Json.emit(action: "remove", status: "error", error: "confirmation required")
|
|
162
185
|
return 1
|
|
163
186
|
end
|
|
187
|
+
unless confirm_all_removal?(@env.ui, vm_label, no_emoji: opts[:no_emoji])
|
|
188
|
+
say_info(::I18n.t("vdhm.messages.remove_all_cancelled", default: "Cancelled. Nothing removed."), opts)
|
|
189
|
+
Util::Json.emit(action: "remove", status: "cancelled", data: { owner: mid })
|
|
190
|
+
return 0
|
|
191
|
+
end
|
|
192
|
+
end
|
|
164
193
|
|
|
165
|
-
|
|
166
|
-
|
|
194
|
+
removed_block = hoster.remove!
|
|
195
|
+
Util::Json.emit(action: "remove", status: "success", data: { removed: removed_block })
|
|
196
|
+
0
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def remove_all_owners(opts)
|
|
200
|
+
hoster = Util::HostsFile.new({ ui: @env.ui }, owner_id: "any")
|
|
201
|
+
return 0 if opts[:dry] && Util::Json.emit(action: "remove", status: "dry-run", data: { mode: "all" })
|
|
167
202
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
203
|
+
unless opts[:yes]
|
|
204
|
+
if opts[:json]
|
|
205
|
+
emit_error(::I18n.t("vdhm.errors.confirmation_required",
|
|
206
|
+
default: "Confirmation required: pass --yes to proceed in --json mode."), opts)
|
|
207
|
+
Util::Json.emit(action: "remove", status: "error", error: "confirmation required")
|
|
173
208
|
return 1
|
|
174
209
|
end
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
data: { owner: mid, key: remove_key })
|
|
179
|
-
|
|
180
|
-
removed = if ipv4?(remove_key)
|
|
181
|
-
hoster.remove_entries!(ips: [remove_key], domains: [])
|
|
182
|
-
else
|
|
183
|
-
hoster.remove_entries!(ips: [], domains: [remove_key])
|
|
184
|
-
end
|
|
185
|
-
Util::Json.emit(action: "remove", status: "success",
|
|
186
|
-
data: { removed: removed, mode: "filtered" })
|
|
210
|
+
unless confirm_prune?(@env.ui, no_emoji: opts[:no_emoji])
|
|
211
|
+
say_info(::I18n.t("vdhm.messages.remove_all_cancelled", default: "Cancelled. Nothing removed."), opts)
|
|
212
|
+
Util::Json.emit(action: "remove", status: "cancelled", data: { mode: "all" })
|
|
187
213
|
return 0
|
|
188
214
|
end
|
|
215
|
+
end
|
|
189
216
|
|
|
190
|
-
|
|
217
|
+
removed = hoster.remove_all_managed!
|
|
218
|
+
Util::Json.emit(action: "remove", status: "success", data: { removed: removed, mode: "all" })
|
|
219
|
+
0
|
|
220
|
+
end
|
|
191
221
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
Util::Json.emit(action: "remove", status: "cancelled", data: { owner: mid })
|
|
197
|
-
return 0
|
|
198
|
-
end
|
|
222
|
+
def cmd_view(_argv, opts)
|
|
223
|
+
hoster = Util::HostsFile.new({ ui: @env.ui }, owner_id: "any")
|
|
224
|
+
managed_map = hoster.entries_in_blocks(:all)
|
|
225
|
+
pairs = collect_view_pairs({}, managed_map)
|
|
199
226
|
|
|
200
|
-
|
|
201
|
-
Util::Json.emit(action: "
|
|
227
|
+
if opts[:json]
|
|
228
|
+
Util::Json.emit(action: "view", status: "success",
|
|
229
|
+
data: { entries: pairs.map { |ip, fqdn| { ip: ip, host: fqdn } } })
|
|
202
230
|
return 0
|
|
231
|
+
end
|
|
203
232
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
begin
|
|
210
|
-
vm_for_view = nil
|
|
211
|
-
with_target_vms(argv.dup, single_target: true) { |m| vm_for_view = m }
|
|
212
|
-
if vm_for_view
|
|
213
|
-
cfg = vm_for_view.config.docker_hosts
|
|
214
|
-
planned_map = compute_entries(vm_for_view, cfg)
|
|
215
|
-
end
|
|
216
|
-
rescue StandardError
|
|
217
|
-
planned_map = {}
|
|
218
|
-
end
|
|
233
|
+
if pairs.empty?
|
|
234
|
+
say_info(::I18n.t("vdhm.messages.no_entries", default: "No hosts entries configured."), opts)
|
|
235
|
+
return 0
|
|
236
|
+
end
|
|
219
237
|
|
|
220
|
-
|
|
221
|
-
|
|
238
|
+
say_info(::I18n.t("vdhm.messages.view_managed_header", default: "Managed hosts entries:"), opts)
|
|
239
|
+
pad = pairs.map { |ip, _| ip.length }.max || 0
|
|
240
|
+
pairs.each { |ip, fqdn| UiHelpers.say(@env.ui, " • #{ip.ljust(pad)} -> #{fqdn}") }
|
|
241
|
+
0
|
|
242
|
+
end
|
|
222
243
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
seen[key] = true
|
|
229
|
-
end
|
|
244
|
+
def collect_view_pairs(planned_map, managed_map)
|
|
245
|
+
pairs = []
|
|
246
|
+
seen = {}
|
|
247
|
+
add = lambda do |ip, fqdn|
|
|
248
|
+
return if fqdn.to_s.empty? || ip.to_s.empty?
|
|
230
249
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
Array(ips).each do |ip|
|
|
234
|
-
next if ip.to_s.empty?
|
|
235
|
-
key = "#{ip}\0#{fqdn}"
|
|
236
|
-
next if seen[key]
|
|
237
|
-
pairs << [ip.to_s, fqdn.to_s]
|
|
238
|
-
seen[key] = true
|
|
239
|
-
end
|
|
240
|
-
end
|
|
250
|
+
key = "#{ip}\0#{fqdn}"
|
|
251
|
+
return if seen[key]
|
|
241
252
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
status: "success",
|
|
246
|
-
data: { entries: pairs.map { |ip, fqdn| { ip: ip, host: fqdn } } }
|
|
247
|
-
)
|
|
248
|
-
return 0
|
|
249
|
-
end
|
|
253
|
+
pairs << [ip.to_s, fqdn.to_s]
|
|
254
|
+
seen[key] = true
|
|
255
|
+
end
|
|
250
256
|
|
|
251
|
-
|
|
257
|
+
planned_map.each { |fqdn, ip| add.call(ip, fqdn) }
|
|
258
|
+
managed_map.each { |fqdn, ips| Array(ips).each { |ip| add.call(ip, fqdn) } }
|
|
259
|
+
pairs
|
|
260
|
+
end
|
|
252
261
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
end
|
|
262
|
+
def require_target_vm(action, argv, opts)
|
|
263
|
+
machine = nil
|
|
264
|
+
with_target_vms(argv, single_target: true) { |m| machine = m }
|
|
265
|
+
return machine if machine
|
|
258
266
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
end
|
|
265
|
-
|
|
266
|
-
UiHelpers.say(@env.ui, "#{emoji_info} #{header}")
|
|
267
|
-
pad = pairs.map { |ip, _| ip.length }.max || 0
|
|
268
|
-
pairs.each do |ip, fqdn|
|
|
269
|
-
UiHelpers.say(@env.ui, " • #{ip.ljust(pad)} -> #{fqdn}")
|
|
270
|
-
end
|
|
271
|
-
return 0
|
|
267
|
+
emit_error(::I18n.t("vdhm.errors.no_machine",
|
|
268
|
+
default: "No target machine found. Run this inside a Vagrant project or pass a VM name."), opts)
|
|
269
|
+
Util::Json.emit(action: action, status: "error", error: "No target machine found") if opts[:json]
|
|
270
|
+
nil
|
|
271
|
+
end
|
|
272
272
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
return 0
|
|
276
|
-
end
|
|
277
|
-
rescue => e
|
|
278
|
-
Util::Json.emit(action: "command", status: "error", error: e.message)
|
|
279
|
-
1
|
|
273
|
+
def emit_error(message, opts)
|
|
274
|
+
UiHelpers.error(@env.ui, "#{UiHelpers.e(:error, no_emoji: opts[:no_emoji])} #{message}")
|
|
280
275
|
end
|
|
281
276
|
|
|
282
|
-
|
|
277
|
+
def say_info(message, opts)
|
|
278
|
+
UiHelpers.say(@env.ui, "#{UiHelpers.e(:info, no_emoji: opts[:no_emoji])} #{message}")
|
|
279
|
+
end
|
|
283
280
|
|
|
284
281
|
def confirm_all_removal?(ui, vm_label, no_emoji:)
|
|
285
282
|
prompt = ::I18n.t(
|
|
286
|
-
"messages.confirm_remove_all",
|
|
287
|
-
default: "This will remove ALL managed hosts entries for %{vm}. Continue? (
|
|
283
|
+
"vdhm.messages.confirm_remove_all",
|
|
284
|
+
default: "This will remove ALL managed hosts entries for %{vm}. Continue? (y/N)",
|
|
288
285
|
vm: vm_label.to_s
|
|
289
286
|
)
|
|
290
287
|
|
|
@@ -294,7 +291,28 @@ module VagrantDockerHostsManager
|
|
|
294
291
|
$stdout.print(line)
|
|
295
292
|
$stdout.flush
|
|
296
293
|
answer = ($stdin.gets || "").to_s
|
|
297
|
-
rescue
|
|
294
|
+
rescue StandardError
|
|
295
|
+
answer = ""
|
|
296
|
+
ensure
|
|
297
|
+
$stdout.puts ""
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
%w[y yes].include?(answer.strip.downcase)
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
def confirm_prune?(ui, no_emoji:)
|
|
304
|
+
prompt = ::I18n.t(
|
|
305
|
+
"vdhm.messages.confirm_prune",
|
|
306
|
+
default: "This will remove ALL managed hosts blocks from EVERY machine (orphans included). Continue? (y/N)"
|
|
307
|
+
)
|
|
308
|
+
|
|
309
|
+
line = "#{UiHelpers.e(:question, no_emoji: no_emoji)} #{prompt} "
|
|
310
|
+
|
|
311
|
+
begin
|
|
312
|
+
$stdout.print(line)
|
|
313
|
+
$stdout.flush
|
|
314
|
+
answer = ($stdin.gets || "").to_s
|
|
315
|
+
rescue StandardError
|
|
298
316
|
answer = ""
|
|
299
317
|
ensure
|
|
300
318
|
$stdout.puts ""
|
|
@@ -310,13 +328,13 @@ module VagrantDockerHostsManager
|
|
|
310
328
|
cand_ip, cand_host = argv[0], argv[1]
|
|
311
329
|
|
|
312
330
|
unless ipv4?(cand_ip)
|
|
313
|
-
msg = ::I18n.t("messages.invalid_ip", default: "Invalid IPv4 address: %{ip}", ip: cand_ip)
|
|
331
|
+
msg = ::I18n.t("vdhm.messages.invalid_ip", default: "Invalid IPv4 address: %{ip}", ip: cand_ip)
|
|
314
332
|
UiHelpers.error(ui, "#{UiHelpers.e(:error, no_emoji: no_emoji)} #{msg}")
|
|
315
333
|
raise ArgumentError, msg
|
|
316
334
|
end
|
|
317
335
|
|
|
318
336
|
unless fqdn?(cand_host)
|
|
319
|
-
msg = ::I18n.t("messages.invalid_host", default: "Invalid host/FQDN: %{host}", host: cand_host)
|
|
337
|
+
msg = ::I18n.t("vdhm.messages.invalid_host", default: "Invalid host/FQDN: %{host}", host: cand_host)
|
|
320
338
|
UiHelpers.error(ui, "#{UiHelpers.e(:error, no_emoji: no_emoji)} #{msg}")
|
|
321
339
|
raise ArgumentError, msg
|
|
322
340
|
end
|
|
@@ -326,7 +344,7 @@ module VagrantDockerHostsManager
|
|
|
326
344
|
end
|
|
327
345
|
|
|
328
346
|
if ipv4?(argv[0])
|
|
329
|
-
msg = ::I18n.t("messages.missing_mapping",
|
|
347
|
+
msg = ::I18n.t("vdhm.messages.missing_mapping",
|
|
330
348
|
default: "Provide both IP and FQDN (e.g. `vagrant hosts apply 1.2.3.4 example.test`).")
|
|
331
349
|
UiHelpers.error(ui, "#{UiHelpers.e(:error, no_emoji: no_emoji)} #{msg}")
|
|
332
350
|
raise ArgumentError, msg
|
|
@@ -347,17 +365,6 @@ module VagrantDockerHostsManager
|
|
|
347
365
|
s.split(".").all? { |lab| lab =~ /\A[a-zA-Z0-9](?:[a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\z/ }
|
|
348
366
|
end
|
|
349
367
|
|
|
350
|
-
def parse_mapping_from_argv!(argv)
|
|
351
|
-
return [nil, nil] if argv.length < 2
|
|
352
|
-
cand_ip, cand_host = argv[0], argv[1]
|
|
353
|
-
if ipv4?(cand_ip) && cand_host !~ /\A-/
|
|
354
|
-
argv.shift(2)
|
|
355
|
-
[cand_ip, cand_host]
|
|
356
|
-
else
|
|
357
|
-
[nil, nil]
|
|
358
|
-
end
|
|
359
|
-
end
|
|
360
|
-
|
|
361
368
|
def parse_remove_key_from_argv!(argv)
|
|
362
369
|
return nil if argv.empty?
|
|
363
370
|
cand = argv[0]
|
|
@@ -391,47 +398,47 @@ module VagrantDockerHostsManager
|
|
|
391
398
|
return print_topic_help(ui, topic.to_s.downcase.strip, no_emoji: no_emoji) if topic && !topic.to_s.strip.empty?
|
|
392
399
|
|
|
393
400
|
emoji_info = UiHelpers.e(:info, no_emoji: no_emoji)
|
|
394
|
-
title = ::I18n.t("help.title",
|
|
401
|
+
title = ::I18n.t("vdhm.help.title", default: "Vagrant Docker Hosts Manager")
|
|
395
402
|
UiHelpers.say(ui, "#{emoji_info} #{title}")
|
|
396
403
|
|
|
397
|
-
UiHelpers.say(ui, ::I18n.t("help.usage",
|
|
404
|
+
UiHelpers.say(ui, ::I18n.t("vdhm.help.usage",
|
|
398
405
|
default: "Usage: vagrant hosts <apply|remove|view|help|version> [options]"))
|
|
399
406
|
UiHelpers.say(ui, "")
|
|
400
407
|
|
|
401
|
-
UiHelpers.say(ui, ::I18n.t("help.commands_header", default: "Commands:"))
|
|
402
|
-
cmds = ::I18n.t("help.commands", default: {})
|
|
408
|
+
UiHelpers.say(ui, ::I18n.t("vdhm.help.commands_header", default: "Commands:"))
|
|
409
|
+
cmds = ::I18n.t("vdhm.help.commands", default: {})
|
|
403
410
|
cmds = {} unless cmds.is_a?(Hash)
|
|
404
411
|
cmds.each_value { |line| UiHelpers.say(ui, " #{line}") }
|
|
405
412
|
|
|
406
413
|
UiHelpers.say(ui, "")
|
|
407
|
-
UiHelpers.say(ui, ::I18n.t("help.options_header", default: "Options:"))
|
|
408
|
-
optsh = ::I18n.t("help.options", default: {})
|
|
414
|
+
UiHelpers.say(ui, ::I18n.t("vdhm.help.options_header", default: "Options:"))
|
|
415
|
+
optsh = ::I18n.t("vdhm.help.options", default: {})
|
|
409
416
|
optsh = {} unless optsh.is_a?(Hash)
|
|
410
417
|
optsh.each_value { |line| UiHelpers.say(ui, " #{line}") }
|
|
411
418
|
|
|
412
|
-
topics = (::I18n.t("help.topic", default: {}).is_a?(Hash) ? ::I18n.t("help.topic").keys.map(&:to_s) : [])
|
|
419
|
+
topics = (::I18n.t("vdhm.help.topic", default: {}).is_a?(Hash) ? ::I18n.t("vdhm.help.topic").keys.map(&:to_s) : [])
|
|
413
420
|
topics = %w[apply remove view version help] if topics.empty?
|
|
414
421
|
|
|
415
422
|
UiHelpers.say(ui, "")
|
|
416
|
-
UiHelpers.say(ui, ::I18n.t("help.topics_header", default: "Help topics:"))
|
|
423
|
+
UiHelpers.say(ui, ::I18n.t("vdhm.help.topics_header", default: "Help topics:"))
|
|
417
424
|
UiHelpers.say(ui, " vagrant hosts help <#{topics.join('|')}>")
|
|
418
425
|
end
|
|
419
426
|
|
|
420
427
|
def print_topic_help(ui, topic, no_emoji: false)
|
|
421
|
-
base = "help.topic.#{topic}"
|
|
428
|
+
base = "vdhm.help.topic.#{topic}"
|
|
422
429
|
wrench = UiHelpers.e(:info, no_emoji: no_emoji)
|
|
423
430
|
|
|
424
|
-
title = ::I18n.t("
|
|
425
|
-
usage = ::I18n.t("
|
|
426
|
-
desc = ::I18n.t("
|
|
427
|
-
opts_hash = ::I18n.t("
|
|
428
|
-
examples = ::I18n.t("
|
|
429
|
-
|
|
430
|
-
t_head = ::I18n.t("help.topic_header", default: "Help: vagrant hosts %{topic}", topic: topic)
|
|
431
|
-
t_usage = ::I18n.t("help.usage_label", default: "Usage:")
|
|
432
|
-
t_desc = ::I18n.t("help.description_label", default: "Description:")
|
|
433
|
-
t_opts = ::I18n.t("help.options_label", default: "Options:")
|
|
434
|
-
t_exs = ::I18n.t("help.examples_label", default: "Examples:")
|
|
431
|
+
title = ::I18n.t("vdhm.#{base}.title", default: topic)
|
|
432
|
+
usage = ::I18n.t("vdhm.#{base}.usage", default: nil)
|
|
433
|
+
desc = ::I18n.t("vdhm.#{base}.description", default: nil)
|
|
434
|
+
opts_hash = ::I18n.t("vdhm.#{base}.options", default: {})
|
|
435
|
+
examples = ::I18n.t("vdhm.#{base}.examples", default: [])
|
|
436
|
+
|
|
437
|
+
t_head = ::I18n.t("vdhm.help.topic_header", default: "Help: vagrant hosts %{topic}", topic: topic)
|
|
438
|
+
t_usage = ::I18n.t("vdhm.help.usage_label", default: "Usage:")
|
|
439
|
+
t_desc = ::I18n.t("vdhm.help.description_label", default: "Description:")
|
|
440
|
+
t_opts = ::I18n.t("vdhm.help.options_label", default: "Options:")
|
|
441
|
+
t_exs = ::I18n.t("vdhm.help.examples_label", default: "Examples:")
|
|
435
442
|
|
|
436
443
|
UiHelpers.say(ui, "#{wrench} #{t_head}")
|
|
437
444
|
|