def test_pod_spec_is_generated(self):
        # Exercise
        spec = domain.build_juju_pod_spec(app_name=self.mock_app_name,
                                          charm_config=self.mock_config,
                                          image_meta=self.mock_image_meta)

        # Assertions
        assert type(spec) == dict
        assert spec == {
            'containers': [{
                'name':
                self.mock_app_name,
                'imageDetails': {
                    'imagePath': self.mock_image_meta.image_path,
                    'username': self.mock_image_meta.repo_username,
                    'password': self.mock_image_meta.repo_password
                },
                'ports': [{
                    'containerPort': self.mock_advertised_port,
                    'protocol': 'TCP'
                }],
                'readinessProbe': {
                    'httpGet': {
                        'path': '/api/health',
                        'port': self.mock_advertised_port
                    },
                    'initialDelaySeconds': 10,
                    'timeoutSeconds': 30
                }
            }]
        }
示例#2
0
def set_juju_pod_spec(fw_adapter, alerting_config=None):
    # Mutable defaults bug as described in https://bit.ly/3cF0k0w
    if not alerting_config:
        alerting_config = dict()

    if not fw_adapter.unit_is_leader():
        logging.debug("Unit is not a leader, skip pod spec configuration")
        # Although PodSpec will not be altered, the pod provisioning process
        # still have to continue
        return True

    if alerting_config:
        logger.debug("Got alerting config: {} {}".format(
            type(alerting_config), alerting_config))

    logging.debug("Building Juju pod spec")
    try:
        juju_pod_spec = build_juju_pod_spec(
            app_name=fw_adapter.get_app_name(),
            charm_config=fw_adapter.get_config(),
            prom_image_meta=fw_adapter.get_image_meta('prometheus-image'),
            nginx_image_meta=fw_adapter.get_image_meta('nginx-image'),
            alerting_config=alerting_config)
        pod_spec = juju_pod_spec.to_dict()
    except CharmError as e:
        fw_adapter.set_unit_status(
            BlockedStatus("Pod spec build failure: {0}".format(e)))
        return False
    logging.debug("Configuring pod: set PodSpec to: {0}".format(pod_spec))
    fw_adapter.set_pod_spec(pod_spec)
    fw_adapter.set_unit_status(MaintenanceStatus("Configuring pod"))
    return True
    def test_pod_spec_with_prometheus_config_is_generated(self):
        # Exercise
        spec = domain.build_juju_pod_spec(
            app_name=self.mock_app_name,
            charm_config=self.mock_config,
            image_meta=self.mock_image_meta,
            prometheus_server_details=self.mock_prometheus_server_details)

        # Assertions
        assert type(spec) == dict
        prom_host = self.mock_prometheus_server_details.host
        prom_port = self.mock_prometheus_server_details.port
        assert spec == {
            'containers': [{
                'name':
                self.mock_app_name,
                'imageDetails': {
                    'imagePath': self.mock_image_meta.image_path,
                    'username': self.mock_image_meta.repo_username,
                    'password': self.mock_image_meta.repo_password
                },
                'ports': [{
                    'containerPort': self.mock_advertised_port,
                    'protocol': 'TCP'
                }],
                'readinessProbe': {
                    'httpGet': {
                        'path': '/api/health',
                        'port': self.mock_advertised_port
                    },
                    'initialDelaySeconds': 10,
                    'timeoutSeconds': 30
                },
                'files': [{
                    'name': 'prometheus-ds',
                    'mountPath': '/etc/grafana/provisioning/datasources',
                    'files': {
                        'prometheus.yaml':
                        textwrap.dedent(f"""
                         apiVersion: 1

                         datasources:
                         - name: Prometheus
                           type: prometheus
                           access: proxy
                           url: http://{prom_host}:{prom_port}
                           isDefault: true
                           editable: false
                    """)
                    }
                }]
            }]
        }
