From 092fe2ece666be08d0ebcac93683ae9fefd3e731 Mon Sep 17 00:00:00 2001 From: David Garcia Date: Mon, 7 Sep 2020 14:25:17 +0200 Subject: [PATCH] Improve vyos-charm and fix some edge cases in magmagw-charm --- .../charms/vyos-config/actions.yaml | 12 - .../charms/vyos-config/src/charm.py | 222 +----------------- .../charms/vyos-config/src/proxy_cluster.py | 71 ------ .../charms/magmagw/actions.yaml | 12 - .../charms/magmagw/src/charm.py | 11 +- 5 files changed, 23 insertions(+), 305 deletions(-) delete mode 100644 magma/hackfest_gateway_vnfd/charms/vyos-config/src/proxy_cluster.py diff --git a/magma/hackfest_gateway_vnfd/charms/vyos-config/actions.yaml b/magma/hackfest_gateway_vnfd/charms/vyos-config/actions.yaml index 26b53376..88c15ea0 100644 --- a/magma/hackfest_gateway_vnfd/charms/vyos-config/actions.yaml +++ b/magma/hackfest_gateway_vnfd/charms/vyos-config/actions.yaml @@ -9,18 +9,6 @@ configure-remote: required: - magmaIP -# Standard OSM functions -start: - description: "Stop the service on the VNF." -stop: - description: "Stop the service on the VNF." -restart: - description: "Stop the service on the VNF." -reboot: - description: "Reboot the VNF virtual machine." -upgrade: - description: "Upgrade the software on the VNF." - # Required by charms.osm.sshproxy run: description: "Run an arbitrary command" diff --git a/magma/hackfest_gateway_vnfd/charms/vyos-config/src/charm.py b/magma/hackfest_gateway_vnfd/charms/vyos-config/src/charm.py index a1c9df2a..b110e1c9 100755 --- a/magma/hackfest_gateway_vnfd/charms/vyos-config/src/charm.py +++ b/magma/hackfest_gateway_vnfd/charms/vyos-config/src/charm.py @@ -30,145 +30,48 @@ from ops.model import ( import os import subprocess import traceback -from proxy_cluster import ProxyCluster -from charms.osm.sshproxy import SSHProxy +from charms.osm.sshproxy import SSHProxyCharm from charms.osm import libansible -class SSHKeysInitialized(EventBase): - def __init__(self, handle, ssh_public_key, ssh_private_key): - super().__init__(handle) - self.ssh_public_key = ssh_public_key - self.ssh_private_key = ssh_private_key - - def snapshot(self): - return { - "ssh_public_key": self.ssh_public_key, - "ssh_private_key": self.ssh_private_key, - } - - def restore(self, snapshot): - self.ssh_public_key = snapshot["ssh_public_key"] - self.ssh_private_key = snapshot["ssh_private_key"] - - -class ProxyClusterEvents(CharmEvents): - ssh_keys_initialized = EventSource(SSHKeysInitialized) - - -class SimpleHAProxyCharm(CharmBase): - - state = StoredState() - on = ProxyClusterEvents() - +class VyosCharm(SSHProxyCharm): def __init__(self, framework, key): super().__init__(framework, key) - # An example of setting charm state - # that's persistent across events - self.state.set_default(is_started=False) - - self.peers = ProxyCluster(self, "proxypeer") - - if not self.state.is_started: - self.state.is_started = True - # Register all of the events we want to observe self.framework.observe(self.on.config_changed, self.on_config_changed) self.framework.observe(self.on.install, self.on_install) self.framework.observe(self.on.start, self.on_start) self.framework.observe(self.on.upgrade_charm, self.on_upgrade_charm) # Charm actions (primitives) - self.framework.observe(self.on.configure_remote_action, self.on_configure_remote_action) - # OSM actions (primitives) - self.framework.observe(self.on.start_action, self.on_start_action) - self.framework.observe(self.on.stop_action, self.on_stop_action) - self.framework.observe(self.on.restart_action, self.on_restart_action) - self.framework.observe(self.on.reboot_action, self.on_reboot_action) - self.framework.observe(self.on.upgrade_action, self.on_upgrade_action) - # SSH Proxy actions (primitives) - self.framework.observe(self.on.generate_ssh_key_action, self.on_generate_ssh_key_action) - self.framework.observe(self.on.get_ssh_public_key_action, self.on_get_ssh_public_key_action) - self.framework.observe(self.on.run_action, self.on_run_action) - self.framework.observe(self.on.verify_ssh_credentials_action, self.on_verify_ssh_credentials_action) - - self.framework.observe(self.on.proxypeer_relation_changed, self.on_proxypeer_relation_changed) - - def get_ssh_proxy(self): - """Get the SSHProxy instance""" - proxy = SSHProxy( - hostname=self.model.config["ssh-hostname"], - username=self.model.config["ssh-username"], - password=self.model.config["ssh-password"], + self.framework.observe( + self.on.configure_remote_action, self.on_configure_remote_action ) - return proxy - - def on_proxypeer_relation_changed(self, event): - if self.peers.is_cluster_initialized: - pubkey = self.peers.ssh_public_key - privkey = self.peers.ssh_private_key - SSHProxy.write_ssh_keys(public=pubkey, private=privkey) - self.on_config_changed(event) - else: - event.defer() def on_config_changed(self, event): """Handle changes in configuration""" - unit = self.model.unit - - # Unit should go into a waiting state until verify_ssh_credentials is successful - unit.status = WaitingStatus("Waiting for SSH credentials") - proxy = self.get_ssh_proxy() - - verified = proxy.verify_credentials() - if verified: - unit.status = ActiveStatus() - else: - unit.status = BlockedStatus("Invalid SSH credentials.") + super().on_config_changed(event) def on_install(self, event): - unit = self.model.unit - unit.status = MaintenanceStatus("Installing Ansible") + """Called when the charm is being installed""" + super().on_install(event) + self.unit.status = MaintenanceStatus("Installing Ansible") libansible.install_ansible_support() - unit.status = ActiveStatus() + self.unit.status = ActiveStatus() def on_start(self, event): - """Called when the charm is being installed""" - if not self.peers.is_joined: - event.defer() - return - - unit = self.model.unit - - if not SSHProxy.has_ssh_key(): - unit.status = MaintenanceStatus("Generating SSH keys...") - pubkey = None - privkey = None - if self.is_leader: - if self.peers.is_cluster_initialized: - SSHProxy.write_ssh_keys( - public=self.peers.ssh_public_key, - private=self.peers.ssh_private_key, - ) - else: - SSHProxy.generate_ssh_key() - self.on.ssh_keys_initialized.emit( - SSHProxy.get_ssh_public_key(), SSHProxy.get_ssh_private_key() - ) - unit.status = ActiveStatus() - else: - unit.status = WaitingStatus("Waiting for leader to populate the keys") + """Called when the charm is being started""" + super().on_start(event) def on_configure_remote_action(self, event): """Configure remote.""" - if self.is_leader: + if self.unit.is_leader(): try: config = self.model.config magmaIP = event.params["magmaIP"] dict_vars = {"MAGMA_AGW_IP": magmaIP} - proxy = self.get_ssh_proxy() result = libansible.execute_playbook( "configure-remote.yaml", config["ssh-hostname"], @@ -188,106 +91,7 @@ class SimpleHAProxyCharm(CharmBase): def on_upgrade_charm(self, event): """Upgrade the charm.""" - unit = self.model.unit - - # Mark the unit as under Maintenance. - unit.status = MaintenanceStatus("Upgrading charm") - - self.on_install(event) - - # When maintenance is done, return to an Active state - unit.status = ActiveStatus() - - ############### - # OSM methods # - ############### - def on_start_action(self, event): - """Start the VNF service on the VM.""" - pass - - def on_stop_action(self, event): - """Stop the VNF service on the VM.""" - pass - - def on_restart_action(self, event): - """Restart the VNF service on the VM.""" - pass - - def on_reboot_action(self, event): - """Reboot the VM.""" - if self.is_leader: - proxy = self.get_ssh_proxy() - stdout, stderr = proxy.run("sudo reboot") - if len(stderr): - event.fail(stderr) - else: - event.fail("Unit is not leader") - return - - def on_upgrade_action(self, event): - """Upgrade the VNF service on the VM.""" - pass - - ##################### - # SSH Proxy methods # - ##################### - def on_generate_ssh_key_action(self, event): - """Generate a new SSH keypair for this unit.""" - if self.is_leader: - if not SSHProxy.generate_ssh_key(): - event.fail("Unable to generate ssh key") - else: - event.fail("Unit is not leader") - return - - def on_get_ssh_public_key_action(self, event): - """Get the SSH public key for this unit.""" - if self.is_leader: - pubkey = SSHProxy.get_ssh_public_key() - event.set_results({"pubkey": SSHProxy.get_ssh_public_key()}) - else: - event.fail("Unit is not leader") - return - - def on_run_action(self, event): - """Run an arbitrary command on the remote host.""" - if self.is_leader: - cmd = event.params["command"] - proxy = self.get_ssh_proxy() - stdout, stderr = proxy.run(cmd) - event.set_results({"output": stdout}) - if len(stderr): - event.fail(stderr) - else: - event.fail("Unit is not leader") - return - - def on_verify_ssh_credentials_action(self, event): - """Verify the SSH credentials for this unit.""" - if self.is_leader: - proxy = self.get_ssh_proxy() - - verified = proxy.verify_credentials() - if verified: - print("Verified!") - event.set_results({"verified": True}) - else: - print("Verification failed!") - event.set_results({"verified": False}) - else: - event.fail("Unit is not leader") - return - - @property - def is_leader(self): - # update the framework to include self.unit.is_leader() - return self.model.unit.is_leader() - - -class LeadershipError(ModelError): - def __init__(self): - super().__init__("not leader") if __name__ == "__main__": - main(SimpleHAProxyCharm) + main(VyosCharm) diff --git a/magma/hackfest_gateway_vnfd/charms/vyos-config/src/proxy_cluster.py b/magma/hackfest_gateway_vnfd/charms/vyos-config/src/proxy_cluster.py deleted file mode 100644 index bbdcb43d..00000000 --- a/magma/hackfest_gateway_vnfd/charms/vyos-config/src/proxy_cluster.py +++ /dev/null @@ -1,71 +0,0 @@ -# Copyright 2020 Canonical Ltd. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from ops.framework import Object, StoredState - - -class ProxyCluster(Object): - - state = StoredState() - - def __init__(self, charm, relation_name): - super().__init__(charm, relation_name) - self._relation_name = relation_name - self._relation = self.framework.model.get_relation(self._relation_name) - - self.framework.observe(charm.on.ssh_keys_initialized, self.on_ssh_keys_initialized) - - self.state.set_default(ssh_public_key=None) - self.state.set_default(ssh_private_key=None) - - def on_ssh_keys_initialized(self, event): - if not self.framework.model.unit.is_leader(): - raise RuntimeError("The initial unit of a cluster must also be a leader.") - - self.state.ssh_public_key = event.ssh_public_key - self.state.ssh_private_key = event.ssh_private_key - if not self.is_joined: - event.defer() - return - - self._relation.data[self.model.app][ - "ssh_public_key" - ] = self.state.ssh_public_key - self._relation.data[self.model.app][ - "ssh_private_key" - ] = self.state.ssh_private_key - - @property - def is_joined(self): - return self._relation is not None - - @property - def ssh_public_key(self): - if self.is_joined: - return self._relation.data[self.model.app].get("ssh_public_key") - - @property - def ssh_private_key(self): - if self.is_joined: - return self._relation.data[self.model.app].get("ssh_private_key") - - @property - def is_cluster_initialized(self): - return ( - True - if self.is_joined - and self._relation.data[self.model.app].get("ssh_public_key") - and self._relation.data[self.model.app].get("ssh_private_key") - else False - ) diff --git a/magma/hackfest_magma-agw-enb_vnfd/charms/magmagw/actions.yaml b/magma/hackfest_magma-agw-enb_vnfd/charms/magmagw/actions.yaml index efb4e7a1..6e82286a 100644 --- a/magma/hackfest_magma-agw-enb_vnfd/charms/magmagw/actions.yaml +++ b/magma/hackfest_magma-agw-enb_vnfd/charms/magmagw/actions.yaml @@ -67,18 +67,6 @@ add-test-subscriber: type: "string" default: "" -# Standard OSM functions -start: - description: "Stop the service on the VNF." -stop: - description: "Stop the service on the VNF." -restart: - description: "Stop the service on the VNF." -reboot: - description: "Reboot the VNF virtual machine." -upgrade: - description: "Upgrade the software on the VNF." - # Required by charms.osm.sshproxy run: description: "Run an arbitrary command" diff --git a/magma/hackfest_magma-agw-enb_vnfd/charms/magmagw/src/charm.py b/magma/hackfest_magma-agw-enb_vnfd/charms/magmagw/src/charm.py index 96378cf4..bad2d873 100755 --- a/magma/hackfest_magma-agw-enb_vnfd/charms/magmagw/src/charm.py +++ b/magma/hackfest_magma-agw-enb_vnfd/charms/magmagw/src/charm.py @@ -146,7 +146,16 @@ class MagmaAGWProxyCharm(SSHProxyCharm): """Resets the hardware ID""" if self.unit.is_leader(): proxy = self.get_ssh_proxy() - stdout, stderr = proxy.run("sudo snowflake --force-new-key") + attempt = 0 + while attempt < 50: + try: + stdout, stderr = proxy.run("sudo snowflake --force-new-key") + break + except subprocess.CalledProcessError: + attempt += 1 + import time + + time.sleep(5) event.set_results({"output": stdout, "stderr": stderr}) else: event.fail("Unit is not leader") -- GitLab