blob: ad0933c0269b80034f6270936dc0cfc034b73477 [file] [log] [blame]
# 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.
import asyncio
import asynctest
import tempfile
from unittest import mock
import juju
import kubernetes
from juju.errors import JujuAPIError
import logging
from .utils import FakeN2VC, FakeMachine, FakeApplication
from n2vc.libjuju import Libjuju
from n2vc.exceptions import (
JujuControllerFailedConnecting,
JujuMachineNotFound,
JujuApplicationNotFound,
JujuActionNotFound,
JujuApplicationExists,
JujuInvalidK8sConfiguration,
JujuLeaderUnitNotFound,
)
from n2vc.k8s_juju_conn import generate_rbac_id
class LibjujuTestCase(asynctest.TestCase):
@asynctest.mock.patch("juju.controller.Controller.update_endpoints")
@asynctest.mock.patch("juju.client.connector.Connector.connect")
@asynctest.mock.patch("juju.controller.Controller.connection")
@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_api_endpoints_db")
def setUp(
self,
mock__get_api_endpoints_db=None,
mock_connection=None,
mock_connect=None,
mock_update_endpoints=None,
):
loop = asyncio.get_event_loop()
n2vc = FakeN2VC()
mock__get_api_endpoints_db.return_value = ["127.0.0.1:17070"]
endpoints = "127.0.0.1:17070"
username = "admin"
password = "secret"
cacert = """
-----BEGIN CERTIFICATE-----
SOMECERT
-----END CERTIFICATE-----"""
self.libjuju = Libjuju(
endpoints,
"192.168.0.155:17070",
username,
password,
cacert,
loop,
log=None,
db={"get_one": []},
n2vc=n2vc,
)
logging.disable(logging.CRITICAL)
loop.run_until_complete(self.libjuju.disconnect())
@asynctest.mock.patch("n2vc.libjuju.Libjuju._create_health_check_task")
@asynctest.mock.patch("n2vc.libjuju.Libjuju._update_api_endpoints_db")
@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_api_endpoints_db")
class LibjujuInitTestCase(asynctest.TestCase):
def setUp(self):
self.loop = asyncio.get_event_loop()
self.n2vc = FakeN2VC()
self.endpoint = "192.168.100.100:17070"
self.username = "admin"
self.password = "secret"
self.cacert = """
-----BEGIN CERTIFICATE-----
SOMECERT
-----END CERTIFICATE-----"""
def test_endpoint_not_in_db(
self,
mock__get_api_endpoints_db,
mock_update_endpoints,
mock_create_health_check_task,
):
mock__get_api_endpoints_db.return_value = ["another_ip"]
Libjuju(
self.endpoint,
"192.168.0.155:17070",
self.username,
self.password,
self.cacert,
self.loop,
log=None,
db={"get_one": []},
n2vc=self.n2vc,
)
mock_update_endpoints.assert_called_once_with([self.endpoint])
mock__get_api_endpoints_db.assert_called_once()
def test_endpoint_in_db(
self,
mock__get_api_endpoints_db,
mock_update_endpoints,
mock_create_health_check_task,
):
mock__get_api_endpoints_db.return_value = [self.endpoint, "another_ip"]
Libjuju(
self.endpoint,
"192.168.0.155:17070",
self.username,
self.password,
self.cacert,
self.loop,
log=None,
db={"get_one": []},
n2vc=self.n2vc,
)
mock_update_endpoints.assert_not_called()
mock__get_api_endpoints_db.assert_called_once()
def test_no_db_endpoints(
self,
mock__get_api_endpoints_db,
mock_update_endpoints,
mock_create_health_check_task,
):
mock__get_api_endpoints_db.return_value = None
Libjuju(
self.endpoint,
"192.168.0.155:17070",
self.username,
self.password,
self.cacert,
self.loop,
log=None,
db={"get_one": []},
n2vc=self.n2vc,
)
mock_update_endpoints.assert_called_once_with([self.endpoint])
mock__get_api_endpoints_db.assert_called_once()
@asynctest.mock.patch("juju.controller.Controller.connect")
@asynctest.mock.patch(
"juju.controller.Controller.api_endpoints",
new_callable=asynctest.CoroutineMock(return_value=["127.0.0.1:17070"]),
)
@asynctest.mock.patch("n2vc.libjuju.Libjuju._update_api_endpoints_db")
class GetControllerTest(LibjujuTestCase):
def setUp(self):
super(GetControllerTest, self).setUp()
def test_diff_endpoint(
self, mock__update_api_endpoints_db, mock_api_endpoints, mock_connect
):
self.libjuju.endpoints = []
controller = self.loop.run_until_complete(self.libjuju.get_controller())
mock__update_api_endpoints_db.assert_called_once_with(["127.0.0.1:17070"])
self.assertIsInstance(controller, juju.controller.Controller)
@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
def test_exception(
self,
mock_disconnect_controller,
mock__update_api_endpoints_db,
mock_api_endpoints,
mock_connect,
):
self.libjuju.endpoints = []
mock__update_api_endpoints_db.side_effect = Exception()
controller = None
with self.assertRaises(JujuControllerFailedConnecting):
controller = self.loop.run_until_complete(self.libjuju.get_controller())
self.assertIsNone(controller)
mock_disconnect_controller.assert_called_once()
def test_same_endpoint_get_controller(
self, mock__update_api_endpoints_db, mock_api_endpoints, mock_connect
):
self.libjuju.endpoints = ["127.0.0.1:17070"]
controller = self.loop.run_until_complete(self.libjuju.get_controller())
mock__update_api_endpoints_db.assert_not_called()
self.assertIsInstance(controller, juju.controller.Controller)
class DisconnectTest(LibjujuTestCase):
def setUp(self):
super(DisconnectTest, self).setUp()
@asynctest.mock.patch("juju.model.Model.disconnect")
def test_disconnect_model(self, mock_disconnect):
self.loop.run_until_complete(self.libjuju.disconnect_model(juju.model.Model()))
mock_disconnect.assert_called_once()
@asynctest.mock.patch("juju.controller.Controller.disconnect")
def test_disconnect_controller(self, mock_disconnect):
self.loop.run_until_complete(
self.libjuju.disconnect_controller(juju.controller.Controller())
)
mock_disconnect.assert_called_once()
@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
@asynctest.mock.patch("n2vc.libjuju.Libjuju.model_exists")
@asynctest.mock.patch("juju.controller.Controller.add_model")
@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
class AddModelTest(LibjujuTestCase):
def setUp(self):
super(AddModelTest, self).setUp()
def test_existing_model(
self,
mock_disconnect_model,
mock_disconnect_controller,
mock_add_model,
mock_model_exists,
mock_get_controller,
):
mock_model_exists.return_value = True
# This should not raise an exception
self.loop.run_until_complete(
self.libjuju.add_model("existing_model", "cloud")
)
mock_disconnect_controller.assert_called()
# TODO Check two job executing at the same time and one returning without doing anything.
def test_non_existing_model(
self,
mock_disconnect_model,
mock_disconnect_controller,
mock_add_model,
mock_model_exists,
mock_get_controller,
):
mock_model_exists.return_value = False
mock_get_controller.return_value = juju.controller.Controller()
self.loop.run_until_complete(
self.libjuju.add_model("nonexisting_model", "cloud")
)
mock_add_model.assert_called_once()
mock_disconnect_controller.assert_called()
mock_disconnect_model.assert_called()
@asynctest.mock.patch("juju.controller.Controller.get_model")
class GetModelTest(LibjujuTestCase):
def setUp(self):
super(GetModelTest, self).setUp()
def test_get_model(
self,
mock_get_model,
):
mock_get_model.return_value = juju.model.Model()
model = self.loop.run_until_complete(
self.libjuju.get_model(juju.controller.Controller(), "model")
)
self.assertIsInstance(model, juju.model.Model)
@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
@asynctest.mock.patch("juju.controller.Controller.list_models")
class ModelExistsTest(LibjujuTestCase):
def setUp(self):
super(ModelExistsTest, self).setUp()
async def test_existing_model(
self,
mock_list_models,
mock_get_controller,
):
mock_list_models.return_value = ["existing_model"]
self.assertTrue(
await self.libjuju.model_exists(
"existing_model", juju.controller.Controller()
)
)
@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
async def test_no_controller(
self,
mock_disconnect_controller,
mock_list_models,
mock_get_controller,
):
mock_list_models.return_value = ["existing_model"]
mock_get_controller.return_value = juju.controller.Controller()
self.assertTrue(await self.libjuju.model_exists("existing_model"))
mock_disconnect_controller.assert_called_once()
async def test_non_existing_model(
self,
mock_list_models,
mock_get_controller,
):
mock_list_models.return_value = ["existing_model"]
self.assertFalse(
await self.libjuju.model_exists(
"not_existing_model", juju.controller.Controller()
)
)
@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
@asynctest.mock.patch("juju.model.Model.get_status")
class GetModelStatusTest(LibjujuTestCase):
def setUp(self):
super(GetModelStatusTest, self).setUp()
def test_success(
self,
mock_get_status,
mock_disconnect_controller,
mock_disconnect_model,
mock_get_model,
mock_get_controller,
):
mock_get_model.return_value = juju.model.Model()
mock_get_status.return_value = {"status"}
status = self.loop.run_until_complete(self.libjuju.get_model_status("model"))
mock_get_status.assert_called_once()
mock_disconnect_controller.assert_called_once()
mock_disconnect_model.assert_called_once()
self.assertEqual(status, {"status"})
def test_exception(
self,
mock_get_status,
mock_disconnect_controller,
mock_disconnect_model,
mock_get_model,
mock_get_controller,
):
mock_get_model.return_value = juju.model.Model()
mock_get_status.side_effect = Exception()
status = None
with self.assertRaises(Exception):
status = self.loop.run_until_complete(
self.libjuju.get_model_status("model")
)
mock_disconnect_controller.assert_called_once()
mock_disconnect_model.assert_called_once()
self.assertIsNone(status)
@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
@asynctest.mock.patch("juju.model.Model.get_machines")
@asynctest.mock.patch("juju.model.Model.add_machine")
@asynctest.mock.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for")
class CreateMachineTest(LibjujuTestCase):
def setUp(self):
super(CreateMachineTest, self).setUp()
def test_existing_machine(
self,
mock_wait_for,
mock_add_machine,
mock_get_machines,
mock_disconnect_controller,
mock_disconnect_model,
mock_get_model,
mock_get_controller,
):
mock_get_model.return_value = juju.model.Model()
mock_get_machines.return_value = {"existing_machine": FakeMachine()}
machine, bool_res = self.loop.run_until_complete(
self.libjuju.create_machine("model", "existing_machine")
)
self.assertIsInstance(machine, FakeMachine)
self.assertFalse(bool_res)
mock_disconnect_controller.assert_called()
mock_disconnect_model.assert_called()
def test_non_existing_machine(
self,
mock_wait_for,
mock_add_machine,
mock_get_machines,
mock_disconnect_controller,
mock_disconnect_model,
mock_get_model,
mock_get_controller,
):
machine = None
bool_res = None
mock_get_model.return_value = juju.model.Model()
with self.assertRaises(JujuMachineNotFound):
machine, bool_res = self.loop.run_until_complete(
self.libjuju.create_machine("model", "non_existing_machine")
)
self.assertIsNone(machine)
self.assertIsNone(bool_res)
mock_disconnect_controller.assert_called()
mock_disconnect_model.assert_called()
def test_no_machine(
self,
mock_wait_for,
mock_add_machine,
mock_get_machines,
mock_disconnect_controller,
mock_disconnect_model,
mock_get_model,
mock_get_controller,
):
mock_get_model.return_value = juju.model.Model()
mock_add_machine.return_value = FakeMachine()
machine, bool_res = self.loop.run_until_complete(
self.libjuju.create_machine("model")
)
self.assertIsInstance(machine, FakeMachine)
self.assertTrue(bool_res)
mock_wait_for.assert_called_once()
mock_add_machine.assert_called_once()
mock_disconnect_controller.assert_called()
mock_disconnect_model.assert_called()
# TODO test provision machine
@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
@asynctest.mock.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for_model")
@asynctest.mock.patch("juju.model.Model.deploy")
class DeployTest(LibjujuTestCase):
def setUp(self):
super(DeployTest, self).setUp()
def test_deploy(
self,
mock_deploy,
mock_wait_for_model,
mock_disconnect_controller,
mock_disconnect_model,
mock_get_model,
mock_get_controller,
):
mock_get_model.return_value = juju.model.Model()
self.loop.run_until_complete(
self.libjuju.deploy("cs:osm", "model", wait=True, timeout=0)
)
mock_deploy.assert_called_once()
mock_wait_for_model.assert_called_once()
mock_disconnect_controller.assert_called_once()
mock_disconnect_model.assert_called_once()
def test_deploy_no_wait(
self,
mock_deploy,
mock_wait_for_model,
mock_disconnect_controller,
mock_disconnect_model,
mock_get_model,
mock_get_controller,
):
mock_get_model.return_value = juju.model.Model()
self.loop.run_until_complete(
self.libjuju.deploy("cs:osm", "model", wait=False, timeout=0)
)
mock_deploy.assert_called_once()
mock_wait_for_model.assert_not_called()
mock_disconnect_controller.assert_called_once()
mock_disconnect_model.assert_called_once()
def test_deploy_exception(
self,
mock_deploy,
mock_wait_for_model,
mock_disconnect_controller,
mock_disconnect_model,
mock_get_model,
mock_get_controller,
):
mock_deploy.side_effect = Exception()
mock_get_model.return_value = juju.model.Model()
with self.assertRaises(Exception):
self.loop.run_until_complete(self.libjuju.deploy("cs:osm", "model"))
mock_deploy.assert_called_once()
mock_wait_for_model.assert_not_called()
mock_disconnect_controller.assert_called_once()
mock_disconnect_model.assert_called_once()
@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
@asynctest.mock.patch(
"juju.model.Model.applications", new_callable=asynctest.PropertyMock
)
@asynctest.mock.patch("juju.model.Model.machines", new_callable=asynctest.PropertyMock)
@asynctest.mock.patch("juju.model.Model.deploy")
@asynctest.mock.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for")
@asynctest.mock.patch("n2vc.libjuju.Libjuju.create_machine")
class DeployCharmTest(LibjujuTestCase):
def setUp(self):
super(DeployCharmTest, self).setUp()
def test_existing_app(
self,
mock_create_machine,
mock_wait_for,
mock_deploy,
mock_machines,
mock_applications,
mock_disconnect_controller,
mock_disconnect_model,
mock_get_model,
mock_get_controller,
):
mock_get_model.return_value = juju.model.Model()
mock_applications.return_value = {"existing_app"}
application = None
with self.assertRaises(JujuApplicationExists):
application = self.loop.run_until_complete(
self.libjuju.deploy_charm(
"existing_app",
"path",
"model",
"machine",
)
)
self.assertIsNone(application)
mock_disconnect_controller.assert_called()
mock_disconnect_model.assert_called()
def test_non_existing_machine(
self,
mock_create_machine,
mock_wait_for,
mock_deploy,
mock_machines,
mock_applications,
mock_disconnect_controller,
mock_disconnect_model,
mock_get_model,
mock_get_controller,
):
mock_get_model.return_value = juju.model.Model()
mock_machines.return_value = {"existing_machine": FakeMachine()}
application = None
with self.assertRaises(JujuMachineNotFound):
application = self.loop.run_until_complete(
self.libjuju.deploy_charm(
"app",
"path",
"model",
"machine",
)
)
self.assertIsNone(application)
mock_disconnect_controller.assert_called()
mock_disconnect_model.assert_called()
def test_2_units(
self,
mock_create_machine,
mock_wait_for,
mock_deploy,
mock_machines,
mock_applications,
mock_disconnect_controller,
mock_disconnect_model,
mock_get_model,
mock_get_controller,
):
mock_get_model.return_value = juju.model.Model()
mock_machines.return_value = {"existing_machine": FakeMachine()}
mock_create_machine.return_value = (FakeMachine(), "other")
mock_deploy.return_value = FakeApplication()
application = self.loop.run_until_complete(
self.libjuju.deploy_charm(
"app",
"path",
"model",
"existing_machine",
num_units=2,
)
)
self.assertIsInstance(application, FakeApplication)
mock_deploy.assert_called_once()
mock_wait_for.assert_called_once()
mock_create_machine.assert_called_once()
mock_disconnect_controller.assert_called()
mock_disconnect_model.assert_called()
def test_1_unit(
self,
mock_create_machine,
mock_wait_for,
mock_deploy,
mock_machines,
mock_applications,
mock_disconnect_controller,
mock_disconnect_model,
mock_get_model,
mock_get_controller,
):
mock_get_model.return_value = juju.model.Model()
mock_machines.return_value = {"existing_machine": FakeMachine()}
mock_deploy.return_value = FakeApplication()
application = self.loop.run_until_complete(
self.libjuju.deploy_charm("app", "path", "model", "existing_machine")
)
self.assertIsInstance(application, FakeApplication)
mock_deploy.assert_called_once()
mock_wait_for.assert_called_once()
mock_disconnect_controller.assert_called()
mock_disconnect_model.assert_called()
@asynctest.mock.patch(
"juju.model.Model.applications", new_callable=asynctest.PropertyMock
)
class GetApplicationTest(LibjujuTestCase):
def setUp(self):
super(GetApplicationTest, self).setUp()
def test_existing_application(
self,
mock_applications,
):
mock_applications.return_value = {"existing_app": "exists"}
model = juju.model.Model()
result = self.libjuju._get_application(model, "existing_app")
self.assertEqual(result, "exists")
def test_non_existing_application(
self,
mock_applications,
):
mock_applications.return_value = {"existing_app": "exists"}
model = juju.model.Model()
result = self.libjuju._get_application(model, "nonexisting_app")
self.assertIsNone(result)
@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
@asynctest.mock.patch("n2vc.juju_watcher.JujuModelWatcher.wait_for")
@asynctest.mock.patch("juju.model.Model.get_action_output")
@asynctest.mock.patch("juju.model.Model.get_action_status")
class ExecuteActionTest(LibjujuTestCase):
def setUp(self):
super(ExecuteActionTest, self).setUp()
def test_no_application(
self,
mock_get_action_status,
mock_get_action_output,
mock_wait_for,
mock__get_application,
mock_disconnect_controller,
mock_disconnect_model,
mock_get_model,
mock_get_controller,
):
mock__get_application.return_value = None
mock_get_model.return_value = juju.model.Model()
output = None
status = None
with self.assertRaises(JujuApplicationNotFound):
output, status = self.loop.run_until_complete(
self.libjuju.execute_action(
"app",
"model",
"action",
)
)
self.assertIsNone(output)
self.assertIsNone(status)
mock_disconnect_controller.assert_called()
mock_disconnect_model.assert_called()
def test_no_action(
self,
mock_get_action_status,
mock_get_action_output,
mock_wait_for,
mock__get_application,
mock_disconnect_controller,
mock_disconnect_model,
mock_get_model,
mock_get_controller,
):
mock_get_model.return_value = juju.model.Model()
mock__get_application.return_value = FakeApplication()
output = None
status = None
with self.assertRaises(JujuActionNotFound):
output, status = self.loop.run_until_complete(
self.libjuju.execute_action(
"app",
"model",
"action",
)
)
self.assertIsNone(output)
self.assertIsNone(status)
mock_disconnect_controller.assert_called()
mock_disconnect_model.assert_called()
@asynctest.mock.patch("asyncio.sleep")
@asynctest.mock.patch("n2vc.tests.unit.utils.FakeUnit.is_leader_from_status")
def test_no_leader(
self,
mock_is_leader_from_status,
mock_sleep,
mock_get_action_status,
mock_get_action_output,
mock_wait_for,
mock__get_application,
mock_disconnect_controller,
mock_disconnect_model,
mock_get_model,
mock_get_controller,
):
mock_get_model.return_value = juju.model.Model()
mock__get_application.return_value = FakeApplication()
mock_is_leader_from_status.return_value = False
output = None
status = None
with self.assertRaises(JujuLeaderUnitNotFound):
output, status = self.loop.run_until_complete(
self.libjuju.execute_action(
"app",
"model",
"action",
)
)
self.assertIsNone(output)
self.assertIsNone(status)
mock_disconnect_controller.assert_called()
mock_disconnect_model.assert_called()
def test_succesful_exec(
self,
mock_get_action_status,
mock_get_action_output,
mock_wait_for,
mock__get_application,
mock_disconnect_controller,
mock_disconnect_model,
mock_get_model,
mock_get_controller,
):
mock_get_model.return_value = juju.model.Model()
mock__get_application.return_value = FakeApplication()
mock_get_action_output.return_value = "output"
mock_get_action_status.return_value = {"id": "status"}
output, status = self.loop.run_until_complete(
self.libjuju.execute_action("app", "model", "existing_action")
)
self.assertEqual(output, "output")
self.assertEqual(status, "status")
mock_wait_for.assert_called_once()
mock_disconnect_controller.assert_called()
mock_disconnect_model.assert_called()
@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
class GetActionTest(LibjujuTestCase):
def setUp(self):
super(GetActionTest, self).setUp()
def test_exception(
self,
mock_get_application,
mock_disconnect_controller,
mock_disconnect_model,
mock_get_model,
mock_get_controller,
):
mock_get_application.side_effect = Exception()
actions = None
with self.assertRaises(Exception):
actions = self.loop.run_until_complete(
self.libjuju.get_actions("app", "model")
)
self.assertIsNone(actions)
mock_disconnect_controller.assert_called_once()
mock_disconnect_model.assert_called_once()
def test_success(
self,
mock_get_application,
mock_disconnect_controller,
mock_disconnect_model,
mock_get_model,
mock_get_controller,
):
mock_get_application.return_value = FakeApplication()
actions = self.loop.run_until_complete(self.libjuju.get_actions("app", "model"))
self.assertEqual(actions, ["existing_action"])
mock_get_controller.assert_called_once()
mock_get_model.assert_called_once()
mock_disconnect_controller.assert_called_once()
mock_disconnect_model.assert_called_once()
@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
@asynctest.mock.patch("juju.application.Application.get_metrics")
@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
class GetMetricsTest(LibjujuTestCase):
def setUp(self):
super(GetMetricsTest, self).setUp()
def test_get_metrics_success(
self,
mock_get_application,
mock_get_metrics,
mock_disconnect_controller,
mock_disconnect_model,
mock_get_model,
mock_get_controller,
):
mock_get_application.return_value = FakeApplication()
mock_get_model.return_value = juju.model.Model()
self.loop.run_until_complete(self.libjuju.get_metrics("model", "app1"))
mock_disconnect_controller.assert_called_once()
mock_disconnect_model.assert_called_once()
def test_get_metrics_exception(
self,
mock_get_application,
mock_get_metrics,
mock_disconnect_controller,
mock_disconnect_model,
mock_get_model,
mock_get_controller,
):
mock_get_model.return_value = juju.model.Model()
mock_get_metrics.side_effect = Exception()
with self.assertRaises(Exception):
self.loop.run_until_complete(self.libjuju.get_metrics("model", "app1"))
mock_disconnect_controller.assert_called_once()
mock_disconnect_model.assert_called_once()
def test_missing_args_exception(
self,
mock_get_application,
mock_get_metrics,
mock_disconnect_controller,
mock_disconnect_model,
mock_get_model,
mock_get_controller,
):
mock_get_model.return_value = juju.model.Model()
with self.assertRaises(Exception):
self.loop.run_until_complete(self.libjuju.get_metrics("", ""))
mock_get_controller.assert_not_called()
mock_get_model.assert_not_called()
mock_disconnect_controller.assert_not_called()
mock_disconnect_model.assert_not_called()
@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
@asynctest.mock.patch("juju.model.Model.add_relation")
class AddRelationTest(LibjujuTestCase):
def setUp(self):
super(AddRelationTest, self).setUp()
@asynctest.mock.patch("logging.Logger.warning")
def test_not_found(
self,
mock_warning,
mock_add_relation,
mock_disconnect_controller,
mock_disconnect_model,
mock_get_model,
mock_get_controller,
):
# TODO in libjuju.py should this fail only with a log message?
result = {"error": "not found", "response": "response", "request-id": 1}
mock_get_model.return_value = juju.model.Model()
mock_add_relation.side_effect = JujuAPIError(result)
self.loop.run_until_complete(
self.libjuju.add_relation(
"model",
"app1:relation1",
"app2:relation2",
)
)
mock_warning.assert_called_with("Relation not found: not found")
mock_disconnect_controller.assert_called_once()
mock_disconnect_model.assert_called_once()
@asynctest.mock.patch("logging.Logger.warning")
def test_already_exists(
self,
mock_warning,
mock_add_relation,
mock_disconnect_controller,
mock_disconnect_model,
mock_get_model,
mock_get_controller,
):
# TODO in libjuju.py should this fail silently?
result = {"error": "already exists", "response": "response", "request-id": 1}
mock_get_model.return_value = juju.model.Model()
mock_add_relation.side_effect = JujuAPIError(result)
self.loop.run_until_complete(
self.libjuju.add_relation(
"model",
"app1:relation1",
"app2:relation2",
)
)
mock_warning.assert_called_with("Relation already exists: already exists")
mock_disconnect_controller.assert_called_once()
mock_disconnect_model.assert_called_once()
def test_exception(
self,
mock_add_relation,
mock_disconnect_controller,
mock_disconnect_model,
mock_get_model,
mock_get_controller,
):
mock_get_model.return_value = juju.model.Model()
result = {"error": "", "response": "response", "request-id": 1}
mock_add_relation.side_effect = JujuAPIError(result)
with self.assertRaises(JujuAPIError):
self.loop.run_until_complete(
self.libjuju.add_relation(
"model",
"app1:relation1",
"app2:relation2",
)
)
mock_disconnect_controller.assert_called_once()
mock_disconnect_model.assert_called_once()
def test_success(
self,
mock_add_relation,
mock_disconnect_controller,
mock_disconnect_model,
mock_get_model,
mock_get_controller,
):
mock_get_model.return_value = juju.model.Model()
self.loop.run_until_complete(
self.libjuju.add_relation(
"model",
"app1:relation1",
"app2:relation2",
)
)
mock_add_relation.assert_called_with("app1:relation1", "app2:relation2")
mock_disconnect_controller.assert_called_once()
mock_disconnect_model.assert_called_once()
def test_saas(
self,
mock_add_relation,
mock_disconnect_controller,
mock_disconnect_model,
mock_get_model,
mock_get_controller,
):
mock_get_model.return_value = juju.model.Model()
self.loop.run_until_complete(
self.libjuju.add_relation(
"model",
"app1:relation1",
"saas_name",
)
)
mock_add_relation.assert_called_with("app1:relation1", "saas_name")
mock_disconnect_controller.assert_called_once()
mock_disconnect_model.assert_called_once()
# TODO destroy_model testcase
# @asynctest.mock.patch("juju.model.Model.get_machines")
# @asynctest.mock.patch("logging.Logger.debug")
# class DestroyMachineTest(LibjujuTestCase):
# def setUp(self):
# super(DestroyMachineTest, self).setUp()
# def test_success_manual_machine(
# self, mock_debug, mock_get_machines,
# ):
# mock_get_machines.side_effect = [
# {"machine": FakeManualMachine()},
# {"machine": FakeManualMachine()},
# {},
# ]
# self.loop.run_until_complete(
# self.libjuju.destroy_machine(juju.model.Model(), "machine", 2,)
# )
# calls = [
# asynctest.call("Waiting for machine machine is destroyed"),
# asynctest.call("Machine destroyed: machine"),
# ]
# mock_debug.assert_has_calls(calls)
# def test_no_machine(
# self, mock_debug, mock_get_machines,
# ):
# mock_get_machines.return_value = {}
# self.loop.run_until_complete(
# self.libjuju.destroy_machine(juju.model.Model(), "machine", 2)
# )
# mock_debug.assert_called_with("Machine not found: machine")
@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_model")
@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
@asynctest.mock.patch("n2vc.libjuju.Libjuju._get_application")
class ConfigureApplicationTest(LibjujuTestCase):
def setUp(self):
super(ConfigureApplicationTest, self).setUp()
def test_success(
self,
mock_get_application,
mock_disconnect_controller,
mock_disconnect_model,
mock_get_model,
mock_get_controller,
):
mock_get_application.return_value = FakeApplication()
self.loop.run_until_complete(
self.libjuju.configure_application(
"model",
"app",
{"config"},
)
)
mock_get_application.assert_called_once()
mock_disconnect_controller.assert_called_once()
mock_disconnect_model.assert_called_once()
def test_exception(
self,
mock_get_application,
mock_disconnect_controller,
mock_disconnect_model,
mock_get_model,
mock_get_controller,
):
mock_get_application.side_effect = Exception()
with self.assertRaises(Exception):
self.loop.run_until_complete(
self.libjuju.configure_application(
"model",
"app",
{"config"},
)
)
mock_disconnect_controller.assert_called_once()
mock_disconnect_model.assert_called_once()
def test_controller_exception(
self,
mock_get_application,
mock_disconnect_controller,
mock_disconnect_model,
mock_get_model,
mock_get_controller,
):
result = {"error": "not found", "response": "response", "request-id": 1}
mock_get_controller.side_effect = JujuAPIError(result)
with self.assertRaises(JujuAPIError):
self.loop.run_until_complete(
self.libjuju.configure_application(
"model",
"app",
{"config"},
)
)
mock_get_model.assert_not_called()
mock_disconnect_controller.assert_not_called()
mock_disconnect_model.assert_not_called()
def test_get_model_exception(
self,
mock_get_application,
mock_disconnect_controller,
mock_disconnect_model,
mock_get_model,
mock_get_controller,
):
result = {"error": "not found", "response": "response", "request-id": 1}
mock_get_model.side_effect = JujuAPIError(result)
with self.assertRaises(JujuAPIError):
self.loop.run_until_complete(
self.libjuju.configure_application(
"model",
"app",
{"config"},
)
)
mock_get_model.assert_called_once()
mock_disconnect_controller.assert_called_once()
mock_disconnect_model.assert_not_called()
# TODO _get_api_endpoints_db test case
# TODO _update_api_endpoints_db test case
# TODO healthcheck test case
@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
@asynctest.mock.patch("juju.controller.Controller.list_models")
class ListModelsTest(LibjujuTestCase):
def setUp(self):
super(ListModelsTest, self).setUp()
def test_containing(
self,
mock_list_models,
mock_disconnect_controller,
mock_get_controller,
):
mock_get_controller.return_value = juju.controller.Controller()
mock_list_models.return_value = ["existingmodel"]
models = self.loop.run_until_complete(self.libjuju.list_models("existing"))
mock_disconnect_controller.assert_called_once()
self.assertEquals(models, ["existingmodel"])
def test_not_containing(
self,
mock_list_models,
mock_disconnect_controller,
mock_get_controller,
):
mock_get_controller.return_value = juju.controller.Controller()
mock_list_models.return_value = ["existingmodel", "model"]
models = self.loop.run_until_complete(self.libjuju.list_models("mdl"))
mock_disconnect_controller.assert_called_once()
self.assertEquals(models, [])
def test_no_contains_arg(
self,
mock_list_models,
mock_disconnect_controller,
mock_get_controller,
):
mock_get_controller.return_value = juju.controller.Controller()
mock_list_models.return_value = ["existingmodel", "model"]
models = self.loop.run_until_complete(self.libjuju.list_models())
mock_disconnect_controller.assert_called_once()
self.assertEquals(models, ["existingmodel", "model"])
@asynctest.mock.patch("n2vc.libjuju.Libjuju.list_models")
class ModelsExistTest(LibjujuTestCase):
def setUp(self):
super(ModelsExistTest, self).setUp()
def test_model_names_none(self, mock_list_models):
mock_list_models.return_value = []
with self.assertRaises(Exception):
self.loop.run_until_complete(self.libjuju.models_exist(None))
def test_model_names_empty(self, mock_list_models):
mock_list_models.return_value = []
with self.assertRaises(Exception):
(exist, non_existing_models) = self.loop.run_until_complete(
self.libjuju.models_exist([])
)
def test_model_names_not_existing(self, mock_list_models):
mock_list_models.return_value = ["prometheus", "grafana"]
(exist, non_existing_models) = self.loop.run_until_complete(
self.libjuju.models_exist(["prometheus2", "grafana"])
)
self.assertFalse(exist)
self.assertEqual(non_existing_models, ["prometheus2"])
def test_model_names_exist(self, mock_list_models):
mock_list_models.return_value = ["prometheus", "grafana"]
(exist, non_existing_models) = self.loop.run_until_complete(
self.libjuju.models_exist(["prometheus", "grafana"])
)
self.assertTrue(exist)
self.assertEqual(non_existing_models, [])
@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
@asynctest.mock.patch("juju.controller.Controller.list_offers")
class ListOffers(LibjujuTestCase):
def setUp(self):
super(ListOffers, self).setUp()
def test_disconnect_controller(
self,
mock_list_offers,
mock_disconnect_controller,
mock_get_controller,
):
mock_get_controller.return_value = juju.controller.Controller()
mock_list_offers.side_effect = Exception()
with self.assertRaises(Exception):
self.loop.run_until_complete(self.libjuju.list_offers("model"))
mock_disconnect_controller.assert_called_once()
def test_empty_list(
self,
mock_list_offers,
mock_disconnect_controller,
mock_get_controller,
):
mock_get_controller.return_value = juju.controller.Controller()
mock_list_offers.return_value = []
offers = self.loop.run_until_complete(self.libjuju.list_offers("model"))
self.assertEqual(offers, [])
mock_disconnect_controller.assert_called_once()
def test_non_empty_list(
self,
mock_list_offers,
mock_disconnect_controller,
mock_get_controller,
):
mock_get_controller.return_value = juju.controller.Controller()
mock_list_offers.return_value = ["offer"]
offers = self.loop.run_until_complete(self.libjuju.list_offers("model"))
self.assertEqual(offers, ["offer"])
mock_disconnect_controller.assert_called_once()
@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
@asynctest.mock.patch("juju.controller.Controller.get_model")
@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_model")
@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
@asynctest.mock.patch("juju.model.Model.consume")
class ConsumeTest(LibjujuTestCase):
def setUp(self):
super(ConsumeTest, self).setUp()
def test_consume(
self,
mock_consume,
mock_disconnect_controller,
mock_disconnect_model,
mock_get_model,
mock_get_controller,
):
mock_get_controller.return_value = juju.controller.Controller()
mock_get_model.return_value = juju.model.Model()
self.loop.run_until_complete(self.libjuju.consume("offer_url", "model_name"))
mock_consume.assert_called_once()
mock_disconnect_model.assert_called_once()
mock_disconnect_controller.assert_called_once()
def test_parsing_error_exception(
self,
mock_consume,
mock_disconnect_controller,
mock_disconnect_model,
mock_get_model,
mock_get_controller,
):
mock_get_controller.return_value = juju.controller.Controller()
mock_get_model.return_value = juju.model.Model()
mock_consume.side_effect = juju.offerendpoints.ParseError("")
with self.assertRaises(juju.offerendpoints.ParseError):
self.loop.run_until_complete(
self.libjuju.consume("offer_url", "model_name")
)
mock_consume.assert_called_once()
mock_disconnect_model.assert_called_once()
mock_disconnect_controller.assert_called_once()
def test_juju_error_exception(
self,
mock_consume,
mock_disconnect_controller,
mock_disconnect_model,
mock_get_model,
mock_get_controller,
):
mock_get_controller.return_value = juju.controller.Controller()
mock_get_model.return_value = juju.model.Model()
mock_consume.side_effect = juju.errors.JujuError("")
with self.assertRaises(juju.errors.JujuError):
self.loop.run_until_complete(
self.libjuju.consume("offer_url", "model_name")
)
mock_consume.assert_called_once()
mock_disconnect_model.assert_called_once()
mock_disconnect_controller.assert_called_once()
def test_juju_api_error_exception(
self,
mock_consume,
mock_disconnect_controller,
mock_disconnect_model,
mock_get_model,
mock_get_controller,
):
mock_get_controller.return_value = juju.controller.Controller()
mock_get_model.return_value = juju.model.Model()
mock_consume.side_effect = juju.errors.JujuAPIError(
{"error": "", "response": "", "request-id": ""}
)
with self.assertRaises(juju.errors.JujuAPIError):
self.loop.run_until_complete(
self.libjuju.consume("offer_url", "model_name")
)
mock_consume.assert_called_once()
mock_disconnect_model.assert_called_once()
mock_disconnect_controller.assert_called_once()
@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_k8s_cloud_credential")
@asynctest.mock.patch("n2vc.libjuju.Libjuju.add_cloud")
class AddK8sTest(LibjujuTestCase):
def setUp(self):
super(AddK8sTest, self).setUp()
name = "cloud"
rbac_id = generate_rbac_id()
token = "token"
client_cert_data = "cert"
configuration = kubernetes.client.configuration.Configuration()
storage_class = "storage_class"
credential_name = name
self._add_k8s_args = {
"name": name,
"rbac_id": rbac_id,
"token": token,
"client_cert_data": client_cert_data,
"configuration": configuration,
"storage_class": storage_class,
"credential_name": credential_name,
}
def test_add_k8s(self, mock_add_cloud, mock_get_k8s_cloud_credential):
self.loop.run_until_complete(self.libjuju.add_k8s(**self._add_k8s_args))
mock_add_cloud.assert_called_once()
mock_get_k8s_cloud_credential.assert_called_once()
def test_add_k8s_exception(self, mock_add_cloud, mock_get_k8s_cloud_credential):
mock_add_cloud.side_effect = Exception()
with self.assertRaises(Exception):
self.loop.run_until_complete(self.libjuju.add_k8s(**self._add_k8s_args))
mock_add_cloud.assert_called_once()
mock_get_k8s_cloud_credential.assert_called_once()
def test_add_k8s_missing_name(self, mock_add_cloud, mock_get_k8s_cloud_credential):
self._add_k8s_args["name"] = ""
with self.assertRaises(Exception):
self.loop.run_until_complete(self.libjuju.add_k8s(**self._add_k8s_args))
mock_add_cloud.assert_not_called()
def test_add_k8s_missing_storage_name(
self, mock_add_cloud, mock_get_k8s_cloud_credential
):
self._add_k8s_args["storage_class"] = ""
with self.assertRaises(Exception):
self.loop.run_until_complete(self.libjuju.add_k8s(**self._add_k8s_args))
mock_add_cloud.assert_not_called()
def test_add_k8s_missing_configuration_keys(
self, mock_add_cloud, mock_get_k8s_cloud_credential
):
self._add_k8s_args["configuration"] = None
with self.assertRaises(Exception):
self.loop.run_until_complete(self.libjuju.add_k8s(**self._add_k8s_args))
mock_add_cloud.assert_not_called()
@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
@asynctest.mock.patch("juju.controller.Controller.add_cloud")
@asynctest.mock.patch("juju.controller.Controller.add_credential")
class AddCloudTest(LibjujuTestCase):
def setUp(self):
super(AddCloudTest, self).setUp()
self.cloud = juju.client.client.Cloud()
self.credential = juju.client.client.CloudCredential()
def test_add_cloud_with_credential(
self,
mock_add_credential,
mock_add_cloud,
mock_disconnect_controller,
mock_get_controller,
):
mock_get_controller.return_value = juju.controller.Controller()
cloud = self.loop.run_until_complete(
self.libjuju.add_cloud("cloud", self.cloud, credential=self.credential)
)
self.assertEqual(cloud, self.cloud)
mock_add_cloud.assert_called_once_with("cloud", self.cloud)
mock_add_credential.assert_called_once_with(
"cloud", credential=self.credential, cloud="cloud"
)
mock_disconnect_controller.assert_called_once()
def test_add_cloud_no_credential(
self,
mock_add_credential,
mock_add_cloud,
mock_disconnect_controller,
mock_get_controller,
):
mock_get_controller.return_value = juju.controller.Controller()
cloud = self.loop.run_until_complete(
self.libjuju.add_cloud("cloud", self.cloud)
)
self.assertEqual(cloud, self.cloud)
mock_add_cloud.assert_called_once_with("cloud", self.cloud)
mock_add_credential.assert_not_called()
mock_disconnect_controller.assert_called_once()
def test_add_cloud_exception(
self,
mock_add_credential,
mock_add_cloud,
mock_disconnect_controller,
mock_get_controller,
):
mock_get_controller.return_value = juju.controller.Controller()
mock_add_cloud.side_effect = Exception()
with self.assertRaises(Exception):
self.loop.run_until_complete(
self.libjuju.add_cloud("cloud", self.cloud, credential=self.credential)
)
mock_add_cloud.assert_called_once_with("cloud", self.cloud)
mock_add_credential.assert_not_called()
mock_disconnect_controller.assert_called_once()
def test_add_credential_exception(
self,
mock_add_credential,
mock_add_cloud,
mock_disconnect_controller,
mock_get_controller,
):
mock_get_controller.return_value = juju.controller.Controller()
mock_add_credential.side_effect = Exception()
with self.assertRaises(Exception):
self.loop.run_until_complete(
self.libjuju.add_cloud("cloud", self.cloud, credential=self.credential)
)
mock_add_cloud.assert_called_once_with("cloud", self.cloud)
mock_add_credential.assert_called_once_with(
"cloud", credential=self.credential, cloud="cloud"
)
mock_disconnect_controller.assert_called_once()
@asynctest.mock.patch("n2vc.libjuju.Libjuju.get_controller")
@asynctest.mock.patch("n2vc.libjuju.Libjuju.disconnect_controller")
@asynctest.mock.patch("juju.controller.Controller.remove_cloud")
class RemoveCloudTest(LibjujuTestCase):
def setUp(self):
super(RemoveCloudTest, self).setUp()
def test_remove_cloud(
self,
mock_remove_cloud,
mock_disconnect_controller,
mock_get_controller,
):
mock_get_controller.return_value = juju.controller.Controller()
self.loop.run_until_complete(self.libjuju.remove_cloud("cloud"))
mock_remove_cloud.assert_called_once_with("cloud")
mock_disconnect_controller.assert_called_once()
def test_remove_cloud_exception(
self,
mock_remove_cloud,
mock_disconnect_controller,
mock_get_controller,
):
mock_get_controller.return_value = juju.controller.Controller()
mock_remove_cloud.side_effect = Exception()
with self.assertRaises(Exception):
self.loop.run_until_complete(self.libjuju.remove_cloud("cloud"))
mock_remove_cloud.assert_called_once_with("cloud")
mock_disconnect_controller.assert_called_once()
@asynctest.mock.patch("kubernetes.client.configuration.Configuration")
class GetK8sCloudCredentials(LibjujuTestCase):
def setUp(self):
super(GetK8sCloudCredentials, self).setUp()
self.cert_data = "cert"
self.token = "token"
@asynctest.mock.patch("n2vc.exceptions.JujuInvalidK8sConfiguration")
def test_not_supported(self, mock_exception, mock_configuration):
mock_configuration.username = ""
mock_configuration.password = ""
mock_configuration.ssl_ca_cert = None
mock_configuration.cert_file = None
mock_configuration.key_file = None
exception_raised = False
self.token = None
self.cert_data = None
try:
_ = self.libjuju.get_k8s_cloud_credential(
mock_configuration,
self.cert_data,
self.token,
)
except JujuInvalidK8sConfiguration as e:
exception_raised = True
self.assertEqual(
e.message,
"authentication method not supported",
)
self.assertTrue(exception_raised)
def test_user_pass(self, mock_configuration):
mock_configuration.username = "admin"
mock_configuration.password = "admin"
mock_configuration.ssl_ca_cert = None
mock_configuration.cert_file = None
mock_configuration.key_file = None
self.token = None
self.cert_data = None
credential = self.libjuju.get_k8s_cloud_credential(
mock_configuration,
self.cert_data,
self.token,
)
self.assertEqual(
credential,
juju.client._definitions.CloudCredential(
attrs={"username": "admin", "password": "admin"}, auth_type="userpass"
),
)
def test_user_pass_with_cert(self, mock_configuration):
mock_configuration.username = "admin"
mock_configuration.password = "admin"
mock_configuration.ssl_ca_cert = None
mock_configuration.cert_file = None
mock_configuration.key_file = None
self.token = None
credential = self.libjuju.get_k8s_cloud_credential(
mock_configuration,
self.cert_data,
self.token,
)
self.assertEqual(
credential,
juju.client._definitions.CloudCredential(
attrs={
"ClientCertificateData": self.cert_data,
"username": "admin",
"password": "admin",
},
auth_type="userpasswithcert",
),
)
def test_user_no_pass(self, mock_configuration):
mock_configuration.username = "admin"
mock_configuration.password = ""
mock_configuration.ssl_ca_cert = None
mock_configuration.cert_file = None
mock_configuration.key_file = None
self.token = None
self.cert_data = None
with mock.patch.object(self.libjuju.log, "debug") as mock_debug:
credential = self.libjuju.get_k8s_cloud_credential(
mock_configuration,
self.cert_data,
self.token,
)
self.assertEqual(
credential,
juju.client._definitions.CloudCredential(
attrs={"username": "admin", "password": ""}, auth_type="userpass"
),
)
mock_debug.assert_called_once_with(
"credential for user admin has empty password"
)
def test_cert(self, mock_configuration):
mock_configuration.username = ""
mock_configuration.password = ""
mock_configuration.api_key = {"authorization": "Bearer Token"}
ssl_ca_cert = tempfile.NamedTemporaryFile()
with open(ssl_ca_cert.name, "w") as ssl_ca_cert_file:
ssl_ca_cert_file.write("cacert")
mock_configuration.ssl_ca_cert = ssl_ca_cert.name
mock_configuration.cert_file = None
mock_configuration.key_file = None
credential = self.libjuju.get_k8s_cloud_credential(
mock_configuration,
self.cert_data,
self.token,
)
self.assertEqual(
credential,
juju.client._definitions.CloudCredential(
attrs={"ClientCertificateData": self.cert_data, "Token": self.token},
auth_type="certificate",
),
)
# TODO: Fix this test when oauth authentication is supported
# def test_oauth2(self, mock_configuration):
# mock_configuration.username = ""
# mock_configuration.password = ""
# mock_configuration.api_key = {"authorization": "Bearer Token"}
# key = tempfile.NamedTemporaryFile()
# with open(key.name, "w") as key_file:
# key_file.write("key")
# mock_configuration.ssl_ca_cert = None
# mock_configuration.cert_file = None
# mock_configuration.key_file = key.name
# credential = self.libjuju.get_k8s_cloud_credential(
# mock_configuration,
# self.cert_data,
# self.token,
# )
# self.assertEqual(
# credential,
# juju.client._definitions.CloudCredential(
# attrs={"ClientKeyData": "key", "Token": "Token"},
# auth_type="oauth2",
# ),
# )
# @asynctest.mock.patch("n2vc.exceptions.JujuInvalidK8sConfiguration")
# def test_oauth2_missing_token(self, mock_exception, mock_configuration):
# mock_configuration.username = ""
# mock_configuration.password = ""
# key = tempfile.NamedTemporaryFile()
# with open(key.name, "w") as key_file:
# key_file.write("key")
# mock_configuration.ssl_ca_cert = None
# mock_configuration.cert_file = None
# mock_configuration.key_file = key.name
# exception_raised = False
# try:
# _ = self.libjuju.get_k8s_cloud_credential(
# mock_configuration,
# self.cert_data,
# self.token,
# )
# except JujuInvalidK8sConfiguration as e:
# exception_raised = True
# self.assertEqual(
# e.message,
# "missing token for auth type oauth2",
# )
# self.assertTrue(exception_raised)
def test_exception_cannot_set_token_and_userpass(self, mock_configuration):
mock_configuration.username = "admin"
mock_configuration.password = "pass"
mock_configuration.api_key = {"authorization": "No_bearer_token"}
mock_configuration.ssl_ca_cert = None
mock_configuration.cert_file = None
mock_configuration.key_file = None
exception_raised = False
try:
_ = self.libjuju.get_k8s_cloud_credential(
mock_configuration,
self.cert_data,
self.token,
)
except JujuInvalidK8sConfiguration as e:
exception_raised = True
self.assertEqual(
e.message,
"Cannot set both token and user/pass",
)
self.assertTrue(exception_raised)