blob: 6851600c6fe5ac225da53ca5b05a144ee3de5ed6 [file] [log] [blame]
sousaeduccfacbb2020-11-04 21:44:01 +00001#!/usr/bin/env python3
David Garcia49379ce2021-02-24 13:48:22 +01002# Copyright 2021 Canonical Ltd.
sousaeduccfacbb2020-11-04 21:44:01 +00003#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15#
16# For those usages not covered by the Apache License, Version 2.0 please
17# contact: legal@canonical.com
18#
19# To get in touch with the maintainers, please contact:
20# osm-charmers@lists.launchpad.net
21##
22
David Garcia49379ce2021-02-24 13:48:22 +010023# pylint: disable=E0213
24
sousaeduccfacbb2020-11-04 21:44:01 +000025import logging
David Garcia49379ce2021-02-24 13:48:22 +010026from typing import NoReturn
sousaeduccfacbb2020-11-04 21:44:01 +000027
sousaeduccfacbb2020-11-04 21:44:01 +000028from ops.main import main
David Garcia49379ce2021-02-24 13:48:22 +010029from opslib.osm.charm import CharmedOsmBase, RelationsMissing
David Garciac753dc52021-03-17 15:28:47 +010030from opslib.osm.interfaces.kafka import KafkaClient
31from opslib.osm.interfaces.mongo import MongoClient
32from opslib.osm.interfaces.mysql import MysqlClient
David Garcia49379ce2021-02-24 13:48:22 +010033from opslib.osm.pod import (
34 ContainerV3Builder,
35 PodSpecV3Builder,
36)
David Garciac753dc52021-03-17 15:28:47 +010037from opslib.osm.validator import ModelValidator, validator
David Garcia49379ce2021-02-24 13:48:22 +010038
sousaeduccfacbb2020-11-04 21:44:01 +000039
40logger = logging.getLogger(__name__)
41
David Garcia49379ce2021-02-24 13:48:22 +010042PORT = 9090
sousaeduccfacbb2020-11-04 21:44:01 +000043
44
David Garcia49379ce2021-02-24 13:48:22 +010045class ConfigModel(ModelValidator):
46 enable_ng_ro: bool
47 database_commonkey: str
48 log_level: str
49 vim_database: str
50 ro_database: str
51 openmano_tenant: str
52
53 @validator("log_level")
54 def validate_log_level(cls, v):
55 if v not in {"INFO", "DEBUG"}:
56 raise ValueError("value must be INFO or DEBUG")
57 return v
sousaeduccfacbb2020-11-04 21:44:01 +000058
59
David Garcia49379ce2021-02-24 13:48:22 +010060class RoCharm(CharmedOsmBase):
61 """GrafanaCharm Charm."""
sousaeduccfacbb2020-11-04 21:44:01 +000062
63 def __init__(self, *args) -> NoReturn:
David Garcia49379ce2021-02-24 13:48:22 +010064 """Prometheus Charm constructor."""
65 super().__init__(*args, oci_image="image")
sousaeduccfacbb2020-11-04 21:44:01 +000066
David Garcia49379ce2021-02-24 13:48:22 +010067 self.kafka_client = KafkaClient(self, "kafka")
68 self.framework.observe(self.on["kafka"].relation_changed, self.configure_pod)
69 self.framework.observe(self.on["kafka"].relation_broken, self.configure_pod)
sousaeduccfacbb2020-11-04 21:44:01 +000070
David Garcia49379ce2021-02-24 13:48:22 +010071 self.mysql_client = MysqlClient(self, "mysql")
72 self.framework.observe(self.on["mysql"].relation_changed, self.configure_pod)
73 self.framework.observe(self.on["mysql"].relation_broken, self.configure_pod)
sousaeduccfacbb2020-11-04 21:44:01 +000074
David Garcia49379ce2021-02-24 13:48:22 +010075 self.mongodb_client = MongoClient(self, "mongodb")
76 self.framework.observe(self.on["mongodb"].relation_changed, self.configure_pod)
77 self.framework.observe(self.on["mongodb"].relation_broken, self.configure_pod)
sousaeduccfacbb2020-11-04 21:44:01 +000078
David Garcia49379ce2021-02-24 13:48:22 +010079 self.framework.observe(self.on["ro"].relation_joined, self._publish_ro_info)
sousaeduccfacbb2020-11-04 21:44:01 +000080
David Garcia49379ce2021-02-24 13:48:22 +010081 def _publish_ro_info(self, event):
sousaeduccfacbb2020-11-04 21:44:01 +000082 """Publishes RO information.
83
84 Args:
85 event (EventBase): RO relation event.
86 """
87 if self.unit.is_leader():
88 rel_data = {
89 "host": self.model.app.name,
David Garcia49379ce2021-02-24 13:48:22 +010090 "port": str(PORT),
sousaeduccfacbb2020-11-04 21:44:01 +000091 }
92 for k, v in rel_data.items():
93 event.relation.data[self.app][k] = v
94
David Garcia49379ce2021-02-24 13:48:22 +010095 def _check_missing_dependencies(self, config: ConfigModel):
96 missing_relations = []
97
98 if config.enable_ng_ro:
99 if self.kafka_client.is_missing_data_in_unit():
100 missing_relations.append("kafka")
101 if self.mongodb_client.is_missing_data_in_unit():
102 missing_relations.append("mongodb")
sousaeduccfacbb2020-11-04 21:44:01 +0000103 else:
David Garcia49379ce2021-02-24 13:48:22 +0100104 if self.mysql_client.is_missing_data_in_unit():
105 missing_relations.append("mysql")
106 if missing_relations:
107 raise RelationsMissing(missing_relations)
sousaeduccfacbb2020-11-04 21:44:01 +0000108
David Garcia49379ce2021-02-24 13:48:22 +0100109 def build_pod_spec(self, image_info):
110 # Validate config
111 config = ConfigModel(**dict(self.config))
112 # Check relations
113 self._check_missing_dependencies(config)
114 # Create Builder for the PodSpec
115 pod_spec_builder = PodSpecV3Builder()
116 # Build Container
117 container_builder = ContainerV3Builder(self.app.name, image_info)
118 container_builder.add_port(name=self.app.name, port=PORT)
119 container_builder.add_http_readiness_probe(
120 "/ro/" if config.enable_ng_ro else "/openmano/tenants",
121 PORT,
122 initial_delay_seconds=10,
123 period_seconds=10,
124 timeout_seconds=5,
125 failure_threshold=3,
126 )
127 container_builder.add_http_liveness_probe(
128 "/ro/" if config.enable_ng_ro else "/openmano/tenants",
129 PORT,
130 initial_delay_seconds=600,
131 period_seconds=10,
132 timeout_seconds=5,
133 failure_threshold=3,
134 )
135 container_builder.add_envs(
136 {
137 "OSMRO_LOG_LEVEL": config.log_level,
138 }
139 )
140 if config.enable_ng_ro:
141 container_builder.add_envs(
142 {
143 "OSMRO_MESSAGE_DRIVER": "kafka",
144 "OSMRO_MESSAGE_HOST": self.kafka_client.host,
145 "OSMRO_MESSAGE_PORT": self.kafka_client.port,
146 # MongoDB configuration
147 "OSMRO_DATABASE_DRIVER": "mongo",
148 "OSMRO_DATABASE_URI": self.mongodb_client.connection_string,
149 "OSMRO_DATABASE_COMMONKEY": config.database_commonkey,
150 }
sousaeduccfacbb2020-11-04 21:44:01 +0000151 )
sousaeduccfacbb2020-11-04 21:44:01 +0000152
David Garcia49379ce2021-02-24 13:48:22 +0100153 else:
154 container_builder.add_envs(
155 {
156 "RO_DB_HOST": self.mysql_client.host,
157 "RO_DB_OVIM_HOST": self.mysql_client.host,
158 "RO_DB_PORT": self.mysql_client.port,
159 "RO_DB_OVIM_PORT": self.mysql_client.port,
160 "RO_DB_USER": self.mysql_client.user,
161 "RO_DB_OVIM_USER": self.mysql_client.user,
162 "RO_DB_PASSWORD": self.mysql_client.password,
163 "RO_DB_OVIM_PASSWORD": self.mysql_client.password,
164 "RO_DB_ROOT_PASSWORD": self.mysql_client.root_password,
165 "RO_DB_OVIM_ROOT_PASSWORD": self.mysql_client.root_password,
166 "RO_DB_NAME": config.ro_database,
167 "RO_DB_OVIM_NAME": config.vim_database,
168 "OPENMANO_TENANT": config.openmano_tenant,
169 }
170 )
171 container = container_builder.build()
172 # Add container to pod spec
173 pod_spec_builder.add_container(container)
174 return pod_spec_builder.build()
sousaeduccfacbb2020-11-04 21:44:01 +0000175
176
177if __name__ == "__main__":
178 main(RoCharm)