vagrant-docker-networks-manager 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: a02b353f50a855257d0e7e7f72279b47666e4f6131c2b621a3d58d3b6a4780ed
4
+ data.tar.gz: 3a2ac68c851a9b6c54ed3aec26c7394086013ac902dcafa19fcc245d6a5da23d
5
+ SHA512:
6
+ metadata.gz: 9d61692ed4dcfd31642630109b346c3c13d7d3adc13473a2a777c5add55f5cdb4b56e29992f72a49d1af59e4915c06c039a4cc0d186bcc6a7867c3eb0f1b50d6
7
+ data.tar.gz: 30c99e6849d84e5ba1d2fe5d378bd195be123e7fad9c55addc3369ddc612d7ff98a73ce7e45a239aebe5f4853576892d330eaacb0082d7cf361edd24b0675f73
data/CHANGELOG.md ADDED
@@ -0,0 +1,16 @@
1
+ # Changelog
2
+
3
+ ## [0.1.1](https://github.com/julienpoirou/vagrant-docker-networks-manager/compare/v0.1.0...v0.1.1) (2025-08-17)
4
+
5
+
6
+ ### CI 🧑‍💻
7
+
8
+ * **release-please:** Add issues:write permission ([1c959e0](https://github.com/julienpoirou/vagrant-docker-networks-manager/commit/1c959e04ac86bc7a81363cf4029e0dc52acfc5f7))
9
+ * **release-please:** Point to dotfiles config ([d123be2](https://github.com/julienpoirou/vagrant-docker-networks-manager/commit/d123be274d8aac8d4f2de2de40df976b58f29a2e))
10
+ * **release-please:** Use generic updater for VERSION file ([#3](https://github.com/julienpoirou/vagrant-docker-networks-manager/issues/3)) ([1cc3003](https://github.com/julienpoirou/vagrant-docker-networks-manager/commit/1cc30033cef9b8be87255c45dd82a1ebe1877e7f))
11
+
12
+
13
+ ### Maintenance đź§ą
14
+
15
+ * **ci:** Unblock CI => RSpec shim & RuboCop config baseline ([#1](https://github.com/julienpoirou/vagrant-docker-networks-manager/issues/1)) ([2e4a1df](https://github.com/julienpoirou/vagrant-docker-networks-manager/commit/2e4a1df9d0d46063c908765d7fbfd17a55fe3f9a))
16
+ * **init:** Bootstrap plugin, CI, CodeQL, Release, Docs ([2b71a69](https://github.com/julienpoirou/vagrant-docker-networks-manager/commit/2b71a69e2b1eb1dd87cdf75b6e9ed1c350afd366))
data/LICENSE.md ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+ ===========
3
+
4
+ Copyright (c) 2025 Julien Poirou <julienpoirou@protonmail.com>
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the “Software”), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in
14
+ all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,320 @@
1
+ # vagrant-docker-networks-manager
2
+
3
+ [![CI](https://github.com/julienpoirou/vagrant-docker-networks-manager/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/julienpoirou/vagrant-docker-networks-manager/actions/workflows/ci.yml)
4
+ [![CodeQL](https://github.com/julienpoirou/vagrant-docker-networks-manager/actions/workflows/codeql.yml/badge.svg)](https://github.com/julienpoirou/vagrant-docker-networks-manager/actions/workflows/codeql.yml)
5
+ [![Release](https://img.shields.io/github/v/release/julienpoirou/vagrant-docker-networks-manager?include_prereleases&sort=semver)](https://github.com/julienpoirou/vagrant-docker-networks-manager/releases)
6
+ [![RubyGems](https://img.shields.io/gem/v/vagrant-docker-networks-manager.svg)](https://rubygems.org/gems/vagrant-docker-networks-manager)
7
+ [![License](https://img.shields.io/github/license/julienpoirou/vagrant-docker-networks-manager.svg)](LICENSE.md)
8
+ [![Conventional Commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-%23FE5196.svg)](https://www.conventionalcommits.org)
9
+ [![Renovate](https://img.shields.io/badge/Renovate-enabled-brightgreen.svg)](https://renovatebot.com)
10
+
11
+ Vagrant plugin to **manage Docker networks** with labeled ownership, safe lifecycle hooks, JSON output, and conflict-aware validation.
12
+
13
+ - Creates a Docker network on `vagrant up` (with labels & marker)
14
+ - Cleans it on `vagrant destroy` **only if owned by this machine** (safe)
15
+ - `vagrant network` CLI: `init | destroy | info | reload | list | prune | rename`
16
+ - IPv4/CIDR validation, subnet conflict detection, optional macvlan
17
+ - i18n (English 🇬🇧 / Français 🇫🇷), emojis, and normalized JSON output
18
+
19
+ > Requirements: **Vagrant ≥ 2.2**, **Ruby ≥ 3.1**, **Docker (CLI + daemon) running**
20
+
21
+ ---
22
+
23
+ ## Table of contents
24
+
25
+ - [Why this plugin?](#why-this-plugin)
26
+ - [Installation](#installation)
27
+ - [Quick start](#quick-start)
28
+ - [Vagrantfile configuration](#vagrantfile-configuration)
29
+ - [CLI usage](#cli-usage)
30
+ - [JSON output examples](#json-output-examples)
31
+ - [Ownership & safety](#ownership--safety)
32
+ - [Subnet validation & conflicts](#subnet-validation--conflicts)
33
+ - [Internationalization](#internationalization)
34
+ - [Environment variables](#environment-variables)
35
+ - [Permissions & OS notes](#permissions--os-notes)
36
+ - [Troubleshooting](#troubleshooting)
37
+ - [Contributing & Development](#contributing--development)
38
+ - [License](#license)
39
+
40
+ > 🇫🇷 **Français :** voir [README.fr.md](README.fr.md)
41
+
42
+ ---
43
+
44
+ ## Why this plugin?
45
+
46
+ Managing Docker networks across Vagrant projects is tedious:
47
+
48
+ - naming consistency, subnet overlaps, and safe cleanup are error-prone
49
+ - destroying a VM shouldn’t delete someone else’s shared network
50
+ - operators need deterministic CLI **and** machine-readable output
51
+
52
+ This plugin solves these by **labeling** networks, keeping a **marker** per machine, validating **CIDR** + detecting **overlaps**, and offering a clean **CLI** with **JSON** output.
53
+
54
+ ---
55
+
56
+ ## Installation
57
+
58
+ From RubyGems (once published):
59
+
60
+ ```bash
61
+ vagrant plugin install vagrant-docker-networks-manager
62
+ ```
63
+
64
+ From source (local path):
65
+
66
+ ```bash
67
+ git clone https://github.com/julienpoirou/vagrant-docker-networks-manager
68
+ cd vagrant-docker-networks-manager
69
+ bundle install
70
+ rake
71
+ vagrant plugin install . # install from the local gemspec
72
+ ```
73
+
74
+ Check it’s available:
75
+
76
+ ```bash
77
+ vagrant network version
78
+ vagrant network help
79
+ ```
80
+
81
+ ---
82
+
83
+ ## Quick start
84
+
85
+ ### Minimal Vagrantfile
86
+
87
+ ```ruby
88
+ Vagrant.configure("2") do |config|
89
+ config.vm.box = "hashicorp/ubuntu-22.04"
90
+
91
+ # Docker network plugin config
92
+ config.docker_network.network_name = "myproj_net" # ⚠️ personalize to avoid collisions
93
+ config.docker_network.network_subnet = "172.28.50.0/24"
94
+ config.docker_network.network_gateway = "172.28.50.1"
95
+ config.docker_network.network_type = "bridge" # or "macvlan"
96
+ config.docker_network.network_parent = nil # required if macvlan
97
+ config.docker_network.network_attachable = true
98
+ config.docker_network.enable_ipv6 = false
99
+ config.docker_network.ip_range = nil # optional
100
+ config.docker_network.cleanup_on_destroy = true
101
+ config.docker_network.locale = "en" # "en" or "fr"
102
+ end
103
+ ```
104
+
105
+ ### Create the network on `up`
106
+
107
+ ```bash
108
+ vagrant up
109
+ ```
110
+
111
+ If a network with the same name already exists:
112
+ - if it’s **owned** by this machine (labels match), it’s “adopted”
113
+ - otherwise you simply get an info message (no destructive action)
114
+
115
+ ### Destroy VM and clean the network
116
+
117
+ ```bash
118
+ vagrant destroy
119
+ ```
120
+
121
+ - The network is removed **only** if created/owned by this machine.
122
+ - To also remove attached containers during Vagrant destroy:
123
+
124
+ ```bash
125
+ VDNM_DESTROY_WITH_CONTAINERS=1 vagrant destroy
126
+ ```
127
+
128
+ ---
129
+
130
+ ## Vagrantfile configuration
131
+
132
+ All options (with defaults):
133
+
134
+ | Key | Type | Default | Notes |
135
+ |----------------------------|---------|--------------------|-------|
136
+ | `network_name` | String | `"network_lo1"` | ⚠️ Personalize to avoid collisions across projects. |
137
+ | `network_subnet` | String | `"172.28.100.0/26"`| Must be **aligned** IPv4/CIDR (e.g. `x.y.z.0/nn`). |
138
+ | `network_type` | String | `"bridge"` | `"bridge"` or `"macvlan"`. |
139
+ | `network_gateway` | String | `"172.28.100.1"` | Must be a **host** address inside `network_subnet`. |
140
+ | `network_parent` | String | `nil` | **Required** if `network_type == "macvlan"`. |
141
+ | `network_attachable` | Bool | `false` | Adds `--attachable`. |
142
+ | `enable_ipv6` | Bool | `false` | Adds `--ipv6`. |
143
+ | `ip_range` | String | `nil` | IPv4/CIDR **inside** `network_subnet`. |
144
+ | `cleanup_on_destroy` | Bool | `true` | Remove network on `vagrant destroy` if owned/created. |
145
+ | `locale` | String | `"en"` | `"en"` or `"fr"`. |
146
+
147
+ Validation performed:
148
+ - Docker name constraints, aligned IPv4/CIDR, `gateway` not network/broadcast
149
+ - `ip_range` must be included in `network_subnet`
150
+ - `macvlan` requires `network_parent`
151
+
152
+ ---
153
+
154
+ ## CLI usage
155
+
156
+ ```
157
+ vagrant network <command> [args] [options]
158
+
159
+ Commands:
160
+ init <name> <subnet>
161
+ destroy <name> [--with-containers] [--yes]
162
+ reload <name> [--yes]
163
+ info <name>
164
+ list [--json]
165
+ prune [--yes]
166
+ rename <old> <new> [<subnet>] [--yes]
167
+
168
+ Global options:
169
+ --json # machine-readable output
170
+ --yes, -y # auto-confirm prompts
171
+ --quiet # reduce output (hide info)
172
+ --no-emoji # disable emojis
173
+ --lang en|fr # force language
174
+ ```
175
+
176
+ Examples:
177
+
178
+ ```bash
179
+ vagrant network init mynet 172.28.100.0/26
180
+ vagrant network info mynet
181
+ vagrant network list
182
+ vagrant network destroy mynet --with-containers --yes
183
+ vagrant network reload mynet --yes
184
+ vagrant network rename oldnet newnet --yes
185
+ vagrant network rename oldnet same-name 10.10.0.0/24 --yes
186
+ vagrant network prune --yes
187
+ ```
188
+
189
+ ---
190
+
191
+ ## JSON output examples
192
+
193
+ Enable with `--json` for any command.
194
+
195
+ **init**
196
+ ```json
197
+ {"action":"init","status":"success","data":{"name":"mynet","subnet":"172.28.100.0/26"}}
198
+ ```
199
+
200
+ **info**
201
+ ```json
202
+ {
203
+ "action":"info",
204
+ "status":"success",
205
+ "data":{
206
+ "network":{
207
+ "Name":"mynet",
208
+ "Id":"...docker-id...",
209
+ "Driver":"bridge",
210
+ "Subnets":["172.28.100.0/26"],
211
+ "Containers":[{"Name":"web","IPv4":"172.28.100.2/26"}]
212
+ }
213
+ }
214
+ }
215
+ ```
216
+
217
+ **prune (nothing to do)**
218
+ ```json
219
+ {"action":"prune","status":"success","data":{"pruned":0,"items":[]}}
220
+ ```
221
+
222
+ Errors are normalized:
223
+ ```json
224
+ {"action":"destroy","status":"error","error":"Network not found.","data":{"name":"ghost"}, "code":1}
225
+ ```
226
+
227
+ ---
228
+
229
+ ## Ownership & safety
230
+
231
+ - Networks are created with labels:
232
+ - `com.vagrant.plugin=docker_networks_manager`
233
+ - `com.vagrant.machine_id=<VAGRANT_MACHINE_ID>`
234
+ - A **marker file** is also written in:
235
+ `.vagrant/machines/<name>/<provider>/docker-networks/<network>.json`
236
+
237
+ On `vagrant destroy`, the plugin **only removes** a network if:
238
+ - the marker indicates it was created by this machine, **or**
239
+ - labels match this machine’s id (ownership)
240
+
241
+ If a network exists but is not owned, the plugin leaves it untouched.
242
+
243
+ ---
244
+
245
+ ## Subnet validation & conflicts
246
+
247
+ Before creating (or renaming to a new subnet), the plugin:
248
+
249
+ 1. Validates `network_subnet` is an **aligned IPv4/CIDR**
250
+ (e.g. `172.28.100.0/24`, not `172.28.100.1/24`)
251
+ 2. Scans existing Docker networks and checks for **overlaps**
252
+ (ignoring the target network when appropriate)
253
+
254
+ This prevents hard-to-debug IP conflicts.
255
+
256
+ ---
257
+
258
+ ## Internationalization
259
+
260
+ - Locales: **en**, **fr**
261
+ - Choose via CLI `--lang en|fr`, or set `locale` in your Vagrantfile, or `VDNM_LANG=en|fr`.
262
+
263
+ Emojis can be disabled with `--no-emoji`.
264
+
265
+ ---
266
+
267
+ ## Environment variables
268
+
269
+ | Variable | Purpose |
270
+ |----------------------------------|---------|
271
+ | `VDNM_LANG` | Force locale (`en`/`fr`) in hooks. |
272
+ | `VDNM_VERBOSE` | When `1`, prints the full `docker` command on STDERR and shows the native Docker output. |
273
+ | `VDNM_SKIP_CONFLICTS` | When `1`, the reload ignores subnet conflict detection (dangerous, for experts only). |
274
+ | `VDNM_DESTROY_WITH_CONTAINERS` | When `1`, on Vagrant destroy the plugin also runs `docker rm -f` for attached containers (in addition to disconnect). |
275
+
276
+ > The CLI `vagrant network destroy <name> --with-containers` achieves the same for the **manual command**.
277
+
278
+ ---
279
+
280
+ ## Permissions & OS notes
281
+
282
+ - **Linux / macOS**: modifying `/etc/hosts` requires privileges. The plugin pipes through `sudo tee -a` when appending, and writes the file when removing. You may be prompted for your password.
283
+ - **Windows**: the plugin uses **PowerShell elevation** (`Start-Process -Verb RunAs`) when needed to append or rewrite the hosts file.
284
+
285
+ > If your shell is already elevated (root/Admin), no prompts appear.
286
+
287
+ ---
288
+
289
+ ## Troubleshooting
290
+
291
+ - **Docker is unavailable**: ensure Docker Desktop/daemon is running and the CLI works (`docker info`).
292
+ - **Invalid subnet**: use aligned IPv4/CIDR (e.g. `10.0.0.0/24`).
293
+ - **Subnet already in use**: another network overlaps. Pick a different range.
294
+ - **Remove failed**: some containers or other constraints may block `docker network rm`. Try `--verbose` (`VDNM_VERBOSE=1`) to see Docker’s output.
295
+ - **macvlan**: remember to set `network_parent` (host interface).
296
+
297
+ ---
298
+
299
+ ## Contributing & Development
300
+
301
+ ```bash
302
+ git clone https://github.com/julienpoirou/vagrant-docker-networks-manager
303
+ cd vagrant-docker-networks-manager
304
+ bundle install
305
+ rake # runs RSpec
306
+ ```
307
+
308
+ - Conventional Commits enforced in PRs.
309
+ - CI runs RuboCop, tests, and builds the gem.
310
+ - See `docs/en/CONTRIBUTING.md` and `docs/en/DEVELOPMENT.md` if present.
311
+
312
+ ---
313
+
314
+ ## License
315
+
316
+ MIT © 2025 [Julien Poirou](mailto:julienpoirou@protonmail.com)
317
+
318
+ ---
319
+
320
+ > Tip: prefer setting a **project-specific** `network_name` (e.g. `myapp_net`) to avoid collisions if multiple Vagrant projects run on the same host.
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,204 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require "fileutils"
5
+ require "time"
6
+ require "shellwords"
7
+ require "open3"
8
+ require_relative "helpers"
9
+ require_relative "util"
10
+ require_relative "network_builder"
11
+ require_relative "version"
12
+
13
+ module VagrantDockerNetworksManager
14
+ class ActionUp
15
+ def initialize(app, _env); @app = app; end
16
+
17
+ def call(env)
18
+ UiHelpers.setup_i18n!
19
+ cfg = env[:machine].config.docker_network
20
+ set_locale!(cfg)
21
+
22
+ unless Util.docker_available?
23
+ env[:ui].error("#{UiHelpers.e(:error)} #{I18n.t('errors.docker_unavailable')}")
24
+ return @app.call(env)
25
+ end
26
+
27
+ name = cfg.network_name
28
+ mid = env[:machine].id
29
+
30
+ if Util.docker_network_exists?(name)
31
+ if owned_by_this_machine?(name, mid)
32
+ write_marker(env, name, cfg)
33
+ env[:ui].info("#{UiHelpers.e(:success)} #{I18n.t('messages.network_exists_adopted', name: name)}")
34
+ else
35
+ env[:ui].info("#{UiHelpers.e(:info)} #{I18n.t('messages.network_exists', name: name)}")
36
+ end
37
+ else
38
+ subnet_label = cfg.network_subnet || "-"
39
+
40
+ if cfg.network_subnet && !VagrantDockerNetworksManager::Util.valid_subnet?(cfg.network_subnet)
41
+ env[:ui].error("#{UiHelpers.e(:error)} #{I18n.t('errors.invalid_subnet')}")
42
+ return @app.call(env)
43
+ end
44
+
45
+ if cfg.network_subnet &&
46
+ VagrantDockerNetworksManager::Util.docker_subnet_conflicts?(
47
+ cfg.network_subnet,
48
+ ignore_network: name
49
+ )
50
+ env[:ui].error("#{UiHelpers.e(:error)} #{I18n.t('errors.subnet_in_use')}")
51
+ return @app.call(env)
52
+ end
53
+
54
+ env[:ui].info("#{UiHelpers.e(:ongoing)} #{I18n.t('log.create_network', name: name, subnet: subnet_label)}")
55
+ builder = NetworkBuilder.new(cfg, machine_id: mid)
56
+ args = builder.build_create_command_args
57
+ if Util.sh!(*args)
58
+ write_marker(env, name, cfg)
59
+ env[:ui].info("#{UiHelpers.e(:success)} #{I18n.t('log.ok')}")
60
+ else
61
+ rendered = args.shelljoin
62
+ env[:ui].error("#{UiHelpers.e(:error)} #{I18n.t('messages.create_failed', cmd: rendered)}")
63
+ end
64
+ end
65
+
66
+ @app.call(env)
67
+ end
68
+
69
+ private
70
+
71
+ def set_locale!(cfg)
72
+ lang = cfg.locale || ENV["VDNM_LANG"]
73
+ return unless lang
74
+ UiHelpers.set_locale!(lang)
75
+ rescue UiHelpers::UnsupportedLocaleError
76
+ UiHelpers.set_locale!("en")
77
+ end
78
+
79
+ def write_marker(env, name, cfg)
80
+ m_id = env[:machine].id
81
+ dir = env[:machine].data_dir.join("docker-networks")
82
+ FileUtils.mkdir_p(dir)
83
+ marker = dir.join("#{name}.json")
84
+ payload = {
85
+ "name" => name,
86
+ "machine_id" => m_id,
87
+ "plugin" => "vagrant-docker-networks-manager",
88
+ "version" => VagrantDockerNetworksManager::VERSION,
89
+ "created_at" => Time.now.utc.iso8601,
90
+ "config" => {
91
+ "type" => cfg.network_type,
92
+ "subnet" => cfg.network_subnet,
93
+ "gateway" => cfg.network_gateway,
94
+ "ip_range" => cfg.ip_range,
95
+ "ipv6" => !!cfg.enable_ipv6,
96
+ "attachable" => !!cfg.network_attachable,
97
+ "parent" => cfg.network_parent
98
+ }
99
+ }
100
+ File.write(marker, JSON.pretty_generate(payload))
101
+ rescue => e
102
+ env[:ui].warn("marker write failed for '#{name}': #{e.message}")
103
+ end
104
+
105
+ def owned_by_this_machine?(name, machine_id)
106
+ labels = Util.read_network_labels(name)
107
+ labels["com.vagrant.plugin"] == "docker_networks_manager" &&
108
+ labels["com.vagrant.machine_id"] == machine_id
109
+ end
110
+ end
111
+
112
+ class ActionDestroy
113
+ def initialize(app, _env); @app = app; end
114
+
115
+ def call(env)
116
+ UiHelpers.setup_i18n!
117
+ cfg = env[:machine].config.docker_network
118
+ set_locale!(cfg)
119
+
120
+ unless Util.docker_available?
121
+ env[:ui].error("#{UiHelpers.e(:error)} #{I18n.t('errors.docker_unavailable')}")
122
+ return @app.call(env)
123
+ end
124
+
125
+ name = cfg.network_name
126
+ mid = env[:machine].id
127
+
128
+ unless cfg.cleanup_on_destroy
129
+ @app.call(env)
130
+ return
131
+ end
132
+
133
+ if created_by_this_machine?(env, name) || owned_by_this_machine?(name, mid)
134
+ env[:ui].info("#{UiHelpers.e(:broom)} #{I18n.t('messages.remove_network', name: name)}")
135
+
136
+ if Util.docker_network_exists?(name)
137
+ out, _e, st = Open3.capture3("docker", "network", "inspect", name)
138
+ if st.success?
139
+ begin
140
+ info = JSON.parse(out).first
141
+ (info["Containers"] || {}).values.each do |c|
142
+ cn = c["Name"]
143
+ env[:ui].info("#{UiHelpers.e(:ongoing)} #{I18n.t('log.disconnect_container', name: cn)}")
144
+ Util.sh!("network", "disconnect", "--force", name, cn)
145
+ if ENV["VDNM_DESTROY_WITH_CONTAINERS"] == "1"
146
+ env[:ui].info("#{UiHelpers.e(:ongoing)} #{I18n.t('log.remove_container', name: cn)}")
147
+ Util.sh!("rm", "-f", cn)
148
+ end
149
+ end
150
+ rescue => e
151
+ env[:ui].warn("failed to parse containers for '#{name}': #{e.message}")
152
+ end
153
+ end
154
+
155
+ if Util.sh!("network", "rm", name)
156
+ delete_marker(env, name)
157
+ env[:ui].info("#{UiHelpers.e(:success)} #{I18n.t('log.ok')}")
158
+ else
159
+ env[:ui].warn("#{UiHelpers.e(:warning)} #{I18n.t('errors.remove_failed')}")
160
+ end
161
+ else
162
+ delete_marker(env, name)
163
+ env[:ui].info("#{UiHelpers.e(:info)} #{I18n.t('messages.nothing_to_do')}")
164
+ end
165
+ else
166
+ env[:ui].info("#{UiHelpers.e(:broom)} #{I18n.t('messages.nothing_to_do')}")
167
+ end
168
+
169
+ @app.call(env)
170
+ end
171
+
172
+ private
173
+
174
+ def set_locale!(cfg)
175
+ lang = cfg.locale || ENV["VDNM_LANG"]
176
+ return unless lang
177
+ UiHelpers.set_locale!(lang)
178
+ rescue UiHelpers::UnsupportedLocaleError
179
+ UiHelpers.set_locale!("en")
180
+ end
181
+
182
+ def marker_path(env, name)
183
+ env[:machine].data_dir.join("docker-networks", "#{name}.json")
184
+ end
185
+
186
+ def created_by_this_machine?(env, name)
187
+ marker = marker_path(env, name)
188
+ return false unless File.exist?(marker)
189
+ j = JSON.parse(File.read(marker)) rescue {}
190
+ j["name"] == name && j["machine_id"] == env[:machine].id
191
+ end
192
+
193
+ def owned_by_this_machine?(name, machine_id)
194
+ labels = Util.read_network_labels(name)
195
+ labels["com.vagrant.plugin"] == "docker_networks_manager" &&
196
+ labels["com.vagrant.machine_id"] == machine_id
197
+ end
198
+
199
+ def delete_marker(env, name)
200
+ m = marker_path(env, name)
201
+ File.delete(m) if File.exist?(m)
202
+ end
203
+ end
204
+ end