LB relation updates
* Ensure vip passed back from lb is included in certificate request * Pull interface from its own repo Change-Id: Ib9fa865c115d54591483db6679dbeb645b3e353f
This commit is contained in:
parent
616059437d
commit
3a34e4b558
@ -24,7 +24,7 @@ requires:
|
||||
certificates:
|
||||
interface: tls-certificates
|
||||
loadbalancer:
|
||||
interface: api-endpoints
|
||||
interface: openstack-loadbalancer
|
||||
alertmanager-service:
|
||||
interface: http
|
||||
prometheus:
|
||||
|
@ -5,3 +5,4 @@ git+https://opendev.org/openstack/charm-ops-openstack#egg=ops_openstack
|
||||
#git+https://opendev.org/openstack/charm-ops-interface-tls-certificates#egg=interface_tls_certificates
|
||||
git+https://github.com/gnuoy/ops-interface-tls-certificates@no-exception-for-inflight-request#egg=interface_tls_certificates
|
||||
git+https://github.com/openstack-charmers/ops-interface-ceph-iscsi-admin-access#egg=interface_ceph_iscsi_admin_access
|
||||
git+https://github.com/openstack-charmers/ops-interface-openstack-loadbalancer#egg=interface_openstack_loadbalancer
|
||||
|
49
src/charm.py
49
src/charm.py
@ -18,6 +18,7 @@ from typing import List, Union, Tuple
|
||||
|
||||
import base64
|
||||
import interface_tls_certificates.ca_client as ca_client
|
||||
import interface_openstack_loadbalancer.loadbalancer as ops_lb_interface
|
||||
import re
|
||||
import secrets
|
||||
import socket
|
||||
@ -27,7 +28,6 @@ import tenacity
|
||||
import ops_openstack.plugins.classes
|
||||
import interface_ceph_iscsi_admin_access.admin_access as admin_access
|
||||
import interface_dashboard
|
||||
import interface_api_endpoints
|
||||
import interface_grafana_dashboard
|
||||
import interface_http
|
||||
import interface_radosgw_user
|
||||
@ -57,6 +57,7 @@ class CephDashboardCharm(ops_openstack.core.OSBaseCharm):
|
||||
TLS_CHARM_CA_CERT_PATH = TLS_CA_CERT_DIR / 'charm_config_juju_ca_cert.crt'
|
||||
TLS_PORT = 8443
|
||||
DASH_DIR = Path('src/dashboards')
|
||||
LB_SERVICE_NAME = "ceph-dashboard"
|
||||
|
||||
class CharmCephOption():
|
||||
"""Manage a charm option to ceph command to manage that option"""
|
||||
@ -175,7 +176,7 @@ class CephDashboardCharm(ops_openstack.core.OSBaseCharm):
|
||||
self._configure_dashboard)
|
||||
self.framework.observe(
|
||||
self.ca_client.on.ca_available,
|
||||
self._on_ca_available)
|
||||
self._configure_dashboard)
|
||||
self.framework.observe(
|
||||
self.ca_client.on.tls_server_config_ready,
|
||||
self._configure_dashboard)
|
||||
@ -189,16 +190,9 @@ class CephDashboardCharm(ops_openstack.core.OSBaseCharm):
|
||||
self.framework.observe(
|
||||
self.on.delete_user_action,
|
||||
self._delete_user_action)
|
||||
self.ingress = interface_api_endpoints.APIEndpointsRequires(
|
||||
self.ingress = ops_lb_interface.OSLoadbalancerRequires(
|
||||
self,
|
||||
'loadbalancer',
|
||||
{
|
||||
'endpoints': [{
|
||||
'service-type': 'ceph-dashboard',
|
||||
'frontend-port': self.TLS_PORT,
|
||||
'backend-port': self.TLS_PORT,
|
||||
'backend-ip': self._get_bind_ip(),
|
||||
'check-type': 'httpd'}]})
|
||||
'loadbalancer')
|
||||
self.grafana_dashboard = \
|
||||
interface_grafana_dashboard.GrafanaDashboardProvides(
|
||||
self,
|
||||
@ -218,8 +212,23 @@ class CephDashboardCharm(ops_openstack.core.OSBaseCharm):
|
||||
self.framework.observe(
|
||||
self.prometheus.on.http_ready,
|
||||
self._configure_dashboard)
|
||||
self.framework.observe(
|
||||
self.ingress.on.lb_relation_ready,
|
||||
self._request_loadbalancer)
|
||||
self.framework.observe(
|
||||
self.ingress.on.lb_configured,
|
||||
self._configure_dashboard)
|
||||
self._stored.set_default(is_started=False)
|
||||
|
||||
def _request_loadbalancer(self, _) -> None:
|
||||
"""Send request to create loadbalancer"""
|
||||
self.ingress.request_loadbalancer(
|
||||
self.LB_SERVICE_NAME,
|
||||
self.TLS_PORT,
|
||||
self.TLS_PORT,
|
||||
self._get_bind_ip(),
|
||||
'httpd')
|
||||
|
||||
def _register_dashboards(self) -> None:
|
||||
"""Register all dashboards with grafana"""
|
||||
for dash_file in self.DASH_DIR.glob("*.json"):
|
||||
@ -273,9 +282,24 @@ class CephDashboardCharm(ops_openstack.core.OSBaseCharm):
|
||||
creds[0]['access_key'],
|
||||
creds[0]['secret_key'])
|
||||
|
||||
def _on_ca_available(self, _) -> None:
|
||||
def request_certificates(self) -> None:
|
||||
"""Request TLS certificates."""
|
||||
if not self.ca_client.is_joined:
|
||||
logging.debug(
|
||||
"Cannot request certificates, relation not present.")
|
||||
return
|
||||
addresses = set()
|
||||
if self.ingress.relations:
|
||||
lb_response = self.ingress.get_frontend_data()
|
||||
if lb_response:
|
||||
lb_config = lb_response[self.LB_SERVICE_NAME]
|
||||
addresses.update(
|
||||
[i for d in lb_config.values() for i in d['ip']])
|
||||
else:
|
||||
logging.debug(
|
||||
("Defering certificate request until loadbalancer has "
|
||||
"responded."))
|
||||
return
|
||||
for binding_name in ['public']:
|
||||
binding = self.model.get_binding(binding_name)
|
||||
addresses.add(binding.network.ingress_address)
|
||||
@ -390,6 +414,7 @@ class CephDashboardCharm(ops_openstack.core.OSBaseCharm):
|
||||
|
||||
def _configure_dashboard(self, _) -> None:
|
||||
"""Configure dashboard"""
|
||||
self.request_certificates()
|
||||
if not self.mon.mons_ready:
|
||||
logging.info("Not configuring dashboard, mons not ready")
|
||||
return
|
||||
|
@ -1,64 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import json
|
||||
|
||||
from ops.framework import (
|
||||
StoredState,
|
||||
EventBase,
|
||||
ObjectEvents,
|
||||
EventSource,
|
||||
Object)
|
||||
|
||||
|
||||
class EndpointDataEvent(EventBase):
|
||||
pass
|
||||
|
||||
|
||||
class APIEndpointsEvents(ObjectEvents):
|
||||
ep_ready = EventSource(EndpointDataEvent)
|
||||
|
||||
|
||||
class APIEndpointsRequires(Object):
|
||||
|
||||
on = APIEndpointsEvents()
|
||||
_stored = StoredState()
|
||||
|
||||
def __init__(self, charm, relation_name, config_dict):
|
||||
super().__init__(charm, relation_name)
|
||||
self.config_dict = config_dict
|
||||
self.relation_name = relation_name
|
||||
self.framework.observe(
|
||||
charm.on[self.relation_name].relation_changed,
|
||||
self._on_relation_changed)
|
||||
|
||||
def _on_relation_changed(self, event):
|
||||
"""Handle the relation-changed event."""
|
||||
event.relation.data[self.model.unit]['endpoints'] = json.dumps(
|
||||
self.config_dict['endpoints'])
|
||||
|
||||
def update_config(self, config_dict):
|
||||
"""Allow for updates to relation."""
|
||||
self.config_dict = config_dict
|
||||
relation = self.model.get_relation(self.relation_name)
|
||||
if relation:
|
||||
relation.data[self.model.unit]['endpoints'] = json.dumps(
|
||||
self.config_dict['endpoints'])
|
||||
|
||||
|
||||
class APIEndpointsProvides(Object):
|
||||
|
||||
on = APIEndpointsEvents()
|
||||
_stored = StoredState()
|
||||
|
||||
def __init__(self, charm):
|
||||
super().__init__(charm, "loadbalancer")
|
||||
# Observe the relation-changed hook event and bind
|
||||
# self.on_relation_changed() to handle the event.
|
||||
self.framework.observe(
|
||||
charm.on["loadbalancer"].relation_changed,
|
||||
self._on_relation_changed)
|
||||
self.charm = charm
|
||||
|
||||
def _on_relation_changed(self, event):
|
||||
"""Handle a change to the loadbalancer relation."""
|
||||
self.on.ep_ready.emit()
|
@ -15,6 +15,7 @@
|
||||
# limitations under the License.
|
||||
|
||||
import base64
|
||||
import json
|
||||
import unittest
|
||||
import sys
|
||||
|
||||
@ -385,6 +386,9 @@ class TestCephDashboardCharmBase(CharmTestCase):
|
||||
_gethostname.return_value = 'server1'
|
||||
cert_rel_id = self.harness.add_relation('certificates', 'vault')
|
||||
dash_rel_id = self.harness.add_relation('dashboard', 'ceph-mon')
|
||||
lb_rel_id = self.harness.add_relation(
|
||||
'loadbalancer',
|
||||
'openstack-loadbalancer')
|
||||
self.harness.begin()
|
||||
self.harness.set_leader()
|
||||
self.harness.charm.TLS_CERT_PATH = mock_TLS_CERT_PATH
|
||||
@ -401,6 +405,40 @@ class TestCephDashboardCharmBase(CharmTestCase):
|
||||
self.harness.add_relation_unit(
|
||||
cert_rel_id,
|
||||
'vault/0')
|
||||
self.harness.add_relation_unit(
|
||||
lb_rel_id,
|
||||
'openstack-loadbalancer/0')
|
||||
# If lb relation is present but has not responded then certs should
|
||||
# not have been requested yet.
|
||||
self.assertEqual(
|
||||
self.harness.get_relation_data(
|
||||
cert_rel_id,
|
||||
'ceph-dashboard/0'),
|
||||
{})
|
||||
self.harness.update_relation_data(
|
||||
lb_rel_id,
|
||||
'openstack-loadbalancer',
|
||||
{
|
||||
'frontends': json.dumps(
|
||||
{
|
||||
'ceph-dashboard': {
|
||||
'admin': {
|
||||
'ip': ['10.20.0.101'],
|
||||
'port': 8443,
|
||||
'protocol': 'http'},
|
||||
'internal': {
|
||||
'ip': ['10.30.0.101'],
|
||||
'port': 8443,
|
||||
'protocol': 'http'},
|
||||
'public': {
|
||||
'ip': ['10.10.0.101'],
|
||||
'port': 8443,
|
||||
'protocol': 'http'}}})})
|
||||
self.assertNotEqual(
|
||||
self.harness.get_relation_data(
|
||||
cert_rel_id,
|
||||
'ceph-dashboard/0'),
|
||||
{})
|
||||
self.harness.update_relation_data(
|
||||
cert_rel_id,
|
||||
'vault/0',
|
||||
|
@ -1,159 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Copyright 2021 Canonical Ltd.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import copy
|
||||
import json
|
||||
import unittest
|
||||
import sys
|
||||
sys.path.append('lib') # noqa
|
||||
sys.path.append('src') # noqa
|
||||
from ops.testing import Harness
|
||||
from ops.charm import CharmBase
|
||||
import interface_api_endpoints
|
||||
|
||||
|
||||
class TestAPIEndpointsRequires(unittest.TestCase):
|
||||
|
||||
class MyCharm(CharmBase):
|
||||
|
||||
def __init__(self, *args):
|
||||
super().__init__(*args)
|
||||
self.seen_events = []
|
||||
self.ingress = interface_api_endpoints.APIEndpointsRequires(
|
||||
self,
|
||||
'loadbalancer',
|
||||
{
|
||||
'endpoints': [{
|
||||
'service-type': 'ceph-dashboard',
|
||||
'frontend-port': 8443,
|
||||
'backend-port': 8443,
|
||||
'backend-ip': '10.0.0.10',
|
||||
'check-type': 'httpd'}]})
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.harness = Harness(
|
||||
self.MyCharm,
|
||||
meta='''
|
||||
name: my-charm
|
||||
requires:
|
||||
loadbalancer:
|
||||
interface: api-endpoints
|
||||
'''
|
||||
)
|
||||
self.eps = [{
|
||||
'service-type': 'ceph-dashboard',
|
||||
'frontend-port': 8443,
|
||||
'backend-port': 8443,
|
||||
'backend-ip': '10.0.0.10',
|
||||
'check-type': 'httpd'}]
|
||||
|
||||
def add_loadbalancer_relation(self):
|
||||
rel_id = self.harness.add_relation(
|
||||
'loadbalancer',
|
||||
'service-loadbalancer')
|
||||
self.harness.add_relation_unit(
|
||||
rel_id,
|
||||
'service-loadbalancer/0')
|
||||
self.harness.update_relation_data(
|
||||
rel_id,
|
||||
'service-loadbalancer/0',
|
||||
{'ingress-address': '10.0.0.3'})
|
||||
return rel_id
|
||||
|
||||
def test_init(self):
|
||||
self.harness.begin()
|
||||
self.assertEqual(
|
||||
self.harness.charm.ingress.config_dict,
|
||||
{'endpoints': self.eps})
|
||||
self.assertEqual(
|
||||
self.harness.charm.ingress.relation_name,
|
||||
'loadbalancer')
|
||||
|
||||
def test__on_relation_changed(self):
|
||||
self.harness.begin()
|
||||
rel_id = self.add_loadbalancer_relation()
|
||||
rel_data = self.harness.get_relation_data(
|
||||
rel_id,
|
||||
'my-charm/0')
|
||||
self.assertEqual(
|
||||
rel_data['endpoints'],
|
||||
json.dumps(self.eps))
|
||||
|
||||
def test_update_config(self):
|
||||
self.harness.begin()
|
||||
rel_id = self.add_loadbalancer_relation()
|
||||
new_eps = copy.deepcopy(self.eps)
|
||||
new_eps.append({
|
||||
'service-type': 'ceph-dashboard',
|
||||
'frontend-port': 9443,
|
||||
'backend-port': 9443,
|
||||
'backend-ip': '10.0.0.10',
|
||||
'check-type': 'https'})
|
||||
self.harness.charm.ingress.update_config(
|
||||
{'endpoints': new_eps})
|
||||
rel_data = self.harness.get_relation_data(
|
||||
rel_id,
|
||||
'my-charm/0')
|
||||
self.assertEqual(
|
||||
rel_data['endpoints'],
|
||||
json.dumps(new_eps))
|
||||
|
||||
|
||||
class TestAPIEndpointsProvides(unittest.TestCase):
|
||||
|
||||
class MyCharm(CharmBase):
|
||||
|
||||
def __init__(self, *args):
|
||||
super().__init__(*args)
|
||||
self.seen_events = []
|
||||
self.api_eps = interface_api_endpoints.APIEndpointsProvides(self)
|
||||
self.framework.observe(
|
||||
self.api_eps.on.ep_ready,
|
||||
self._log_event)
|
||||
|
||||
def _log_event(self, event):
|
||||
self.seen_events.append(type(event).__name__)
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.harness = Harness(
|
||||
self.MyCharm,
|
||||
meta='''
|
||||
name: my-charm
|
||||
provides:
|
||||
loadbalancer:
|
||||
interface: api-endpoints
|
||||
'''
|
||||
)
|
||||
|
||||
def test_on_changed(self):
|
||||
self.harness.begin()
|
||||
# No MonReadyEvent as relation is absent
|
||||
self.assertEqual(
|
||||
self.harness.charm.seen_events,
|
||||
[])
|
||||
rel_id = self.harness.add_relation('loadbalancer', 'ceph-dashboard')
|
||||
self.harness.add_relation_unit(
|
||||
rel_id,
|
||||
'ceph-dashboard/0')
|
||||
self.harness.update_relation_data(
|
||||
rel_id,
|
||||
'ceph-dashboard/0',
|
||||
{'ingress-address': '10.0.0.3'})
|
||||
self.assertEqual(
|
||||
self.harness.charm.seen_events,
|
||||
['EndpointDataEvent'])
|
Loading…
Reference in New Issue
Block a user