Use rehomed identity-service interface

Use new rehomed identity-service interface from keystone-k8s.

Depends-On: I75dac5894f456d6b9de5aa10e43c0d1ebbcceda8
Change-Id: I5d043b0096dada205aef05e0ef903ed2f495618d
This commit is contained in:
James Page 2022-10-17 10:34:40 +01:00
parent ffb6177be5
commit a584b82a4f
4 changed files with 46 additions and 442 deletions

View File

@ -6,7 +6,7 @@
echo "WARNING: Charm interface libs are excluded from ASO python package."
charmcraft fetch-lib charms.nginx_ingress_integrator.v0.ingress
charmcraft fetch-lib charms.data_platform_libs.v0.database_requires
charmcraft fetch-lib charms.sunbeam_keystone_operator.v0.identity_service
charmcraft fetch-lib charms.keystone_k8s.v0.identity_service
charmcraft fetch-lib charms.keystone_k8s.v0.cloud_credentials
charmcraft fetch-lib charms.rabbitmq_k8s.v0.rabbitmq
charmcraft fetch-lib charms.sunbeam_ovn_central_operator.v0.ovsdb

View File

@ -409,7 +409,7 @@ class IdentityServiceRequiresHandler(RelationHandler):
def setup_event_handler(self) -> ops.charm.Object:
"""Configure event handlers for an Identity service relation."""
logger.debug("Setting up Identity Service event handler")
import charms.sunbeam_keystone_operator.v0.identity_service as sun_id
import charms.keystone_k8s.v0.identity_service as sun_id
id_svc = sun_id.IdentityServiceRequires(
self.charm, self.relation_name, self.service_endpoints, self.region
)

View File

