Merge "Config drive support for ceph radosgw"
This commit is contained in:
commit
19ced862a7
@ -64,6 +64,9 @@ Configure Ironic and Glance with RADOS Gateway
|
|||||||
swift_api_version = v1
|
swift_api_version = v1
|
||||||
swift_endpoint_url = http://RADOS_IP:PORT
|
swift_endpoint_url = http://RADOS_IP:PORT
|
||||||
swift_temp_url_key = TEMP_URL_KEY
|
swift_temp_url_key = TEMP_URL_KEY
|
||||||
temp_url_endpoint_type=radosgw
|
|
||||||
|
[deploy]
|
||||||
|
|
||||||
|
object_store_endpoint_type = radosgw
|
||||||
|
|
||||||
#. Restart Ironic conductor service(s).
|
#. Restart Ironic conductor service(s).
|
||||||
|
@ -1089,11 +1089,8 @@
|
|||||||
# the check entirely. (integer value)
|
# the check entirely. (integer value)
|
||||||
#sync_local_state_interval = 180
|
#sync_local_state_interval = 180
|
||||||
|
|
||||||
# Whether to upload the config drive to Swift. (boolean value)
|
|
||||||
#configdrive_use_swift = false
|
|
||||||
|
|
||||||
# Name of the Swift container to store config drive data. Used
|
# Name of the Swift container to store config drive data. Used
|
||||||
# when configdrive_use_swift is True. (string value)
|
# when configdrive_use_object_store is True. (string value)
|
||||||
#configdrive_swift_container = ironic_configdrive_container
|
#configdrive_swift_container = ironic_configdrive_container
|
||||||
|
|
||||||
# Timeout (seconds) for waiting for node inspection. 0 -
|
# Timeout (seconds) for waiting for node inspection. 0 -
|
||||||
@ -1396,6 +1393,18 @@
|
|||||||
# Allowed values: netboot, local
|
# Allowed values: netboot, local
|
||||||
#default_boot_option = <None>
|
#default_boot_option = <None>
|
||||||
|
|
||||||
|
# Whether to upload the config drive to object store. Set this
|
||||||
|
# option to True to store config drive in swift or radosgw.
|
||||||
|
# (boolean value)
|
||||||
|
# Deprecated group/name - [conductor]/configdrive_use_swift
|
||||||
|
#configdrive_use_object_store = false
|
||||||
|
|
||||||
|
# Type of object store endpoint type to be used as a backend
|
||||||
|
# (string value)
|
||||||
|
# Allowed values: swift, radosgw
|
||||||
|
# Deprecated group/name - [glance]/temp_url_endpoint_type
|
||||||
|
#object_store_endpoint_type = swift
|
||||||
|
|
||||||
|
|
||||||
[dhcp]
|
[dhcp]
|
||||||
|
|
||||||
@ -1645,12 +1654,6 @@
|
|||||||
# downloads. Required for temporary URLs. (string value)
|
# downloads. Required for temporary URLs. (string value)
|
||||||
#swift_temp_url_key = <None>
|
#swift_temp_url_key = <None>
|
||||||
|
|
||||||
# Type of endpoint to use for temporary URLs. If the Glance
|
|
||||||
# backend is Swift, use "swift"; if it is CEPH with RADOS
|
|
||||||
# gateway, use "radosgw". (string value)
|
|
||||||
# Allowed values: swift, radosgw
|
|
||||||
#temp_url_endpoint_type = swift
|
|
||||||
|
|
||||||
# Tenant ID (string value)
|
# Tenant ID (string value)
|
||||||
#tenant_id = <None>
|
#tenant_id = <None>
|
||||||
|
|
||||||
|
@ -58,6 +58,54 @@ for example::
|
|||||||
ironic node-set-provision-state --config-drive /dir/configdrive_files $node_identifier active
|
ironic node-set-provision-state --config-drive /dir/configdrive_files $node_identifier active
|
||||||
|
|
||||||
|
|
||||||
|
Configuration drive storage in an object store
|
||||||
|
----------------------------------------------
|
||||||
|
|
||||||
|
Under normal circumstances, the configuration drive can be stored in the
|
||||||
|
Bare Metal service when the size is less than 64KB. Optionally, if the size
|
||||||
|
is larger than 64KB there is support to store it in swift or radosgw backed
|
||||||
|
object store. Both swift and radosgw use swift-style APIs.
|
||||||
|
|
||||||
|
The following option in ``/etc/ironic/ironic.conf`` enables swift as an object
|
||||||
|
store backend to store config drive. This uses the Identity service to
|
||||||
|
establish a session between the Bare Metal service and the
|
||||||
|
Object Storage service. ::
|
||||||
|
|
||||||
|
[deploy]
|
||||||
|
...
|
||||||
|
|
||||||
|
configdrive_use_object_store = True
|
||||||
|
|
||||||
|
Use the following options in ``/etc/ironic/ironic.conf`` to enable radosgw.
|
||||||
|
Credentials in the swift section are needed because radosgw will not use the
|
||||||
|
Identity service and relies on radosgw's username and password authentication
|
||||||
|
instead. ::
|
||||||
|
|
||||||
|
[deploy]
|
||||||
|
...
|
||||||
|
|
||||||
|
configdrive_use_object_store = True
|
||||||
|
object_store_endpoint_type = radosgw
|
||||||
|
|
||||||
|
[swift]
|
||||||
|
...
|
||||||
|
|
||||||
|
username = USERNAME
|
||||||
|
password = PASSWORD
|
||||||
|
auth_url = http://RADOSGW_IP:8000/auth/v1
|
||||||
|
|
||||||
|
Make sure that if an agent_* driver is being used, edit
|
||||||
|
``/etc/glance/glance-api.conf`` to store the instance images in respective
|
||||||
|
object store (radosgw or swift) as well::
|
||||||
|
|
||||||
|
[glance_store]
|
||||||
|
...
|
||||||
|
|
||||||
|
swift_store_user = USERNAME
|
||||||
|
swift_store_key = PASSWORD
|
||||||
|
swift_store_auth_address = http://RADOSGW_OR_SWIFT_IP:PORT/auth/v1
|
||||||
|
|
||||||
|
|
||||||
Accessing the configuration drive data
|
Accessing the configuration drive data
|
||||||
--------------------------------------
|
--------------------------------------
|
||||||
|
|
||||||
@ -81,10 +129,13 @@ the configuration drive and mount it, for example::
|
|||||||
mount $CONFIG_DEV /mnt/config
|
mount $CONFIG_DEV /mnt/config
|
||||||
|
|
||||||
|
|
||||||
.. [*] A config drive could also be a data block with a VFAT filesystem
|
.. [*] A configuration drive could also be a data block with a VFAT filesystem
|
||||||
on it instead of ISO 9660. But it's unlikely that it would be needed
|
on it instead of ISO 9660. But it's unlikely that it would be needed
|
||||||
since ISO 9660 is widely supported across operating systems.
|
since ISO 9660 is widely supported across operating systems.
|
||||||
|
|
||||||
|
For more information see `Store metadata on a configuration drive
|
||||||
|
<http://docs.openstack.org/user-guide/cli-config-drive.html>`_.
|
||||||
|
|
||||||
|
|
||||||
Cloud-init integration
|
Cloud-init integration
|
||||||
----------------------
|
----------------------
|
||||||
|
@ -147,7 +147,7 @@ class GlanceImageService(base_image_service.BaseImageService,
|
|||||||
}
|
}
|
||||||
|
|
||||||
endpoint_url = CONF.glance.swift_endpoint_url
|
endpoint_url = CONF.glance.swift_endpoint_url
|
||||||
if CONF.glance.temp_url_endpoint_type == 'radosgw':
|
if CONF.deploy.object_store_endpoint_type == 'radosgw':
|
||||||
chunks = urlparse.urlsplit(CONF.glance.swift_endpoint_url)
|
chunks = urlparse.urlsplit(CONF.glance.swift_endpoint_url)
|
||||||
if not chunks.path:
|
if not chunks.path:
|
||||||
endpoint_url = urlparse.urljoin(
|
endpoint_url = urlparse.urljoin(
|
||||||
@ -184,7 +184,7 @@ class GlanceImageService(base_image_service.BaseImageService,
|
|||||||
'Swift temporary URLs require a Swift endpoint URL. '
|
'Swift temporary URLs require a Swift endpoint URL. '
|
||||||
'You must provide "swift_endpoint_url" as a config option.'))
|
'You must provide "swift_endpoint_url" as a config option.'))
|
||||||
if (not CONF.glance.swift_account and
|
if (not CONF.glance.swift_account and
|
||||||
CONF.glance.temp_url_endpoint_type == 'swift'):
|
CONF.deploy.object_store_endpoint_type == 'swift'):
|
||||||
raise exc.MissingParameterValue(_(
|
raise exc.MissingParameterValue(_(
|
||||||
'Swift temporary URLs require a Swift account string. '
|
'Swift temporary URLs require a Swift account string. '
|
||||||
'You must provide "swift_account" as a config option.'))
|
'You must provide "swift_account" as a config option.'))
|
||||||
|
@ -23,7 +23,7 @@ from swiftclient import utils as swift_utils
|
|||||||
from ironic.common import exception
|
from ironic.common import exception
|
||||||
from ironic.common.i18n import _
|
from ironic.common.i18n import _
|
||||||
from ironic.common import keystone
|
from ironic.common import keystone
|
||||||
|
from ironic.conf import CONF
|
||||||
|
|
||||||
_SWIFT_SESSION = None
|
_SWIFT_SESSION = None
|
||||||
|
|
||||||
@ -39,8 +39,22 @@ class SwiftAPI(object):
|
|||||||
"""API for communicating with Swift."""
|
"""API for communicating with Swift."""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
session = _get_swift_session()
|
"""Initialize the connection with swift or radosgw
|
||||||
self.connection = swift_client.Connection(session=session)
|
|
||||||
|
:raises: ConfigInvalid if required keystone authorization credentials
|
||||||
|
with swift are missing.
|
||||||
|
"""
|
||||||
|
params = {}
|
||||||
|
if CONF.deploy.object_store_endpoint_type == 'radosgw':
|
||||||
|
params = {'authurl': CONF.swift.auth_url,
|
||||||
|
'user': CONF.swift.username,
|
||||||
|
'key': CONF.swift.password}
|
||||||
|
else:
|
||||||
|
# NOTE(aNuposic): Session will be initiated only when connection
|
||||||
|
# with swift is initialized. Since v3.2.0 swiftclient supports
|
||||||
|
# instantiating the API client from keystoneauth session.
|
||||||
|
params = {'session': _get_swift_session()}
|
||||||
|
self.connection = swift_client.Connection(**params)
|
||||||
|
|
||||||
def create_object(self, container, obj, filename,
|
def create_object(self, container, obj, filename,
|
||||||
object_headers=None):
|
object_headers=None):
|
||||||
|
@ -85,6 +85,8 @@ class BaseConductorManager(object):
|
|||||||
:raises: DriverLoadError if an enabled driver cannot be loaded.
|
:raises: DriverLoadError if an enabled driver cannot be loaded.
|
||||||
:raises: DriverNameConflict if a classic driver and a dynamic driver
|
:raises: DriverNameConflict if a classic driver and a dynamic driver
|
||||||
are both enabled and have the same name.
|
are both enabled and have the same name.
|
||||||
|
:raises: ConfigInvalid if required config options for connection with
|
||||||
|
radosgw are missing while storing config drive.
|
||||||
"""
|
"""
|
||||||
if self._started:
|
if self._started:
|
||||||
raise RuntimeError(_('Attempt to start an already running '
|
raise RuntimeError(_('Attempt to start an already running '
|
||||||
@ -172,6 +174,18 @@ class BaseConductorManager(object):
|
|||||||
self._periodic_task_callables,
|
self._periodic_task_callables,
|
||||||
executor_factory=periodics.ExistingExecutor(self._executor))
|
executor_factory=periodics.ExistingExecutor(self._executor))
|
||||||
|
|
||||||
|
# Check for required config options if object_store_endpoint_type is
|
||||||
|
# radosgw
|
||||||
|
if (CONF.deploy.configdrive_use_object_store and
|
||||||
|
CONF.deploy.object_store_endpoint_type == "radosgw"):
|
||||||
|
if (None in (CONF.swift.auth_url, CONF.swift.username,
|
||||||
|
CONF.swift.password)):
|
||||||
|
msg = _("Parameters missing to make a connection with "
|
||||||
|
"radosgw. Ensure that [swift]/auth_url, "
|
||||||
|
"[swift]/username, and [swift]/password are all "
|
||||||
|
"configured.")
|
||||||
|
raise exception.ConfigInvalid(msg)
|
||||||
|
|
||||||
# clear all target_power_state with locks by this conductor
|
# clear all target_power_state with locks by this conductor
|
||||||
self.dbapi.clear_node_target_power_state(self.host)
|
self.dbapi.clear_node_target_power_state(self.host)
|
||||||
# clear all locks held by this conductor before registering
|
# clear all locks held by this conductor before registering
|
||||||
|
@ -2695,17 +2695,20 @@ def _get_configdrive_obj_name(node):
|
|||||||
def _store_configdrive(node, configdrive):
|
def _store_configdrive(node, configdrive):
|
||||||
"""Handle the storage of the config drive.
|
"""Handle the storage of the config drive.
|
||||||
|
|
||||||
If configured, the config drive data are uploaded to Swift. The Node's
|
If configured, the config drive data are uploaded to swift or radosgw.
|
||||||
instance_info is updated to include either the temporary Swift URL
|
The Node's instance_info is updated to include either the temporary
|
||||||
from the upload, or if no upload, the actual config drive data.
|
Swift URL from the upload, or if no upload, the actual config drive data.
|
||||||
|
|
||||||
:param node: an Ironic node object.
|
:param node: an Ironic node object.
|
||||||
:param configdrive: A gzipped and base64 encoded configdrive.
|
:param configdrive: A gzipped and base64 encoded configdrive.
|
||||||
:raises: SwiftOperationError if an error occur when uploading the
|
:raises: SwiftOperationError if an error occur when uploading the
|
||||||
config drive to Swift.
|
config drive to swift or radosgw.
|
||||||
|
:raises: ConfigInvalid if required keystone authorization credentials
|
||||||
|
with swift are missing.
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if CONF.conductor.configdrive_use_swift:
|
if CONF.deploy.configdrive_use_object_store:
|
||||||
# NOTE(lucasagomes): No reason to use a different timeout than
|
# NOTE(lucasagomes): No reason to use a different timeout than
|
||||||
# the one used for deploying the node
|
# the one used for deploying the node
|
||||||
timeout = CONF.conductor.deploy_callback_timeout
|
timeout = CONF.conductor.deploy_callback_timeout
|
||||||
|
@ -107,13 +107,11 @@ opts = [
|
|||||||
'conductor will check for nodes that it should '
|
'conductor will check for nodes that it should '
|
||||||
'"take over". Set it to a negative value to disable '
|
'"take over". Set it to a negative value to disable '
|
||||||
'the check entirely.')),
|
'the check entirely.')),
|
||||||
cfg.BoolOpt('configdrive_use_swift',
|
|
||||||
default=False,
|
|
||||||
help=_('Whether to upload the config drive to Swift.')),
|
|
||||||
cfg.StrOpt('configdrive_swift_container',
|
cfg.StrOpt('configdrive_swift_container',
|
||||||
default='ironic_configdrive_container',
|
default='ironic_configdrive_container',
|
||||||
help=_('Name of the Swift container to store config drive '
|
help=_('Name of the Swift container to store config drive '
|
||||||
'data. Used when configdrive_use_swift is True.')),
|
'data. Used when configdrive_use_object_store is '
|
||||||
|
'True.')),
|
||||||
cfg.IntOpt('inspect_timeout',
|
cfg.IntOpt('inspect_timeout',
|
||||||
default=1800,
|
default=1800,
|
||||||
help=_('Timeout (seconds) for waiting for node inspection. '
|
help=_('Timeout (seconds) for waiting for node inspection. '
|
||||||
|
@ -72,6 +72,20 @@ opts = [
|
|||||||
'default is "netboot", but it will be changed to '
|
'default is "netboot", but it will be changed to '
|
||||||
'"local" in the future. It is recommended to set '
|
'"local" in the future. It is recommended to set '
|
||||||
'an explicit value for this option.')),
|
'an explicit value for this option.')),
|
||||||
|
cfg.BoolOpt('configdrive_use_object_store',
|
||||||
|
default=False,
|
||||||
|
deprecated_group='conductor',
|
||||||
|
deprecated_name='configdrive_use_swift',
|
||||||
|
help=_('Whether to upload the config drive to object store. '
|
||||||
|
'Set this option to True to store config drive '
|
||||||
|
'in swift or radosgw.')),
|
||||||
|
cfg.StrOpt('object_store_endpoint_type',
|
||||||
|
default='swift',
|
||||||
|
deprecated_group='glance',
|
||||||
|
deprecated_name='temp_url_endpoint_type',
|
||||||
|
choices=['swift', 'radosgw'],
|
||||||
|
help=_('Type of object store endpoint type to be '
|
||||||
|
'used as a backend')),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -103,12 +103,6 @@ opts = [
|
|||||||
'value between 1 and 32, a single-tenant store will use '
|
'value between 1 and 32, a single-tenant store will use '
|
||||||
'multiple containers to store images, and this value '
|
'multiple containers to store images, and this value '
|
||||||
'will determine how many containers are created.')),
|
'will determine how many containers are created.')),
|
||||||
cfg.StrOpt('temp_url_endpoint_type',
|
|
||||||
default='swift',
|
|
||||||
choices=['swift', 'radosgw'],
|
|
||||||
help=_('Type of endpoint to use for temporary URLs. If the '
|
|
||||||
'Glance backend is Swift, use "swift"; if it is CEPH '
|
|
||||||
'with RADOS gateway, use "radosgw".')),
|
|
||||||
cfg.StrOpt('glance_host',
|
cfg.StrOpt('glance_host',
|
||||||
default='$my_ip',
|
default='$my_ip',
|
||||||
help=_('Default glance hostname or IP address.')),
|
help=_('Default glance hostname or IP address.')),
|
||||||
|
@ -744,7 +744,7 @@ class TestGlanceSwiftTempURL(base.TestCase):
|
|||||||
|
|
||||||
@mock.patch('swiftclient.utils.generate_temp_url', autospec=True)
|
@mock.patch('swiftclient.utils.generate_temp_url', autospec=True)
|
||||||
def test_swift_temp_url_radosgw(self, tempurl_mock):
|
def test_swift_temp_url_radosgw(self, tempurl_mock):
|
||||||
self.config(temp_url_endpoint_type='radosgw', group='glance')
|
self.config(object_store_endpoint_type='radosgw', group='deploy')
|
||||||
path = ('/v1'
|
path = ('/v1'
|
||||||
'/glance'
|
'/glance'
|
||||||
'/757274c4-2856-4bd2-bb20-9a4a231e187b')
|
'/757274c4-2856-4bd2-bb20-9a4a231e187b')
|
||||||
@ -769,7 +769,7 @@ class TestGlanceSwiftTempURL(base.TestCase):
|
|||||||
def test_swift_temp_url_radosgw_endpoint_with_swift(self, tempurl_mock):
|
def test_swift_temp_url_radosgw_endpoint_with_swift(self, tempurl_mock):
|
||||||
self.config(swift_endpoint_url='https://swift.radosgw.com/swift',
|
self.config(swift_endpoint_url='https://swift.radosgw.com/swift',
|
||||||
group='glance')
|
group='glance')
|
||||||
self.config(temp_url_endpoint_type='radosgw', group='glance')
|
self.config(object_store_endpoint_type='radosgw', group='deploy')
|
||||||
path = ('/v1'
|
path = ('/v1'
|
||||||
'/glance'
|
'/glance'
|
||||||
'/757274c4-2856-4bd2-bb20-9a4a231e187b')
|
'/757274c4-2856-4bd2-bb20-9a4a231e187b')
|
||||||
@ -793,7 +793,7 @@ class TestGlanceSwiftTempURL(base.TestCase):
|
|||||||
def test_swift_temp_url_radosgw_endpoint_invalid(self, tempurl_mock):
|
def test_swift_temp_url_radosgw_endpoint_invalid(self, tempurl_mock):
|
||||||
self.config(swift_endpoint_url='https://swift.radosgw.com/eggs/',
|
self.config(swift_endpoint_url='https://swift.radosgw.com/eggs/',
|
||||||
group='glance')
|
group='glance')
|
||||||
self.config(temp_url_endpoint_type='radosgw', group='glance')
|
self.config(object_store_endpoint_type='radosgw', group='deploy')
|
||||||
self.service._validate_temp_url_config = mock.Mock()
|
self.service._validate_temp_url_config = mock.Mock()
|
||||||
|
|
||||||
self.assertRaises(exception.InvalidParameterValue,
|
self.assertRaises(exception.InvalidParameterValue,
|
||||||
@ -851,7 +851,7 @@ class TestGlanceSwiftTempURL(base.TestCase):
|
|||||||
|
|
||||||
def test__validate_temp_url_no_account_exception_radosgw(self):
|
def test__validate_temp_url_no_account_exception_radosgw(self):
|
||||||
self.config(swift_account=None, group='glance')
|
self.config(swift_account=None, group='glance')
|
||||||
self.config(temp_url_endpoint_type='radosgw', group='glance')
|
self.config(object_store_endpoint_type='radosgw', group='deploy')
|
||||||
self.service._validate_temp_url_config()
|
self.service._validate_temp_url_config()
|
||||||
|
|
||||||
def test__validate_temp_url_endpoint_less_than_download_delay(self):
|
def test__validate_temp_url_endpoint_less_than_download_delay(self):
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import mock
|
import mock
|
||||||
|
from oslo_config import cfg
|
||||||
import six
|
import six
|
||||||
from six.moves import builtins as __builtin__
|
from six.moves import builtins as __builtin__
|
||||||
from six.moves import http_client
|
from six.moves import http_client
|
||||||
@ -24,6 +25,7 @@ from ironic.common import exception
|
|||||||
from ironic.common import swift
|
from ironic.common import swift
|
||||||
from ironic.tests import base
|
from ironic.tests import base
|
||||||
|
|
||||||
|
CONF = cfg.CONF
|
||||||
|
|
||||||
if six.PY3:
|
if six.PY3:
|
||||||
import io
|
import io
|
||||||
@ -39,10 +41,35 @@ class SwiftTestCase(base.TestCase):
|
|||||||
self.swift_exception = swift_exception.ClientException('', '')
|
self.swift_exception = swift_exception.ClientException('', '')
|
||||||
|
|
||||||
def test___init__(self, connection_mock, keystone_mock):
|
def test___init__(self, connection_mock, keystone_mock):
|
||||||
|
"""Check if client is properly initialized with swift"""
|
||||||
|
|
||||||
swift.SwiftAPI()
|
swift.SwiftAPI()
|
||||||
connection_mock.assert_called_once_with(
|
connection_mock.assert_called_once_with(
|
||||||
session=keystone_mock.return_value)
|
session=keystone_mock.return_value)
|
||||||
|
|
||||||
|
def test___init___radosgw(self, connection_mock, swift_session_mock):
|
||||||
|
"""Check if client is properly initialized with radosgw"""
|
||||||
|
|
||||||
|
auth_url = 'http://1.2.3.4'
|
||||||
|
username = 'foo'
|
||||||
|
password = 'foo_password'
|
||||||
|
CONF.set_override('object_store_endpoint_type', 'radosgw',
|
||||||
|
group='deploy')
|
||||||
|
opts = [cfg.StrOpt('auth_url'), cfg.StrOpt('username'),
|
||||||
|
cfg.StrOpt('password')]
|
||||||
|
CONF.register_opts(opts, group='swift')
|
||||||
|
|
||||||
|
CONF.set_override('auth_url', auth_url, group='swift')
|
||||||
|
CONF.set_override('username', username, group='swift')
|
||||||
|
CONF.set_override('password', password, group='swift')
|
||||||
|
|
||||||
|
swift.SwiftAPI()
|
||||||
|
params = {'authurl': auth_url,
|
||||||
|
'user': username,
|
||||||
|
'key': password}
|
||||||
|
connection_mock.assert_called_once_with(**params)
|
||||||
|
swift_session_mock.assert_not_called()
|
||||||
|
|
||||||
@mock.patch.object(__builtin__, 'open', autospec=True)
|
@mock.patch.object(__builtin__, 'open', autospec=True)
|
||||||
def test_create_object(self, open_mock, connection_mock, keystone_mock):
|
def test_create_object(self, open_mock, connection_mock, keystone_mock):
|
||||||
swiftapi = swift.SwiftAPI()
|
swiftapi = swift.SwiftAPI()
|
||||||
|
@ -250,6 +250,28 @@ class StartStopTestCase(mgr_utils.ServiceSetUpMixin, tests_db_base.DbTestCase):
|
|||||||
self.service.del_host()
|
self.service.del_host()
|
||||||
self.assertTrue(wait_mock.called)
|
self.assertTrue(wait_mock.called)
|
||||||
|
|
||||||
|
def test_start_fails_on_missing_config_for_configdrive(self):
|
||||||
|
"""Check to fail conductor on missing config options"""
|
||||||
|
|
||||||
|
missing_parameters_error = ("Parameters missing to make a "
|
||||||
|
"connection with radosgw")
|
||||||
|
CONF.set_override('configdrive_use_object_store', True,
|
||||||
|
group='deploy')
|
||||||
|
CONF.set_override('object_store_endpoint_type', 'radosgw',
|
||||||
|
group='deploy')
|
||||||
|
params = {'auth_url': 'http://1.2.3.4',
|
||||||
|
'username': 'foo', 'password': 'foo_pass'}
|
||||||
|
CONF.register_opts((cfg.StrOpt(x) for x in params),
|
||||||
|
group='swift')
|
||||||
|
for key, value in params.items():
|
||||||
|
test_params = params.copy()
|
||||||
|
test_params[key] = None
|
||||||
|
for test_key, test_value in test_params.items():
|
||||||
|
CONF.set_override(key, test_value, group='swift')
|
||||||
|
with self.assertRaisesRegex(exception.ConfigInvalid,
|
||||||
|
missing_parameters_error):
|
||||||
|
self._start_service()
|
||||||
|
|
||||||
|
|
||||||
class CheckInterfacesTestCase(mgr_utils.ServiceSetUpMixin,
|
class CheckInterfacesTestCase(mgr_utils.ServiceSetUpMixin,
|
||||||
tests_db_base.DbTestCase):
|
tests_db_base.DbTestCase):
|
||||||
|
@ -1433,7 +1433,8 @@ class DoNodeDeployTearDownTestCase(mgr_utils.ServiceSetUpMixin,
|
|||||||
@mock.patch('ironic.drivers.modules.fake.FakeDeploy.deploy')
|
@mock.patch('ironic.drivers.modules.fake.FakeDeploy.deploy')
|
||||||
def test__do_node_deploy_configdrive_swift_error(self, mock_deploy,
|
def test__do_node_deploy_configdrive_swift_error(self, mock_deploy,
|
||||||
mock_swift):
|
mock_swift):
|
||||||
CONF.set_override('configdrive_use_swift', True, group='conductor')
|
CONF.set_override('configdrive_use_object_store', True,
|
||||||
|
group='deploy')
|
||||||
self._start_service()
|
self._start_service()
|
||||||
# test when driver.deploy.deploy returns DEPLOYDONE
|
# test when driver.deploy.deploy returns DEPLOYDONE
|
||||||
mock_deploy.return_value = states.DEPLOYDONE
|
mock_deploy.return_value = states.DEPLOYDONE
|
||||||
@ -5042,7 +5043,8 @@ class StoreConfigDriveTestCase(tests_base.TestCase):
|
|||||||
expected_instance_info = {'configdrive': 'http://1.2.3.4'}
|
expected_instance_info = {'configdrive': 'http://1.2.3.4'}
|
||||||
|
|
||||||
# set configs and mocks
|
# set configs and mocks
|
||||||
CONF.set_override('configdrive_use_swift', True, group='conductor')
|
CONF.set_override('configdrive_use_object_store', True,
|
||||||
|
group='deploy')
|
||||||
CONF.set_override('configdrive_swift_container', container_name,
|
CONF.set_override('configdrive_swift_container', container_name,
|
||||||
group='conductor')
|
group='conductor')
|
||||||
CONF.set_override('deploy_callback_timeout', timeout,
|
CONF.set_override('deploy_callback_timeout', timeout,
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- Adds support for storing the configdrive in radosgw using
|
||||||
|
the swift API.
|
||||||
|
- |
|
||||||
|
Adds support to use the radosgw authentication mechanism that relies
|
||||||
|
on username and password instead of auth token.
|
||||||
|
The following options must be specified in ironic configuration file:
|
||||||
|
|
||||||
|
* ``[swift]/auth_url``
|
||||||
|
* ``[swift]/username``
|
||||||
|
* ``[swift]/password``
|
||||||
|
|
||||||
|
deprecations:
|
||||||
|
- The ``[conductor]/configdrive_use_swift`` and
|
||||||
|
``[glance]/temp_url_endpoint_type`` options are deprecated and will be
|
||||||
|
removed in the Queens release.
|
||||||
|
Use ``[deploy]/configdrive_use_object_store`` and
|
||||||
|
``[deploy]/object_store_endpoint_type`` respectively instead.
|
||||||
|
upgrade:
|
||||||
|
- Adds a ``[deploy]/object_store_endpoint_type`` option to specify the
|
||||||
|
type of endpoint to use for instance images and configdrive storage.
|
||||||
|
Allowed values are 'swift' or 'radosgw'. The default is 'swift'.
|
Loading…
Reference in New Issue
Block a user