Exemplo n.º 1
0
class TestEndpointProvider(unittest.TestCase):
    def setUp(self):
        self.harness = Harness(EndpointProviderCharm, meta=PROVIDER_META)
        self.addCleanup(self.harness.cleanup)
        self.harness.set_leader(True)
        self.harness.begin()

    def test_provider_default_scrape_relations_not_in_meta(self):
        """Tests that the Provider raises exception when no promethes_scrape in meta."""
        harness = Harness(
            EndpointProviderCharm,
            # No provider relation with `prometheus_scrape` as interface
            meta="""
                name: provider-tester
                containers:
                    prometheus:
                        resource: prometheus-image
                prometheus-tester: {}
                provides:
                    non-standard-name:
                        interface: prometheus_scrape
                """,
        )
        self.assertRaises(RelationNotFoundError, harness.begin)

    def test_provider_default_scrape_relation_wrong_interface(self):
        """Tests that Provider raises exception if the default relation has the wrong interface."""
        harness = Harness(
            EndpointProviderCharm,
            # No provider relation with `prometheus_scrape` as interface
            meta="""
                name: provider-tester
                containers:
                    prometheus:
                        resource: prometheus-image
                prometheus-tester: {}
                provides:
                    metrics-endpoint:
                        interface: not_prometheus_scrape
                """,
        )
        self.assertRaises(RelationInterfaceMismatchError, harness.begin)

    def test_provider_default_scrape_relation_wrong_role(self):
        """Tests that Provider raises exception if the default relation has the wrong role."""
        harness = Harness(
            EndpointProviderCharm,
            # No provider relation with `prometheus_scrape` as interface
            meta="""
                name: provider-tester
                containers:
                    prometheus:
                        resource: prometheus-image
                prometheus-tester: {}
                requires:
                    metrics-endpoint:
                        interface: prometheus_scrape
                """,
        )
        self.assertRaises(RelationRoleMismatchError, harness.begin)

    @patch("ops.testing._TestingModelBackend.network_get")
    def test_provider_sets_scrape_metadata(self, _):
        rel_id = self.harness.add_relation(RELATION_NAME, "provider")
        self.harness.add_relation_unit(rel_id, "provider/0")
        data = self.harness.get_relation_data(rel_id,
                                              self.harness.model.app.name)
        self.assertIn("scrape_metadata", data)
        scrape_metadata = data["scrape_metadata"]
        self.assertIn("model", scrape_metadata)
        self.assertIn("model_uuid", scrape_metadata)
        self.assertIn("application", scrape_metadata)

    @patch("ops.testing._TestingModelBackend.network_get")
    def test_provider_unit_sets_bind_address_on_pebble_ready(
            self, mock_net_get):
        bind_address = "192.0.8.2"
        fake_network = {
            "bind-addresses": [{
                "interface-name":
                "eth0",
                "addresses": [{
                    "hostname": "prometheus-tester-0",
                    "value": bind_address
                }],
            }]
        }
        mock_net_get.return_value = fake_network
        rel_id = self.harness.add_relation(RELATION_NAME, "provider")
        self.harness.container_pebble_ready("prometheus-tester")
        data = self.harness.get_relation_data(rel_id,
                                              self.harness.charm.unit.name)
        self.assertIn("prometheus_scrape_host", data)
        self.assertEqual(data["prometheus_scrape_host"], bind_address)

    @patch("ops.testing._TestingModelBackend.network_get")
    def test_provider_unit_sets_bind_address_on_relation_joined(
            self, mock_net_get):
        bind_address = "192.0.8.2"
        fake_network = {
            "bind-addresses": [{
                "interface-name":
                "eth0",
                "addresses": [{
                    "hostname": "prometheus-tester-0",
                    "value": bind_address
                }],
            }]
        }
        mock_net_get.return_value = fake_network
        rel_id = self.harness.add_relation(RELATION_NAME, "provider")
        self.harness.add_relation_unit(rel_id, "provider/0")
        data = self.harness.get_relation_data(rel_id,
                                              self.harness.charm.unit.name)
        self.assertIn("prometheus_scrape_host", data)
        self.assertEqual(data["prometheus_scrape_host"], bind_address)

    @patch("ops.testing._TestingModelBackend.network_get")
    def test_provider_supports_multiple_jobs(self, _):
        rel_id = self.harness.add_relation(RELATION_NAME, "provider")
        self.harness.add_relation_unit(rel_id, "provider/0")
        data = self.harness.get_relation_data(rel_id,
                                              self.harness.model.app.name)
        self.assertIn("scrape_jobs", data)
        jobs = json.loads(data["scrape_jobs"])
        self.assertEqual(len(jobs), len(JOBS))
        names = [job["job_name"] for job in jobs]
        job_names = [job["job_name"] for job in JOBS]
        self.assertListEqual(names, job_names)

    @patch("ops.testing._TestingModelBackend.network_get")
    def test_provider_sanitizes_jobs(self, _):
        rel_id = self.harness.add_relation(RELATION_NAME, "provider")
        self.harness.add_relation_unit(rel_id, "provider/0")
        data = self.harness.get_relation_data(rel_id,
                                              self.harness.model.app.name)
        self.assertIn("scrape_jobs", data)
        jobs = json.loads(data["scrape_jobs"])
        for job in jobs:
            keys = set(job.keys())
            self.assertTrue(keys.issubset(ALLOWED_KEYS))

    @patch("ops.testing._TestingModelBackend.network_get")
    def test_each_alert_rule_is_topology_labeled(self, _):
        rel_id = self.harness.add_relation(RELATION_NAME, "provider")
        self.harness.add_relation_unit(rel_id, "provider/0")
        data = self.harness.get_relation_data(rel_id,
                                              self.harness.model.app.name)
        self.assertIn("alert_rules", data)
        alerts = json.loads(data["alert_rules"])
        self.assertIn("groups", alerts)
        self.assertEqual(len(alerts["groups"]), 1)
        group = alerts["groups"][0]
        for rule in group["rules"]:
            self.assertIn("labels", rule)
            labels = rule["labels"]
            self.assertIn("juju_model", labels)
            self.assertIn("juju_application", labels)
            self.assertIn("juju_model_uuid", labels)

    @patch("ops.testing._TestingModelBackend.network_get")
    def test_each_alert_expression_is_topology_labeled(self, _):
        rel_id = self.harness.add_relation(RELATION_NAME, "provider")
        self.harness.add_relation_unit(rel_id, "provider/0")
        data = self.harness.get_relation_data(rel_id,
                                              self.harness.model.app.name)
        self.assertIn("alert_rules", data)
        alerts = json.loads(data["alert_rules"])
        self.assertIn("groups", alerts)
        self.assertEqual(len(alerts["groups"]), 1)
        group = alerts["groups"][0]
        for rule in group["rules"]:
            self.assertIn("expr", rule)
            for labels in expression_labels(rule["expr"]):
                self.assertIn("juju_model", labels)
                self.assertIn("juju_model_uuid", labels)
                self.assertIn("juju_application", labels)