示例#4
0
def on_start_handler(event, fw_adapter):
    if not fw_adapter.am_i_leader():
        return

    juju_pod_spec = build_juju_pod_spec(
        app_name=fw_adapter.get_app_name(),
        charm_config=fw_adapter.get_config(),
        image_meta=fw_adapter.get_image_meta('grafana-image'),
    )

    fw_adapter.set_pod_spec(juju_pod_spec)
    fw_adapter.set_unit_status(MaintenanceStatus("Configuring pod"))
示例#5
0
def on_prom_available_handler(event, fw_adapter):
    if not fw_adapter.am_i_leader():
        return

    juju_pod_spec = build_juju_pod_spec(
        app_name=fw_adapter.get_app_name(),
        charm_config=fw_adapter.get_config(),
        image_meta=fw_adapter.get_image_meta('grafana-image'),
        prometheus_server_details=event.server_details,
    )

    fw_adapter.set_pod_spec(juju_pod_spec)
    fw_adapter.set_unit_status(MaintenanceStatus("Configuring pod"))
    def test_pod_spec_is_generated(self):
        # Set up
        mock_app_name = f'{uuid4()}'

        mock_advertised_port = random.randint(1, 65535)

        mock_config = {
            'advertised-port': mock_advertised_port,
        }

        mock_image_meta = ImageMeta({
            'registrypath': str(uuid4()),
            'username': str(uuid4()),
            'password': str(uuid4()),
        })

        # Exercise
        spec = domain.build_juju_pod_spec(app_name=mock_app_name,
                                          charm_config=mock_config,
                                          image_meta=mock_image_meta)

        # Assertions
        assert type(spec) == dict
        assert spec == {
            'containers': [{
                'name':
                mock_app_name,
                'imageDetails': {
                    'imagePath': mock_image_meta.image_path,
                    'username': mock_image_meta.repo_username,
                    'password': mock_image_meta.repo_password
                },
                'ports': [{
                    'containerPort': mock_advertised_port,
                    'protocol': 'TCP'
                }],
                'readinessProbe': {
                    'httpGet': {
                        'path': '/api/health',
                        'port': mock_advertised_port
                    },
                    'initialDelaySeconds': 10,
                    'timeoutSeconds': 30
                }
            }]
        }
示例#7
0
def on_server_new_relation_handler(event, state, fw_adapter):
    log.debug("Got event {}".format(event))
    if not fw_adapter.am_i_leader():
        return

    mysql_details = \
        interface_mysql.MySQLServerDetails.restore(state.mysql_server_details)
    prometheus_details = \
        interface_http.ServerDetails.restore(state.prometheus_server_details)

    juju_pod_spec = build_juju_pod_spec(
        app_name=fw_adapter.get_app_name(),
        charm_config=fw_adapter.get_config(),
        image_meta=fw_adapter.get_image_meta('grafana-image'),
        mysql_server_details=mysql_details,
        prometheus_server_details=prometheus_details,
    )

    log.info("Updating juju podspec with new backend details")
    fw_adapter.set_pod_spec(juju_pod_spec)
    fw_adapter.set_unit_status(MaintenanceStatus("Configuring pod"))
def set_juju_pod_spec(fw_adapter):
    if not fw_adapter.am_i_leader():
        logging.debug("Unit is not a leader, skip pod spec configuration")
        return

    charm_config = fw_adapter.get_config()

    logging.debug("Building AlertManager config file")
    alertmanager_config = build_alertmanager_config(
        base64_config_yaml=charm_config["alertmanager-config"],
        base64_secrets_yaml=charm_config["alertmanager-secrets"])

    logging.debug("Building Juju pod spec")
    juju_pod_spec = build_juju_pod_spec(
        app_name=fw_adapter.get_app_name(),
        charm_config=charm_config,
        image_meta=fw_adapter.get_image_meta('alertmanager-image'),
        alertmanager_config=alertmanager_config)

    logging.debug("Configuring pod")
    fw_adapter.set_pod_spec(juju_pod_spec.to_dict())
    fw_adapter.set_unit_status(MaintenanceStatus("Configuring pod"))
