From e52489b3eb8c153bc1ea429a4dd5a7ae11a4ff97 Mon Sep 17 00:00:00 2001 From: Liam Young Date: Thu, 20 Apr 2023 14:58:08 +0000 Subject: [PATCH] Unit tests and CI config Change-Id: I2dfa889913caba8f6ac96ec4e9393c23fdda6100 --- .gitreview | 5 +++ .zuul.yaml | 10 +++++ src/charm.py | 35 +++++++-------- tests/unit/test_charm.py | 92 +++++++++++++++++++++++++++++++++++----- 4 files changed, 112 insertions(+), 30 deletions(-) create mode 100644 .gitreview create mode 100644 .zuul.yaml diff --git a/.gitreview b/.gitreview new file mode 100644 index 0000000..afdea8f --- /dev/null +++ b/.gitreview @@ -0,0 +1,5 @@ +[gerrit] +host=review.opendev.org +port=29418 +project=openstack/charm-openstack-hypervisor.git +defaultbranch=main diff --git a/.zuul.yaml b/.zuul.yaml new file mode 100644 index 0000000..c77bcb6 --- /dev/null +++ b/.zuul.yaml @@ -0,0 +1,10 @@ +- project: + templates: + - openstack-python3-charm-yoga-jobs + - openstack-cover-jobs + vars: + charm_build_name: keystone-k8s + juju_channel: 3.1/stable + juju_classic_mode: false + microk8s_channel: 1.26-strict/stable + microk8s_classic_mode: false diff --git a/src/charm.py b/src/charm.py index b33a2d8..b9f535a 100755 --- a/src/charm.py +++ b/src/charm.py @@ -30,12 +30,12 @@ import string import subprocess from typing import List +import ops.framework import ops_sunbeam.charm as sunbeam_charm import ops_sunbeam.guard as sunbeam_guard import ops_sunbeam.ovn.relation_handlers as ovn_relation_handlers import ops_sunbeam.relation_handlers as sunbeam_rhandlers from netifaces import AF_INET, gateways, ifaddresses -import ops.framework from ops.main import main logger = logging.getLogger(__name__) @@ -68,7 +68,7 @@ class HypervisorOperatorCharm(sunbeam_charm.OSBaseOperatorCharm): def __init__(self, framework: ops.framework.Framework) -> None: """Run constructor.""" super().__init__(framework) - self._state.set_default(metadata_secret='') + self._state.set_default(metadata_secret="") def get_relation_handlers( self, handlers: List[sunbeam_rhandlers.RelationHandler] = None @@ -90,12 +90,13 @@ class HypervisorOperatorCharm(sunbeam_charm.OSBaseOperatorCharm): """Ensure systemd services running.""" # This should taken care of by the snap svcs = [ - 'snap.openstack-hypervisor.neutron-ovn-metadata-agent.service', - 'snap.openstack-hypervisor.nova-api-metadata.service', - 'snap.openstack-hypervisor.nova-compute.service'] + "snap.openstack-hypervisor.neutron-ovn-metadata-agent.service", + "snap.openstack-hypervisor.nova-api-metadata.service", + "snap.openstack-hypervisor.nova-compute.service", + ] for svc in svcs: - if os.system(f'systemctl is-active --quiet {svc}') != 0: - os.system(f'systemctl start {svc}') + if os.system(f"systemctl is-active --quiet {svc}") != 0: + os.system(f"systemctl start {svc}") def generate_metadata_secret(self) -> str: """Generate a secure secret. @@ -139,7 +140,7 @@ class HypervisorOperatorCharm(sunbeam_charm.OSBaseOperatorCharm): contexts = self.contexts() sb_connection_strs = list(contexts.ovsdb_cms.db_ingress_sb_connection_strs) if not sb_connection_strs: - raise AttributeError(name='ovsdb southbound ingress string') + raise AttributeError(name="ovsdb southbound ingress string") snap_data = { "compute.cpu-mode": "host-model", "compute.spice-proxy-address": config("ip-address") or local_ip, @@ -157,14 +158,11 @@ class HypervisorOperatorCharm(sunbeam_charm.OSBaseOperatorCharm): "network.dns-servers": config("dns-servers"), "network.enable-gateway": json.dumps(config("enable-gateway")), "network.external-bridge": config("external-bridge"), - "network.external-bridge-address": config("external-bridge-address") or "10.20.20.1/24", + "network.external-bridge-address": config("external-bridge-address") + or "10.20.20.1/24", "network.ip-address": config("ip-address") or local_ip, - "network.ovn-key": base64.b64encode( - contexts.certificates.key.encode() - ).decode(), - "network.ovn-cert": base64.b64encode( - contexts.certificates.cert.encode() - ).decode(), + "network.ovn-key": base64.b64encode(contexts.certificates.key.encode()).decode(), + "network.ovn-cert": base64.b64encode(contexts.certificates.cert.encode()).decode(), "network.ovn-cacert": base64.b64encode( contexts.certificates.ca_cert.encode() ).decode(), @@ -174,12 +172,11 @@ class HypervisorOperatorCharm(sunbeam_charm.OSBaseOperatorCharm): "node.ip-address": config("ip-address") or local_ip, "rabbitmq.url": contexts.amqp.transport_url, } - - cmd = ["snap", "set", "openstack-hypervisor"] + [ - f"{k}={v}" for k, v in snap_data.items() - ] except AttributeError as e: raise sunbeam_guard.WaitingExceptionError("Data missing: {}".format(e.name)) + cmd = ["snap", "set", "openstack-hypervisor"] + for k in sorted(snap_data.keys()): + cmd.append(f"{k}={snap_data[k]}") subprocess.check_call(cmd) self.ensure_services_running() self._state.unit_bootstrapped = True diff --git a/tests/unit/test_charm.py b/tests/unit/test_charm.py index 0e6b239..fe65bfb 100644 --- a/tests/unit/test_charm.py +++ b/tests/unit/test_charm.py @@ -14,12 +14,10 @@ """Tests for Openstack hypervisor charm.""" -import unittest -import mock -import ops_sunbeam.test_utils as test_utils +import base64 +import json -import ops.testing -from ops.testing import Harness +import ops_sunbeam.test_utils as test_utils import charm @@ -32,8 +30,10 @@ class _HypervisorOperatorCharm(charm.HypervisorOperatorCharm): self.seen_events = [] super().__init__(framework) + class TestCharm(test_utils.CharmTestCase): - PATCHES = ['subprocess'] + PATCHES = ["subprocess", "socket"] + def setUp(self): """Setup OpenStack Hypervisor tests.""" super().setUp(charm, self.PATCHES) @@ -42,15 +42,85 @@ class TestCharm(test_utils.CharmTestCase): self.harness = test_utils.get_harness( _HypervisorOperatorCharm, container_calls=self.container_calls, - charm_config=config_data + charm_config=config_data, ) self.addCleanup(self.harness.cleanup) - self.harness.begin() + + def initial_setup(self): + rel_id = self.harness.add_relation("certificates", "vault") + self.harness.add_relation_unit(rel_id, "vault/0") + self.harness.update_config({"snap-channel": "essex/stable", "ip-address": "10.0.0.10"}) + self.harness.begin_with_initial_hooks() + csr = {"certificate_signing_request": test_utils.TEST_CSR} + self.harness.update_relation_data( + rel_id, + self.harness.charm.unit.name, + { + "ingress-address": "10.0.0.34", + "certificate_signing_requests": json.dumps([csr]), + }, + ) + test_utils.add_certificates_relation_certs(self.harness, rel_id) + ovs_rel_id = self.harness.add_relation("ovsdb-cms", "ovn-relay") + self.harness.add_relation_unit(ovs_rel_id, "ovn-relay/0") + self.harness.update_relation_data( + ovs_rel_id, + "ovn-relay/0", + { + "bound-address": "10.1.176.143", + "bound-hostname": "ovn-relay-0.ovn-relay-endpoints.openstack.svc.cluster.local", + "egress-subnets": "10.20.21.10/32", + "ingress-address": "10.20.21.10", + "ingress-bound-address": "10.20.21.10", + "private-address": "10.20.21.10", + }, + ) def test_all_relations(self): """Test all the charms relations.""" + self.socket.getfqdn.return_value = "test.local" + self.initial_setup() self.harness.set_leader() - self.harness.update_config({'snap-channel': 'essex/stable'}) - test_utils.add_all_relations(self.harness) self.subprocess.check_call.assert_any_call( - ['snap', 'install', 'openstack-hypervisor', '--channel', 'essex/stable']) + ["snap", "install", "openstack-hypervisor", "--channel", "essex/stable"] + ) + test_utils.add_complete_amqp_relation(self.harness) + test_utils.add_complete_identity_credentials_relation(self.harness) + metadata = self.harness.charm.metadata_secret() + ovn_cacert = test_utils.TEST_CA + "\n" + "\n".join(test_utils.TEST_CHAIN) + ovn_cacert = base64.b64encode(ovn_cacert.encode()).decode() + private_key = base64.b64encode( + self.harness.charm.contexts().certificates.key.encode() + ).decode() + certificate = base64.b64encode(test_utils.TEST_SERVER_CERT.encode()).decode() + expect_settings = [ + "compute.cpu-mode=host-model", + "compute.spice-proxy-address=10.0.0.10", + "compute.virt-type=kvm", + f"credentials.ovn-metadata-proxy-shared-secret={metadata}", + "identity.auth-url=None", + "identity.password=user-password", + "identity.project-domain-name=pdomain_-ame", + "identity.project-name=user-project", + "identity.region-name=region12", + "identity.user-domain-name=udomain-name", + "identity.username=username", + "logging.debug=false", + "network.dns-domain=openstack.local", + "network.dns-servers=8.8.8.8", + "network.enable-gateway=false", + "network.external-bridge=br-ex", + "network.external-bridge-address=10.20.20.1/24", + "network.ip-address=10.0.0.10", + f"network.ovn-cacert={ovn_cacert}", + f"network.ovn-cert={certificate}", + f"network.ovn-key={private_key}", + "network.ovn-sb-connection=ssl:10.20.21.10:6642", + "network.physnet-name=physnet1", + "node.fqdn=test.local", + "node.ip-address=10.0.0.10", + "rabbitmq.url=rabbit://hypervisor:rabbit.pass@10.0.0.13:5672/openstack", + ] + expect_set_cmd = ["snap", "set", "openstack-hypervisor"] + expect_set_cmd.extend(expect_settings) + self.subprocess.check_call.assert_any_call(expect_set_cmd)