Exemplo n.º 2
0
class TestCharm(unittest.TestCase):
    def setUp(self):
        self.harness = Harness(MongoDBCharm)
        self.addCleanup(self.harness.cleanup)
        mongo_resource = {
            "registrypath": "mongodb:4.4.1",
            "username": "******",
            "password": "******"
        }
        self.harness.add_oci_resource("mongodb-image", mongo_resource)
        self.harness.begin()
        self.peer_rel_id = self.harness.add_relation('mongodb', 'mongodb')

    @patch('ops.testing._TestingPebbleClient.pull')
    def test_replica_set_name_can_be_changed(self, _):
        self.harness.set_leader(True)
        self.harness.container_pebble_ready("mongodb")

        # check default replica set name
        plan = self.harness.get_container_pebble_plan("mongodb")
        self.assertEqual(replica_set_name(plan), "rs0")

        # check replica set name can be changed
        self.harness.update_config({"replica_set_name": "new_name"})
        plan = self.harness.get_container_pebble_plan("mongodb")
        self.assertEqual(replica_set_name(plan), "new_name")

    @patch("mongoserver.MongoDB.reconfigure_replica_set")
    def test_replica_set_is_reconfigured_when_peer_joins(self, mock_reconf):
        self.harness.set_leader(True)
        self.harness.add_relation_unit(self.peer_rel_id, 'mongodb/1')
        self.harness.update_relation_data(self.peer_rel_id, 'mongodb/1',
                                          {'private-address': '10.0.0.1'})
        peers = [
            'mongodb-k8s-0.mongodb-k8s-endpoints',
            'mongodb-k8s-1.mongodb-k8s-endpoints'
        ]
        mock_reconf.assert_called_once_with(peers)

    def test_replica_set_uri_data_is_generated_correctly(self):
        self.harness.set_leader(True)
        replica_set_uri = self.harness.charm.mongo.replica_set_uri()
        data = self.harness.get_relation_data(self.peer_rel_id,
                                              self.harness.model.app.name)
        cred = "root:{}".format(data['root_password'])
        self.assertEqual(
            replica_set_uri,
            'mongodb://{}@mongodb-k8s-0.mongodb-k8s-endpoints:27017/admin'.
            format(cred))

    def test_leader_sets_key_and_root_credentials(self):
        self.harness.set_leader(False)
        self.harness.set_leader(True)
        data = self.harness.get_relation_data(self.peer_rel_id,
                                              self.harness.model.app.name)
        self.assertIsNotNone(data['root_password'])
        self.assertIsNotNone(data['security_key'])

    @patch('mongoserver.MongoDB.version')
    def test_charm_provides_version(self, mock_version):
        self.harness.set_leader(True)
        mock_version.return_value = "4.4.1"
        version = self.harness.charm.mongo.version()
        self.assertEqual(version, "4.4.1")

    @patch('mongoserver.MongoDB.is_ready')
    def test_start_is_deferred_if_monog_is_not_ready(self, is_ready):
        is_ready.return_value = False
        self.harness.set_leader(True)
        with self.assertLogs(level="DEBUG") as logger:
            self.harness.charm.on.start.emit()
            is_ready.assert_called()
            for message in sorted(logger.output):
                if "DEBUG:ops.framework:Deferring" in message:
                    self.assertIn("StartEvent", message)

    @patch('mongoserver.MongoDB.initialize_replica_set')
    @patch('mongoserver.MongoDB.is_ready')
    def test_start_is_deffered_if_monog_is_not_initialized(
            self, is_ready, initialize):
        is_ready.return_value = True
        initialize.side_effect = RuntimeError("Not Initialized")
        self.harness.set_leader(True)
        with self.assertLogs(level="DEBUG") as logger:
            self.harness.charm.on.start.emit()
            is_ready.assert_called()
            self.assertIn(
                "INFO:charm:Deferring on_start since : error=Not Initialized",
                sorted(logger.output))
