# 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,
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:
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.
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:
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
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"
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):
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):