Skip to content
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
13 changes: 8 additions & 5 deletions checkvsphere/vcmd/media.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,15 @@ def run():
check = Check()

if args.vihost:
host_view = si.content.viewManager.CreateContainerView(
si.content.rootFolder, [vim.HostSystem], True)
try:
parentView = next(x for x in host_view.view if x.name.lower() == args.vihost.lower())
except:
host = find_entity_views(
si,
vim.HostSystem,
begin_entity=si.content.rootFolder,
sieve={'name': args.vihost},
)
if not host:
raise CheckVsphereException(f"host {args.vihost} not found")
parentView = host[0]['obj'].obj
else:
parentView = si.content.rootFolder

Expand Down
18 changes: 17 additions & 1 deletion checkvsphere/vcmd/snapshots.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import logging
from pyVmomi import vim
from monplugin import Check, Status
from .. import CheckVsphereException
from ..tools import cli, service_instance
from datetime import datetime, timedelta, timezone
from ..tools.helper import (
Expand Down Expand Up @@ -107,6 +108,8 @@ def run():
global check
global args
parser = get_argparser()
parser.add_optional_arguments(cli.Argument.VIHOST)

args = parser.get_args()

if not (args.warning or args.critical):
Expand All @@ -117,10 +120,23 @@ def run():

args._si = service_instance.connect(args)

if args.vihost:
host = find_entity_views(
args._si,
vim.HostSystem,
begin_entity=args._si.content.rootFolder,
sieve={'name': args.vihost},
)
if not host:
raise CheckVsphereException(f"host {args.vihost} not found")
parentView = host[0]['obj'].obj
else:
parentView = args._si.content.rootFolder

vms = find_entity_views(
args._si,
vim.VirtualMachine,
begin_entity=args._si.content.rootFolder,
begin_entity=parentView,
properties=['name', 'snapshot', 'resourcePool', 'config.template']
)

Expand Down
13 changes: 8 additions & 5 deletions checkvsphere/vcmd/vmtools.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,15 @@ def run():
args._si = service_instance.connect(args)

if args.vihost:
host_view = args._si.content.viewManager.CreateContainerView(
args._si.content.rootFolder, [vim.HostSystem], True)
try:
parentView = next(x for x in host_view.view if x.name.lower() == args.vihost.lower())
except:
host = find_entity_views(
args._si,
vim.HostSystem,
begin_entity=args._si.content.rootFolder,
sieve={'name': args.vihost},
)
if not host:
raise CheckVsphereException(f"host {args.vihost} not found")
parentView = host[0]['obj'].obj
else:
parentView = args._si.content.rootFolder

Expand Down
2 changes: 1 addition & 1 deletion checkvsphere/vcmd/vsan.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ def check_healthtest(check, clusters):
continue
check.add_message(
health2state(test.testHealth),
f"Cluster: {cluster['moref'].name} Group: { group.groupName } Status: { test.testHealth } Test: { test.testName }"
f"Cluster: {cluster['name']} Group: { group.groupName } Status: { test.testHealth } Test: { test.testName }"
)

opts = {}
Expand Down
58 changes: 58 additions & 0 deletions tests/integration_vcsim/test_cli_vcsim.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,18 @@ def test_vm_tools_not_installed_flag_can_escalate(run_cli, cli_connection_args):
assert "tools not installed" in result.stdout


def test_vm_tools_vihost_filter_works_with_vcsim(
run_cli, run_govc, cli_connection_args
):
host_name = _get_host_paths(run_govc)[0].rsplit("/", 1)[-1]

result = run_cli(["vm-tools", "--vihost", host_name] + cli_connection_args)

assert result.returncode == 0, result.stdout + result.stderr
assert "OK:" in result.stdout
assert "VMs checked for VMware Tools state" in result.stdout


def test_vm_guestfs_unknown_vm_returns_unknown(run_cli, cli_connection_args):
result = run_cli(
["vm-guestfs", "--vm-name", "definitely-missing-vm"] + cli_connection_args
Expand Down Expand Up @@ -192,6 +204,35 @@ def test_snapshots_age_threshold_with_created_snapshot(
assert vm_name in result.stdout


def test_snapshots_vihost_filter_works_with_created_snapshot(
run_cli, run_govc, cli_connection_args
):
vm_path = _get_vm_paths(run_govc)[0]
vm_name = vm_path.rsplit("/", 1)[-1]
host_name = re.sub(r"_VM\d+$", "", vm_name)
snapshot_name = "pytest-snap-host"

create_result = run_govc(["snapshot.create", "-vm", vm_path, snapshot_name])
assert create_result.returncode == 0, create_result.stdout + create_result.stderr

result = run_cli(
[
"snapshots",
"--mode",
"count",
"--warning",
"0",
"--vihost",
host_name,
]
+ cli_connection_args
)

assert result.returncode == 1, result.stdout + result.stderr
assert "WARNING:" in result.stdout
assert "snapshots" in result.stdout


def test_perf_host_maintenance_state_can_be_configured(
run_cli, run_govc, cli_connection_args
):
Expand Down Expand Up @@ -390,3 +431,20 @@ def test_media_changes_state_with_cdrom_insert(
restored_result = run_cli(["media", "--allowed", allowed_regex] + cli_connection_args)
assert restored_result.returncode == 0, restored_result.stdout + restored_result.stderr
assert "OK:" in restored_result.stdout


def test_media_vihost_filter_works_with_vcsim(run_cli, run_govc, cli_connection_args):
vm_path = _get_vm_paths(run_govc)[0]
vm_name = vm_path.rsplit("/", 1)[-1]
host_name = re.sub(r"_VM\d+$", "", vm_name)
allowed_regex = "^{}$".format(re.escape(vm_name))

_disconnect_removable_devices(run_govc, vm_path)

result = run_cli(
["media", "--vihost", host_name, "--allowed", allowed_regex]
+ cli_connection_args
)

assert result.returncode == 0, result.stdout + result.stderr
assert "OK:" in result.stdout
68 changes: 68 additions & 0 deletions tests/unit/test_vsan_healthtest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import types

from monplugin import Status

from checkvsphere.vcmd import vsan


class ExplodingClusterMoref:
@property
def name(self):
raise AssertionError("unexpected remote name fetch")


class FakeCheck:
def __init__(self):
self.messages = []

def add_message(self, status, message):
self.messages.append((status, message))

def check_messages(self, separator='\n', separator_all='\n', **opts):
return (Status.OK, separator.join(message for _, message in self.messages))

def exit(self, status, message):
raise SystemExit((status, message))


def test_check_healthtest_uses_prefetched_cluster_name(monkeypatch):
monkeypatch.setattr(vsan, "args", types.SimpleNamespace(
banned=[],
allowed=[],
exclude_group=[],
include_group=[],
exclude_test=[],
include_test=[],
match_method="search",
verbose=0,
))

check = FakeCheck()
clusters = [{
"name": "cluster-a",
"moref": ExplodingClusterMoref(),
"healthSummary": types.SimpleNamespace(
vsanConfig=types.SimpleNamespace(vsanEnabled=True),
groups=[
types.SimpleNamespace(
groupName="group-a",
groupTests=[
types.SimpleNamespace(
testHealth="green",
testName="test-a",
)
],
)
],
),
}]

try:
vsan.check_healthtest(check, clusters)
except SystemExit as exc:
status, message = exc.code
else:
raise AssertionError("expected check_healthtest to exit")

assert status == Status.OK
assert "Cluster: cluster-a" in message
Loading