Exemplo n.º 3
0
class TestSourceConsumer(unittest.TestCase):
    def setUp(self):
        self.harness = Harness(ConsumerCharm, meta=CONSUMER_META)
        self.addCleanup(self.harness.cleanup)
        self.harness.set_leader(True)
        self.harness.begin()

    @patch("ops.testing._TestingModelBackend.network_get")
    def test_consumer_sets_scrape_data(self, _):
        rel_id = self.harness.add_relation("grafana-source", "consumer")
        self.harness.add_relation_unit(rel_id, "consumer/0")
        data = self.harness.get_relation_data(rel_id,
                                              self.harness.model.app.name)
        self.assertIn("grafana_source_data", data)
        scrape_data = data["grafana_source_data"]
        self.assertIn("model", scrape_data)
        self.assertIn("model_uuid", scrape_data)
        self.assertIn("application", scrape_data)

    @patch("ops.testing._TestingModelBackend.network_get")
    def test_consumer_unit_sets_bind_address_on_pebble_ready(
            self, mock_net_get):
        bind_address = "1.2.3.4"
        fake_network = {
            "bind-addresses": [{
                "interface-name":
                "eth0",
                "addresses": [{
                    "hostname": "grafana-tester-0",
                    "value": bind_address
                }],
            }]
        }
        mock_net_get.return_value = fake_network
        rel_id = self.harness.add_relation("grafana-source", "consumer")
        self.harness.container_pebble_ready("grafana-tester")
        self.harness.add_relation_unit(rel_id, "consumer/0")
        data = self.harness.get_relation_data(rel_id,
                                              self.harness.charm.unit.name)
        self.assertIn("grafana_source_host", data)
        self.assertEqual(data["grafana_source_host"], f"{bind_address}:9090")

    @patch("ops.testing._TestingModelBackend.network_get")
    def test_consumer_unit_sets_bind_address_on_relation_joined(
            self, mock_net_get):
        bind_address = "1.2.3.4"
        fake_network = {
            "bind-addresses": [{
                "interface-name":
                "eth0",
                "addresses": [{
                    "hostname": "grafana-tester-0",
                    "value": bind_address
                }],
            }]
        }
        mock_net_get.return_value = fake_network
        rel_id = self.harness.add_relation("grafana-source", "consumer")
        self.harness.add_relation_unit(rel_id, "consumer/0")
        data = self.harness.get_relation_data(rel_id,
                                              self.harness.charm.unit.name)
        self.assertIn("grafana_source_host", data)
        self.assertEqual(data["grafana_source_host"], f"{bind_address}:9090")
