2 # Copyright 2022 Canonical Ltd.
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
8 # http://www.apache.org/licenses/LICENSE-2.0
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
16 # For those usages not covered by the Apache License, Version 2.0 please
17 # contact: legal@canonical.com
19 # To get in touch with the maintainers, please contact:
20 # osm-charmers@lists.launchpad.net
27 class BaseRelationClient(ops
.framework
.Object
):
28 """Requires side of a Kafka Endpoint"""
32 charm
: ops
.charm
.CharmBase
,
34 mandatory_fields
: list = [],
36 super().__init
__(charm
, relation_name
)
37 self
.relation_name
= relation_name
38 self
.mandatory_fields
= mandatory_fields
39 self
._update
_relation
()
41 def get_data_from_unit(self
, key
: str):
43 # This update relation doesn't seem to be needed, but I added it because apparently
44 # the data is empty in the unit tests.
45 # In reality, the constructor is called in every hook.
46 # In the unit tests when doing an update_relation_data, apparently it is not called.
47 self
._update
_relation
()
49 for unit
in self
.relation
.units
:
50 data
= self
.relation
.data
[unit
].get(key
)
54 def get_data_from_app(self
, key
: str):
55 if not self
.relation
or self
.relation
.app
not in self
.relation
.data
:
56 # This update relation doesn't seem to be needed, but I added it because apparently
57 # the data is empty in the unit tests.
58 # In reality, the constructor is called in every hook.
59 # In the unit tests when doing an update_relation_data, apparently it is not called.
60 self
._update
_relation
()
61 if self
.relation
and self
.relation
.app
in self
.relation
.data
:
62 data
= self
.relation
.data
[self
.relation
.app
].get(key
)
66 def is_missing_data_in_unit(self
):
67 return not all([self
.get_data_from_unit(field
) for field
in self
.mandatory_fields
])
69 def is_missing_data_in_app(self
):
70 return not all([self
.get_data_from_app(field
) for field
in self
.mandatory_fields
])
72 def _update_relation(self
):
73 self
.relation
= self
.framework
.model
.get_relation(self
.relation_name
)
76 class MongoClient(BaseRelationClient
):
77 """Requires side of a Mongo Endpoint"""
79 mandatory_fields_mapping
= {
80 "reactive": ["connection_string"],
81 "ops": ["replica_set_uri", "replica_set_name"],
84 def __init__(self
, charm
: ops
.charm
.CharmBase
, relation_name
: str):
85 super().__init
__(charm
, relation_name
, mandatory_fields
=[])
88 def connection_string(self
):
90 replica_set_uri
= self
.get_data_from_unit("replica_set_uri")
91 replica_set_name
= self
.get_data_from_unit("replica_set_name")
92 return f
"{replica_set_uri}?replicaSet={replica_set_name}"
94 return self
.get_data_from_unit("connection_string")
97 return not self
.is_missing_data_in_unit_ops()
99 def is_missing_data_in_unit(self
):
100 return self
.is_missing_data_in_unit_ops() and self
.is_missing_data_in_unit_reactive()
102 def is_missing_data_in_unit_ops(self
):
104 [self
.get_data_from_unit(field
) for field
in self
.mandatory_fields_mapping
["ops"]]
107 def is_missing_data_in_unit_reactive(self
):
109 [self
.get_data_from_unit(field
) for field
in self
.mandatory_fields_mapping
["reactive"]]
113 class MysqlClient(BaseRelationClient
):
114 """Requires side of a Mysql Endpoint"""
116 mandatory_fields
= ["host", "port", "user", "password", "root_password"]
118 def __init__(self
, charm
: ops
.charm
.CharmBase
, relation_name
: str):
119 super().__init
__(charm
, relation_name
, self
.mandatory_fields
)
123 return self
.get_data_from_unit("host")
127 return self
.get_data_from_unit("port")
131 return self
.get_data_from_unit("user")
135 return self
.get_data_from_unit("password")
138 def root_password(self
):
139 return self
.get_data_from_unit("root_password")
143 return self
.get_data_from_unit("database")
145 def get_root_uri(self
, database
: str):
147 Get the URI for the mysql connection with the root user credentials
148 :param: database: Database name
149 :return: A string with the following format:
150 mysql://root:<root_password>@<mysql_host>:<mysql_port>/<database>
152 return "mysql://root:{}@{}:{}/{}".format(
153 self
.root_password
, self
.host
, self
.port
, database
158 Get the URI for the mysql connection with the standard user credentials
159 :param: database: Database name
160 :return: A string with the following format:
161 mysql://<user>:<password>@<mysql_host>:<mysql_port>/<database>
163 return "mysql://{}:{}@{}:{}/{}".format(
164 self
.user
, self
.password
, self
.host
, self
.port
, self
.database