Add support for Ceph dashboard support
This change adds an admin-access interface to pass the admin credentials and api endpoint details to another charm. The dashboard charm uses this information registern the iscsi gateways with the dashboard. Change-Id: I5336ecab6a08e71dda22ba0347b8bee2f5683c3f
This commit is contained in:
parent
2027e50020
commit
0434825ea9
@ -23,6 +23,9 @@ requires:
|
||||
interface: ceph-client
|
||||
certificates:
|
||||
interface: tls-certificates
|
||||
provides:
|
||||
admin-access:
|
||||
interface: ceph-iscsi-admin-access
|
||||
peers:
|
||||
cluster:
|
||||
interface: ceph-iscsi-peer
|
||||
|
29
osci.yaml
Normal file
29
osci.yaml
Normal file
@ -0,0 +1,29 @@
|
||||
- project:
|
||||
templates:
|
||||
- charm-unit-jobs
|
||||
check:
|
||||
jobs:
|
||||
- ceph-iscsi-focal-octopus
|
||||
- ceph-iscsi-focal-octopus-ec
|
||||
vars:
|
||||
needs_charm_build: true
|
||||
charm_build_name: ceph-iscsi
|
||||
build_type: charmcraft
|
||||
- job:
|
||||
name: ceph-iscsi-focal-octopus
|
||||
parent: func-target
|
||||
dependencies:
|
||||
- osci-lint
|
||||
- tox-py35
|
||||
- tox-py36
|
||||
- tox-py37
|
||||
- tox-py38
|
||||
vars:
|
||||
tox_extra_args: focal
|
||||
- job:
|
||||
name: ceph-iscsi-focal-octopus-ec
|
||||
parent: func-target
|
||||
dependencies: &smoke-jobs
|
||||
- ceph-iscsi-focal-octopus
|
||||
vars:
|
||||
tox_extra_args: focal-ec
|
@ -4,3 +4,4 @@ git+https://github.com/canonical/operator.git#egg=ops
|
||||
git+https://opendev.org/openstack/charm-ops-interface-ceph-client#egg=interface_ceph_client
|
||||
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/openstack-charmers/ops-interface-ceph-iscsi-admin-access#egg=interface_ceph_iscsi_admin_access
|
||||
|
48
src/charm.py
48
src/charm.py
@ -17,12 +17,12 @@
|
||||
"""Charm for deploying and maintaining the Ceph iSCSI service."""
|
||||
|
||||
import copy
|
||||
import socket
|
||||
import logging
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import string
|
||||
import socket
|
||||
import secrets
|
||||
from pathlib import Path
|
||||
|
||||
@ -36,6 +36,7 @@ import ops.model
|
||||
import charmhelpers.core.host as ch_host
|
||||
import charmhelpers.core.templating as ch_templating
|
||||
import interface_ceph_client.ceph_client as ceph_client
|
||||
import interface_ceph_iscsi_admin_access.admin_access as admin_access
|
||||
import interface_ceph_iscsi_peer
|
||||
import interface_tls_certificates.ca_client as ca_client
|
||||
|
||||
@ -102,7 +103,20 @@ class GatewayClientPeerAdapter(
|
||||
"""
|
||||
ips = copy.deepcopy(self.allowed_ips)
|
||||
ips.extend(self.relation.peer_addresses)
|
||||
return ' '.join(sorted(ips))
|
||||
return ','.join(sorted(ips))
|
||||
|
||||
|
||||
class AdminAccessAdapter(
|
||||
ops_openstack.adapters.OpenStackOperRelationAdapter):
|
||||
|
||||
@property
|
||||
def trusted_ips(self):
|
||||
"""List of IP addresses permitted to use API.
|
||||
|
||||
:returns: Ceph iSCSI clients
|
||||
:rtype: str
|
||||
"""
|
||||
return ','.join(sorted(self.relation.client_addresses))
|
||||
|
||||
|
||||
class TLSCertificatesAdapter(
|
||||
@ -130,6 +144,7 @@ class CephISCSIGatewayAdapters(
|
||||
'ceph-client': CephClientAdapter,
|
||||
'cluster': GatewayClientPeerAdapter,
|
||||
'certificates': TLSCertificatesAdapter,
|
||||
'admin-access': AdminAccessAdapter,
|
||||
}
|
||||
|
||||
|
||||
@ -184,12 +199,19 @@ class CephISCSIGatewayCharmBase(
|
||||
self.peers = interface_ceph_iscsi_peer.CephISCSIGatewayPeers(
|
||||
self,
|
||||
'cluster')
|
||||
self.admin_access = \
|
||||
admin_access.CephISCSIAdminAccessProvides(
|
||||
self,
|
||||
'admin-access')
|
||||
self.ca_client = ca_client.CAClient(
|
||||
self,
|
||||
'certificates')
|
||||
self.adapters = CephISCSIGatewayAdapters(
|
||||
(self.ceph_client, self.peers, self.ca_client),
|
||||
(self.ceph_client, self.peers, self.ca_client, self.admin_access),
|
||||
self)
|
||||
self.framework.observe(
|
||||
self.admin_access.on.admin_access_request,
|
||||
self.publish_admin_access_info)
|
||||
self.framework.observe(
|
||||
self.ceph_client.on.broker_available,
|
||||
self.request_ceph_pool)
|
||||
@ -240,6 +262,7 @@ class CephISCSIGatewayCharmBase(
|
||||
alphabet = string.ascii_letters + string.digits
|
||||
password = ''.join(secrets.choice(alphabet) for i in range(8))
|
||||
self.peers.set_admin_password(password)
|
||||
self.publish_admin_access_info(event)
|
||||
|
||||
def config_get(self, key):
|
||||
"""Retrieve config option.
|
||||
@ -274,7 +297,6 @@ class CephISCSIGatewayCharmBase(
|
||||
|
||||
def request_ceph_pool(self, event):
|
||||
"""Request pools from Ceph cluster."""
|
||||
print("request_ceph_pool")
|
||||
if not self.ceph_client.broker_available:
|
||||
logging.info("Cannot request ceph setup at this time")
|
||||
return
|
||||
@ -440,8 +462,26 @@ class CephISCSIGatewayCharmBase(
|
||||
encoding=serialization.Encoding.PEM))
|
||||
subprocess.check_call(['update-ca-certificates'])
|
||||
self._stored.enable_tls = True
|
||||
# Endpoint has switch to TLS, need to inform users.
|
||||
self.publish_admin_access_info(event)
|
||||
self.render_config(event)
|
||||
|
||||
def publish_admin_access_info(self, event):
|
||||
"""Publish creds and endpoint to related charms"""
|
||||
if not self.peers.admin_password:
|
||||
logging.info("Defering setup")
|
||||
event.defer()
|
||||
return
|
||||
if self._stored.enable_tls:
|
||||
scheme = 'https'
|
||||
else:
|
||||
scheme = 'http'
|
||||
self.admin_access.publish_gateway(
|
||||
socket.getfqdn(),
|
||||
'admin',
|
||||
self.peers.admin_password,
|
||||
scheme)
|
||||
|
||||
def custom_status_check(self):
|
||||
"""Custom update status checks."""
|
||||
if ch_host.is_container():
|
||||
|
@ -11,4 +11,8 @@ api_secure = {{ certificates.enable_tls }}
|
||||
api_user = admin
|
||||
api_password = {{ cluster.admin_password }}
|
||||
api_port = 5000
|
||||
{% if admin_access.trusted_ips -%}
|
||||
trusted_ip_list = {{ cluster.trusted_ips }},{{ admin_access.trusted_ips }}
|
||||
{% else -%}
|
||||
trusted_ip_list = {{ cluster.trusted_ips }}
|
||||
{% endif -%}
|
||||
|
@ -139,8 +139,10 @@ class TestCephISCSIGatewayCharmBase(CharmTestCase):
|
||||
PATCHES = [
|
||||
'ch_templating',
|
||||
'gwcli_client',
|
||||
'subprocess',
|
||||
'os',
|
||||
'secrets',
|
||||
'socket',
|
||||
'subprocess',
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
@ -148,6 +150,12 @@ class TestCephISCSIGatewayCharmBase(CharmTestCase):
|
||||
self.harness = Harness(
|
||||
_CephISCSIGatewayCharmBase,
|
||||
)
|
||||
self.test_hostname = 'server1'
|
||||
self.socket.gethostname.return_value = self.test_hostname
|
||||
self.test_fqdn = self.test_hostname + '.foo'
|
||||
self.socket.getfqdn.return_value = self.test_fqdn
|
||||
self.secrets.choice.return_value = 'r'
|
||||
self.test_admin_password = 'rrrrrrrr'
|
||||
self.gwc = MagicMock()
|
||||
self.gwcli_client.GatewayClient.return_value = self.gwc
|
||||
|
||||
@ -182,7 +190,7 @@ class TestCephISCSIGatewayCharmBase(CharmTestCase):
|
||||
self.assertFalse(self.harness.charm._stored.target_created)
|
||||
self.assertFalse(self.harness.charm._stored.enable_tls)
|
||||
|
||||
def add_cluster_relation(self):
|
||||
def add_base_cluster_relation(self):
|
||||
rel_id = self.harness.add_relation('cluster', 'ceph-iscsi')
|
||||
self.harness.add_relation_unit(
|
||||
rel_id,
|
||||
@ -197,10 +205,33 @@ class TestCephISCSIGatewayCharmBase(CharmTestCase):
|
||||
})
|
||||
return rel_id
|
||||
|
||||
def complete_cluster_relation(self, rel_id):
|
||||
self.harness.update_relation_data(
|
||||
rel_id,
|
||||
'ceph-iscsi/1',
|
||||
{
|
||||
'ingress-address': '10.0.0.2',
|
||||
'gateway_ready': 'True',
|
||||
'gateway_fqdn': 'ceph-iscsi-1.example'
|
||||
})
|
||||
|
||||
def add_admin_access_relation(self):
|
||||
rel_id = self.harness.add_relation('admin-access', '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.2',
|
||||
})
|
||||
return rel_id
|
||||
|
||||
@patch('socket.getfqdn')
|
||||
def test_on_create_target_action(self, _getfqdn):
|
||||
_getfqdn.return_value = 'ceph-iscsi-0.example'
|
||||
self.add_cluster_relation()
|
||||
self.add_base_cluster_relation()
|
||||
self.harness.begin()
|
||||
action_event = MagicMock()
|
||||
action_event.params = {
|
||||
@ -245,7 +276,7 @@ class TestCephISCSIGatewayCharmBase(CharmTestCase):
|
||||
@patch('socket.getfqdn')
|
||||
def test_on_create_target_action_ec(self, _getfqdn):
|
||||
_getfqdn.return_value = 'ceph-iscsi-0.example'
|
||||
self.add_cluster_relation()
|
||||
self.add_base_cluster_relation()
|
||||
self.harness.begin()
|
||||
action_event = MagicMock()
|
||||
action_event.params = {
|
||||
@ -296,10 +327,8 @@ class TestCephISCSIGatewayCharmBase(CharmTestCase):
|
||||
'iscsi-metapool',
|
||||
'disk1')
|
||||
|
||||
@patch.object(charm.secrets, 'choice')
|
||||
def test_on_has_peers(self, _choice):
|
||||
def test_on_has_peers(self):
|
||||
rel_id = self.harness.add_relation('cluster', 'ceph-iscsi')
|
||||
_choice.return_value = 'r'
|
||||
self.harness.begin()
|
||||
self.harness.add_relation_unit(
|
||||
rel_id,
|
||||
@ -316,10 +345,10 @@ class TestCephISCSIGatewayCharmBase(CharmTestCase):
|
||||
'gateway_fqdn': 'ceph-iscsi-1.example'
|
||||
})
|
||||
self.assertEqual(
|
||||
self.harness.charm.peers.admin_password, 'rrrrrrrr')
|
||||
self.harness.charm.peers.admin_password, self.test_admin_password)
|
||||
|
||||
def test_on_has_peers_not_leader(self):
|
||||
self.add_cluster_relation()
|
||||
self.add_base_cluster_relation()
|
||||
self.harness.begin()
|
||||
self.assertIsNone(
|
||||
self.harness.charm.peers.admin_password)
|
||||
@ -329,7 +358,7 @@ class TestCephISCSIGatewayCharmBase(CharmTestCase):
|
||||
self.harness.charm.peers.admin_password)
|
||||
|
||||
def test_on_has_peers_existing_password(self):
|
||||
rel_id = self.add_cluster_relation()
|
||||
rel_id = self.add_base_cluster_relation()
|
||||
self.harness.update_relation_data(
|
||||
rel_id,
|
||||
'ceph-iscsi',
|
||||
@ -370,7 +399,7 @@ class TestCephISCSIGatewayCharmBase(CharmTestCase):
|
||||
def test_on_pools_available(self):
|
||||
self.os.path.exists.return_value = False
|
||||
self.os.path.basename = os.path.basename
|
||||
rel_id = self.add_cluster_relation()
|
||||
rel_id = self.add_base_cluster_relation()
|
||||
self.harness.update_relation_data(
|
||||
rel_id,
|
||||
'ceph-iscsi',
|
||||
@ -392,9 +421,7 @@ class TestCephISCSIGatewayCharmBase(CharmTestCase):
|
||||
rel_data = self.harness.get_relation_data(rel_id, 'ceph-iscsi/0')
|
||||
self.assertEqual(rel_data['gateway_ready'], 'True')
|
||||
|
||||
@patch('socket.gethostname')
|
||||
def test_on_certificates_relation_joined(self, _gethostname):
|
||||
_gethostname.return_value = 'server1'
|
||||
def test_on_certificates_relation_joined(self):
|
||||
rel_id = self.harness.add_relation('certificates', 'vault')
|
||||
self.harness.begin()
|
||||
self.harness.add_relation_unit(
|
||||
@ -407,19 +434,17 @@ class TestCephISCSIGatewayCharmBase(CharmTestCase):
|
||||
rel_data = self.harness.get_relation_data(rel_id, 'ceph-iscsi/0')
|
||||
self.assertEqual(
|
||||
rel_data['application_cert_requests'],
|
||||
'{"server1": {"sans": ["10.0.0.10", "server1"]}}')
|
||||
'{"server1.foo": {"sans": ["10.0.0.10", "server1"]}}')
|
||||
|
||||
@patch('socket.gethostname')
|
||||
def test_on_certificates_relation_changed(self, _gethostname):
|
||||
def test_on_certificates_relation_changed(self):
|
||||
mock_TLS_CERT_PATH = MagicMock()
|
||||
mock_TLS_CA_CERT_PATH = MagicMock()
|
||||
mock_TLS_KEY_PATH = MagicMock()
|
||||
mock_KEY_AND_CERT_PATH = MagicMock()
|
||||
mock_TLS_PUB_KEY_PATH = MagicMock()
|
||||
_gethostname.return_value = 'server1'
|
||||
self.subprocess.check_output.return_value = b'pubkey'
|
||||
rel_id = self.harness.add_relation('certificates', 'vault')
|
||||
self.add_cluster_relation()
|
||||
self.add_base_cluster_relation()
|
||||
self.harness.begin()
|
||||
self.harness.charm.TLS_CERT_PATH = mock_TLS_CERT_PATH
|
||||
self.harness.charm.TLS_CA_CERT_PATH = mock_TLS_CA_CERT_PATH
|
||||
@ -460,3 +485,26 @@ class TestCephISCSIGatewayCharmBase(CharmTestCase):
|
||||
self.assertIsInstance(
|
||||
self.harness.charm.unit.status,
|
||||
BlockedStatus)
|
||||
|
||||
def test_publish_admin_access_info(self):
|
||||
cluster_rel_id = self.add_base_cluster_relation()
|
||||
admin_access_rel_id = self.add_admin_access_relation()
|
||||
self.harness.begin()
|
||||
self.harness.set_leader()
|
||||
self.complete_cluster_relation(cluster_rel_id)
|
||||
self.assertEqual(
|
||||
self.harness.get_relation_data(
|
||||
admin_access_rel_id,
|
||||
'ceph-iscsi/0'),
|
||||
{
|
||||
'host': '10.0.0.10',
|
||||
'name': self.test_fqdn,
|
||||
'port': '5000',
|
||||
'scheme': 'http'})
|
||||
self.assertEqual(
|
||||
self.harness.get_relation_data(
|
||||
admin_access_rel_id,
|
||||
'ceph-iscsi'),
|
||||
{
|
||||
'password': self.test_admin_password,
|
||||
'username': 'admin'})
|
||||
|
Loading…
Reference in New Issue
Block a user