Skip to content

Commit d01cc2a

Browse files
authored
Merge pull request #125 from apatard/global_status
Global status support
2 parents 2c11272 + 1de96a7 commit d01cc2a

File tree

4 files changed

+97
-0
lines changed

4 files changed

+97
-0
lines changed

.github/workflows/tox.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ jobs:
4949
TOX_PARALLEL_NO_SPINNER: 1
5050
TOXENV: ${{ matrix.tox_env }}
5151
FORCE_COLOR: 1
52+
PYTEST_REQPASS: 24
5253

5354
steps:
5455
- name: Check vagrant presence

setup.cfg

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ test =
3939
coverage>=6.3
4040
pytest-cov>=3.0.0
4141
pytest>=7.0.0
42+
pytest-plus>=0.2
4243

4344
[options.packages.find]
4445
where = src

src/vagrant/__init__.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,9 @@ def get_vagrant_executable():
138138

139139
# Classes for listings of Statuses, Boxes, and Plugins
140140
Status = collections.namedtuple("Status", ["name", "state", "provider"])
141+
GlobalStatus = collections.namedtuple(
142+
"GlobalStatus", ["id", "state", "provider", "home"]
143+
)
141144
Box = collections.namedtuple("Box", ["name", "provider", "version"])
142145
Plugin = collections.namedtuple("Plugin", ["name", "version", "system"])
143146

@@ -525,6 +528,24 @@ def status(self, vm_name=None):
525528
output = self._run_vagrant_command(["status", "--machine-readable", vm_name])
526529
return self._parse_status(output)
527530

531+
def global_status(self, prune=False):
532+
"""
533+
Return the results of a `vagrant global-status` call as a list of one or more
534+
GlobalStatus objects. A GlobalStatus contains the following attributes:
535+
536+
- id: The VM id.
537+
- state: The state of the underlying guest machine (i.e. VM).
538+
- provider: the name of the VM provider, e.g. 'virtualbox'. None
539+
if no provider is output by vagrant.
540+
- home: the path to the machine vagrantfile for the VM
541+
"""
542+
# machine-readable output are CSV lines
543+
cmd = ["global-status", "--machine-readable"]
544+
if prune is True:
545+
cmd.append("--prune")
546+
output = self._run_vagrant_command(cmd)
547+
return self._parse_global_status(output)
548+
528549
def _normalize_status(self, status, provider):
529550
"""
530551
Normalise VM status to cope with state name being different
@@ -562,6 +583,32 @@ def _parse_status(self, output):
562583

563584
return statuses
564585

586+
def _parse_global_status(self, output):
587+
"""
588+
Unit testing is so much easier when Vagrant is removed from the
589+
equation.
590+
"""
591+
parsed = self._parse_machine_readable_output(output)
592+
statuses = []
593+
vm_id = state = provider = home = None
594+
for timestamp, target, kind, data in parsed:
595+
if kind == "machine-id":
596+
vm_id = data
597+
elif kind == "provider-name":
598+
provider = data
599+
elif kind == "machine-home":
600+
home = data
601+
elif kind == "state":
602+
state = data
603+
if vm_id and provider and home and state:
604+
state = self._normalize_status(state, provider)
605+
status = GlobalStatus(
606+
id=vm_id, state=state, provider=provider, home=home
607+
)
608+
statuses.append(status)
609+
vm_id = state = provider = home = None
610+
return statuses
611+
565612
def conf(self, ssh_config=None, vm_name=None):
566613
"""
567614
Parse ssh_config into a dict containing the keys defined in ssh_config,

tests/test_vagrant.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,54 @@ def test_parse_status(vm_dir):
222222
)
223223

224224

225+
def test_parse_global_status(vm_dir):
226+
"""
227+
Test the parsing the output of the `vagrant global-status` command.
228+
"""
229+
listing = """1651503808,,metadata,machine-count,2
230+
1651503808,,machine-id,9ec0e5d
231+
1651503808,,provider-name,libvirt
232+
1651503808,,machine-home,/tmp
233+
1651503808,,state,preparing
234+
1651503808,,machine-id,61395ad
235+
1651503808,,provider-name,libvirt
236+
1651503808,,machine-home,/home/rtp/.cache/molecule/sbd/default
237+
1651503808,,state,running
238+
1651504022,,ui,info,id
239+
1651504022,,ui,info,name
240+
1651504022,,ui,info,provider
241+
1651504022,,ui,info,state
242+
1651504022,,ui,info,directory
243+
1651504022,,ui,info,
244+
1651504022,,ui,info,-------------------------------------------------------------------------------------------------------------
245+
1651504022,,ui,info,9ec0e5d
246+
1651504022,,ui,info,bionic
247+
1651504022,,ui,info,libvirt
248+
1651504022,,ui,info,preparing
249+
1651504022,,ui,info,/tmp
250+
1651504022,,ui,info,
251+
1651504022,,ui,info,61395ad
252+
1651504022,,ui,info,instance-sbd-default
253+
1651504022,,ui,info,libvirt
254+
1651504022,,ui,info,running
255+
1651504022,,ui,info,/home/rtp/.cache/molecule/sbd/default
256+
1651504022,,ui,info,
257+
11651504022,,ui,info, \\nThe above shows information about all known Vagrant environments\\non this machine...
258+
"""
259+
# Can compare tuples to GlobalStatus class b/c GlobalStatus is a collections.namedtuple.
260+
goal = [
261+
("9ec0e5d", "preparing", "libvirt", "/tmp"),
262+
("61395ad", "running", "libvirt", "/home/rtp/.cache/molecule/sbd/default"),
263+
]
264+
v = vagrant.Vagrant(vm_dir)
265+
parsed = v._parse_global_status(listing)
266+
assert (
267+
goal == parsed
268+
), "The parsing of the test listing did not match the goal.\nlisting={!r}\ngoal={!r}\nparsed_listing={!r}".format(
269+
listing, goal, parsed
270+
)
271+
272+
225273
def test_parse_aws_status(vm_dir):
226274
"""
227275
Test the parsing the output of the `vagrant status` command for an aws instance.

0 commit comments

Comments
 (0)