Exemplo n.º 4
0
class TestCharm(unittest.TestCase):
    @patch("charm.KubernetesServicePatch", lambda x, y: None)
    @patch_network_get(private_address="1.1.1.1")
    def setUp(self, *unused):
        self.harness = Harness(PrometheusCharm)
        self.addCleanup(self.harness.cleanup)
        self.harness.begin_with_initial_hooks()

    @patch_network_get(private_address="1.1.1.1")
    def test_grafana_is_provided_port_and_source(self, *unused):
        rel_id = self.harness.add_relation("grafana-source", "grafana")
        self.harness.add_relation_unit(rel_id, "grafana/0")
        grafana_host = self.harness.get_relation_data(
            rel_id, self.harness.model.unit.name)["grafana_source_host"]
        self.assertEqual(grafana_host, "{}:{}".format("1.1.1.1", "9090"))

    def test_default_cli_log_level_is_info(self):
        plan = self.harness.get_container_pebble_plan("prometheus")
        self.assertEqual(cli_arg(plan, "--log.level"), "info")

    def test_invalid_log_level_defaults_to_debug(self):
        bad_log_config = {"log_level": "bad-level"}
        with self.assertLogs(level="ERROR") as logger:
            self.harness.update_config(bad_log_config)
            expected_logs = [
                "ERROR:root:Invalid loglevel: bad-level given, "
                "debug/info/warn/error/fatal allowed. "
                "defaulting to DEBUG loglevel."
            ]
            self.assertEqual(sorted(logger.output), expected_logs)

        plan = self.harness.get_container_pebble_plan("prometheus")
        self.assertEqual(cli_arg(plan, "--log.level"), "debug")

    def test_valid_log_level_is_accepted(self):
        valid_log_config = {"log_level": "warn"}
        self.harness.update_config(valid_log_config)

        plan = self.harness.get_container_pebble_plan("prometheus")
        self.assertEqual(cli_arg(plan, "--log.level"), "warn")

    @patch_network_get(private_address="1.1.1.1")
    def test_ingress_relation_not_set(self):
        self.harness.set_leader(True)

        plan = self.harness.get_container_pebble_plan("prometheus")
        self.assertEqual(cli_arg(plan, "--web.external-url"),
                         "http://1.1.1.1:9090")

    @patch_network_get(private_address="1.1.1.1")
    def test_ingress_relation_set(self):
        self.harness.set_leader(True)

        rel_id = self.harness.add_relation("ingress", "traefik-ingress")
        self.harness.add_relation_unit(rel_id, "traefik-ingress/0")

        plan = self.harness.get_container_pebble_plan("prometheus")
        self.assertEqual(cli_arg(plan, "--web.external-url"),
                         "http://1.1.1.1:9090")

    @patch_network_get(private_address="1.1.1.1")
    def test_web_external_url_has_precedence_over_ingress_relation(self):
        self.harness.set_leader(True)

        self.harness.update_config({"web_external_url": "http://*****:*****@patch_network_get(private_address="1.1.1.1")
    def test_web_external_url_set(self):
        self.harness.set_leader(True)

        self.harness.update_config({"web_external_url": "http://*****:*****@patch("prometheus_server.Prometheus.reload_configuration")
    def test_configuration_reload(self, trigger_configuration_reload):
        self.harness.container_pebble_ready("prometheus")

        trigger_configuration_reload.assert_called()

        self.harness.update_config({"log_level": "INFO"})
        trigger_configuration_reload.assert_called()
Exemplo n.º 5
0
class TestCharm(unittest.TestCase):
    @patch.object(CassandraOperatorCharm, "_goal_units", new=lambda x: 1)
    @patch.object(CassandraOperatorCharm, "_bind_address", new=lambda x: "1.1.1.1")
    @patch.object(ops.model.Container, "pull", new=fake_pull)
    @patch.object(ops.model.Container, "push", new=fake_push)
    def setUp(self):
        self.harness = Harness(CassandraOperatorCharm)
        self.addCleanup(self.harness.cleanup)
        self.harness.begin_with_initial_hooks()
        self.harness.set_leader(True)

    def tearDown(self):
        global FILES
        FILES = {}

    def test_relation_is_set(self):
        rel_id = self.harness.add_relation("database", "otherapp")
        self.assertIsInstance(rel_id, int)
        self.harness.add_relation_unit(rel_id, "otherapp/0")
        self.harness.update_relation_data(rel_id, "otherapp", {})
        self.assertEqual(
            self.harness.get_relation_data(rel_id, self.harness.model.app.name)["port"],
            "9042",
        )
        self.assertEqual(
            self.harness.get_relation_data(rel_id, self.harness.model.app.name)["address"],
            "cassandra-k8s-0.cassandra-k8s-endpoints.None.svc.cluster.local",
        )

    def test_root_password_is_set(self):
        rel = self.harness.charm.model.get_relation("cassandra-peers")
        self.assertEqual(rel.data[self.harness.charm.app].get("root_password", None), None)
        self.assertEqual(bool(self.harness.charm.cassandra.root_password(None)), True)

    def test_config_file_is_set(self):
        self.harness.container_pebble_ready("cassandra")
        sample_content = yaml.safe_load(SAMPLE_CONFIG)
        content_str = (
            self.harness.charm.unit.get_container("cassandra")
            .pull("/etc/cassandra/cassandra.yaml")
            .read()
        )
        content = yaml.safe_load(content_str)
        assert content == sample_content

    @patch("ops.testing._TestingModelBackend.network_get")
    @patch("ops.testing._TestingPebbleClient.list_files")
    def test_prometheus_data_set(self, mock_net_get, mock_list_files):
        bind_address = "1.1.1.1"
        fake_network = {
            "bind-addresses": [
                {
                    "interface-name": "eth0",
                    "addresses": [{"hostname": "cassandra-tester-0", "value": bind_address}],
                }
            ]
        }
        mock_net_get.return_value = fake_network
        rel_id = self.harness.add_relation("monitoring", "otherapp")
        self.assertIsInstance(rel_id, int)
        self.harness.add_relation_unit(rel_id, "otherapp/0")
        self.harness.update_relation_data(rel_id, "otherapp", {})
        self.assertEqual(
            json.loads(
                self.harness.get_relation_data(rel_id, self.harness.model.app.name)["scrape_jobs"]
            )[0]["static_configs"][0]["targets"],
            ["*:9500"],
        )

    @patch("ops.testing._TestingModelBackend.network_get")
    @patch("ops.testing._TestingPebbleClient.list_files")
    def test_heap_size_default(self, mock_net_get, mock_list_files):
        cassandra_environment = self._start_cassandra_and_get_pebble_service().environment

        self.assertEqual(cassandra_environment["JVM_OPTS"], "-Xms6G -Xmx6G")
        self.assertEqual(self.harness.model.unit.status, ops.model.ActiveStatus())

    @patch("ops.testing._TestingModelBackend.network_get")
    @patch("ops.testing._TestingPebbleClient.list_files")
    def test_heap_size_config_success(self, mock_net_get, mock_list_files):
        self.harness.update_config({"heap_size": "1g"})

        cassandra_environment = self._start_cassandra_and_get_pebble_service().environment

        self.assertEqual(cassandra_environment["JVM_OPTS"], "-Xms1g -Xmx1g")
        self.assertEqual(self.harness.model.unit.status, ops.model.ActiveStatus())

    @patch("ops.testing._TestingModelBackend.network_get")
    @patch("ops.testing._TestingPebbleClient.list_files")
    def test_heap_size_config_invalid(self, mock_net_get, mock_list_files):
        self.harness.update_config({"heap_size": "0.5g"})

        self.assertEqual(
            self.harness.model.unit.status,
            ops.model.BlockedStatus("Invalid Cassandra heap size setting: '0.5g'"),
        )

    def _start_cassandra_and_get_pebble_service(self):
        container = self.harness.model.unit.get_container("cassandra")

        self.harness.charm.on.cassandra_pebble_ready.emit(container)

        pebble_plan = self.harness.get_container_pebble_plan("cassandra")
        return pebble_plan.services["cassandra"]