Skip to content

Global status support #125

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/tox.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ jobs:
TOX_PARALLEL_NO_SPINNER: 1
TOXENV: ${{ matrix.tox_env }}
FORCE_COLOR: 1
PYTEST_REQPASS: 24

steps:
- name: Check vagrant presence
Expand Down
1 change: 1 addition & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ test =
coverage>=6.3
pytest-cov>=3.0.0
pytest>=7.0.0
pytest-plus>=0.2

[options.packages.find]
where = src
Expand Down
47 changes: 47 additions & 0 deletions src/vagrant/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,9 @@ def get_vagrant_executable():

# Classes for listings of Statuses, Boxes, and Plugins
Status = collections.namedtuple("Status", ["name", "state", "provider"])
GlobalStatus = collections.namedtuple(
"GlobalStatus", ["id", "state", "provider", "home"]
)
Box = collections.namedtuple("Box", ["name", "provider", "version"])
Plugin = collections.namedtuple("Plugin", ["name", "version", "system"])

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

def global_status(self, prune=False):
"""
Return the results of a `vagrant global-status` call as a list of one or more
GlobalStatus objects. A GlobalStatus contains the following attributes:

- id: The VM id.
- state: The state of the underlying guest machine (i.e. VM).
- provider: the name of the VM provider, e.g. 'virtualbox'. None
if no provider is output by vagrant.
- home: the path to the machine vagrantfile for the VM
"""
# machine-readable output are CSV lines
cmd = ["global-status", "--machine-readable"]
if prune is True:
cmd.append("--prune")
output = self._run_vagrant_command(cmd)
return self._parse_global_status(output)

def _normalize_status(self, status, provider):
"""
Normalise VM status to cope with state name being different
Expand Down Expand Up @@ -562,6 +583,32 @@ def _parse_status(self, output):

return statuses

def _parse_global_status(self, output):
"""
Unit testing is so much easier when Vagrant is removed from the
equation.
"""
parsed = self._parse_machine_readable_output(output)
statuses = []
vm_id = state = provider = home = None
for timestamp, target, kind, data in parsed:
if kind == "machine-id":
vm_id = data
elif kind == "provider-name":
provider = data
elif kind == "machine-home":
home = data
elif kind == "state":
state = data
if vm_id and provider and home and state:
state = self._normalize_status(state, provider)
status = GlobalStatus(
id=vm_id, state=state, provider=provider, home=home
)
statuses.append(status)
vm_id = state = provider = home = None
return statuses

def conf(self, ssh_config=None, vm_name=None):
"""
Parse ssh_config into a dict containing the keys defined in ssh_config,
Expand Down
48 changes: 48 additions & 0 deletions tests/test_vagrant.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,54 @@ def test_parse_status(vm_dir):
)


def test_parse_global_status(vm_dir):
"""
Test the parsing the output of the `vagrant global-status` command.
"""
listing = """1651503808,,metadata,machine-count,2
1651503808,,machine-id,9ec0e5d
1651503808,,provider-name,libvirt
1651503808,,machine-home,/tmp
1651503808,,state,preparing
1651503808,,machine-id,61395ad
1651503808,,provider-name,libvirt
1651503808,,machine-home,/home/rtp/.cache/molecule/sbd/default
1651503808,,state,running
1651504022,,ui,info,id
1651504022,,ui,info,name
1651504022,,ui,info,provider
1651504022,,ui,info,state
1651504022,,ui,info,directory
1651504022,,ui,info,
1651504022,,ui,info,-------------------------------------------------------------------------------------------------------------
1651504022,,ui,info,9ec0e5d
1651504022,,ui,info,bionic
1651504022,,ui,info,libvirt
1651504022,,ui,info,preparing
1651504022,,ui,info,/tmp
1651504022,,ui,info,
1651504022,,ui,info,61395ad
1651504022,,ui,info,instance-sbd-default
1651504022,,ui,info,libvirt
1651504022,,ui,info,running
1651504022,,ui,info,/home/rtp/.cache/molecule/sbd/default
1651504022,,ui,info,
11651504022,,ui,info, \\nThe above shows information about all known Vagrant environments\\non this machine...
"""
# Can compare tuples to GlobalStatus class b/c GlobalStatus is a collections.namedtuple.
goal = [
("9ec0e5d", "preparing", "libvirt", "/tmp"),
("61395ad", "running", "libvirt", "/home/rtp/.cache/molecule/sbd/default"),
]
v = vagrant.Vagrant(vm_dir)
parsed = v._parse_global_status(listing)
assert (
goal == parsed
), "The parsing of the test listing did not match the goal.\nlisting={!r}\ngoal={!r}\nparsed_listing={!r}".format(
listing, goal, parsed
)


def test_parse_aws_status(vm_dir):
"""
Test the parsing the output of the `vagrant status` command for an aws instance.
Expand Down