Fix PLA relations, add missing ENVs, and include it in the bundle
[osm/devops.git] / installers / charm / pla / src / charm.py
1 #!/usr/bin/env python3
2 # Copyright 2020 Canonical Ltd.
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain 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,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15
16 import sys
17 import logging
18
19 sys.path.append("lib")
20
21 from ops.charm import CharmBase
22 from ops.framework import StoredState, Object
23 from ops.main import main
24 from ops.model import (
25 ActiveStatus,
26 MaintenanceStatus,
27 WaitingStatus,
28 )
29
30 from glob import glob
31 from pathlib import Path
32 from string import Template
33
34 logger = logging.getLogger(__name__)
35
36
37 class PLACharm(CharmBase):
38 state = StoredState()
39
40 def __init__(self, framework, key):
41 super().__init__(framework, key)
42 self.state.set_default(spec=None)
43 self.state.set_default(kafka_host=None)
44 self.state.set_default(kafka_port=None)
45 self.state.set_default(mongodb_uri=None)
46 self.state.set_default(mysql_host=None)
47 self.state.set_default(mysql_port=None)
48
49 # Observe Charm related events
50 self.framework.observe(self.on.config_changed, self.on_config_changed)
51 self.framework.observe(self.on.start, self.on_start)
52 self.framework.observe(self.on.upgrade_charm, self.on_upgrade_charm)
53
54 # Relations
55 self.framework.observe(
56 self.on.kafka_relation_changed, self.on_kafka_relation_changed
57 )
58 self.framework.observe(
59 self.on.mongo_relation_changed, self.on_mongo_relation_changed
60 )
61 self.framework.observe(
62 self.on.mysql_relation_changed, self.on_mysql_relation_changed
63 )
64
65 def _apply_spec(self):
66 # Only apply the spec if this unit is a leader.
67 unit = self.model.unit
68 if not unit.is_leader():
69 unit.status = ActiveStatus("Ready")
70 return
71 if not self.state.kafka_host or not self.state.kafka_port:
72 unit.status = WaitingStatus("Waiting for Kafka")
73 return
74 if not self.state.mongodb_uri:
75 unit.status = WaitingStatus("Waiting for MongoDB")
76 return
77 if not self.state.mysql_host or not self.state.mysql_port:
78 unit.status = WaitingStatus("Waiting for MySQL")
79 return
80
81 unit.status = MaintenanceStatus("Applying new pod spec")
82
83 new_spec = self.make_pod_spec()
84 if new_spec == self.state.spec:
85 unit.status = ActiveStatus("Ready")
86 return
87 self.framework.model.pod.set_spec(new_spec)
88 self.state.spec = new_spec
89 unit.status = ActiveStatus("Ready")
90
91 def make_pod_spec(self):
92 config = self.framework.model.config
93
94 mysql_uri = "mysql://root:{}@{}:{}/{}".format(
95 self.state.mysql_root_password,
96 self.state.mysql_host,
97 self.state.mysql_port,
98 self.state.mysql_database,
99 )
100 ports = [
101 {"name": "port", "containerPort": config["port"], "protocol": "TCP",},
102 ]
103
104 config_spec = {
105 "OSMPLA_MESSAGE_DRIVER": "kafka",
106 "OSMPLA_MESSAGE_HOST": self.state.kafka_host,
107 "OSMPLA_MESSAGE_PORT": self.state.kafka_port,
108 "OSMPLA_DATABASE_DRIVER": "mongo",
109 "OSMPLA_DATABASE_URI": self.state.mongodb_uri,
110 "OSMPLA_GLOBAL_LOG_LEVEL": config["log_level"],
111 "OSMPLA_SQL_DATABASE_URI": mysql_uri,
112 "OSMPLA_DATABASE_COMMONKEY": config["database_common_key"],
113 }
114
115 spec = {
116 "version": 2,
117 "containers": [
118 {
119 "name": self.framework.model.app.name,
120 "image": config["image"],
121 "ports": ports,
122 "config": config_spec,
123 }
124 ],
125 }
126
127 return spec
128
129 def on_config_changed(self, event):
130 """Handle changes in configuration"""
131 self._apply_spec()
132
133 def on_start(self, event):
134 """Called when the charm is being installed"""
135 self._apply_spec()
136
137 def on_upgrade_charm(self, event):
138 """Upgrade the charm."""
139 unit = self.model.unit
140 unit.status = MaintenanceStatus("Upgrading charm")
141 self.on_start(event)
142
143 def on_kafka_relation_changed(self, event):
144 unit = self.model.unit
145 if not unit.is_leader():
146 return
147 self.state.kafka_host = event.relation.data[event.unit].get("host")
148 self.state.kafka_port = event.relation.data[event.unit].get("port")
149 self._apply_spec()
150
151 def on_mongo_relation_changed(self, event):
152 unit = self.model.unit
153 if not unit.is_leader():
154 return
155 self.state.mongodb_uri = event.relation.data[event.unit].get(
156 "connection_string"
157 )
158 self._apply_spec()
159
160 def on_mysql_relation_changed(self, event):
161 unit = self.model.unit
162 if not unit.is_leader():
163 return
164 unit_data = event.relation.data[event.unit]
165 self.state.mysql_host = unit_data.get("host")
166 self.state.mysql_port = unit_data.get("port")
167 self.state.mysql_root_password = unit_data.get("root_password")
168 self.state.mysql_database = self.model.config["database"]
169 self._apply_spec()
170
171
172 if __name__ == "__main__":
173 main(PLACharm)