From 7bbd49b4dd1e7666dd9a466cbdcc7b6d9aac5bc0 Mon Sep 17 00:00:00 2001 From: Mingyuan Qi Date: Sat, 2 Feb 2019 17:05:01 +0800 Subject: [PATCH 1/5] Pulling application image from specified registry Registries where application images pulled from during application-apply are replaced if alternative registries are set. The images are pulled from user specified registry and tagged to local image tag. Local image tag will not be changed comparing to using default registry. As a result, images pushed to local registry (192.168.204.2) are still available as cache whatever alternative registries are set or not. Test: AIO-SX/AIO-DX/Standard 2+2: Private registry without proxy - application-apply pass Default registry with/without proxy - application-apply pass Story: 2004711 Task: 29212 Change-Id: I0cc110601e78c6adb3c6f2b747dfb6c92a0c82fd Signed-off-by: Mingyuan Qi --- .../sysinv/sysinv/conductor/kube_app.py | 89 +++++++++++++++++-- 1 file changed, 83 insertions(+), 6 deletions(-) diff --git a/sysinv/sysinv/sysinv/sysinv/conductor/kube_app.py b/sysinv/sysinv/sysinv/sysinv/conductor/kube_app.py index 9c5d7e2ea9..41c3b9b961 100644 --- a/sysinv/sysinv/sysinv/sysinv/conductor/kube_app.py +++ b/sysinv/sysinv/sysinv/sysinv/conductor/kube_app.py @@ -1183,6 +1183,37 @@ class DockerHelper(object): def __init__(self, dbapi): self._dbapi = dbapi + self.k8s_registry = None + self.gcr_registry = None + self.quay_registry = None + self.docker_registry = None + + def _get_registry_parameters(self): + try: + registry = self._dbapi.service_parameter_get_all( + service=constants.SERVICE_TYPE_DOCKER, + section=constants.SERVICE_PARAM_SECTION_DOCKER_REGISTRY, + ) + return registry + except Exception: + return None + + def _retrieve_specified_registries(self): + registry_params = self._get_registry_parameters() + if registry_params: + for param in registry_params: + if param.name == \ + constants.SERVICE_PARAM_NAME_DOCKER_K8S_REGISTRY: + self.k8s_registry = str(param.value) + if param.name == \ + constants.SERVICE_PARAM_NAME_DOCKER_GCR_REGISTRY: + self.gcr_registry = str(param.value) + if param.name == \ + constants.SERVICE_PARAM_NAME_DOCKER_QUAY_REGISTRY: + self.quay_registry = str(param.value) + if param.name == \ + constants.SERVICE_PARAM_NAME_DOCKER_DOCKER_REGISTRY: + self.docker_registry = str(param.value) def _start_armada_service(self, client): try: @@ -1317,9 +1348,50 @@ class DockerHelper(object): registry_server = '{}:{}'.format(registry_ip, common.REGISTRY_PORT) return registry_server + def _get_img_tag_with_registry(self, pub_img_tag): + registry_name = pub_img_tag[0:1 + pub_img_tag.find('/')] + img_name = pub_img_tag[1 + pub_img_tag.find('/'):] + if registry_name: + if 'k8s.gcr.io' in registry_name: + registry = self.k8s_registry + elif 'gcr.io' in registry_name: + registry = self.gcr_registry + elif 'quay.io' in registry_name: + registry = self.quay_registry + elif 'docker.io' in registry_name: + registry = self.docker_registry + else: + # try docker.io registry as default + # if other registries newly added + # or docker.io repository detected + LOG.info("Registry %s not recognized or docker.io repository " + "detected. Pulling from public/private registry" + % registry_name) + registry = self.docker_registry + if registry: + return str(registry) + '/' + pub_img_tag + else: + return pub_img_tag + + # replace registry + if registry: + return str(registry) + '/' + img_name + else: + return pub_img_tag + else: + # docker.io registry as default + # if no registries specified in img tag + registry = self.docker_registry + if registry: + return str(registry) + '/' + pub_img_tag + else: + return pub_img_tag + def download_an_image(self, img_tag): rc = True + # retrieve user specified registries first + self._retrieve_specified_registries() local_registry_server = self.get_local_docker_registry_server() start = time.time() @@ -1333,17 +1405,20 @@ class DockerHelper(object): try: # Pull the image from the public registry LOG.info("Image %s is not available in local registry, " - "download started from public registry" % img_tag) + "download started from public/private registry" + % img_tag) pub_img_tag = img_tag.replace(local_registry_server + "/", "") - client.pull(pub_img_tag) + target_img_tag = self._get_img_tag_with_registry(pub_img_tag) + client.pull(target_img_tag) except Exception as e: rc = False - LOG.error("Image %s download failed from public registry: %s" % (pub_img_tag, e)) + LOG.error("Image %s download failed from public/private" + "registry: %s" % (target_img_tag, e)) return img_tag, rc try: # Tag and push the image to the local registry - client.tag(pub_img_tag, img_tag) + client.tag(target_img_tag, img_tag) client.push(img_tag, auth_config=local_registry_auth) except Exception as e: rc = False @@ -1354,9 +1429,11 @@ class DockerHelper(object): else: try: - LOG.info("Image %s download started from public registry" % img_tag) + LOG.info("Image %s download started from public/private registry" % img_tag) client = docker.APIClient(timeout=INSTALLATION_TIMEOUT) - client.pull(img_tag) + target_img_tag = self._get_img_tag_with_registry(img_tag) + client.pull(target_img_tag) + client.tag(target_img_tag, img_tag) except Exception as e: rc = False LOG.error("Image %s download failed from public registry: %s" % (img_tag, e)) From 99e86fc151d326f4c26f9005d8cf84028078261c Mon Sep 17 00:00:00 2001 From: Kristine Bujold Date: Fri, 15 Feb 2019 15:35:40 -0500 Subject: [PATCH 2/5] Move heat static configs to Armada manifest Move all heat static configurations from the overrides to the Armada manifest. This is being done so we have a consistent way of managing containerized openstack configurations. Static configurations will be located in the Armada manifest and dynamic configuration will be located in the overrides files. Story: 2003909 Task: 29455 Change-Id: Ie35b1696b9fce0458db724fc8163d5d181e0768a Signed-off-by: Kristine Bujold --- .../stx-openstack-helm/centos/build_srpm.data | 2 +- .../stx-openstack-helm/manifests/manifest-no-tests.yaml | 4 ++++ .../stx-openstack-helm/manifests/manifest.yaml | 4 ++++ sysinv/sysinv/centos/build_srpm.data | 2 +- sysinv/sysinv/sysinv/sysinv/helm/heat.py | 7 +------ 5 files changed, 11 insertions(+), 8 deletions(-) diff --git a/kubernetes/applications/stx-openstack/stx-openstack-helm/centos/build_srpm.data b/kubernetes/applications/stx-openstack/stx-openstack-helm/centos/build_srpm.data index 7037828a98..074c38202e 100644 --- a/kubernetes/applications/stx-openstack/stx-openstack-helm/centos/build_srpm.data +++ b/kubernetes/applications/stx-openstack/stx-openstack-helm/centos/build_srpm.data @@ -1,3 +1,3 @@ SRC_DIR="stx-openstack-helm" COPY_LIST_TO_TAR="$PKG_BASE/../../../helm-charts/rbd-provisioner $PKG_BASE/../../../helm-charts/garbd" -TIS_PATCH_VER=4 +TIS_PATCH_VER=5 diff --git a/kubernetes/applications/stx-openstack/stx-openstack-helm/stx-openstack-helm/manifests/manifest-no-tests.yaml b/kubernetes/applications/stx-openstack/stx-openstack-helm/stx-openstack-helm/manifests/manifest-no-tests.yaml index 784efab68b..58d744324f 100644 --- a/kubernetes/applications/stx-openstack/stx-openstack-helm/stx-openstack-helm/manifests/manifest-no-tests.yaml +++ b/kubernetes/applications/stx-openstack/stx-openstack-helm/stx-openstack-helm/manifests/manifest-no-tests.yaml @@ -927,6 +927,10 @@ data: release_group: osh-openstack-heat component: test values: + endpoints: + oslo_cache: + hosts: + default: heat-memcached labels: api: node_selector_key: openstack-control-plane diff --git a/kubernetes/applications/stx-openstack/stx-openstack-helm/stx-openstack-helm/manifests/manifest.yaml b/kubernetes/applications/stx-openstack/stx-openstack-helm/stx-openstack-helm/manifests/manifest.yaml index 8f3f47eab8..48852f9f85 100644 --- a/kubernetes/applications/stx-openstack/stx-openstack-helm/stx-openstack-helm/manifests/manifest.yaml +++ b/kubernetes/applications/stx-openstack/stx-openstack-helm/stx-openstack-helm/manifests/manifest.yaml @@ -927,6 +927,10 @@ data: release_group: osh-openstack-heat component: test values: + endpoints: + oslo_cache: + hosts: + default: heat-memcached labels: api: node_selector_key: openstack-control-plane diff --git a/sysinv/sysinv/centos/build_srpm.data b/sysinv/sysinv/centos/build_srpm.data index be4508a9e5..97482ad914 100644 --- a/sysinv/sysinv/centos/build_srpm.data +++ b/sysinv/sysinv/centos/build_srpm.data @@ -1,2 +1,2 @@ SRC_DIR="sysinv" -TIS_PATCH_VER=303 +TIS_PATCH_VER=304 diff --git a/sysinv/sysinv/sysinv/sysinv/helm/heat.py b/sysinv/sysinv/sysinv/sysinv/helm/heat.py index 8a5af46f7a..d988b88b60 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/heat.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/heat.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2018 Wind River Systems, Inc. +# Copyright (c) 2018-2019 Wind River Systems, Inc. # # SPDX-License-Identifier: Apache-2.0 # @@ -73,11 +73,6 @@ class HeatHelm(openstack.OpenstackBaseHelm): 'auth': self._get_endpoints_identity_overrides( self.SERVICE_NAME, self.AUTH_USERS), }, - 'oslo_cache': { - 'hosts': { - 'default': 'heat-memcached' - } - }, 'oslo_db': { 'auth': self._get_endpoints_oslo_db_overrides( self.SERVICE_NAME, [self.SERVICE_NAME]) From 0ce137a99a5fe04490dc23d2574beb6b1adbf343 Mon Sep 17 00:00:00 2001 From: Kristine Bujold Date: Mon, 18 Feb 2019 12:56:25 -0500 Subject: [PATCH 3/5] Move gnocchi and ceilometer static configs Move all gnocchi and ceilometer static configurations from the overrides to the Armada manifest. This is being done so we have a consistent way of managing containerized openstack configurations. Static configurations will be located in the Armada manifest and dynamic configuration will be located in the overrides files. Story: 2003909 Task: 29535 Change-Id: Ieab861cb1751146b70f722e70b8f89d81c0ed9a5 Signed-off-by: Kristine Bujold --- .../stx-openstack-helm/centos/build_srpm.data | 2 +- .../manifests/manifest-no-tests.yaml | 41 +++++++++++++ .../manifests/manifest.yaml | 41 +++++++++++++ sysinv/sysinv/centos/build_srpm.data | 2 +- .../sysinv/sysinv/sysinv/helm/ceilometer.py | 11 +--- sysinv/sysinv/sysinv/sysinv/helm/gnocchi.py | 57 +------------------ 6 files changed, 88 insertions(+), 66 deletions(-) diff --git a/kubernetes/applications/stx-openstack/stx-openstack-helm/centos/build_srpm.data b/kubernetes/applications/stx-openstack/stx-openstack-helm/centos/build_srpm.data index 7037828a98..074c38202e 100644 --- a/kubernetes/applications/stx-openstack/stx-openstack-helm/centos/build_srpm.data +++ b/kubernetes/applications/stx-openstack/stx-openstack-helm/centos/build_srpm.data @@ -1,3 +1,3 @@ SRC_DIR="stx-openstack-helm" COPY_LIST_TO_TAR="$PKG_BASE/../../../helm-charts/rbd-provisioner $PKG_BASE/../../../helm-charts/garbd" -TIS_PATCH_VER=4 +TIS_PATCH_VER=5 diff --git a/kubernetes/applications/stx-openstack/stx-openstack-helm/stx-openstack-helm/manifests/manifest-no-tests.yaml b/kubernetes/applications/stx-openstack/stx-openstack-helm/stx-openstack-helm/manifests/manifest-no-tests.yaml index 784efab68b..f6c4ed34f7 100644 --- a/kubernetes/applications/stx-openstack/stx-openstack-helm/stx-openstack-helm/manifests/manifest-no-tests.yaml +++ b/kubernetes/applications/stx-openstack/stx-openstack-helm/stx-openstack-helm/manifests/manifest-no-tests.yaml @@ -1102,6 +1102,45 @@ data: anti: type: default: requiredDuringSchedulingIgnoredDuringExecution + gnocchi: + indexer: + driver: mariadb + keystone_authtoken: + interface: internal + dependencies: + static: + db_sync: + jobs: + - gnocchi-storage-init + - gnocchi-db-init + services: + - endpoint: internal + service: oslo_db + metricd: + services: + - endpoint: internal + service: oslo_db + - endpoint: internal + service: oslo_cache + - endpoint: internal + service: metric + tests: + services: + - endpoint: internal + service: identity + - endpoint: internal + service: oslo_db + - endpoint: internal + service: metric + manifests: + daemonset_statsd: false + job_db_init_indexer: false + secret_db_indexer: false + service_statsd: false + endpoints: + oslo_cache: + hosts: + default: memcached source: type: tar location: http://172.17.0.1/helm_charts/gnocchi-0.1.0.tgz @@ -1265,6 +1304,8 @@ data: oslo_messaging_notifications: topics: - notifications + notification: + batch_size: 100 pipeline: sources: - name: meter_source diff --git a/kubernetes/applications/stx-openstack/stx-openstack-helm/stx-openstack-helm/manifests/manifest.yaml b/kubernetes/applications/stx-openstack/stx-openstack-helm/stx-openstack-helm/manifests/manifest.yaml index 8f3f47eab8..de996f660b 100644 --- a/kubernetes/applications/stx-openstack/stx-openstack-helm/stx-openstack-helm/manifests/manifest.yaml +++ b/kubernetes/applications/stx-openstack/stx-openstack-helm/stx-openstack-helm/manifests/manifest.yaml @@ -1102,6 +1102,45 @@ data: anti: type: default: requiredDuringSchedulingIgnoredDuringExecution + gnocchi: + indexer: + driver: mariadb + keystone_authtoken: + interface: internal + dependencies: + static: + db_sync: + jobs: + - gnocchi-storage-init + - gnocchi-db-init + services: + - endpoint: internal + service: oslo_db + metricd: + services: + - endpoint: internal + service: oslo_db + - endpoint: internal + service: oslo_cache + - endpoint: internal + service: metric + tests: + services: + - endpoint: internal + service: identity + - endpoint: internal + service: oslo_db + - endpoint: internal + service: metric + manifests: + daemonset_statsd: false + job_db_init_indexer: false + secret_db_indexer: false + service_statsd: false + endpoints: + oslo_cache: + hosts: + default: memcached source: type: tar location: http://172.17.0.1/helm_charts/gnocchi-0.1.0.tgz @@ -1265,6 +1304,8 @@ data: oslo_messaging_notifications: topics: - notifications + notification: + batch_size: 100 pipeline: sources: - name: meter_source diff --git a/sysinv/sysinv/centos/build_srpm.data b/sysinv/sysinv/centos/build_srpm.data index be4508a9e5..97482ad914 100644 --- a/sysinv/sysinv/centos/build_srpm.data +++ b/sysinv/sysinv/centos/build_srpm.data @@ -1,2 +1,2 @@ SRC_DIR="sysinv" -TIS_PATCH_VER=303 +TIS_PATCH_VER=304 diff --git a/sysinv/sysinv/sysinv/sysinv/helm/ceilometer.py b/sysinv/sysinv/sysinv/sysinv/helm/ceilometer.py index e1defe82dc..a29b2b906f 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/ceilometer.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/ceilometer.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2018 Wind River Systems, Inc. +# Copyright (c) 2018-2019 Wind River Systems, Inc. # # SPDX-License-Identifier: Apache-2.0 # @@ -112,19 +112,14 @@ class CeilometerHelm(openstack.OpenstackBaseHelm): return shared_services_types def _get_conf_ceilometer_notification_overrides(self): - notification_overrides = { - 'batch_size': 100 - } - system = self._get_system() if system.system_type == constants.TIS_AIO_BUILD: batch_timeout = 25 else: batch_timeout = 5 - notification_overrides.update( - {'batch_timeout': batch_timeout, - 'messaging_urls': {'values': self._get_notification_messaging_urls()}}) + notification_overrides = {'batch_timeout': batch_timeout, + 'messaging_urls': {'values': self._get_notification_messaging_urls()}} return notification_overrides def _get_notification_messaging_urls(self): diff --git a/sysinv/sysinv/sysinv/sysinv/helm/gnocchi.py b/sysinv/sysinv/sysinv/sysinv/helm/gnocchi.py index 4d08caa3c8..9595b19faf 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/gnocchi.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/gnocchi.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2018 Wind River Systems, Inc. +# Copyright (c) 2018-2019 Wind River Systems, Inc. # # SPDX-License-Identifier: Apache-2.0 # @@ -26,11 +26,6 @@ class GnocchiHelm(openstack.OpenstackBaseHelm): common.HELM_NS_OPENSTACK: { 'images': self._get_images_overrides(), 'pod': self._get_pod_overrides(), - 'conf': self._get_conf_overrides(), - 'dependencies': { - 'static': self._get_static_dependencies_overrides() - }, - 'manifests': self._get_manifests_overrides(), 'endpoints': self._get_endpoints_overrides(), } } @@ -68,53 +63,6 @@ class GnocchiHelm(openstack.OpenstackBaseHelm): } } - def _get_static_dependencies_overrides(self): - return { - 'db_sync': { - 'jobs': [ - 'gnocchi-storage-init', - 'gnocchi-db-init', - ], - 'services': [ - {'endpoint': 'internal', 'service': 'oslo_db'} - ] - }, - 'metricd': { - 'services': [ - {'endpoint': 'internal', 'service': 'oslo_db'}, - {'endpoint': 'internal', 'service': 'oslo_cache'}, - {'endpoint': 'internal', 'service': 'metric'} - ] - }, - 'tests': { - 'services': [ - {'endpoint': 'internal', 'service': 'identity'}, - {'endpoint': 'internal', 'service': 'oslo_db'}, - {'endpoint': 'internal', 'service': 'metric'} - ] - } - } - - def _get_manifests_overrides(self): - return { - 'daemonset_statsd': False, - 'service_statsd': False, - 'job_db_init_indexer': False, - 'secret_db_indexer': False, - } - - def _get_conf_overrides(self): - return { - 'gnocchi': { - 'indexer': { - 'driver': 'mariadb' - }, - 'keystone_authtoken': { - 'interface': 'internal' - } - } - } - def _get_endpoints_overrides(self): return { 'identity': { @@ -125,9 +73,6 @@ class GnocchiHelm(openstack.OpenstackBaseHelm): 'auth': { 'memcached_secret_key': self._get_common_password('auth_memcache_key') - }, - 'hosts': { - 'default': 'memcached' } }, 'oslo_db': { From 53b9e4661561c85aabe802d098e79c1c099e6bec Mon Sep 17 00:00:00 2001 From: SidneyAn Date: Mon, 18 Feb 2019 22:03:57 +0800 Subject: [PATCH 4/5] retry func iconfig_update_file when host personality is None when we run "system dns-modify" command, the command will response after sysinv-db was updated, and file "/etc/resolv.conf" will be updated asynchronously by another process "sysinv-agent". Once the attr "_ihost_personality" of agent is None(initial value), it will not update file "/etc/resolv.conf" and will not inform sysinv client also, which will lead command dns-modify failed silently. This patch will retry function iconfig_update_file by which sysinv-agent update file "/etc/resolv.conf" when attr "_ihost_personality" is None. Closes-bug: 1812269 Change-Id: I3a0437750a53607c04932c1b9b818e83903bb28b Signed-off-by: SidneyAn --- sysinv/sysinv/sysinv/sysinv/agent/manager.py | 11 +++++++++++ sysinv/sysinv/sysinv/sysinv/common/exception.py | 6 ++++++ 2 files changed, 17 insertions(+) diff --git a/sysinv/sysinv/sysinv/sysinv/agent/manager.py b/sysinv/sysinv/sysinv/sysinv/agent/manager.py index 6ee010f05c..08f1d6b640 100644 --- a/sysinv/sysinv/sysinv/sysinv/agent/manager.py +++ b/sysinv/sysinv/sysinv/sysinv/agent/manager.py @@ -1291,6 +1291,12 @@ class AgentManager(service.PeriodicService): fileinput.close() os.rename(temp_platform_conf_file, tsc.PLATFORM_CONF_FILE) + def _retry_on_personality_is_none(ex): + LOG.info('Caught exception. Retrying... Exception: {}'.format(ex)) + return isinstance(ex, exception.LocalManagementPersonalityNotFound) + + @retrying.retry(wait_fixed=10 * 1000, stop_max_delay=300 * 1000, + retry_on_exception=_retry_on_personality_is_none) @utils.synchronized(LOCK_AGENT_ACTION, external=False) def iconfig_update_file(self, context, iconfig_uuid, iconfig_dict): """Configure the iiconfig_uuid, by updating file based upon @@ -1314,6 +1320,11 @@ class AgentManager(service.PeriodicService): if not permissions: permissions = constants.CONFIG_FILE_PERMISSION_DEFAULT + if not self._ihost_personality: + raise exception.LocalManagementPersonalityNotFound( + config_uuid=iconfig_uuid, config_dict=iconfig_dict, + host_personality=self._ihost_personality) + if self._ihost_personality in iconfig_dict['personalities']: file_content = iconfig_dict['file_content'] diff --git a/sysinv/sysinv/sysinv/sysinv/common/exception.py b/sysinv/sysinv/sysinv/sysinv/common/exception.py index 3b96cb78b6..dd9f0d4527 100644 --- a/sysinv/sysinv/sysinv/sysinv/common/exception.py +++ b/sysinv/sysinv/sysinv/sysinv/common/exception.py @@ -1298,6 +1298,12 @@ class InvalidHelmNamespace(Invalid): message = _("Invalid helm overrides namespace (%(namespace)s) for chart %(chart)s.") +class LocalManagementPersonalityNotFound(NotFound): + message = _("Local management personality is None: " + "config_uuid=%(config_uuid)s, config_dict=%(config_dict)s, " + "host_personality=%(host_personality)s") + + class LocalManagementIpNotFound(NotFound): message = _("Local management IP not found: " "config_uuid=%(config_uuid)s, config_dict=%(config_dict)s, " From 28766a8d43f579fb027f4152c3f6586418e1eb9d Mon Sep 17 00:00:00 2001 From: Irina Mihai Date: Wed, 20 Feb 2019 21:11:56 +0000 Subject: [PATCH 5/5] Prevent download and creation of default Cirros glance image - downloading the Cirros image fails in glance-bootstrap if the hardcoded requested image is not found - to workaround this issue, we disable the download and creation of the Cirros image in glance-bootstrap through the overrides -> this has no other impact as the image can be created after the chart's installation using "openstack image create" Change-Id: I418eb236f5eceb0124eb73787fe12e2f0aa2d9e1 Closes-Bug: 1814142 Signed-off-by: Irina Mihai --- sysinv/sysinv/sysinv/sysinv/helm/glance.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sysinv/sysinv/sysinv/sysinv/helm/glance.py b/sysinv/sysinv/sysinv/sysinv/helm/glance.py index 737d8e63b7..b3fc0d4392 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/glance.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/glance.py @@ -36,6 +36,7 @@ class GlanceHelm(openstack.OpenstackBaseHelm): 'storage': self._get_storage_overrides(), 'conf': self._get_conf_overrides(), 'images': self._get_images_overrides(), + 'bootstrap': self._get_bootstrap_overrides() } } @@ -161,6 +162,15 @@ class GlanceHelm(openstack.OpenstackBaseHelm): return conf + def _get_bootstrap_overrides(self): + # By default, prevent the download and creation of the Cirros image. + # TODO: Remove if/when pulling from external registries is supported. + bootstrap = { + 'enabled': False + } + + return bootstrap + def _get_primary_ceph_backend(self): try: backend = self.dbapi.storage_backend_get_by_name(