podman 1.0.3
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/lib/podman.rb +1 -0
- data/lib/vagrant/podman/action/build.rb +99 -0
- data/lib/vagrant/podman/action/compare_synced_folders.rb +65 -0
- data/lib/vagrant/podman/action/connect_networks.rb +80 -0
- data/lib/vagrant/podman/action/create.rb +165 -0
- data/lib/vagrant/podman/action/destroy.rb +34 -0
- data/lib/vagrant/podman/action/destroy_build_image.rb +51 -0
- data/lib/vagrant/podman/action/destroy_network.rb +53 -0
- data/lib/vagrant/podman/action/forwarded_ports.rb +36 -0
- data/lib/vagrant/podman/action/has_ssh.rb +21 -0
- data/lib/vagrant/podman/action/host_machine.rb +75 -0
- data/lib/vagrant/podman/action/host_machine_build_dir.rb +49 -0
- data/lib/vagrant/podman/action/host_machine_port_checker.rb +34 -0
- data/lib/vagrant/podman/action/host_machine_port_warning.rb +40 -0
- data/lib/vagrant/podman/action/host_machine_required.rb +20 -0
- data/lib/vagrant/podman/action/host_machine_sync_folders.rb +176 -0
- data/lib/vagrant/podman/action/host_machine_sync_folders_disable.rb +91 -0
- data/lib/vagrant/podman/action/init_state.rb +23 -0
- data/lib/vagrant/podman/action/is_build.rb +19 -0
- data/lib/vagrant/podman/action/is_host_machine_created.rb +32 -0
- data/lib/vagrant/podman/action/login.rb +51 -0
- data/lib/vagrant/podman/action/prepare_forwarded_port_collision_params.rb +64 -0
- data/lib/vagrant/podman/action/prepare_networks.rb +397 -0
- data/lib/vagrant/podman/action/prepare_nfs_settings.rb +60 -0
- data/lib/vagrant/podman/action/prepare_nfs_valid_ids.rb +22 -0
- data/lib/vagrant/podman/action/prepare_ssh.rb +48 -0
- data/lib/vagrant/podman/action/pull.rb +30 -0
- data/lib/vagrant/podman/action/start.rb +24 -0
- data/lib/vagrant/podman/action/stop.rb +24 -0
- data/lib/vagrant/podman/action/wait_for_running.rb +71 -0
- data/lib/vagrant/podman/action.rb +319 -0
- data/lib/vagrant/podman/cap/has_communicator.rb +14 -0
- data/lib/vagrant/podman/cap/proxy_machine.rb +15 -0
- data/lib/vagrant/podman/cap/public_address.rb +26 -0
- data/lib/vagrant/podman/command/exec.rb +112 -0
- data/lib/vagrant/podman/command/logs.rb +111 -0
- data/lib/vagrant/podman/command/run.rb +76 -0
- data/lib/vagrant/podman/communicator.rb +199 -0
- data/lib/vagrant/podman/config.rb +368 -0
- data/lib/vagrant/podman/driver/compose.rb +315 -0
- data/lib/vagrant/podman/driver.rb +417 -0
- data/lib/vagrant/podman/errors.rb +108 -0
- data/lib/vagrant/podman/executor/local.rb +48 -0
- data/lib/vagrant/podman/executor/vagrant.rb +88 -0
- data/lib/vagrant/podman/hostmachine/Vagrantfile +3 -0
- data/lib/vagrant/podman/plugin.rb +89 -0
- data/lib/vagrant/podman/provider.rb +216 -0
- data/lib/vagrant/podman/synced_folder.rb +35 -0
- data/templates/locales/providers_podman.yml +321 -0
- metadata +103 -0
@@ -0,0 +1,315 @@
|
|
1
|
+
# Copyright (c) HashiCorp, Inc.
|
2
|
+
# SPDX-License-Identifier: BUSL-1.1
|
3
|
+
|
4
|
+
require "json"
|
5
|
+
require "log4r"
|
6
|
+
|
7
|
+
module VagrantPlugins
|
8
|
+
module PodmanProvider
|
9
|
+
class Driver
|
10
|
+
class Compose < Driver
|
11
|
+
|
12
|
+
# @return [Integer] Maximum number of seconds to wait for lock
|
13
|
+
LOCK_TIMEOUT = 60
|
14
|
+
# @return [String] Compose file format version
|
15
|
+
COMPOSE_VERSION = "2".freeze
|
16
|
+
|
17
|
+
# @return [Pathname] data directory to store composition
|
18
|
+
attr_reader :data_directory
|
19
|
+
# @return [Vagrant::Machine]
|
20
|
+
attr_reader :machine
|
21
|
+
|
22
|
+
# Create a new driver instance
|
23
|
+
#
|
24
|
+
# @param [Vagrant::Machine] machine Machine instance for this driver
|
25
|
+
def initialize(machine)
|
26
|
+
if !Vagrant::Util::Which.which("podman-compose")
|
27
|
+
raise Errors::PodmanComposeNotInstalledError
|
28
|
+
end
|
29
|
+
super()
|
30
|
+
@machine = machine
|
31
|
+
@data_directory = Pathname.new(machine.env.local_data_path).
|
32
|
+
join("podman-compose")
|
33
|
+
@data_directory.mkpath
|
34
|
+
@logger = Log4r::Logger.new("vagrant::podman::driver::compose")
|
35
|
+
@compose_lock = Mutex.new
|
36
|
+
@logger.debug("Podman compose driver initialize for machine `#{@machine.name}` (`#{@machine.id}`)")
|
37
|
+
@logger.debug("Data directory for composition file `#{@data_directory}`")
|
38
|
+
end
|
39
|
+
|
40
|
+
# Updates the podman compose config file with the given arguments
|
41
|
+
#
|
42
|
+
# @param [String] dir - local directory or git repo URL
|
43
|
+
# @param [Hash] opts - valid key: extra_args
|
44
|
+
# @param [Block] block
|
45
|
+
# @return [Nil]
|
46
|
+
def build(dir, **opts, &block)
|
47
|
+
name = machine.name.to_s
|
48
|
+
@logger.debug("Applying build for `#{name}` using `#{dir}` directory.")
|
49
|
+
begin
|
50
|
+
update_composition do |composition|
|
51
|
+
services = composition["services"] ||= {}
|
52
|
+
services[name] ||= {}
|
53
|
+
services[name]["build"] = {"context" => dir}
|
54
|
+
# Extract custom podmanfile location if set
|
55
|
+
if opts[:extra_args] && opts[:extra_args].include?("--file")
|
56
|
+
services[name]["build"]["podmanfile"] = opts[:extra_args][opts[:extra_args].index("--file") + 1]
|
57
|
+
end
|
58
|
+
# Extract any build args that can be found
|
59
|
+
case opts[:extra_args]
|
60
|
+
when Array
|
61
|
+
if opts[:extra_args].include?("--build-arg")
|
62
|
+
idx = 0
|
63
|
+
extra_args = {}
|
64
|
+
while(idx < opts[:extra_args].size)
|
65
|
+
arg_value = opts[:extra_args][idx]
|
66
|
+
idx += 1
|
67
|
+
if arg_value.start_with?("--build-arg")
|
68
|
+
if !arg_value.include?("=")
|
69
|
+
arg_value = opts[:extra_args][idx]
|
70
|
+
idx += 1
|
71
|
+
end
|
72
|
+
key, val = arg_value.to_s.split("=", 2).to_s.split("=")
|
73
|
+
extra_args[key] = val
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
when Hash
|
78
|
+
services[name]["build"]["args"] = opts[:extra_args]
|
79
|
+
end
|
80
|
+
end
|
81
|
+
rescue => error
|
82
|
+
@logger.error("Failed to apply build using `#{dir}` directory: #{error.class} - #{error}")
|
83
|
+
update_composition do |composition|
|
84
|
+
composition["services"].delete(name)
|
85
|
+
end
|
86
|
+
raise
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def create(params, **opts, &block)
|
91
|
+
# NOTE: Use the direct machine name as we don't
|
92
|
+
# need to worry about uniqueness with compose
|
93
|
+
name = machine.name.to_s
|
94
|
+
image = params.fetch(:image)
|
95
|
+
links = Array(params.fetch(:links, [])).map do |link|
|
96
|
+
case link
|
97
|
+
when Array
|
98
|
+
link
|
99
|
+
else
|
100
|
+
link.to_s.split(":")
|
101
|
+
end
|
102
|
+
end
|
103
|
+
ports = Array(params[:ports])
|
104
|
+
volumes = Array(params[:volumes]).map do |v|
|
105
|
+
v = v.to_s
|
106
|
+
host, guest = v.split(":", 2)
|
107
|
+
if v.include?(":") && (Vagrant::Util::Platform.windows? || Vagrant::Util::Platform.wsl?)
|
108
|
+
host = Vagrant::Util::Platform.windows_path(host)
|
109
|
+
# NOTE: Podman does not support UNC style paths (which also
|
110
|
+
# means that there's no long path support). Hopefully this
|
111
|
+
# will be fixed someday and the gsub below can be removed.
|
112
|
+
host.gsub!(/^[^A-Za-z]+/, "")
|
113
|
+
end
|
114
|
+
# if host path is a volume key, don't expand it.
|
115
|
+
# if both exist (a path and a key) show warning and move on
|
116
|
+
# otherwise assume it's a realative path and expand the host path
|
117
|
+
compose_config = get_composition
|
118
|
+
if compose_config["volumes"] && compose_config["volumes"].keys.include?(host)
|
119
|
+
if File.directory?(@machine.env.cwd.join(host).to_s)
|
120
|
+
@machine.env.ui.warn(I18n.t("podman_provider.volume_path_not_expanded",
|
121
|
+
host: host))
|
122
|
+
end
|
123
|
+
else
|
124
|
+
@logger.debug("Path expanding #{host} to current Vagrant working dir instead of podman-compose config file directory")
|
125
|
+
host = @machine.env.cwd.join(host).to_s
|
126
|
+
end
|
127
|
+
"#{host}:#{guest}"
|
128
|
+
end
|
129
|
+
cmd = Array(params.fetch(:cmd))
|
130
|
+
env = Hash[*params.fetch(:env).flatten.map(&:to_s)]
|
131
|
+
expose = Array(params[:expose])
|
132
|
+
@logger.debug("Creating container `#{name}`")
|
133
|
+
begin
|
134
|
+
update_args = [:apply]
|
135
|
+
update_args.push(:detach) if params[:detach]
|
136
|
+
update_args << block
|
137
|
+
update_composition(*update_args) do |composition|
|
138
|
+
services = composition["services"] ||= {}
|
139
|
+
services[name] ||= {}
|
140
|
+
if params[:extra_args].is_a?(Hash)
|
141
|
+
services[name].merge!(
|
142
|
+
Hash[
|
143
|
+
params[:extra_args].map{ |k, v|
|
144
|
+
[k.to_s, v]
|
145
|
+
}
|
146
|
+
]
|
147
|
+
)
|
148
|
+
end
|
149
|
+
services[name].merge!(
|
150
|
+
"environment" => env,
|
151
|
+
"expose" => expose,
|
152
|
+
"ports" => ports,
|
153
|
+
"volumes" => volumes,
|
154
|
+
"links" => links,
|
155
|
+
"command" => cmd
|
156
|
+
)
|
157
|
+
services[name]["image"] = image if image
|
158
|
+
services[name]["hostname"] = params[:hostname] if params[:hostname]
|
159
|
+
services[name]["privileged"] = true if params[:privileged]
|
160
|
+
services[name]["pty"] = true if params[:pty]
|
161
|
+
end
|
162
|
+
rescue => error
|
163
|
+
@logger.error("Failed to create container `#{name}`: #{error.class} - #{error}")
|
164
|
+
update_composition do |composition|
|
165
|
+
composition["services"].delete(name)
|
166
|
+
end
|
167
|
+
raise
|
168
|
+
end
|
169
|
+
get_container_id(name)
|
170
|
+
end
|
171
|
+
|
172
|
+
def rm(cid)
|
173
|
+
if created?(cid)
|
174
|
+
destroy = false
|
175
|
+
synchronized do
|
176
|
+
compose_execute("rm", "-f", machine.name.to_s)
|
177
|
+
update_composition do |composition|
|
178
|
+
if composition["services"] && composition["services"].key?(machine.name.to_s)
|
179
|
+
@logger.info("Removing container `#{machine.name}`")
|
180
|
+
if composition["services"].size > 1
|
181
|
+
composition["services"].delete(machine.name.to_s)
|
182
|
+
else
|
183
|
+
destroy = true
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
if destroy
|
188
|
+
@logger.info("No containers remain. Destroying full environment.")
|
189
|
+
compose_execute("down", "--volumes", "--rmi", "local")
|
190
|
+
@logger.info("Deleting composition path `#{composition_path}`")
|
191
|
+
composition_path.delete
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
def rmi(*_)
|
198
|
+
true
|
199
|
+
end
|
200
|
+
|
201
|
+
def created?(cid)
|
202
|
+
result = super
|
203
|
+
if !result
|
204
|
+
composition = get_composition
|
205
|
+
if composition["services"] && composition["services"].has_key?(machine.name.to_s)
|
206
|
+
result = true
|
207
|
+
end
|
208
|
+
end
|
209
|
+
result
|
210
|
+
end
|
211
|
+
|
212
|
+
private
|
213
|
+
|
214
|
+
# Lookup the ID for the container with the given name
|
215
|
+
#
|
216
|
+
# @param [String] name Name of container
|
217
|
+
# @return [String] Container ID
|
218
|
+
def get_container_id(name)
|
219
|
+
compose_execute("ps", "-q", name).chomp
|
220
|
+
end
|
221
|
+
|
222
|
+
# Execute a `podman-compose` command
|
223
|
+
def compose_execute(*cmd, **opts, &block)
|
224
|
+
synchronized do
|
225
|
+
execute("podman-compose", "-f", composition_path.to_s,
|
226
|
+
"-p", machine.env.cwd.basename.to_s, *cmd, **opts, &block)
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
# Apply any changes made to the composition
|
231
|
+
def apply_composition!(*args)
|
232
|
+
block = args.detect{|arg| arg.is_a?(Proc) }
|
233
|
+
execute_args = ["up", "--remove-orphans"]
|
234
|
+
if args.include?(:detach)
|
235
|
+
execute_args << "-d"
|
236
|
+
end
|
237
|
+
machine.env.lock("compose", retry: true) do
|
238
|
+
if block
|
239
|
+
compose_execute(*execute_args, &block)
|
240
|
+
else
|
241
|
+
compose_execute(*execute_args)
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
# Update the composition and apply changes if requested
|
247
|
+
#
|
248
|
+
# @param [Boolean] apply Apply composition changes
|
249
|
+
def update_composition(*args)
|
250
|
+
synchronized do
|
251
|
+
machine.env.lock("compose", retry: true) do
|
252
|
+
composition = get_composition
|
253
|
+
result = yield composition
|
254
|
+
write_composition(composition)
|
255
|
+
if args.include?(:apply) || (args.include?(:conditional) && result)
|
256
|
+
apply_composition!(*args)
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
# @return [Hash] current composition contents
|
263
|
+
def get_composition
|
264
|
+
composition = {"version" => COMPOSE_VERSION.dup}
|
265
|
+
if composition_path.exist?
|
266
|
+
composition = Vagrant::Util::DeepMerge.deep_merge(composition, YAML.load(composition_path.read))
|
267
|
+
end
|
268
|
+
composition = Vagrant::Util::DeepMerge.deep_merge(composition, machine.provider_config.compose_configuration.dup)
|
269
|
+
@logger.debug("Fetched composition with provider configuration applied: #{composition}")
|
270
|
+
composition
|
271
|
+
end
|
272
|
+
|
273
|
+
# Save the composition
|
274
|
+
#
|
275
|
+
# @param [Hash] composition New composition
|
276
|
+
def write_composition(composition)
|
277
|
+
@logger.debug("Saving composition to `#{composition_path}`: #{composition}")
|
278
|
+
tmp_file = Tempfile.new("vagrant-podman-compose")
|
279
|
+
tmp_file.write(composition.to_yaml)
|
280
|
+
tmp_file.close
|
281
|
+
synchronized do
|
282
|
+
FileUtils.mv(tmp_file.path, composition_path.to_s)
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
# @return [Pathname] path to the podman-compose.yml file
|
287
|
+
def composition_path
|
288
|
+
data_directory.join("podman-compose.yml")
|
289
|
+
end
|
290
|
+
|
291
|
+
def synchronized
|
292
|
+
if !@compose_lock.owned?
|
293
|
+
timeout = LOCK_TIMEOUT.to_f
|
294
|
+
until @compose_lock.owned?
|
295
|
+
if @compose_lock.try_lock
|
296
|
+
if timeout > 0
|
297
|
+
timeout -= sleep(1)
|
298
|
+
else
|
299
|
+
raise Errors::ComposeLockTimeoutError
|
300
|
+
end
|
301
|
+
end
|
302
|
+
end
|
303
|
+
got_lock = true
|
304
|
+
end
|
305
|
+
begin
|
306
|
+
result = yield
|
307
|
+
ensure
|
308
|
+
@compose_lock.unlock if got_lock
|
309
|
+
end
|
310
|
+
result
|
311
|
+
end
|
312
|
+
end
|
313
|
+
end
|
314
|
+
end
|
315
|
+
end
|