From: Mark Beierl Date: Thu, 20 Apr 2023 03:46:47 +0000 (+0000) Subject: OSM-1033 Juju Key for Model X-Git-Url: https://osm.etsi.org/gitweb/?a=commitdiff_plain;h=refs%2Fchanges%2F43%2F13243%2F1;p=osm%2FLCM.git OSM-1033 Juju Key for Model Uses authorized_keys in the vim_config to create the model Change-Id: I969f8879da227c8d82afff2754e5b5f51d17bd8d Signed-off-by: Mark Beierl --- diff --git a/osm_lcm/temporal/juju_paas_activities.py b/osm_lcm/temporal/juju_paas_activities.py index d8cc55c..f964ea7 100644 --- a/osm_lcm/temporal/juju_paas_activities.py +++ b/osm_lcm/temporal/juju_paas_activities.py @@ -14,17 +14,12 @@ # See the License for the specific language governing permissions and # limitations under the License. import asyncio +import base64 import logging from juju.application import Application from juju.controller import Controller -from temporalio import activity +from n2vc.config import EnvironConfig from n2vc.temporal_libjuju import ConnectionInfo, Libjuju -from osm_common.temporal_constants import ( - ACTIVITY_TEST_VIM_CONNECTIVITY, - ACTIVITY_CREATE_MODEL, - ACTIVITY_DEPLOY_CHARM, - ACTIVITY_CHECK_CHARM_STATUS, -) from osm_common.dataclasses.temporal_dataclasses import ( CharmInfo, CheckCharmStatusInput, @@ -32,6 +27,13 @@ from osm_common.dataclasses.temporal_dataclasses import ( TestVimConnectivityInput, VduInstantiateInput, ) +from osm_common.temporal_constants import ( + ACTIVITY_TEST_VIM_CONNECTIVITY, + ACTIVITY_CREATE_MODEL, + ACTIVITY_DEPLOY_CHARM, + ACTIVITY_CHECK_CHARM_STATUS, +) +from temporalio import activity class JujuPaasConnector: @@ -44,6 +46,7 @@ class JujuPaasConnector: def __init__(self, db): self.db = db self.logger = logging.getLogger(f"lcm.act.{self.__class__.__name__}") + self.config = EnvironConfig() def _decrypt_password(self, vim_content: dict) -> str: """Decrypt a password. @@ -155,9 +158,34 @@ class JujuPaasConnector: back-off strategy for this activity, as it will naturally block and wait on each connection attempt. """ - model_name = create_model_input.model_name - libjuju = self._get_libjuju(create_model_input.vim_uuid) - await libjuju.add_model(model_name) + controller = await self._get_controller(create_model_input.vim_uuid) + if create_model_input.model_name in await controller.list_models(): + self.logger.debug(f"Model {create_model_input.model_name} already created") + return + + vim_content = self.db.get_one( + "vim_accounts", {"_id": create_model_input.vim_uuid} + ) + vim_config = vim_content["config"] + + config = { + "endpoints": ",".join(await controller.api_endpoints), + "user": vim_content["vim_user"], + "secret": self._decrypt_password(vim_content), + "cacert": base64.b64encode( + vim_config["ca_cert_content"].encode("utf-8") + ).decode("utf-8"), + "authorized-keys": vim_config["authorized_keys"], + } + + self.logger.debug(f"Creating model {create_model_input.model_name}") + await controller.add_model( + create_model_input.model_name, + config=config, + cloud_name=vim_config["cloud"], + credential_name=vim_config["cloud_credentials"], + ) + self.logger.debug(f"Model {create_model_input.model_name} created") @activity.defn(name=ACTIVITY_DEPLOY_CHARM) async def deploy_charm(self, deploy_charm_input: VduInstantiateInput) -> None: diff --git a/osm_lcm/tests/test_juju_paas_activities.py b/osm_lcm/tests/test_juju_paas_activities.py index 3e56bd5..ddafd54 100644 --- a/osm_lcm/tests/test_juju_paas_activities.py +++ b/osm_lcm/tests/test_juju_paas_activities.py @@ -19,6 +19,7 @@ import asyncio import unittest.mock as mock from juju.application import Application +from juju.controller import Controller from juju.model import Model from juju.errors import JujuError from juju.unit import Unit @@ -29,11 +30,10 @@ from osm_common.dataclasses.temporal_dataclasses import ( ModelInfo, VduInstantiateInput, ) -from osm_common.dbbase import DbException from osm_lcm.temporal.juju_paas_activities import JujuPaasConnector from parameterized import parameterized from temporalio.testing import ActivityEnvironment -from unittest.mock import AsyncMock, Mock +from unittest.mock import ANY, AsyncMock, Mock vim_id = "some-vim-uuid" namespace = "some-namespace" @@ -41,6 +41,23 @@ model_info = ModelInfo(vim_id, namespace) connection_info = ConnectionInfo( "1.2.3.4:17070", "user", "password", "cacert", "cloud_name", "cloud_credentials" ) +vim_content = { + "_id": "82258772-0145-47cf-9a56-98a83aab38cc", + "name": "juju-with-key", + "vim_type": "paas", + "description": "", + "vim_url": "10.152.183.83:17070", + "vim_user": "admin", + "vim_password": "********", + "vim_tenant_name": "null", + "config": { + "paas_provider": "juju", + "cloud": "microk8s", + "cloud_credentials": "microk8s", + "authorized_keys": "1yc2EAAAADAQABAAABAQDM3js", + "ca_cert_content": "BEGIN CERTIFICATE\nMIIEEj", + }, +} class TestJujuPaasConnector(asynctest.TestCase): @@ -48,45 +65,35 @@ class TestJujuPaasConnector(asynctest.TestCase): self.db = Mock() self.env = ActivityEnvironment() self.juju_paas_connector = JujuPaasConnector(self.db) + self.controller = AsyncMock(spec=Controller) - @asynctest.mock.patch("osm_lcm.temporal.juju_paas_activities.Libjuju.add_model") - @asynctest.mock.patch( - "osm_lcm.temporal.juju_paas_activities.JujuPaasConnector._get_connection_info" - ) - async def test_create_model_nominal_case( - self, mock_get_connection_info, mock_add_model - ): - mock_get_connection_info.return_value = connection_info - await self.env.run(self.juju_paas_connector.create_model, model_info) - mock_get_connection_info.assert_called_once_with(vim_id) - mock_add_model.assert_called_once_with(namespace) + async def get_controller(_: str): + return self.controller - @asynctest.mock.patch("osm_lcm.temporal.juju_paas_activities.Libjuju.add_model") - @asynctest.mock.patch( - "osm_lcm.temporal.juju_paas_activities.JujuPaasConnector._get_connection_info" - ) - async def test_create_model_raises_juju_exception( - self, mock_get_connection_info, mock_add_model - ): - mock_get_connection_info.return_value = connection_info - mock_add_model.side_effect = JujuError() - with self.assertRaises(JujuError): - await self.env.run(self.juju_paas_connector.create_model, model_info) - mock_get_connection_info.assert_called_once_with(vim_id) - mock_add_model.assert_called_once_with(namespace) + self.juju_paas_connector._get_controller = get_controller + self._api_endpoints = [] + self.controller.api_endpoints = self.api_endpoints - @asynctest.mock.patch("osm_lcm.temporal.juju_paas_activities.Libjuju.add_model") - @asynctest.mock.patch( - "osm_lcm.temporal.juju_paas_activities.JujuPaasConnector._get_connection_info" - ) - async def test_create_model_raises_db_exception( - self, mock_get_connection_info, mock_add_model - ): - mock_get_connection_info.side_effect = DbException("not found") - with self.assertRaises(DbException): - await self.env.run(self.juju_paas_connector.create_model, model_info) - mock_get_connection_info.assert_called_once_with(vim_id) - mock_add_model.assert_not_called() + @property + async def api_endpoints(self): + return self._api_endpoints + + async def test_create_model_nominal_case(self): + self.db.get_one.side_effect = [vim_content] + self.juju_paas_connector._decrypt_password = Mock() + self.juju_paas_connector._decrypt_password.side_effect = ["password"] + await self.env.run(self.juju_paas_connector.create_model, model_info) + self.controller.add_model.assert_called_once_with( + model_info.model_name, + config=ANY, + cloud_name=vim_content["config"]["cloud"], + credential_name=vim_content["config"]["cloud_credentials"], + ) + + async def test_create_model_already_exists(self): + self.controller.list_models.return_value = [model_info.model_name] + await self.env.run(self.juju_paas_connector.create_model, model_info) + self.controller.add_model.assert_not_called() class TestJujuPaasActivitiesBase(asynctest.TestCase):