Skip to content

Commit 436b537

Browse files
authored
Merge pull request #16 from theko2fi/dev/0.3.0
Dev/0.3.0
2 parents 5720747 + 140be9a commit 436b537

File tree

27 files changed

+1200
-173
lines changed

27 files changed

+1200
-173
lines changed

.github/workflows/docs-push.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
init-html-short-title: Theko2fi.Multipass Collection Docs
3838
init-extra-html-theme-options: |
3939
documentation_home_url=https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/branch/main/
40+
init-append-conf-py: "html_js_files=[('https://eu.umami.is/script.js', {'data-website-id': '0086c656-f41e-4131-ac3f-59bf72b1c4d8','defer': 'defer'})]"
4041

4142
publish-docs-gh-pages:
4243
# for now we won't run this on forks

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,6 @@ github_action_key*
77
.vscode/
88
dfdf.json
99
test-playbook.yml
10-
changelogs/.plugin-cache.yaml
10+
changelogs/.plugin-cache.yaml
11+
plugins/modules/__pycache__/
12+
ansible.cfg

CHANGELOG.rst

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,31 @@ Theko2Fi.Multipass Release Notes
55
.. contents:: Topics
66

77

8+
v0.3.0
9+
======
10+
11+
Release Summary
12+
---------------
13+
14+
Release Date: 2024-02-29
15+
16+
The collection now contains module and option to manage directory mapping between host and Multipass virtual machines.
17+
18+
19+
It also contains a Multipass driver for Molecule which allow to use Multipass instances for provisioning test resources.
20+
21+
22+
Minor Changes
23+
-------------
24+
25+
- molecule_multipass - a Multipass driver for Molecule.
26+
- multipass_vm - add ``mount`` option which allows to mount host directories inside multipass instances.
27+
28+
New Modules
29+
-----------
30+
31+
- theko2fi.multipass.multipass_mount - Module to manage directory mapping between host and Multipass virtual machine
32+
833
v0.2.3
934
======
1035

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ Please note that this collection is **not** developed by [Canonical](https://can
2121
- [multipass_vm_purge](https://theko2fi.github.io/ansible-multipass-collection/branch/main/multipass_vm_purge_module.html) - Module to purge all deleted Multipass virtual machines permanently
2222
- [multipass_vm_transfer_into](https://theko2fi.github.io/ansible-multipass-collection/branch/main/multipass_vm_transfer_into_module.html) - Module to copy a file into a Multipass virtual machine
2323
- [multipass_config_get](https://theko2fi.github.io/ansible-multipass-collection/branch/main/multipass_config_get_module.html) - Module to get Multipass configuration setting
24+
- [multipass_mount](https://theko2fi.github.io/ansible-multipass-collection/branch/main/multipass_mount_module.html) - Module to manage directory mapping between host and Multipass virtual machines
25+
* Roles:
26+
- molecule_multipass - Molecule Multipass driver
2427

2528
## Installation
2629

changelogs/changelog.yaml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,29 @@ releases:
7070
fragments:
7171
- v0.2.3.yaml
7272
release_date: '2024-01-05'
73+
0.3.0:
74+
changes:
75+
minor_changes:
76+
- molecule_multipass - a Multipass driver for Molecule.
77+
- multipass_vm - add ``mount`` option which allows to mount host directories
78+
inside multipass instances.
79+
release_summary: 'Release Date: 2024-02-29
80+
81+
82+
The collection now contains module and option to manage directory mapping
83+
between host and Multipass virtual machines.
84+
85+
86+
87+
It also contains a Multipass driver for Molecule which allow to use Multipass
88+
instances for provisioning test resources.
89+
90+
'
91+
fragments:
92+
- v0.3.0.yaml
93+
modules:
94+
- description: Module to manage directory mapping between host and Multipass virtual
95+
machine
96+
name: multipass_mount
97+
namespace: ''
98+
release_date: '2024-03-01'

changelogs/fragments/v0.3.0.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
release_summary: |
2+
Release Date: 2024-02-29
3+
4+
The collection now contains module and option to manage directory mapping between host and Multipass virtual machines.
5+
6+
7+
It also contains a Multipass driver for Molecule which allow to use Multipass instances for provisioning test resources.
8+
minor_changes:
9+
- multipass_vm - add ``mount`` option which allows to mount host directories inside multipass instances.
10+
- molecule_multipass - a Multipass driver for Molecule.

galaxy.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ namespace: theko2fi
88
name: multipass
99

1010
# The version of the collection. Must be compatible with semantic versioning
11-
version: 0.2.3
11+
version: 0.3.0
1212

1313
# The path to the Markdown (.md) readme file. This path is relative to the root of the collection
1414
readme: README.md

plugins/module_utils/errors.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
11
#!/usr/bin/python
22
#
3-
# Copyright (c) 2022, Kenneth KOFFI <https://www.linkedin.com/in/kenneth-koffi-6b1218178/>
3+
# Copyright (c) 2024, Kenneth KOFFI (https://www.linkedin.com/in/kenneth-koffi-6b1218178/)
44
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
55
# SPDX-License-Identifier: GPL-3.0-or-later
66

7+
class MountExistsError(Exception):
8+
pass
9+
10+
class MountNonExistentError(Exception):
11+
pass
12+
713
class MultipassFileTransferError(Exception):
814
pass
915

1016
class MultipassContentTransferError(Exception):
1117
pass
1218

1319
class SocketError(Exception):
14-
pass
20+
pass

plugins/module_utils/multipass.py

Lines changed: 51 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,11 @@
55
import json
66
import time
77
from shlex import split as shlexsplit
8-
from .errors import SocketError
8+
from .errors import SocketError, MountNonExistentError, MountExistsError
99

10+
def get_existing_mounts(vm_name):
11+
vm = MultipassClient().get_vm(vm_name)
12+
return vm.info().get('info').get(vm_name).get("mounts")
1013

1114
# Added decorator to automatically retry on unpredictable module failures
1215
def retry_on_failure(ExceptionsToCheck, max_retries=5, delay=5, backoff=2):
@@ -29,6 +32,7 @@ class MultipassVM:
2932
def __init__(self, vm_name, multipass_cmd):
3033
self.cmd = multipass_cmd
3134
self.vm_name = vm_name
35+
3236
# Will retry to execute info() if SocketError occurs
3337
@retry_on_failure(ExceptionsToCheck=SocketError)
3438
def info(self):
@@ -48,6 +52,7 @@ def info(self):
4852
else:
4953
raise Exception("Multipass info command failed: {0}".format(stderr.decode(encoding="utf-8")))
5054
return json.loads(stdout)
55+
5156
def delete(self, purge=False):
5257
cmd = [self.cmd, "delete", self.vm_name]
5358
if purge:
@@ -67,8 +72,10 @@ def delete(self, purge=False):
6772
self.vm_name, stderr.decode(encoding="utf-8")
6873
)
6974
)
75+
7076
def shell(self):
7177
raise Exception("The shell command is not supported in the Multipass SDK. Consider using exec.")
78+
7279
def exec(self, cmd_to_execute, working_directory=""):
7380
cmd = [self.cmd, "exec", self.vm_name]
7481
if working_directory:
@@ -84,18 +91,21 @@ def exec(self, cmd_to_execute, working_directory=""):
8491
if(exitcode != 0):
8592
raise Exception("Multipass exec command failed: {0}".format(stderr.decode(encoding="utf-8")))
8693
return stdout, stderr
94+
8795
def stop(self):
8896
cmd = [self.cmd, "stop", self.vm_name]
8997
try:
9098
subprocess.check_output(cmd)
9199
except:
92100
raise Exception("Error stopping Multipass VM {0}".format(self.vm_name))
101+
93102
def start(self):
94103
cmd = [self.cmd, "start", self.vm_name]
95104
try:
96105
subprocess.check_output(cmd)
97106
except:
98107
raise Exception("Error starting Multipass VM {0}".format(self.vm_name))
108+
99109
def restart(self):
100110
cmd = [self.cmd, "restart", self.vm_name]
101111
try:
@@ -109,6 +119,7 @@ class MultipassClient:
109119
"""
110120
def __init__(self, multipass_cmd="multipass"):
111121
self.cmd = multipass_cmd
122+
112123
def launch(self, vm_name=None, cpu=1, disk="5G", mem="1G", image=None, cloud_init=None):
113124
if(not vm_name):
114125
# similar to Multipass's VM name generator
@@ -124,20 +135,24 @@ def launch(self, vm_name=None, cpu=1, disk="5G", mem="1G", image=None, cloud_ini
124135
except:
125136
raise Exception("Error launching Multipass VM {0}".format(vm_name))
126137
return MultipassVM(vm_name, self.cmd)
138+
127139
def transfer(self, src, dest):
128140
cmd = [self.cmd, "transfer", src, dest]
129141
try:
130142
subprocess.check_output(cmd)
131143
except:
132144
raise Exception("Multipass transfer command failed.")
145+
133146
def get_vm(self, vm_name):
134147
return MultipassVM(vm_name, self.cmd)
148+
135149
def purge(self):
136150
cmd = [self.cmd, "purge"]
137151
try:
138152
subprocess.check_output(cmd)
139153
except:
140154
raise Exception("Purge command failed.")
155+
141156
def list(self):
142157
cmd = [self.cmd, "list", "--format", "json"]
143158
out = subprocess.Popen(cmd,
@@ -148,6 +163,7 @@ def list(self):
148163
if(not exitcode == 0):
149164
raise Exception("Multipass list command failed: {0}".format(stderr))
150165
return json.loads(stdout)
166+
151167
def find(self):
152168
cmd = [self.cmd, "find", "--format", "json"]
153169
out = subprocess.Popen(cmd,
@@ -158,30 +174,52 @@ def find(self):
158174
if(not exitcode == 0):
159175
raise Exception("Multipass find command failed: {0}".format(stderr))
160176
return json.loads(stdout)
161-
def mount(self, src, target):
162-
cmd = [self.cmd, "mount", src, target]
163-
try:
164-
subprocess.check_output(cmd)
165-
except:
166-
raise Exception("Multipass mount command failed.")
167-
def unmount(self, mount):
168-
cmd = [self.cmd, "unmount", mount]
169-
try:
170-
subprocess.check_output(cmd)
171-
except:
172-
raise Exception("Multipass unmount command failed.")
177+
178+
def mount(self, src, target, mount_type='classic', uid_maps=[], gid_maps=[]):
179+
mount_options = ["--type", mount_type]
180+
for uid_map in uid_maps:
181+
mount_options.extend(["--uid-map", uid_map])
182+
for gid_map in gid_maps:
183+
mount_options.extend(["--gid-map", gid_map])
184+
cmd = [self.cmd, "mount"] + mount_options + [src, target]
185+
out = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
186+
_,stderr = out.communicate()
187+
exitcode = out.wait()
188+
stderr_cleaned = stderr.decode(encoding="utf-8").splitlines()
189+
if(not exitcode == 0):
190+
for error_msg in stderr_cleaned:
191+
if 'is already mounted' in error_msg:
192+
raise MountExistsError
193+
raise Exception("Multipass mount command failed: {0}".format(stderr.decode(encoding="utf-8").rstrip()))
194+
195+
def umount(self, mount):
196+
cmd = [self.cmd, "umount", mount]
197+
out = subprocess.Popen(cmd,
198+
stdout=subprocess.PIPE,
199+
stderr=subprocess.PIPE)
200+
_,stderr = out.communicate()
201+
exitcode = out.wait()
202+
stderr_cleaned = stderr.decode(encoding="utf-8").splitlines()
203+
if(not exitcode == 0):
204+
for error_msg in stderr_cleaned:
205+
if 'is not mounted' in error_msg:
206+
raise MountNonExistentError
207+
raise Exception("{}".format(stderr.decode(encoding="utf-8").rstrip()))
208+
173209
def recover(self, vm_name):
174210
cmd = [self.cmd, "recover", vm_name]
175211
try:
176212
subprocess.check_output(cmd)
177213
except:
178214
raise Exception("Multipass recover command failed.")
215+
179216
def suspend(self):
180217
cmd = [self.cmd, "suspend"]
181218
try:
182219
subprocess.check_output(cmd)
183220
except:
184221
raise Exception("Multipass suspend command failed.")
222+
185223
def get(self, key):
186224
cmd = [self.cmd, "get", key]
187225
out = subprocess.Popen(cmd,

0 commit comments

Comments
 (0)