Add Keystone charm
[osm/devops.git] / installers / charm / osm-keystone / src / interfaces.py
1 # Copyright 2021 Canonical Ltd.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License"); you may
4 # not use this file except in compliance with the License. You may obtain
5 # a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 # License for the specific language governing permissions and limitations
13 # under the License.
14 #
15 # For those usages not covered by the Apache License, Version 2.0 please
16 # contact: legal@canonical.com
17 #
18 # To get in touch with the maintainers, please contact:
19 # osm-charmers@lists.launchpad.net
20 #
21 #
22 # This file populates the Actions tab on Charmhub.
23 # See https://juju.is/docs/some-url-to-be-determined/ for a checklist and guidance.
24
25 """Interfaces used by this charm."""
26
27 import ops.charm
28 import ops.framework
29 import ops.model
30
31
32 class BaseRelationClient(ops.framework.Object):
33 """Requires side of a Kafka Endpoint."""
34
35 def __init__(
36 self,
37 charm: ops.charm.CharmBase,
38 relation_name: str,
39 mandatory_fields: list = [],
40 ):
41 super().__init__(charm, relation_name)
42 self.relation_name = relation_name
43 self.mandatory_fields = mandatory_fields
44 self._update_relation()
45
46 def get_data_from_unit(self, key: str):
47 """Get data from unit relation data."""
48 if not self.relation:
49 # This update relation doesn't seem to be needed, but I added it because apparently
50 # the data is empty in the unit tests.
51 # In reality, the constructor is called in every hook.
52 # In the unit tests when doing an update_relation_data, apparently it is not called.
53 self._update_relation()
54 if self.relation:
55 for unit in self.relation.units:
56 data = self.relation.data[unit].get(key)
57 if data:
58 return data
59
60 def get_data_from_app(self, key: str):
61 """Get data from app relation data."""
62 if not self.relation or self.relation.app not in self.relation.data:
63 # This update relation doesn't seem to be needed, but I added it because apparently
64 # the data is empty in the unit tests.
65 # In reality, the constructor is called in every hook.
66 # In the unit tests when doing an update_relation_data, apparently it is not called.
67 self._update_relation()
68 if self.relation and self.relation.app in self.relation.data:
69 data = self.relation.data[self.relation.app].get(key)
70 if data:
71 return data
72
73 def is_missing_data_in_unit(self):
74 """Check if mandatory fields are present in any of the unit's relation data."""
75 return not all([self.get_data_from_unit(field) for field in self.mandatory_fields])
76
77 def is_missing_data_in_app(self):
78 """Check if mandatory fields are set in relation data."""
79 return not all([self.get_data_from_app(field) for field in self.mandatory_fields])
80
81 def _update_relation(self):
82 self.relation = self.framework.model.get_relation(self.relation_name)
83
84
85 class MysqlClient(BaseRelationClient):
86 """Requires side of a Mysql Endpoint."""
87
88 mandatory_fields = ["host", "port", "user", "password", "root_password"]
89
90 def __init__(self, charm: ops.charm.CharmBase, relation_name: str):
91 super().__init__(charm, relation_name, self.mandatory_fields)
92
93 @property
94 def host(self):
95 """Host."""
96 return self.get_data_from_unit("host")
97
98 @property
99 def port(self):
100 """Port."""
101 return self.get_data_from_unit("port")
102
103 @property
104 def user(self):
105 """User."""
106 return self.get_data_from_unit("user")
107
108 @property
109 def password(self):
110 """Password."""
111 return self.get_data_from_unit("password")
112
113 @property
114 def root_password(self):
115 """Root password."""
116 return self.get_data_from_unit("root_password")
117
118 @property
119 def database(self):
120 """Database."""
121 return self.get_data_from_unit("database")
122
123 def get_root_uri(self, database: str):
124 """Get the URI for the mysql connection with the root user credentials.
125
126 Args:
127 database: Database name
128
129 Return:
130 A string with the following format:
131 mysql://root:<root_password>@<mysql_host>:<mysql_port>/<database>
132 """
133 return "mysql://root:{}@{}:{}/{}".format(
134 self.root_password, self.host, self.port, database
135 )
136
137 def get_uri(self):
138 """Get the URI for the mysql connection with the standard user credentials.
139
140 Args:
141 database: Database name
142 Return:
143 A string with the following format:
144 mysql://<user>:<password>@<mysql_host>:<mysql_port>/<database>
145 """
146 return "mysql://{}:{}@{}:{}/{}".format(
147 self.user, self.password, self.host, self.port, self.database
148 )
149
150
151 class KeystoneServer(ops.framework.Object):
152 """Provides side of a Keystone Endpoint."""
153
154 relation_name: str = None
155
156 def __init__(self, charm: ops.charm.CharmBase, relation_name: str):
157 super().__init__(charm, relation_name)
158 self.relation_name = relation_name
159
160 def publish_info(
161 self,
162 host: str,
163 port: int,
164 user_domain_name: str,
165 project_domain_name: str,
166 username: str,
167 password: str,
168 service: str,
169 keystone_db_password: str,
170 region_id: str,
171 admin_username: str,
172 admin_password: str,
173 admin_project_name: str,
174 ):
175 """Publish information in Keystone relation."""
176 if self.framework.model.unit.is_leader():
177 for relation in self.framework.model.relations[self.relation_name]:
178 relation_data = relation.data[self.framework.model.app]
179 relation_data["host"] = str(host)
180 relation_data["port"] = str(port)
181 relation_data["user_domain_name"] = str(user_domain_name)
182 relation_data["project_domain_name"] = str(project_domain_name)
183 relation_data["username"] = str(username)
184 relation_data["password"] = str(password)
185 relation_data["service"] = str(service)
186 relation_data["keystone_db_password"] = str(keystone_db_password)
187 relation_data["region_id"] = str(region_id)
188 relation_data["admin_username"] = str(admin_username)
189 relation_data["admin_password"] = str(admin_password)
190 relation_data["admin_project_name"] = str(admin_project_name)