示例#9
0
def set_juju_pod_spec(fw_adapter, alerting_config={}):
    if not fw_adapter.unit_is_leader():
        logging.debug("Unit is not a leader, skip pod spec configuration")
        return

    if alerting_config:
        logger.debug("Got alerting config: {} {}".format(
            type(alerting_config), alerting_config))

    logging.debug("Building Juju pod spec")
    try:
        juju_pod_spec = build_juju_pod_spec(
            app_name=fw_adapter.get_app_name(),
            charm_config=fw_adapter.get_config(),
            image_meta=fw_adapter.get_image_meta('prometheus-image'),
            alerting_config=alerting_config)
    except CharmError as e:
        fw_adapter.set_unit_status(
            BlockedStatus("Pod spec build failure: {0}".format(e)))
        return

    logging.debug("Configuring pod")
    fw_adapter.set_pod_spec(juju_pod_spec.to_dict())
    fw_adapter.set_unit_status(MaintenanceStatus("Configuring pod"))
    def test_pod_spec_with_mysql_and_prometheus_config_is_generated(self):
        # Exercise
        spec = domain.build_juju_pod_spec(
            app_name=self.mock_app_name,
            charm_config=self.mock_config,
            image_meta=self.mock_image_meta,
            prometheus_server_details=self.mock_prometheus_server_details,
            mysql_server_details=self.mock_mysql_server_details)

        # Assertions
        assert type(spec) == dict
        prom_host = self.mock_prometheus_server_details.host
        prom_port = self.mock_prometheus_server_details.port
        assert spec == {
            'containers': [{
                'name':
                self.mock_app_name,
                'imageDetails': {
                    'imagePath': self.mock_image_meta.image_path,
                    'username': self.mock_image_meta.repo_username,
                    'password': self.mock_image_meta.repo_password
                },
                'ports': [{
                    'containerPort': self.mock_advertised_port,
                    'protocol': 'TCP'
                }],
                'readinessProbe': {
                    'httpGet': {
                        'path': '/api/health',
                        'port': self.mock_advertised_port
                    },
                    'initialDelaySeconds': 10,
                    'timeoutSeconds': 30
                },
                'files': [{
                    'name': 'prometheus-ds',
                    'mountPath': '/etc/grafana/provisioning/datasources',
                    'files': {
                        'prometheus.yaml':
                        textwrap.dedent(f"""
                         apiVersion: 1

                         datasources:
                         - name: Prometheus
                           type: prometheus
                           access: proxy
                           url: http://{prom_host}:{prom_port}
                           isDefault: true
                           editable: false
                    """)
                    }
                }, {
                    'name': 'mysql-db-config',
                    'mountPath': '/etc/grafana',
                    'files': {
                        'grafana.ini':
                        textwrap.dedent(f"""
                        [database]
                        type = mysql
                        host = {self.mock_mysql_server_details.address}
                        name = {self.mock_mysql_server_details.database}
                        user = {self.mock_mysql_server_details.username}
                        password = {self.mock_mysql_server_details.password}

                        ;ca_cert_path =
                        ;client_key_path =
                        ;client_cert_path =
                        ;server_cert_name =
                        # Max idle conn setting default is 2
                        ;max_idle_conn = 2

                        # Max conn setting default is 0 (mean not set)
                        ;max_open_conn =

                        # Connection Max Lifetime default is 14400
                        # (means 14400 seconds or 4 hours)
                        ;conn_max_lifetime = 14400

                        # Set to true to log the sql calls and execution times.
                        ;log_queries =
                        """)
                    }
                }]
            }]
        }
    def test__pod_spec_is_generated(self):
        # Set up
        mock_app_name = str(uuid4())

        mock_external_labels = {
            str(uuid4()): str(uuid4()),
            str(uuid4()): str(uuid4()),
            str(uuid4()): str(uuid4()),
        }

        mock_config = {
            'external-labels': json.dumps(mock_external_labels),
            'monitor-k8s': False
        }

        mock_image_meta = ImageMeta({
            'registrypath': str(uuid4()),
            'username': str(uuid4()),
            'password': str(uuid4()),
        })

        am_config = domain.AlertManagerConfigFile({str(uuid4()): str(uuid4())})

        # Exercise
        juju_pod_spec = domain.build_juju_pod_spec(
            app_name=mock_app_name,
            charm_config=mock_config,
            image_meta=mock_image_meta,
            alertmanager_config=am_config)

        # Assertions
        assert isinstance(juju_pod_spec, domain.AlertManagerJujuPodSpec)
        assert juju_pod_spec.to_dict() == {
            'containers': [{
                'name':
                mock_app_name,
                'imageDetails': {
                    'imagePath': mock_image_meta.image_path,
                    'username': mock_image_meta.repo_username,
                    'password': mock_image_meta.repo_password
                },
                'args': [
                    '--config.file=/etc/alertmanager/alertmanager.yml',
                    '--storage.path=/alertmanager',
                    '--cluster.listen-address=0.0.0.0:9094',
                    '--cluster.peer=alertmanager-0.alertmanager-endpoints:9094'
                ],
                'ports': [{
                    'name': 'web',
                    'containerPort': 9093,
                    'protocol': 'TCP'
                }, {
                    'name': 'peering-tcp',
                    'containerPort': 9094,
                    'protocol': 'TCP'
                }, {
                    'name': 'peering-udp',
                    'containerPort': 9094,
                    'protocol': 'UDP'
                }],
                'readinessProbe': {
                    'httpGet': {
                        'path': '/-/ready',
                        'port': 9093
                    },
                    'initialDelaySeconds': 10,
                    'timeoutSeconds': 30
                },
                'livenessProbe': {
                    'httpGet': {
                        'path': '/-/healthy',
                        'port': 9093
                    },
                    'initialDelaySeconds': 30,
                    'timeoutSeconds': 30
                },
                'files': [{
                    'name': 'config',
                    'mountPath': '/etc/alertmanager',
                    'files': {
                        'alertmanager.yml': am_config.yaml_dump()
                    }
                }]
            }]
        }