@ -26,7 +26,7 @@ Two events are also available to respond to:
A basic example showing the usage of this relation follows:
```
from charms.sunbeam_sunbeam_identity_service_operator.v0.identity_service import IdentityServiceRequires
from charms.sunbeam_keystone_operator.v0.identity_service import IdentityServiceRequires
class IdentityServiceClientCharm(CharmBase):
def __init__(self, *args):
@ -75,19 +75,8 @@ class IdentityServiceClientCharm(CharmBase):
```
"""
# The unique Charmhub library identifier, never change it
LIBID = "6a7cb19b98314ecf916e3fcb02708608"
# Increment this major API version when introducing breaking changes
LIBAPI = 0
# Increment this PATCH version before using `charmcraft publish-lib` or reset
# to 0 if you are raising the major API version
LIBPATCH = 1
import json
import logging
import requests
from ops.framework import (
StoredState,
@ -96,10 +85,20 @@ from ops.framework import (
EventSource,
Object,
)
from ops.model import Relation
from typing import List
logger = logging.getLogger(__name__)
# The unique Charmhub library identifier, never change it
LIBID = "0fa7fe7236c14c6e9624acf232b9a3b0"
# Increment this major API version when introducing breaking changes
LIBAPI = 0
# Increment this PATCH version before using `charmcraft publish-lib` or reset
# to 0 if you are raising the major API version
LIBPATCH = 1
logger = logging.getLogger(__name__)
@ -309,6 +308,20 @@ class IdentityServiceRequires(Object):
"""Return the service_user_id."""
return self.get_remote_app_data('service-user-id')
@property
def internal_auth_url(self) -> str:
"""Return the internal_auth_url."""
return self.get_remote_app_data('internal-auth-url')
@property
def admin_auth_url(self) -> str:
"""Return the admin_auth_url."""
return self.get_remote_app_data('admin-auth-url')
@property
def public_auth_url(self) -> str:
"""Return the public_auth_url."""
return self.get_remote_app_data('public-auth-url')
def register_services(self, service_endpoints: dict,
region: str) -> None:
@ -316,7 +329,9 @@ class IdentityServiceRequires(Object):
if self.model.unit.is_leader():
logging.debug("Requesting service registration")
app_data = self._identity_service_rel.data[self.charm.app]
app_data["service-endpoints"] = json.dumps(service_endpoints)
app_data["service-endpoints"] = json.dumps(
service_endpoints, sort_keys=True
)
app_data["region"] = region
@ -337,7 +352,6 @@ class ReadyIdentityServiceClientsEvent(EventBase):
self.service_endpoints = service_endpoints
self.region = region
self.client_app_name = client_app_name
def snapshot(self):
return {
@ -399,14 +413,13 @@ class IdentityServiceProvides(Object):
REQUIRED_KEYS = [
'service-endpoints',
'region']
values = [
event.relation.data[event.relation.app].get(k)
for k in REQUIRED_KEYS ]
for k in REQUIRED_KEYS
]
# Validate data on the relation
if all(values):
print(event.relation.id)
print(event.relation.name)
service_eps = json.loads(
event.relation.data[event.relation.app]['service-endpoints'])
self.on.ready_identity_service_clients.emit(
@ -439,11 +452,18 @@ class IdentityServiceProvides(Object):
service_domain: str,
service_password: str,
service_project: str,
service_user: str):
service_user: str,
internal_auth_url: str,
admin_auth_url: str,
public_auth_url: str):
logging.debug("Setting identity_service connection information.")
_identity_service_rel = None
for relation in self.framework.model.relations[relation_name]:
if relation.id == relation_id:
_identity_service_rel = relation
if not _identity_service_rel:
# Relation has disappeared so skip send of data
return
app_data = _identity_service_rel.data[self.charm.app]
app_data["api-version"] = api_version
app_data["auth-host"] = auth_host
@ -468,3 +488,6 @@ class IdentityServiceProvides(Object):
app_data["service-user-name"] = service_user.name
app_data["service-user-id"] = service_user.id
app_data["service-password"] = service_password
app_data["internal-auth-url"] = internal_auth_url
app_data["admin-auth-url"] = admin_auth_url
app_data["public-auth-url"] = public_auth_url

View File

@ -1,419 +0,0 @@
"""IdentityServiceProvides and Requires module.
This library contains the Requires and Provides classes for handling
the identity_service interface.
Import `IdentityServiceRequires` in your charm, with the charm object and the
relation name:
- self
- "identity_service"
Also provide additional parameters to the charm object:
- service
- internal_url
- public_url
- admin_url
- region
- username
- vhost
Two events are also available to respond to:
- connected
- ready
- goneaway
A basic example showing the usage of this relation follows:
```
from charms.sunbeam_sunbeam_identity_service_operator.v0.identity_service import IdentityServiceRequires
class IdentityServiceClientCharm(CharmBase):
def __init__(self, *args):
super().__init__(*args)
# IdentityService Requires
self.identity_service = IdentityServiceRequires(
self, "identity_service",
service = "my-service"
internal_url = "http://internal-url"
public_url = "http://public-url"
admin_url = "http://admin-url"
region = "region"
)
self.framework.observe(
self.identity_service.on.connected, self._on_identity_service_connected)
self.framework.observe(
self.identity_service.on.ready, self._on_identity_service_ready)
self.framework.observe(
self.identity_service.on.goneaway, self._on_identity_service_goneaway)
def _on_identity_service_connected(self, event):
'''React to the IdentityService connected event.
This event happens when n IdentityService relation is added to the
model before credentials etc have been provided.
'''
# Do something before the relation is complete
pass
def _on_identity_service_ready(self, event):
'''React to the IdentityService ready event.
The IdentityService interface will use the provided config for the
request to the identity server.
'''
# IdentityService Relation is ready. Do something with the completed relation.
pass
def _on_identity_service_goneaway(self, event):
'''React to the IdentityService goneaway event.
This event happens when an IdentityService relation is removed.
'''
# IdentityService Relation has goneaway. shutdown services or suchlike
pass
```
"""
# The unique Charmhub library identifier, never change it
LIBID = "deadbeef"
# Increment this major API version when introducing breaking changes
LIBAPI = 0
# Increment this PATCH version before using `charmcraft publish-lib` or reset
# to 0 if you are raising the major API version
LIBPATCH = 1
import json
import logging
import requests
from ops.framework import (
StoredState,
EventBase,
ObjectEvents,
EventSource,
Object,
)
from ops.model import Relation
from typing import List
logger = logging.getLogger(__name__)
class CloudCredentialsConnectedEvent(EventBase):
"""CloudCredentials connected Event."""
pass
class CloudCredentialsReadyEvent(EventBase):
"""CloudCredentials ready for use Event."""
pass
class CloudCredentialsGoneAwayEvent(EventBase):
"""CloudCredentials relation has gone-away Event"""
pass
class CloudCredentialsServerEvents(ObjectEvents):
"""Events class for `on`"""
connected = EventSource(CloudCredentialsConnectedEvent)
ready = EventSource(CloudCredentialsReadyEvent)
goneaway = EventSource(CloudCredentialsGoneAwayEvent)
class CloudCredentialsRequires(Object):
"""
CloudCredentialsRequires class
"""
on = CloudCredentialsServerEvents()
_stored = StoredState()
def __init__(self, charm, relation_name: str):
super().__init__(charm, relation_name)
self.charm = charm
self.relation_name = relation_name
self.framework.observe(
self.charm.on[relation_name].relation_joined,
self._on_cloud_credentials_relation_joined,
)
self.framework.observe(
self.charm.on[relation_name].relation_changed,
self._on_cloud_credentials_relation_changed,
)
self.framework.observe(
self.charm.on[relation_name].relation_departed,
self._on_cloud_credentials_relation_changed,
)
self.framework.observe(
self.charm.on[relation_name].relation_broken,
self._on_cloud_credentials_relation_broken,
)
def _on_cloud_credentials_relation_joined(self, event):
"""CloudCredentials relation joined."""
logging.debug("CloudCredentials on_joined")
self.on.connected.emit()
self.request_credentials()
def _on_cloud_credentials_relation_changed(self, event):
"""CloudCredentials relation changed."""
logging.debug("CloudCredentials on_changed")
try:
self.on.ready.emit()
except AttributeError:
logger.exception('Error when emitting event')
def _on_cloud_credentials_relation_broken(self, event):
"""CloudCredentials relation broken."""
logging.debug("CloudCredentials on_broken")
self.on.goneaway.emit()
@property
def _cloud_credentials_rel(self) -> Relation:
"""The CloudCredentials relation."""
return self.framework.model.get_relation(self.relation_name)
def get_remote_app_data(self, key: str) -> str:
"""Return the value for the given key from remote app data."""
data = self._cloud_credentials_rel.data[self._cloud_credentials_rel.app]
return data.get(key)
@property
def api_version(self) -> str:
"""Return the api_version."""
return self.get_remote_app_data('api-version')
@property
def auth_host(self) -> str:
"""Return the auth_host."""
return self.get_remote_app_data('auth-host')
@property
def auth_port(self) -> str:
"""Return the auth_port."""
return self.get_remote_app_data('auth-port')
@property
def auth_protocol(self) -> str:
"""Return the auth_protocol."""
return self.get_remote_app_data('auth-protocol')
@property
def internal_host(self) -> str:
"""Return the internal_host."""
return self.get_remote_app_data('internal-host')
@property
def internal_port(self) -> str:
"""Return the internal_port."""
return self.get_remote_app_data('internal-port')
@property
def internal_protocol(self) -> str:
"""Return the internal_protocol."""
return self.get_remote_app_data('internal-protocol')
@property
def username(self) -> str:
"""Return the username."""
return self.get_remote_app_data('username')
@property
def password(self) -> str:
"""Return the password."""
return self.get_remote_app_data('password')
@property
def project_name(self) -> str:
"""Return the project name."""
return self.get_remote_app_data('project-name')
@property
def project_id(self) -> str:
"""Return the project id."""
return self.get_remote_app_data('project-id')
@property
def user_domain_name(self) -> str:
"""Return the name of the user domain."""
return self.get_remote_app_data('user-domain-name')
@property
def user_domain_id(self) -> str:
"""Return the id of the user domain."""
return self.get_remote_app_data('user-domain-id')
@property
def project_domain_name(self) -> str:
"""Return the name of the project domain."""
return self.get_remote_app_data('project-domain-name')
@property
def project_domain_id(self) -> str:
"""Return the id of the project domain."""
return self.get_remote_app_data('project-domain-id')
@property
def region(self) -> str:
"""Return the region for the auth urls."""
return self.get_remote_app_data('region')
def request_credentials(self) -> None:
"""Request credentials from the CloudCredentials server."""
if self.model.unit.is_leader():
logging.debug(f'Requesting credentials for {self.charm.app.name}')
app_data = self._cloud_credentials_rel.data[self.charm.app]
app_data['username'] = self.charm.app.name
class HasCloudCredentialsClientsEvent(EventBase):
"""Has CloudCredentialsClients Event."""
pass
class ReadyCloudCredentialsClientsEvent(EventBase):
"""CloudCredentialsClients Ready Event."""
def __init__(self, handle, relation_id, relation_name, username):
super().__init__(handle)
self.relation_id = relation_id
self.relation_name = relation_name
self.username = username
def snapshot(self):
return {
"relation_id": self.relation_id,
"relation_name": self.relation_name,
"username": self.username,
}
def restore(self, snapshot):
super().restore(snapshot)
self.relation_id = snapshot["relation_id"]
self.relation_name = snapshot["relation_name"]
self.username = snapshot["username"]
class CloudCredentialsClientsGoneAwayEvent(EventBase):
"""Has CloudCredentialsClientsGoneAwayEvent Event."""
pass
class CloudCredentialsClientEvents(ObjectEvents):
"""Events class for `on`"""
has_cloud_credentials_clients = EventSource(
HasCloudCredentialsClientsEvent
)
ready_cloud_credentials_clients = EventSource(
ReadyCloudCredentialsClientsEvent
)
cloud_credentials_clients_gone = EventSource(
CloudCredentialsClientsGoneAwayEvent
)
class CloudCredentialsProvides(Object):
"""
CloudCredentialsProvides class
"""
on = CloudCredentialsClientEvents()
_stored = StoredState()
def __init__(self, charm, relation_name):
super().__init__(charm, relation_name)
self.charm = charm
self.relation_name = relation_name
self.framework.observe(
self.charm.on[relation_name].relation_joined,
self._on_cloud_credentials_relation_joined,
)
self.framework.observe(
self.charm.on[relation_name].relation_changed,
self._on_cloud_credentials_relation_changed,
)
self.framework.observe(
self.charm.on[relation_name].relation_broken,
self._on_cloud_credentials_relation_broken,
)
def _on_cloud_credentials_relation_joined(self, event):
"""Handle CloudCredentials joined."""
logging.debug("CloudCredentialsProvides on_joined")
self.on.has_cloud_credentials_clients.emit()
def _on_cloud_credentials_relation_changed(self, event):
"""Handle CloudCredentials changed."""
logging.debug("CloudCredentials on_changed")
REQUIRED_KEYS = ['username']
values = [
event.relation.data[event.relation.app].get(k)
for k in REQUIRED_KEYS
]
# Validate data on the relation
if all(values):
username = event.relation.data[event.relation.app]['username']
self.on.ready_cloud_credentials_clients.emit(
event.relation.id,
event.relation.name,
username,
)
def _on_cloud_credentials_relation_broken(self, event):
"""Handle CloudCredentials broken."""
logging.debug("CloudCredentialsProvides on_departed")
self.on.cloud_credentials_clients_gone.emit()
def set_cloud_credentials(self, relation_name: int,
relation_id: str,
api_version: str,
auth_host: str,
auth_port: str,
auth_protocol: str,
internal_host: str,
internal_port: str,
internal_protocol: str,
username: str,
password: str,
project_name: str,
project_id: str,
user_domain_name: str,
user_domain_id: str,
project_domain_name: str,
project_domain_id: str,
region: str):
logging.debug("Setting cloud_credentials connection information.")
for relation in self.framework.model.relations[relation_name]:
if relation.id == relation_id:
_cloud_credentials_rel = relation
app_data = _cloud_credentials_rel.data[self.charm.app]
app_data["api-version"] = api_version
app_data["auth-host"] = auth_host
app_data["auth-port"] = str(auth_port)
app_data["auth-protocol"] = auth_protocol
app_data["internal-host"] = internal_host
app_data["internal-port"] = str(internal_port)
app_data["internal-protocol"] = internal_protocol
app_data["username"] = username
app_data["password"] = password
app_data["project-name"] = project_name
app_data["project-id"] = project_id
app_data["user-domain-name"] = user_domain_name
app_data["user-domain-id"] = user_domain_id
app_data["project-domain-name"] = project_domain_name
app_data["project-domain-id"] = project_domain_id
app_data["region"] = region