From 8e36f135e623aff6e397b3f5c35ee733e50fa0d0 Mon Sep 17 00:00:00 2001 From: Liam Young Date: Thu, 4 Mar 2021 17:34:52 +0000 Subject: [PATCH] This patch add experimental s3 support for Trilio This patch allows an s3 backend to be used to store Trilio artefacts. Connection auth and endpoint are set via the s3 charm config options. To use an s3 backend the backup-target-type should be set to 'experimental-s3'. func-test-pr: https://github.com/openstack-charmers/zaza-openstack-tests/pull/516 Change-Id: I1dab03d25e6e583d88d69ea15e5b5119151c9676 --- osci.yaml | 7 + src/config.yaml | 6 +- src/lib/charm/openstack/trilio_dm.py | 69 ++++- src/templates/tvault-contego.conf | 6 +- src/templates/tvault-object-store.conf | 19 ++ src/tests/bundles/bionic-train-41-s3.yaml | 249 ++++++++++++++++++ src/tests/tests.yaml | 22 +- .../test_lib_charm_openstack_trilio_dm.py | 2 +- 8 files changed, 358 insertions(+), 22 deletions(-) create mode 100644 src/templates/tvault-object-store.conf create mode 100644 src/tests/bundles/bionic-train-41-s3.yaml diff --git a/osci.yaml b/osci.yaml index 767d0ec..68d59b1 100644 --- a/osci.yaml +++ b/osci.yaml @@ -11,6 +11,7 @@ - focal-ussuri-41 - bionic-queens-40 - bionic-queens-41 + - bionic-train-41-s3 vars: needs_charm_build: true charm_build_name: trilio-data-mover @@ -68,3 +69,9 @@ dependencies: *smoke-jobs vars: tox_extra_args: bionic-ussuri-41 +- job: + name: bionic-train-41-s3 + parent: func-target + dependencies: *smoke-jobs + vars: + tox_extra_args: bionic-train-41-s3 diff --git a/src/config.yaml b/src/config.yaml index cdde034..8d46c6e 100644 --- a/src/config.yaml +++ b/src/config.yaml @@ -32,11 +32,11 @@ options: # UNSUPPORTED tv-s3-secret-key: type: string - default: sample_s3_secret_key + default: description: S3 secret access key tv-s3-access-key: type: string - default: sample_s3_access_key + default: description: S3 access key tv-s3-region-name: type: string @@ -44,7 +44,7 @@ options: description: S3 region name tv-s3-bucket: type: string - default: sample_s3_bucket_name + default: description: S3 bucket name tv-s3-endpoint-url: type: string diff --git a/src/lib/charm/openstack/trilio_dm.py b/src/lib/charm/openstack/trilio_dm.py index bfc0baf..4ab2a9b 100644 --- a/src/lib/charm/openstack/trilio_dm.py +++ b/src/lib/charm/openstack/trilio_dm.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import copy import os import charmhelpers.core.hookenv as hookenv @@ -45,6 +46,14 @@ class DataMoverDBAdapter(os_adapters.DatabaseRelationAdapter): return self.get_uri(prefix="dmapi") +@charms_openstack.adapters.config_property +def translated_backup_target_type(cls): + _type = hookenv.config("backup-target-type").lower() + if _type == "experimental-s3": + return 's3' + return _type + + @os_adapters.config_property def ceph_dir(ceph): return os.path.join("/var/lib/charm", hookenv.service_name()) @@ -94,13 +103,14 @@ class TrilioDataMoverBaseCharm( data_mover_conf = "/etc/tvault-contego/tvault-contego.conf" logrotate_conf = "/etc/logrotate.d/tvault-contego" + object_store_conf = "/etc/tvault-object-store/tvault-object-store.conf" service_type = "data-mover" default_service = "tvault-contego" required_relations = ["amqp", "shared-db"] - packages = ["tvault-contego", "nfs-common", "contego"] + base_packages = ["tvault-contego", "nfs-common", "contego"] # configuration file permissions user = "root" @@ -114,6 +124,26 @@ class TrilioDataMoverBaseCharm( os_release_pkg = "nova-common" package_codenames = os_utils.PACKAGE_CODENAMES + @property + def backup_target_type(self): + # The main purpose of this property is to translate experimental-s3 + # to s3 and s3 to UNKNOWN. This forces the deployer to + # use 'experimental-s3' for s3 support but the code can stay clean and + # refer to s3. + _type = hookenv.config("backup-target-type").lower() + if _type == 'experimental-s3': + return 's3' + if _type == 'nfs': + return 'nfs' + return 'UNKNOWN' + + @property + def packages(self): + _pkgs = copy.deepcopy(self.base_packages) + if self.backup_target_type == 's3': + _pkgs.append('python3-s3-fuse-plugin') + return _pkgs + # Set ceph keyring prefix to charm specific location @property def ceph_keyring_path_prefix(self): @@ -169,25 +199,42 @@ class TrilioDataMoverBaseCharm( @property def services(self): - if hookenv.config("backup-target-type") == "s3": + if self.backup_target_type == "s3": return ["tvault-contego", "tvault-object-store"] return ["tvault-contego"] @property def restart_map(self): - if reactive.flags.is_flag_set("ceph.available"): - return { - self.data_mover_conf: self.services, - self.ceph_conf: self.services, - } - return { + _restart_map = { self.data_mover_conf: self.services, } + if reactive.flags.is_flag_set("ceph.available"): + _restart_map[self.ceph_conf] = self.services + if self.backup_target_type == 's3': + _restart_map[self.object_store_conf] = ['tvault-object-store'] + return _restart_map def custom_assess_status_check(self): """Check required configuration options are set""" - if not hookenv.config("nfs-shares"): - return "blocked", "nfs-shares configuration not set" + check_config_set = [] + if self.backup_target_type == "nfs": + check_config_set = ['nfs-shares'] + elif self.backup_target_type == "s3": + check_config_set = [ + "tv-s3-secret-key", + "tv-s3-access-key", + "tv-s3-region-name", + "tv-s3-bucket", + "tv-s3-endpoint-url"] + unset_config = [c for c in check_config_set if not hookenv.config(c)] + if unset_config: + return "blocked", "{} configuration not set".format( + ', '.join(unset_config)) + # For s3 support backup-target-type should be set to 'experimental-s3' + # as s3 support is pre-production. The self.backup_target_type + # property will do any transaltion needed. + if self.backup_target_type not in ["nfs", "s3"]: + return "blocked", "Backup target type not supported" return None, None def request_access_to_groups(self, ceph): @@ -216,7 +263,7 @@ class TrilioDataMoverRockyCharm(TrilioDataMoverBaseCharm): # Python version used to execute installed workload python_version = 3 - packages = ["python3-tvault-contego", "nfs-common", "contego"] + base_packages = ["python3-tvault-contego", "nfs-common", "contego"] @classmethod def trilio_version_package(cls): diff --git a/src/templates/tvault-contego.conf b/src/templates/tvault-contego.conf index 6578a9b..e815d62 100644 --- a/src/templates/tvault-contego.conf +++ b/src/templates/tvault-contego.conf @@ -13,13 +13,13 @@ dmapi_transport_url = {{ amqp.transport_url }} rabbit_virtual_host = {{ amqp.vhost }} {% endif -%} -{% if options.backup_target_type == 'nfs' -%} +{% if options.translated_backup_target_type == 'nfs' -%} # NFS vault_storage_nfs_export = {{ options.nfs_shares }} vault_storage_nfs_options = {{ options.nfs_options }} {% endif -%} -{% if options.backup_target_type == 's3' -%} +{% if options.translated_backup_target_type == 's3' -%} # S3 vault_storage_nfs_export = TrilioVault vault_s3_auth_version = DEFAULT @@ -31,7 +31,7 @@ vault_s3_endpoint_url = {{ options.tv_s3_endpoint_url }} {% endif -%} # MISC -vault_storage_type = {{ options.backup_target_type }} +vault_storage_type = {{ options.translated_backup_target_type }} vault_data_directory_old = {{ options.tv_data_dir_old }} vault_data_directory = {{ options.tv_data_dir }} diff --git a/src/templates/tvault-object-store.conf b/src/templates/tvault-object-store.conf new file mode 100644 index 0000000..952375d --- /dev/null +++ b/src/templates/tvault-object-store.conf @@ -0,0 +1,19 @@ +[DEFAULT] +verbose = {{ options.verbose }} +debug = {{ options.debug }} +log_file = /var/log/tvault-object-store/tvault-object-store.log + +vault_storage_nfs_export = TrilioVault +vault_data_directory = /var/triliovault-mounts +vault_data_directory_old = /var/triliovault +vault_storage_type = {{ options.translated_backup_target_type }} +vault_storage_nfs_export = TrilioVault +vault_s3_auth_version = DEFAULT +vault_s3_access_key_id = {{ options.tv_s3_access_key }} +vault_s3_secret_access_key = {{ options.tv_s3_secret_key }} +vault_s3_region_name = {{ options.tv_s3_region_name }} +vault_s3_bucket = {{ options.tv_s3_bucket }} +vault_s3_endpoint_url = {{ options.tv_s3_endpoint_url }} + +[s3fuse_sys_admin] +helper_command = sudo /usr/bin/nova-rootwrap /etc/nova/rootwrap.conf privsep-helper diff --git a/src/tests/bundles/bionic-train-41-s3.yaml b/src/tests/bundles/bionic-train-41-s3.yaml new file mode 100644 index 0000000..c5f0647 --- /dev/null +++ b/src/tests/bundles/bionic-train-41-s3.yaml @@ -0,0 +1,249 @@ +local_overlay_enabled: False +variables: + openstack-origin: &openstack-origin 'cloud:bionic-train' + triliovault-pkg-source: &triliovault-pkg-source 'deb [trusted=yes] https://apt.fury.io/triliodata-4-1/ /' + +series: &series bionic + +relations: + - - 'nova-compute:amqp' + - 'rabbitmq-server:amqp' + - - 'neutron-gateway:amqp' + - 'rabbitmq-server:amqp' + - - 'neutron-gateway:amqp-nova' + - 'rabbitmq-server:amqp' + - - 'keystone:shared-db' + - 'mysql:shared-db' + - - 'cinder:identity-service' + - 'keystone:identity-service' + - - 'nova-cloud-controller:identity-service' + - 'keystone:identity-service' + - - 'glance:identity-service' + - 'keystone:identity-service' + - - 'neutron-api:identity-service' + - 'keystone:identity-service' + - - 'neutron-openvswitch:neutron-plugin-api' + - 'neutron-api:neutron-plugin-api' + - - 'cinder:shared-db' + - 'mysql:shared-db' + - - 'neutron-api:shared-db' + - 'mysql:shared-db' + - - 'cinder:amqp' + - 'rabbitmq-server:amqp' + - - 'neutron-api:amqp' + - 'rabbitmq-server:amqp' + - - 'neutron-gateway:neutron-plugin-api' + - 'neutron-api:neutron-plugin-api' + - - 'glance:shared-db' + - 'mysql:shared-db' + - - 'glance:amqp' + - 'rabbitmq-server:amqp' + - - 'nova-cloud-controller:image-service' + - 'glance:image-service' + - - 'nova-compute:image-service' + - 'glance:image-service' + - - 'nova-cloud-controller:amqp' + - 'rabbitmq-server:amqp' + - - 'nova-cloud-controller:quantum-network-service' + - 'neutron-gateway:quantum-network-service' + - - 'nova-compute:neutron-plugin' + - 'neutron-openvswitch:neutron-plugin' + - - 'neutron-openvswitch:amqp' + - 'rabbitmq-server:amqp' + - - 'nova-cloud-controller:shared-db' + - 'mysql:shared-db' + - - 'nova-cloud-controller:neutron-api' + - 'neutron-api:neutron-api' + - - 'nova-cloud-controller:cloud-compute' + - 'nova-compute:cloud-compute' + - - 'trilio-wlm:shared-db' + - 'mysql:shared-db' + - - 'trilio-wlm:amqp' + - 'rabbitmq-server:amqp' + - - 'trilio-wlm:identity-service' + - 'keystone:identity-service' + - - 'glance:ceph' + - 'ceph-mon:client' + - - 'ceph-mon:osd' + - 'ceph-osd:mon' + - - 'ceph-osd:secrets-storage' + - 'vault:secrets' + - - 'cinder:storage-backend' + - 'cinder-ceph:storage-backend' + - - 'cinder-ceph:ceph' + - 'ceph-mon:client' + - - 'cinder-ceph:ceph-access' + - 'nova-compute:ceph-access' + - - 'vault:shared-db' + - 'mysql:shared-db' + - - 'vault:certificates' + - 'keystone:certificates' + - - 'vault:certificates' + - 'neutron-api:certificates' + - - 'vault:certificates' + - 'cinder:certificates' + - - 'vault:certificates' + - 'glance:certificates' + - - 'vault:certificates' + - 'nova-cloud-controller:certificates' + - - 'placement:shared-db' + - 'mysql:shared-db' + - - 'placement:identity-service' + - 'keystone:identity-service' + - - 'placement:placement' + - 'nova-cloud-controller:placement' + - - 'vault:certificates' + - 'placement:certificates' + - - 'vault:certificates' + - 'trilio-wlm:certificates' + - - 'trilio-data-mover:amqp' + - 'rabbitmq-server:amqp' + - - 'trilio-data-mover:juju-info' + - 'nova-compute:juju-info' + - - 'trilio-dm-api:identity-service' + - 'keystone:identity-service' + - - 'trilio-dm-api:shared-db' + - 'mysql:shared-db' + - - 'trilio-dm-api:amqp' + - 'rabbitmq-server:amqp' + - - 'trilio-dm-api:certificates' + - 'vault:certificates' + - - 'trilio-horizon-plugin:dashboard-plugin' + - 'openstack-dashboard:dashboard-plugin' + - - 'openstack-dashboard:identity-service' + - 'keystone:identity-service' + - - 'trilio-data-mover:ceph' + - 'ceph-mon:client' + - - 'trilio-data-mover:shared-db' + - 'mysql:shared-db' + - - 'ceph-radosgw:mon' + - 'ceph-mon:radosgw' + - - 'ceph-radosgw:identity-service' + - 'keystone:identity-service' + - - 'ceph-radosgw:certificates' + - 'vault:certificates' +applications: + ceph-radosgw: + charm: cs:~openstack-charmers-next/ceph-radosgw + num_units: 1 + options: + source: *openstack-origin + glance: + charm: cs:~openstack-charmers-next/glance + num_units: 1 + options: + openstack-origin: *openstack-origin + cinder: + charm: cs:~openstack-charmers-next/cinder + num_units: 1 + options: + openstack-origin: *openstack-origin + block-device: "None" + glance-api-version: 2 + keystone: + charm: cs:~openstack-charmers-next/keystone + series: bionic + num_units: 1 + options: + openstack-origin: *openstack-origin + admin-password: openstack + mysql: + charm: cs:~openstack-charmers-next/percona-cluster + num_units: 1 + options: + innodb-buffer-pool-size: 256M + max-connections: 1000 + neutron-api: + charm: cs:~openstack-charmers-next/neutron-api + num_units: 1 + options: + openstack-origin: *openstack-origin + flat-network-providers: physnet1 + neutron-security-groups: true + neutron-gateway: + charm: cs:~openstack-charmers-next/neutron-gateway + num_units: 1 + options: + openstack-origin: *openstack-origin + bridge-mappings: physnet1:br-ex + neutron-openvswitch: + charm: cs:~openstack-charmers-next/neutron-openvswitch + num_units: 0 + nova-cloud-controller: + charm: cs:~openstack-charmers-next/nova-cloud-controller + num_units: 1 + options: + openstack-origin: *openstack-origin + network-manager: Neutron + debug: true + nova-compute: + charm: cs:~openstack-charmers-next/nova-compute + num_units: 3 + constraints: mem=4G + options: + openstack-origin: *openstack-origin + config-flags: default_ephemeral_format=ext4 + enable-live-migration: true + enable-resize: true + migration-auth-type: ssh + debug: true + cpu-model: kvm64 + cpu-mode: custom + # Allow for more retries when testing ontop of openstack + config-flags: block_device_allocate_retries=120 + rabbitmq-server: + charm: cs:~openstack-charmers-next/rabbitmq-server + num_units: 1 + trilio-data-mover: + charm: ../../../trilio-data-mover + options: + triliovault-pkg-source: *triliovault-pkg-source + backup-target-type: experimental-s3 + trilio-dm-api: + charm: cs:~openstack-charmers-next/trilio-dm-api + num_units: 1 + options: + openstack-origin: *openstack-origin + triliovault-pkg-source: *triliovault-pkg-source + trilio-horizon-plugin: + charm: cs:~openstack-charmers-next/trilio-horizon-plugin + options: + triliovault-pkg-source: *triliovault-pkg-source + trilio-wlm: + charm: cs:~openstack-charmers-next/trilio-wlm + num_units: 1 + options: + openstack-origin: *openstack-origin + triliovault-pkg-source: *triliovault-pkg-source + backup-target-type: experimental-s3 + ceph-mon: + charm: cs:~openstack-charmers-next/ceph-mon + num_units: 3 + options: + source: *openstack-origin + expected-osd-count: 3 + ceph-osd: + charm: cs:~openstack-charmers-next/ceph-osd + constraints: mem=1G + num_units: 3 + options: + source: *openstack-origin + osd-encrypt-keymanager: vault + osd-encrypt: True + storage: + osd-devices: cinder,40G + cinder-ceph: + charm: cs:~openstack-charmers-next/cinder-ceph + vault: + num_units: 1 + charm: cs:~openstack-charmers-next/vault + placement: + charm: cs:~openstack-charmers-next/placement + num_units: 1 + options: + openstack-origin: *openstack-origin + openstack-dashboard: + charm: cs:~openstack-charmers-next/openstack-dashboard + num_units: 1 + options: + openstack-origin: *openstack-origin diff --git a/src/tests/tests.yaml b/src/tests/tests.yaml index 0505eaf..6b4e1b9 100644 --- a/src/tests/tests.yaml +++ b/src/tests/tests.yaml @@ -1,15 +1,26 @@ charm_name: trilio-data-mover tests: - - zaza.openstack.charm_tests.trilio.tests.TrilioDataMoverTest + - zaza.openstack.charm_tests.trilio.tests.TrilioDataMoverNFSTest + - s3: + - zaza.openstack.charm_tests.trilio.tests.TrilioDataMoverS3Test configure: - - zaza.openstack.charm_tests.trilio.setup.basic_setup + - s3: + - zaza.openstack.charm_tests.vault.setup.auto_initialize + - zaza.openstack.charm_tests.trilio.setup.basic_setup + - zaza.openstack.charm_tests.glance.setup.add_cirros_image + - zaza.openstack.charm_tests.glance.setup.add_lts_image + - zaza.openstack.charm_tests.neutron.setup.basic_overcloud_network + - zaza.openstack.charm_tests.nova.setup.create_flavors + - zaza.openstack.charm_tests.nova.setup.manage_ssh_key - zaza.openstack.charm_tests.vault.setup.auto_initialize + - zaza.openstack.charm_tests.trilio.setup.basic_setup - zaza.openstack.charm_tests.glance.setup.add_cirros_image - zaza.openstack.charm_tests.glance.setup.add_lts_image - zaza.openstack.charm_tests.neutron.setup.basic_overcloud_network - zaza.openstack.charm_tests.nova.setup.create_flavors - zaza.openstack.charm_tests.nova.setup.manage_ssh_key gate_bundles: + - s3: bionic-train-41-s3 - bionic-stein-40 - bionic-stein-41 - bionic-train-40 @@ -35,10 +46,13 @@ target_deploy_status: workload-status-message: "Ceph broker request incomplete" trilio-wlm: workload-status: blocked - workload-status-message: "nfs-shares configuration not set" + workload-status-message-regex: "configuration not set|Unit is ready" trilio-data-mover: workload-status: blocked - workload-status-message: "nfs-shares configuration not set" + workload-status-message-regex: "configuration not set|Unit is ready" glance: workload-status: waiting workload-status-message: "Incomplete relations: storage-backend" + ceph-radosgw: + workload-status: waiting + workload-status-message: "Incomplete relations: mon" diff --git a/unit_tests/test_lib_charm_openstack_trilio_dm.py b/unit_tests/test_lib_charm_openstack_trilio_dm.py index d57a580..337c259 100644 --- a/unit_tests/test_lib_charm_openstack_trilio_dm.py +++ b/unit_tests/test_lib_charm_openstack_trilio_dm.py @@ -39,7 +39,7 @@ class TestTrilioDataMoverRockyCharms(Helper): def test_services_s3(self): dm_charm = trilio_dm.TrilioDataMoverRockyCharm() self.patch_object(trilio_dm.hookenv, "config") - self.config.return_value = "s3" + self.config.return_value = "experimental-s3" self.assertEqual( dm_charm.services, ["tvault-contego", "tvault-object-store"] )