示例#12
0
    def test__pod_spec_is_generated():
        # Set up
        mock_app_name = str(uuid4())

        mock_external_labels = {
            str(uuid4()): str(uuid4()),
            str(uuid4()): str(uuid4()),
            str(uuid4()): str(uuid4()),
        }

        mock_config = get_default_charm_config()
        mock_config['external-labels'] = json.dumps(mock_external_labels)

        mock_image_meta = ImageMeta({
            'registrypath': str(uuid4()),
            'username': str(uuid4()),
            'password': str(uuid4()),
        })

        mock_args_config = domain.build_prometheus_cli_args(mock_config)

        # Exercise
        juju_pod_spec = domain.build_juju_pod_spec(app_name=mock_app_name,
                                                   charm_config=mock_config,
                                                   image_meta=mock_image_meta)

        # Assertions
        assert isinstance(juju_pod_spec, domain.PrometheusJujuPodSpec)
        assert juju_pod_spec.to_dict() == {
            'containers': [{
                'name':
                mock_app_name,
                'imageDetails': {
                    'imagePath': mock_image_meta.image_path,
                    'username': mock_image_meta.repo_username,
                    'password': mock_image_meta.repo_password
                },
                'args':
                mock_args_config,
                'ports': [{
                    'containerPort': 9090,
                    'protocol': 'TCP'
                }],
                'readinessProbe': {
                    'httpGet': {
                        'path': '/-/ready',
                        'port': 9090
                    },
                    'initialDelaySeconds': 10,
                    'timeoutSeconds': 30
                },
                'livenessProbe': {
                    'httpGet': {
                        'path': '/-/healthy',
                        'port': 9090
                    },
                    'initialDelaySeconds': 30,
                    'timeoutSeconds': 30
                },
                'files': [{
                    'name': 'config',
                    'mountPath': '/etc/prometheus',
                    'files': {
                        'prometheus.yml':
                        yaml.dump({
                            'global': {
                                'scrape_interval': '15s',
                                'scrape_timeout': '10s',
                                'evaluation_interval': '1m',
                                'external_labels': mock_external_labels
                            },
                            'scrape_configs': [{
                                'job_name':
                                'prometheus',
                                'scrape_interval':
                                '5s',
                                'static_configs': [{
                                    'targets': ['localhost:9090']
                                }]
                            }],
                            'alerting': {}
                        })
                    }
                }]
            }]
        }
    def test__pod_spec_is_generated(self):
        # Set up
        mock_app_name = str(uuid4())

        mock_external_labels = {
            str(uuid4()): str(uuid4()),
            str(uuid4()): str(uuid4()),
            str(uuid4()): str(uuid4()),
        }

        mock_config = get_default_charm_config()
        mock_config['external-labels'] = json.dumps(mock_external_labels)

        mock_image_meta = ImageMeta({
            'registrypath': str(uuid4()),
            'username': str(uuid4()),
            'password': str(uuid4()),
        })

        mock_args_config = domain.build_prometheus_cli_args(mock_config)

        # Exercise
        juju_pod_spec = domain.build_juju_pod_spec(
            app_name=mock_app_name,
            charm_config=mock_config,
            prom_image_meta=mock_image_meta,
            nginx_image_meta=mock_image_meta)

        expected_nginx_config = textwrap.dedent("""\
        server {
            listen 80;
            server_name _;
            access_log /var/log/nginx/prometheus-http.access.log main;
            error_log /var/log/nginx/prometheus-http.error.log;
            location / {
                proxy_pass http://localhost:9090;
            }
        }""")

        # Assertions
        assert isinstance(juju_pod_spec, domain.PrometheusJujuPodSpec)
        self.assertEqual(
            juju_pod_spec.to_dict(), {
                'containers': [{
                    'name':
                    mock_app_name,
                    'imageDetails': {
                        'imagePath': mock_image_meta.image_path,
                        'username': mock_image_meta.repo_username,
                        'password': mock_image_meta.repo_password
                    },
                    'args':
                    mock_args_config,
                    'readinessProbe': {
                        'httpGet': {
                            'path': '/-/ready',
                            'port': 9090
                        },
                        'initialDelaySeconds': 10,
                        'timeoutSeconds': 30
                    },
                    'livenessProbe': {
                        'httpGet': {
                            'path': '/-/healthy',
                            'port': 9090
                        },
                        'initialDelaySeconds': 30,
                        'timeoutSeconds': 30
                    },
                    'files': [{
                        'name': 'prom-config',
                        'mountPath': '/etc/prometheus',
                        'files': {
                            'prometheus.yml':
                            yaml.dump({
                                'global': {
                                    'scrape_interval': '15s',
                                    'scrape_timeout': '10s',
                                    'evaluation_interval': '1m',
                                    'external_labels': mock_external_labels
                                },
                                'scrape_configs': [{
                                    'metrics_path':
                                    '/metrics',
                                    'honor_timestamps':
                                    True,
                                    'scheme':
                                    'http',
                                    'job_name':
                                    'prometheus',
                                    'scrape_interval':
                                    '5s',
                                    'scrape_timeout':
                                    '5s',
                                    'static_configs': [{
                                        'targets': ['localhost:9090']
                                    }]
                                }],
                                'alerting': {}
                            })
                        }
                    }]
                }, {
                    'name':
                    '{0}-nginx'.format(mock_app_name),
                    'imageDetails': {
                        'imagePath': mock_image_meta.image_path,
                        'username': mock_image_meta.repo_username,
                        'password': mock_image_meta.repo_password
                    },
                    'ports': [{
                        'containerPort': 80,
                        'name': 'nginx-http',
                        'protocol': 'TCP'
                    }, {
                        'containerPort': 443,
                        'name': 'nginx-https',
                        'protocol': 'TCP'
                    }],
                    'files': [{
                        'name': 'nginx-config',
                        'mountPath': '/etc/nginx/conf.d',
                        'files': {
                            'default.conf': expected_nginx_config
                        }
                    }]
                }]
            })