1 # Copyright 2021 Canonical Ltd.
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
7 # http://www.apache.org/licenses/LICENSE-2.0
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
15 # For those usages not covered by the Apache License, Version 2.0 please
16 # contact: legal@canonical.com
18 # To get in touch with the maintainers, please contact:
19 # osm-charmers@lists.launchpad.net
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.
25 """Interfaces used by this charm."""
32 class BaseRelationClient(ops
.framework
.Object
):
33 """Requires side of a Kafka Endpoint."""
37 charm
: ops
.charm
.CharmBase
,
39 mandatory_fields
: list = [],
41 super().__init
__(charm
, relation_name
)
42 self
.relation_name
= relation_name
43 self
.mandatory_fields
= mandatory_fields
44 self
._update
_relation
()
46 def get_data_from_unit(self
, key
: str):
47 """Get data from unit relation data."""
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
()
55 for unit
in self
.relation
.units
:
56 data
= self
.relation
.data
[unit
].get(key
)
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
)
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
])
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
])
81 def _update_relation(self
):
82 self
.relation
= self
.framework
.model
.get_relation(self
.relation_name
)
85 class MysqlClient(BaseRelationClient
):
86 """Requires side of a Mysql Endpoint."""
88 mandatory_fields
= ["host", "port", "user", "password", "root_password"]
90 def __init__(self
, charm
: ops
.charm
.CharmBase
, relation_name
: str):
91 super().__init
__(charm
, relation_name
, self
.mandatory_fields
)
96 return self
.get_data_from_unit("host")
101 return self
.get_data_from_unit("port")
106 return self
.get_data_from_unit("user")
111 return self
.get_data_from_unit("password")
114 def root_password(self
):
116 return self
.get_data_from_unit("root_password")
121 return self
.get_data_from_unit("database")
123 def get_root_uri(self
, database
: str):
124 """Get the URI for the mysql connection with the root user credentials.
127 database: Database name
130 A string with the following format:
131 mysql://root:<root_password>@<mysql_host>:<mysql_port>/<database>
133 return "mysql://root:{}@{}:{}/{}".format(
134 self
.root_password
, self
.host
, self
.port
, database
138 """Get the URI for the mysql connection with the standard user credentials.
141 database: Database name
143 A string with the following format:
144 mysql://<user>:<password>@<mysql_host>:<mysql_port>/<database>
146 return "mysql://{}:{}@{}:{}/{}".format(
147 self
.user
, self
.password
, self
.host
, self
.port
, self
.database
151 class KeystoneServer(ops
.framework
.Object
):
152 """Provides side of a Keystone Endpoint."""
154 relation_name
: str = None
156 def __init__(self
, charm
: ops
.charm
.CharmBase
, relation_name
: str):
157 super().__init
__(charm
, relation_name
)
158 self
.relation_name
= relation_name
164 user_domain_name
: str,
165 project_domain_name
: str,
169 keystone_db_password
: str,
173 admin_project_name
: str,
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
)