Merge branch 'master' into lourot/bug/1877076

This commit is contained in:
Aurelien Lourot
2020-11-05 11:31:52 +01:00
15 changed files with 491 additions and 53 deletions
+1
View File
@@ -29,6 +29,7 @@ python-ceilometerclient
python-cinderclient
python-glanceclient
python-heatclient
python-ironicclient
python-keystoneclient
python-manilaclient
python-neutronclient
+1
View File
@@ -44,6 +44,7 @@ install_require = [
'python-barbicanclient>=4.0.1,<5.0.0',
'python-designateclient>=1.5,<3.0.0',
'python-heatclient<2.0.0',
'python-ironicclient',
'python-glanceclient<3.0.0',
'python-keystoneclient<3.22.0',
'python-manilaclient<2.0.0',
+2 -2
View File
@@ -42,7 +42,7 @@ class TestTempestSetup(unittest.TestCase):
'TEST_GATEWAY': 'test',
'TEST_CIDR_EXT': 'test',
'TEST_FIP_RANGE': 'test',
'TEST_NAMESERVER': 'test',
'TEST_NAME_SERVER': 'test',
'TEST_CIDR_PRIV': 'test',
}
tempest_setup.add_environment_var_config(ctxt, ['neutron'])
@@ -55,7 +55,7 @@ class TestTempestSetup(unittest.TestCase):
ctxt = {}
get_deployment_context.return_value = {
'TEST_GATEWAY': 'test',
'TEST_NAMESERVER': 'test',
'TEST_NAME_SERVER': 'test',
'TEST_CIDR_PRIV': 'test',
}
with self.assertRaises(Exception) as context:
@@ -504,7 +504,7 @@ class TestOpenStackUtils(ut_utils.BaseTestCase):
glance_mock.images.upload.assert_called_once_with(
'9d1125af',
f(),
)
backend=None)
self.resource_reaches_status.assert_called_once_with(
glance_mock.images,
'9d1125af',
@@ -529,7 +529,11 @@ class TestOpenStackUtils(ut_utils.BaseTestCase):
self.upload_image_to_glance.assert_called_once_with(
glance_mock,
'wibbly/c.img',
'bob')
'bob',
backend=None,
disk_format='qcow2',
visibility='public',
container_format='bare')
def test_create_image_pass_directory(self):
glance_mock = mock.MagicMock()
@@ -549,7 +553,11 @@ class TestOpenStackUtils(ut_utils.BaseTestCase):
self.upload_image_to_glance.assert_called_once_with(
glance_mock,
'tests/c.img',
'bob')
'bob',
backend=None,
disk_format='qcow2',
visibility='public',
container_format='bare')
self.gettempdir.assert_not_called()
def test_create_ssh_key(self):
+43 -6
View File
@@ -32,8 +32,37 @@ def basic_setup():
"""
def _get_default_glance_client():
"""Create default Glance client using overcloud credentials."""
keystone_session = openstack_utils.get_overcloud_keystone_session()
glance_client = openstack_utils.get_glance_session_client(keystone_session)
return glance_client
def get_stores_info(glance_client=None):
"""Retrieve glance backing store info.
:param glance_client: Authenticated glanceclient
:type glance_client: glanceclient.Client
"""
glance_client = glance_client or _get_default_glance_client()
stores = glance_client.images.get_stores_info().get("stores", [])
return stores
def get_store_ids(glance_client=None):
"""Retrieve glance backing store ids.
:param glance_client: Authenticated glanceclient
:type glance_client: glanceclient.Client
"""
stores = get_stores_info(glance_client)
return [store["id"] for store in stores]
def add_image(image_url, glance_client=None, image_name=None, tags=[],
properties=None):
properties=None, backend=None, disk_format='qcow2',
visibility='public', container_format='bare'):
"""Retrieve image from ``image_url`` and add it to glance.
:param image_url: Retrievable URL with image data
@@ -47,10 +76,14 @@ def add_image(image_url, glance_client=None, image_name=None, tags=[],
:param properties: Properties to add to image
:type properties: dict
"""
if not glance_client:
keystone_session = openstack_utils.get_overcloud_keystone_session()
glance_client = openstack_utils.get_glance_session_client(
keystone_session)
glance_client = glance_client or _get_default_glance_client()
if backend is not None:
stores = get_store_ids(glance_client)
if backend not in stores:
raise ValueError("Invalid backend: %(backend)s "
"(available: %(available)s)" % {
"backend": backend,
"available": ", ".join(stores)})
if image_name:
image = openstack_utils.get_images_by_name(
glance_client, image_name)
@@ -65,7 +98,11 @@ def add_image(image_url, glance_client=None, image_name=None, tags=[],
image_url,
image_name,
tags=tags,
properties=properties)
properties=properties,
backend=backend,
disk_format=disk_format,
visibility=visibility,
container_format=container_format)
def add_cirros_image(glance_client=None, image_name=None):
@@ -0,0 +1,15 @@
# Copyright 2020 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.
"""Collection of code for setting up and testing ironic."""
+184
View File
@@ -0,0 +1,184 @@
# Copyright 2020 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.
"""Code for configuring ironic."""
import copy
import os
import tenacity
import zaza.openstack.charm_tests.glance.setup as glance_setup
import zaza.openstack.utilities.openstack as openstack_utils
from zaza.openstack.utilities import (
cli as cli_utils,
)
import zaza.model as zaza_model
FLAVORS = {
'bm1.small': {
'flavorid': 2,
'ram': 2048,
'disk': 20,
'vcpus': 1,
'properties': {
"resources:CUSTOM_BAREMETAL1_SMALL": 1,
},
},
'bm1.medium': {
'flavorid': 3,
'ram': 4096,
'disk': 40,
'vcpus': 2,
'properties': {
"resources:CUSTOM_BAREMETAL1_MEDIUM": 1,
},
},
'bm1.large': {
'flavorid': 4,
'ram': 8192,
'disk': 40,
'vcpus': 4,
'properties': {
"resources:CUSTOM_BAREMETAL1_LARGE": 1,
},
},
'bm1.tempest': {
'flavorid': 6,
'ram': 256,
'disk': 1,
'vcpus': 1,
'properties': {
"resources:CUSTOM_BAREMETAL1_TEMPEST": 1,
},
},
'bm2.tempest': {
'flavorid': 7,
'ram': 512,
'disk': 1,
'vcpus': 1,
'properties': {
"resources:CUSTOM_BAREMETAL2_TEMPEST": 1,
},
},
}
def _add_image(url, image_name, backend="swift",
disk_format="raw", container_format="bare"):
for attempt in tenacity.Retrying(
stop=tenacity.stop_after_attempt(3),
reraise=True):
with attempt:
glance_setup.add_image(
url,
image_name=image_name,
backend=backend,
disk_format=disk_format,
container_format=container_format)
def add_ironic_deployment_image(initrd_url=None, kernel_url=None):
"""Add Ironic deploy images to glance.
:param initrd_url: URL where the ari image resides
:type initrd_url: str
:param kernel_url: URL where the aki image resides
:type kernel_url: str
"""
base_name = 'ironic-deploy'
initrd_name = "{}-initrd".format(base_name)
vmlinuz_name = "{}-vmlinuz".format(base_name)
if not initrd_url:
initrd_url = os.environ.get('TEST_IRONIC_DEPLOY_INITRD', None)
if not kernel_url:
kernel_url = os.environ.get('TEST_IRONIC_DEPLOY_VMLINUZ', None)
if not all([initrd_url, kernel_url]):
raise ValueError("Missing required deployment image URLs")
_add_image(
initrd_url,
initrd_name,
backend="swift",
disk_format="ari",
container_format="ari")
_add_image(
kernel_url,
vmlinuz_name,
backend="swift",
disk_format="aki",
container_format="aki")
def add_ironic_os_image(image_url=None):
"""Upload the operating system images built for bare metal deployments.
:param image_url: URL where the image resides
:type image_url: str
"""
image_url = image_url or os.environ.get(
'TEST_IRONIC_RAW_BM_IMAGE', None)
image_name = "baremetal-ubuntu-image"
if image_url is None:
raise ValueError("Missing image_url")
_add_image(
image_url,
image_name,
backend="swift",
disk_format="raw",
container_format="bare")
def set_temp_url_secret():
"""Run the set-temp-url-secret on the ironic-conductor leader.
This is needed if direct boot method is enabled.
"""
zaza_model.run_action_on_leader(
'ironic-conductor',
'set-temp-url-secret',
action_params={})
def create_bm_flavors(nova_client=None):
"""Create baremetal flavors.
:param nova_client: Authenticated nova client
:type nova_client: novaclient.v2.client.Client
"""
if not nova_client:
keystone_session = openstack_utils.get_overcloud_keystone_session()
nova_client = openstack_utils.get_nova_session_client(
keystone_session)
cli_utils.setup_logging()
names = [flavor.name for flavor in nova_client.flavors.list()]
# Disable scheduling based on standard flavor properties
default_properties = {
"resources:VCPU": 0,
"resources:MEMORY_MB": 0,
"resources:DISK_GB": 0,
}
for flavor in FLAVORS.keys():
if flavor not in names:
properties = copy.deepcopy(default_properties)
properties.update(FLAVORS[flavor]["properties"])
bm_flavor = nova_client.flavors.create(
name=flavor,
ram=FLAVORS[flavor]['ram'],
vcpus=FLAVORS[flavor]['vcpus'],
disk=FLAVORS[flavor]['disk'],
flavorid=FLAVORS[flavor]['flavorid'])
bm_flavor.set_keys(properties)
@@ -0,0 +1,83 @@
# Copyright 2020 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.
"""Encapsulate ironic testing."""
import logging
import ironicclient.client as ironic_client
import zaza.openstack.charm_tests.test_utils as test_utils
import zaza.openstack.utilities.openstack as openstack_utils
def _get_ironic_client(ironic_api_version="1.58"):
keystone_session = openstack_utils.get_overcloud_keystone_session()
ironic = ironic_client.Client(1, session=keystone_session,
os_ironic_api_version=ironic_api_version)
return ironic
class IronicTest(test_utils.OpenStackBaseTest):
"""Run Ironic specific tests."""
_SERVICES = ['ironic-api']
def test_110_catalog_endpoints(self):
"""Verify that the endpoints are present in the catalog."""
overcloud_auth = openstack_utils.get_overcloud_auth()
keystone_client = openstack_utils.get_keystone_client(
overcloud_auth)
actual_endpoints = keystone_client.service_catalog.get_endpoints()
actual_interfaces = [endpoint['interface'] for endpoint in
actual_endpoints["baremetal"]]
for expected_interface in ('internal', 'admin', 'public'):
assert(expected_interface in actual_interfaces)
def test_400_api_connection(self):
"""Simple api calls to check service is up and responding."""
ironic = _get_ironic_client()
logging.info('listing conductors')
conductors = ironic.conductor.list()
assert(len(conductors) > 0)
# By default, only IPMI HW type is enabled. iDrac and Redfish
# can optionally be enabled
drivers = ironic.driver.list()
driver_names = [drv.name for drv in drivers]
expected = ['intel-ipmi', 'ipmi']
for exp in expected:
assert(exp in driver_names)
assert(len(driver_names) == 2)
def test_900_restart_on_config_change(self):
"""Checking restart happens on config change.
Change debug mode and assert that change propagates to the correct
file and that services are restarted as a result
"""
self.restart_on_changed_debug_oslo_config_file(
'/etc/ironic/ironic.conf', self._SERVICES)
def test_910_pause_resume(self):
"""Run pause and resume tests.
Pause service and check services are stopped then resume and check
they are started
"""
logging.info('Skipping pause resume test LP: #1886202...')
return
with self.pause_resume(self._SERVICES):
logging.info("Testing pause resume")
+12 -9
View File
@@ -38,31 +38,34 @@ class BaseGuestCreateTest(unittest.TestCase):
zaza.openstack.configure.guest.launch_instance(instance_key)
class CirrosGuestCreateTest(BaseGuestCreateTest):
class CirrosGuestCreateTest(test_utils.OpenStackBaseTest):
"""Tests to launch a cirros image."""
def test_launch_small_instance(self):
"""Launch a cirros instance and test connectivity."""
zaza.openstack.configure.guest.launch_instance(
glance_setup.CIRROS_IMAGE_NAME)
self.RESOURCE_PREFIX = 'zaza-nova'
self.launch_guest(
'cirros', instance_key=glance_setup.CIRROS_IMAGE_NAME)
class LTSGuestCreateTest(BaseGuestCreateTest):
class LTSGuestCreateTest(test_utils.OpenStackBaseTest):
"""Tests to launch a LTS image."""
def test_launch_small_instance(self):
"""Launch a Bionic instance and test connectivity."""
zaza.openstack.configure.guest.launch_instance(
glance_setup.LTS_IMAGE_NAME)
self.RESOURCE_PREFIX = 'zaza-nova'
self.launch_guest(
'ubuntu', instance_key=glance_setup.LTS_IMAGE_NAME)
class LTSGuestCreateVolumeBackedTest(BaseGuestCreateTest):
class LTSGuestCreateVolumeBackedTest(test_utils.OpenStackBaseTest):
"""Tests to launch a LTS image."""
def test_launch_small_instance(self):
"""Launch a Bionic instance and test connectivity."""
zaza.openstack.configure.guest.launch_instance(
glance_setup.LTS_IMAGE_NAME,
self.RESOURCE_PREFIX = 'zaza-nova'
self.launch_guest(
'volume-backed-ubuntu', instance_key=glance_setup.LTS_IMAGE_NAME,
use_boot_volume=True)
+63 -1
View File
@@ -15,11 +15,14 @@
"""Encapsulate OVN testing."""
import logging
import tenacity
import juju
import tenacity
import zaza
import zaza.model
import zaza.openstack.charm_tests.test_utils as test_utils
import zaza.openstack.utilities.generic as generic_utils
import zaza.openstack.utilities.openstack as openstack_utils
@@ -36,10 +39,19 @@ class BaseCharmOperationTest(test_utils.BaseCharmTest):
"""Run class setup for OVN charm operation tests."""
super(BaseCharmOperationTest, cls).setUpClass()
cls.services = ['NotImplemented'] # This must be overridden
cls.nrpe_checks = ['NotImplemented'] # This must be overridden
cls.current_release = openstack_utils.get_os_release(
openstack_utils.get_current_os_release_pair(
cls.release_application or cls.application_name))
@tenacity.retry(
retry=tenacity.retry_if_result(lambda ret: ret is not None),
# sleep for 2mins to allow 1min cron job to run...
wait=tenacity.wait_fixed(120),
stop=tenacity.stop_after_attempt(2))
def _retry_check_commands_on_units(self, cmds, units):
return generic_utils.check_commands_on_units(cmds, units)
def test_pause_resume(self):
"""Run pause and resume tests.
@@ -50,6 +62,20 @@ class BaseCharmOperationTest(test_utils.BaseCharmTest):
logging.info('Testing pause resume (services="{}")'
.format(self.services))
def test_nrpe_configured(self):
"""Confirm that the NRPE service check files are created."""
units = zaza.model.get_units(self.application_name)
cmds = []
for check_name in self.nrpe_checks:
cmds.append(
'egrep -oh /usr/local.* /etc/nagios/nrpe.d/'
'check_{}.cfg'.format(check_name)
)
ret = self._retry_check_commands_on_units(cmds, units)
if ret:
logging.info(ret)
self.assertIsNone(ret, msg=ret)
class CentralCharmOperationTest(BaseCharmOperationTest):
"""OVN Central Charm operation tests."""
@@ -62,6 +88,22 @@ class CentralCharmOperationTest(BaseCharmOperationTest):
'ovn-northd',
'ovsdb-server',
]
source = zaza.model.get_application_config(
cls.application_name)['source']['value']
logging.info(source)
if 'train' in source:
cls.nrpe_checks = [
'ovn-northd',
'ovn-nb-ovsdb',
'ovn-sb-ovsdb',
]
else:
# Ussuri or later (distro or cloudarchive)
cls.nrpe_checks = [
'ovn-northd',
'ovn-ovsdb-server-sb',
'ovn-ovsdb-server-nb',
]
class ChassisCharmOperationTest(BaseCharmOperationTest):
@@ -76,6 +118,26 @@ class ChassisCharmOperationTest(BaseCharmOperationTest):
cls.services = [
'ovn-controller',
]
if cls.application_name == 'ovn-chassis':
principal_app_name = 'magpie'
else:
principal_app_name = cls.application_name
source = zaza.model.get_application_config(
principal_app_name)['source']['value']
logging.info(source)
if 'train' in source:
cls.nrpe_checks = [
'ovn-host',
'ovs-vswitchd',
'ovsdb-server',
]
else:
# Ussuri or later (distro or cloudarchive)
cls.nrpe_checks = [
'ovn-controller',
'ovsdb-server',
'ovs-vswitchd',
]
class OVSOVNMigrationTest(test_utils.BaseCharmTest):
+5 -2
View File
@@ -26,10 +26,12 @@ import zaza.openstack.charm_tests.glance.setup as glance_setup
SETUP_ENV_VARS = {
'neutron': ['TEST_GATEWAY', 'TEST_CIDR_EXT', 'TEST_FIP_RANGE',
'TEST_NAMESERVER', 'TEST_CIDR_PRIV'],
'TEST_NAME_SERVER', 'TEST_CIDR_PRIV'],
'swift': ['TEST_SWIFT_IP'],
}
IGNORABLE_VARS = ['TEST_CIDR_PRIV']
TEMPEST_FLAVOR_NAME = 'm1.tempest'
TEMPEST_ALT_FLAVOR_NAME = 'm2.tempest'
TEMPEST_SVC_LIST = ['ceilometer', 'cinder', 'glance', 'heat', 'horizon',
@@ -198,7 +200,8 @@ def add_environment_var_config(ctxt, services):
if value:
ctxt[var.lower()] = value
else:
missing_vars.append(var)
if var not in IGNORABLE_VARS:
missing_vars.append(var)
if missing_vars:
raise ValueError(
("Environment variables [{}] must all be set to run this"
@@ -52,9 +52,11 @@ http_image = http://{{ test_swift_ip }}:80/swift/v1/images/cirros-0.3.4-x86_64-u
{% if 'neutron' in enabled_services %}
[network]
{% if test_cidr_priv %}
project_network_cidr = {{ test_cidr_priv }}
{% endif %}
public_network_id = {{ ext_net }}
dns_servers = {{ test_nameserver }}
dns_servers = {{ test_name_server }}
project_networks_reachable = false
[network-feature-enabled]
@@ -54,9 +54,11 @@ http_image = http://{{ test_swift_ip }}:80/swift/v1/images/cirros-0.3.4-x86_64-u
{% if 'neutron' in enabled_services %}
[network]
{% if test_cidr_priv %}
project_network_cidr = {{ test_cidr_priv }}
{% endif %}
public_network_id = {{ ext_net }}
dns_servers = {{ test_nameserver }}
dns_servers = {{ test_name_server }}
project_networks_reachable = false
floating_network_name = {{ ext_net }}
+51 -24
View File
@@ -127,10 +127,28 @@ class BaseCharmTest(unittest.TestCase):
else:
cls.model_name = model.get_juju_model()
cls.test_config = lifecycle_utils.get_charm_config(fatal=False)
if application_name:
cls.application_name = application_name
else:
cls.application_name = cls.test_config['charm_name']
charm_under_test_name = cls.test_config['charm_name']
deployed_app_names = model.sync_deployed(model_name=cls.model_name)
if charm_under_test_name in deployed_app_names:
# There is an application named like the charm under test.
# Let's consider it the application under test:
cls.application_name = charm_under_test_name
else:
# Let's search for any application whose name starts with the
# name of the charm under test and assume it's the application
# under test:
for app_name in deployed_app_names:
if app_name.startswith(charm_under_test_name):
cls.application_name = app_name
break
else:
logging.warning('Could not find application under test')
return
cls.lead_unit = model.get_lead_unit_name(
cls.application_name,
model_name=cls.model_name)
@@ -526,7 +544,8 @@ class OpenStackBaseTest(BaseCharmTest):
# Test did not define self.RESOURCE_PREFIX, ignore.
pass
def launch_guest(self, guest_name, userdata=None):
def launch_guest(self, guest_name, userdata=None, use_boot_volume=False,
instance_key=None):
"""Launch two guests to use in tests.
Note that it is up to the caller to have set the RESOURCE_PREFIX class
@@ -539,25 +558,38 @@ class OpenStackBaseTest(BaseCharmTest):
:type guest_name: str
:param userdata: Userdata to attach to instance
:type userdata: Optional[str]
:param use_boot_volume: Whether to boot guest from a shared volume.
:type use_boot_volume: boolean
:param instance_key: Key to collect associated config data with.
:type instance_key: Optional[str]
:returns: Nova instance objects
:rtype: Server
"""
instance_key = instance_key or glance_setup.LTS_IMAGE_NAME
instance_name = '{}-{}'.format(self.RESOURCE_PREFIX, guest_name)
instance = self.retrieve_guest(instance_name)
if instance:
logging.info('Removing already existing instance ({}) with '
'requested name ({})'
.format(instance.id, instance_name))
openstack_utils.delete_resource(
self.nova_client.servers,
instance.id,
msg="server")
for attempt in tenacity.Retrying(
stop=tenacity.stop_after_attempt(3),
wait=tenacity.wait_exponential(
multiplier=1, min=2, max=10)):
with attempt:
old_instance_with_same_name = self.retrieve_guest(
instance_name)
if old_instance_with_same_name:
logging.info(
'Removing already existing instance ({}) with '
'requested name ({})'
.format(old_instance_with_same_name.id, instance_name))
openstack_utils.delete_resource(
self.nova_client.servers,
old_instance_with_same_name.id,
msg="server")
return configure_guest.launch_instance(
glance_setup.LTS_IMAGE_NAME,
vm_name=instance_name,
userdata=userdata)
return configure_guest.launch_instance(
instance_key,
vm_name=instance_name,
use_boot_volume=use_boot_volume,
userdata=userdata)
def launch_guests(self, userdata=None):
"""Launch two guests to use in tests.
@@ -572,15 +604,10 @@ class OpenStackBaseTest(BaseCharmTest):
"""
launched_instances = []
for guest_number in range(1, 2+1):
for attempt in tenacity.Retrying(
stop=tenacity.stop_after_attempt(3),
wait=tenacity.wait_exponential(
multiplier=1, min=2, max=10)):
with attempt:
launched_instances.append(
self.launch_guest(
guest_name='ins-{}'.format(guest_number),
userdata=userdata))
launched_instances.append(
self.launch_guest(
guest_name='ins-{}'.format(guest_number),
userdata=userdata))
return launched_instances
def retrieve_guest(self, guest_name):
+14 -4
View File
@@ -123,6 +123,10 @@ CHARM_TYPES = {
'pkg': 'ceph-common',
'origin_setting': 'source'
},
'placement': {
'pkg': 'placement-common',
'origin_setting': 'openstack-origin'
},
}
# Older tests use the order the services appear in the list to imply
@@ -143,6 +147,7 @@ UPGRADE_SERVICES = [
'type': CHARM_TYPES['openstack-dashboard']},
{'name': 'ovn-central', 'type': CHARM_TYPES['ovn-central']},
{'name': 'ceph-mon', 'type': CHARM_TYPES['ceph-mon']},
{'name': 'placement', 'type': CHARM_TYPES['placement']},
]
@@ -2059,7 +2064,8 @@ def delete_volume_backup(cinder, vol_backup_id):
def upload_image_to_glance(glance, local_path, image_name, disk_format='qcow2',
visibility='public', container_format='bare'):
visibility='public', container_format='bare',
backend=None):
"""Upload the given image to glance and apply the given label.
:param glance: Authenticated glanceclient
@@ -2085,7 +2091,7 @@ def upload_image_to_glance(glance, local_path, image_name, disk_format='qcow2',
disk_format=disk_format,
visibility=visibility,
container_format=container_format)
glance.images.upload(image.id, open(local_path, 'rb'))
glance.images.upload(image.id, open(local_path, 'rb'), backend=backend)
resource_reaches_status(
glance.images,
@@ -2097,7 +2103,8 @@ def upload_image_to_glance(glance, local_path, image_name, disk_format='qcow2',
def create_image(glance, image_url, image_name, image_cache_dir=None, tags=[],
properties=None):
properties=None, backend=None, disk_format='qcow2',
visibility='public', container_format='bare'):
"""Download the image and upload it to glance.
Download an image from image_url and upload it to glance labelling
@@ -2131,7 +2138,10 @@ def create_image(glance, image_url, image_name, image_cache_dir=None, tags=[],
if not os.path.exists(local_path):
download_image(image_url, local_path)
image = upload_image_to_glance(glance, local_path, image_name)
image = upload_image_to_glance(
glance, local_path, image_name, backend=backend,
disk_format=disk_format, visibility=visibility,
container_format=container_format)
for tag in tags:
result = glance.image_tags.update(image.id, tag)
logging.debug(