Add set-temp-url-secret action
This commit is contained in:
parent
9e5d61b70e
commit
b1b8940ccd
|
@ -0,0 +1,13 @@
|
|||
set-temp-url-secret:
|
||||
description: |
|
||||
Set Temp-Url-Key in the service object storage account. This enables Ironic
|
||||
to use the "direct" deploy method. In order for this to work, both Glance
|
||||
and Ironic must use the same tenant in their respective configs.
|
||||
|
||||
This action must be performed on the ironic-conductor leader, after the
|
||||
deployment is complete. Glance must either use Swift/RadosGW as a storage
|
||||
backend, or multi-backend must be enabled in Glance with Swift as one of
|
||||
the supported stores.
|
||||
|
||||
A relation can be created between Glance and RadosGW, which will enable
|
||||
RadosGW to act as a backend for Glance.
|
|
@ -0,0 +1,122 @@
|
|||
#!/usr/local/sbin/charm-env python3
|
||||
# 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.
|
||||
|
||||
import hashlib
|
||||
import os
|
||||
import sys
|
||||
import traceback
|
||||
import uuid
|
||||
|
||||
# Load modules from $CHARM_DIR/lib
|
||||
sys.path.append('lib')
|
||||
sys.path.append('reactive')
|
||||
|
||||
from charms.layer import basic
|
||||
basic.bootstrap_charm_deps()
|
||||
basic.init_config_states()
|
||||
|
||||
import charms.reactive as reactive
|
||||
import charms.leadership as leadership
|
||||
|
||||
import charms_openstack.bus
|
||||
import charms_openstack.charm as charm
|
||||
|
||||
import charmhelpers.core as ch_core
|
||||
|
||||
import charm.openstack.ironic.clients as clients
|
||||
|
||||
charms_openstack.bus.discover()
|
||||
|
||||
|
||||
def set_temp_url_secret(*args):
|
||||
"""Set Temp-Url-Key on storage account"""
|
||||
if not reactive.is_flag_set('leadership.is_leader'):
|
||||
return ch_core.hookenv.action_fail('action must be run on the leader '
|
||||
'unit.')
|
||||
if not reactive.is_flag_set('config.complete'):
|
||||
return ch_core.hookenv.action_fail('required relations are not yet '
|
||||
'available, please defer action'
|
||||
'until deployment is complete.')
|
||||
identity_service = reactive.endpoint_from_flag(
|
||||
'identity-credentials.available')
|
||||
try:
|
||||
keystone_session = clients.create_keystone_session(identity_service)
|
||||
except Exception as e:
|
||||
ch_core.hookenv.action_fail('Failed to create keystone session ("{}")'
|
||||
.format(e))
|
||||
|
||||
os_cli = clients.OSClients(keystone_session)
|
||||
if os_cli.has_swift() is False:
|
||||
ch_core.hookenv.action_fail(
|
||||
'Swift not yet available. Please wait for deployment to finish')
|
||||
|
||||
if os_cli.has_glance() is False:
|
||||
ch_core.hookenv.action_fail(
|
||||
'Glance not yet available. Please wait for deployment to finish')
|
||||
|
||||
if "swift" not in os_cli.glance_stores:
|
||||
ch_core.hookenv.action_fail(
|
||||
'Glance does not support Swift storage backend. '
|
||||
'Please add relation between glance and ceph-radosgw/swift')
|
||||
|
||||
current_secret = leadership.leader_get("temp_url_secret")
|
||||
current_swift_secret = os_cli.get_object_account_properties().get(
|
||||
'temp-url-key', None)
|
||||
|
||||
if not current_secret or current_swift_secret != current_secret:
|
||||
secret = hashlib.sha1(
|
||||
str(uuid.uuid4()).encode()).hexdigest()
|
||||
os_cli.set_object_account_property("temp-url-key", secret)
|
||||
leadership.leader_set({"temp_url_secret": secret})
|
||||
# render configs on leader, and assess status. Every other unit
|
||||
# will render theirs when leader-settings-changed executes.
|
||||
shared_db = reactive.endpoint_from_flag(
|
||||
'shared-db.available')
|
||||
ironic_api = reactive.endpoint_from_flag(
|
||||
'ironic-api.available')
|
||||
amqp = reactive.endpoint_from_flag(
|
||||
'amqp.available')
|
||||
|
||||
with charm.provide_charm_instance() as ironic_charm:
|
||||
ironic_charm.render_with_interfaces(
|
||||
charm.optional_interfaces(
|
||||
(identity_service, shared_db, ironic_api, amqp)))
|
||||
ironic_charm._assess_status()
|
||||
|
||||
|
||||
ACTIONS = {
|
||||
'set-temp-url-secret': set_temp_url_secret,
|
||||
}
|
||||
|
||||
|
||||
def main(args):
|
||||
action_name = os.path.basename(args[0])
|
||||
try:
|
||||
action = ACTIONS[action_name]
|
||||
except KeyError:
|
||||
return 'Action {} undefined'.format(action_name)
|
||||
else:
|
||||
try:
|
||||
action(args)
|
||||
except Exception as e:
|
||||
ch_core.hookenv.log('action "{}" failed: "{}" "{}"'
|
||||
.format(action_name, str(e),
|
||||
traceback.format_exc()),
|
||||
level=ch_core.hookenv.ERROR)
|
||||
ch_core.hookenv.action_fail(str(e))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main(sys.argv))
|
|
@ -0,0 +1 @@
|
|||
actions.py
|
|
@ -77,24 +77,72 @@ options:
|
|||
Enabling this option will preserve the data on disk after release (not
|
||||
recommended for production).
|
||||
provisioning-network:
|
||||
default: deployment
|
||||
default: !!null ""
|
||||
type: string
|
||||
description: |
|
||||
The name or ID of the provisioning network. This network is used to deploy
|
||||
bare metal nodes. This option is mandatory to allow Neutron network interfaces.
|
||||
bare metal nodes. This option is mandatory to allow Neutron network interfaces.
|
||||
cleaning-network:
|
||||
default: deployment
|
||||
default: !!null ""
|
||||
type: string
|
||||
description: |
|
||||
The name or ID of the cleaning network. This network is used to clean
|
||||
bare metal nodes after they have been releases. This option is mandatory
|
||||
to allow Neutron network interfaces. The same network may be used for both
|
||||
cleaning and provisioning.
|
||||
extra-pxe-params:
|
||||
default: ""
|
||||
enabled-network-interfaces:
|
||||
type: string
|
||||
default: "flat, neutron, noop"
|
||||
description: |
|
||||
Comma separated list of network interfaces to be enabled in the Ironic config.
|
||||
Valid options are:
|
||||
* flat
|
||||
* neutron
|
||||
* noop
|
||||
|
||||
Note: When enabling "neutron", you will also have to set the provisioning-network
|
||||
and the cleaning-network options. The settings for these networks can be overwritten
|
||||
per node, but they need to be set globally for ironic to start. The "neutron" network
|
||||
interface is needed if you require additional enablement from a ml2 driver you may
|
||||
have enabled in your deployment, such as switch configuration.
|
||||
default-network-interface:
|
||||
type: string
|
||||
default: "flat"
|
||||
description: |
|
||||
The default network interface to use for nodes that do not explicitly set a network
|
||||
interface type. The default network interface specified here, must also exist in the
|
||||
list of enabled-network-interfaces.
|
||||
enabled-deploy-interfaces:
|
||||
type: string
|
||||
default: "direct, iscsi"
|
||||
description: |
|
||||
Comma separated list of deploy interfaces to use.
|
||||
Valid options are:
|
||||
* direct
|
||||
* iscsi
|
||||
|
||||
Note: To enable the direct deploy interface, the following conditions must be
|
||||
met in your deployment of OpenStack:
|
||||
* ceph-radosgw or swift is deployed and available
|
||||
* glance is deployed and has a relation set to ceph-radosgw or swift
|
||||
* You ran the set-temp-url-secret action of this charm
|
||||
If any of these conditions are not met, the direct deploy interface will not be
|
||||
enabled in the config, and the charm will go into blocked state.
|
||||
|
||||
Note: The iscsi deploy mode requires that ironic-conductor be deployed on a VM
|
||||
or a bare metal machine. That is because the iscsi kernel module is not namespaced,
|
||||
and the ironic-conductor will not be able to log into any iscsi target.
|
||||
default-deploy-interface:
|
||||
type: string
|
||||
default: "direct"
|
||||
description: |
|
||||
The default deploy interface to use for nodes that do not explicitly set a deploy
|
||||
interface.
|
||||
pxe-append-params:
|
||||
default: "nofb nomodeset vga=normal console=tty0 console=ttyS0,115200n8"
|
||||
type: string
|
||||
description: |
|
||||
Additional kernel command line parameters to pass to the deployment kernel.
|
||||
Kernel command line parameters to pass to the deployment kernel.
|
||||
Options must be space delimited and will be passed as is to the deployment image.
|
||||
Aside from regular linux kernel command line parameters, you can also configure
|
||||
the ironic python agent (IPA) from within the deployment image. See the IPA
|
||||
|
@ -104,9 +152,10 @@ options:
|
|||
default: true
|
||||
type: boolean
|
||||
description: |
|
||||
Enables automated cleaning of nodes. This is run when setting a node to available
|
||||
Globally enables automated cleaning of nodes. This is run when setting a node to available
|
||||
state, or when deleting an instance. Cleaning will bring the node in a baseline
|
||||
state. You can safely disable this feature if all tenants of your OpenStack deployment
|
||||
are trusted, or if you have a single tenant.
|
||||
|
||||
Note: Automated cleaning can be toggled on a per node basis, via node properties.
|
||||
Note: node cleaning may take a long time, especially if secure erase is enabled.
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
includes:
|
||||
- layer:leadership
|
||||
- layer:openstack-principle
|
||||
- interface:mysql-shared
|
||||
- interface:rabbitmq
|
||||
|
@ -8,4 +9,6 @@ repo: https://github.com/gabriel-samfira/charm-ironic-conductor
|
|||
options:
|
||||
basic:
|
||||
use_venv: true
|
||||
include_system_packages: true
|
||||
include_system_packages: False
|
||||
packages: [ 'libffi-dev', 'libssl-dev', 'libpython3.6-dev' ]
|
||||
|
||||
|
|
|
@ -0,0 +1,122 @@
|
|||
from keystoneauth1 import loading
|
||||
from keystoneauth1 import session as ks_session
|
||||
from keystoneauth1 import exceptions as ks_exc
|
||||
|
||||
import glanceclient
|
||||
import swiftclient
|
||||
import keystoneclient
|
||||
|
||||
|
||||
def create_keystone_session(keystone, verify=True):
|
||||
plugin_name = "password"
|
||||
username = keystone.credentials_username()
|
||||
password = keystone.credentials_password()
|
||||
|
||||
plugin_args = {
|
||||
"username": username,
|
||||
"password": password,
|
||||
}
|
||||
|
||||
project_name = keystone.credentials_project()
|
||||
|
||||
auth_url = "%s://%s:%s" % (
|
||||
keystone.auth_protocol(),
|
||||
keystone.auth_host(),
|
||||
keystone.credentials_port())
|
||||
|
||||
plugin_args.update({
|
||||
"auth_url": auth_url,
|
||||
"project_name": project_name,
|
||||
})
|
||||
|
||||
keystone_version = keystone.api_version()
|
||||
if keystone_version and int(keystone_version) == 3:
|
||||
plugin_name = "v3" + plugin_name
|
||||
|
||||
project_domain_name = keystone.credentials_project_domain_name()
|
||||
plugin_args["project_domain_name"] = project_domain_name
|
||||
|
||||
user_domain_name = keystone.credentials_user_domain_name()
|
||||
plugin_args["user_domain_name"] = user_domain_name
|
||||
|
||||
loader = loading.get_plugin_loader(plugin_name)
|
||||
auth = loader.load_from_options(**plugin_args)
|
||||
return ks_session.Session(auth=auth, verify=verify)
|
||||
|
||||
|
||||
class OSClients(object):
|
||||
|
||||
def __init__(self, session, cacert=None):
|
||||
self._session = session
|
||||
self._img_cli = glanceclient.Client(
|
||||
session=self._session, version=2)
|
||||
self._obj_cli = swiftclient.Connection(
|
||||
session=self._session, cacert=cacert)
|
||||
self._ks = keystoneclient.v3.Client(
|
||||
session=session)
|
||||
self._stores = None
|
||||
|
||||
@property
|
||||
def _stores_info(self):
|
||||
if self._stores:
|
||||
return self._stores
|
||||
self._stores = self._img_cli.images.get_stores_info().get(
|
||||
"stores", [])
|
||||
return self._stores
|
||||
|
||||
@property
|
||||
def glance_stores(self):
|
||||
return [stor["id"] for stor in self._stores_info]
|
||||
|
||||
def get_default_glance_store(self):
|
||||
for stor in self._stores_info:
|
||||
if stor.get("default"):
|
||||
return stor["id"]
|
||||
raise ValueError("no default store set")
|
||||
|
||||
def get_object_account_properties(self):
|
||||
acct = self._obj_cli.get_account()
|
||||
props = {}
|
||||
for prop, val in acct[0].items():
|
||||
if prop.startswith('x-account-meta-'):
|
||||
props[prop.replace("x-account-meta-","")] = val
|
||||
return props
|
||||
|
||||
def set_object_account_property(self, prop, value):
|
||||
current_props = self.get_object_account_properties()
|
||||
prop = prop.lower()
|
||||
if current_props.get(prop, None) == value:
|
||||
return
|
||||
meta_key = 'x-account-meta-%s' % prop
|
||||
headers = {
|
||||
meta_key: value}
|
||||
self._obj_cli.post_account(headers)
|
||||
|
||||
def delete_object_account_property(self, prop):
|
||||
prop = prop.lower()
|
||||
meta_key = 'x-account-meta-%s' % prop
|
||||
headers = {
|
||||
meta_key: ''}
|
||||
self._obj_cli.post_account(headers)
|
||||
|
||||
def _has_service_type(self, svc_type, interface="public"):
|
||||
try:
|
||||
svc_id = self._ks.services.find(type=svc_type)
|
||||
except ks_exc.http.NotFound:
|
||||
return False
|
||||
|
||||
try:
|
||||
self._ks.endpoints.find(
|
||||
service_id=svc_id.id, interface=interface)
|
||||
except ks_exc.http.NotFound:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def has_swift(self):
|
||||
return self._has_service_type("object-store")
|
||||
|
||||
def has_glance(self):
|
||||
return self._has_service_type("image")
|
||||
|
||||
|
|
@ -114,3 +114,11 @@ def get_pxe_config_class(charm_config):
|
|||
if series == "bionic":
|
||||
return PXEBootBionic(charm_config)
|
||||
return PXEBootBase(charm_config)
|
||||
|
||||
# TODO: Create keystone session
|
||||
# TODO: create swift client
|
||||
# TODO: generate secret
|
||||
# TODO: set tmp-url-key to secret
|
||||
# TODO: Config property function that returns the secret from leader data
|
||||
def set_temp_url_secret(keystone):
|
||||
pass
|
|
@ -15,9 +15,15 @@ from charms_openstack.adapters import (
|
|||
import charm.openstack.ironic.controller_utils as controller_utils
|
||||
import charms_openstack.adapters as adapters
|
||||
import charmhelpers.contrib.network.ip as ch_ip
|
||||
import charms.leadership as leadership
|
||||
import charms.reactive as reactive
|
||||
|
||||
PACKAGES = [
|
||||
'ironic-conductor',
|
||||
'python3-keystoneauth1',
|
||||
'python3-keystoneclient',
|
||||
'python3-glanceclient',
|
||||
'python3-swiftclient',
|
||||
'python-mysqldb',
|
||||
'python3-dracclient',
|
||||
'python3-sushy',
|
||||
|
@ -58,6 +64,12 @@ def internal_interface_ip(args):
|
|||
return ch_ip.get_relation_ip("internal")
|
||||
|
||||
|
||||
@adapters.config_property
|
||||
def temp_url_secret(self):
|
||||
url_secret = leadership.leader_get("temp_url_secret")
|
||||
return url_secret
|
||||
|
||||
|
||||
class IronicAdapters(OpenStackRelationAdapters):
|
||||
|
||||
relation_adapters = {
|
||||
|
@ -102,19 +114,36 @@ class IronicConductorCharm(charms_openstack.charm.OpenStackCharm):
|
|||
}
|
||||
|
||||
group = "ironic"
|
||||
mandatory_config = []
|
||||
|
||||
def __init__(self, **kw):
|
||||
super().__init__(**kw)
|
||||
self.pxe_config = controller_utils.get_pxe_config_class(
|
||||
self.config)
|
||||
self.packages.extend(self.pxe_config.determine_packages())
|
||||
self.config["tftpboot"] = self.pxe_config.TFTP_ROOT
|
||||
self.config["httpboot"] = self.pxe_config.HTTP_ROOT
|
||||
self.config["ironic_user"] = self.pxe_config.IRONIC_USER
|
||||
self.config["ironic_group"] = self.pxe_config.IRONIC_GROUP
|
||||
self.restart_map.update(self.pxe_config.get_restart_map())
|
||||
self._setup_pxe_config(self.pxe_config)
|
||||
self._configure_defaults()
|
||||
if "neutron" in self.enabled_network_interfaces:
|
||||
self.mandatory_config.extend([
|
||||
"provisioning-network",
|
||||
"cleaning-network"])
|
||||
|
||||
def _configure_defaults(self):
|
||||
net_iface = self.config.get("default-network-interface", None)
|
||||
if not net_iface:
|
||||
self.config["default-network-interface"] = "flat"
|
||||
iface = self.config.get("default-deploy-interface", None)
|
||||
if not iface:
|
||||
self.config["default-deploy-interface"] = "direct"
|
||||
|
||||
def _setup_pxe_config(self, cfg):
|
||||
self.packages.extend(cfg.determine_packages())
|
||||
self.config["tftpboot"] = cfg.TFTP_ROOT
|
||||
self.config["httpboot"] = cfg.HTTP_ROOT
|
||||
self.config["ironic_user"] = cfg.IRONIC_USER
|
||||
self.config["ironic_group"] = cfg.IRONIC_GROUP
|
||||
self.restart_map.update(cfg.get_restart_map())
|
||||
self.services.append(
|
||||
self.pxe_config.HTTPD_SERVICE_NAME)
|
||||
cfg.HTTPD_SERVICE_NAME)
|
||||
|
||||
def install(self):
|
||||
self.configure_source()
|
||||
|
@ -134,4 +163,84 @@ class IronicConductorCharm(charms_openstack.charm.OpenStackCharm):
|
|||
dict(
|
||||
database=self.config['database'],
|
||||
username=self.config['database-user'], )
|
||||
]
|
||||
]
|
||||
|
||||
def _validate_network_interfaces(self, interfaces):
|
||||
valid_interfaces = ["flat", "neutron", "noop"]
|
||||
for interface in interfaces:
|
||||
if interface not in valid_interfaces:
|
||||
raise ValueError(
|
||||
'Network interface "%s" is not valid. Valid '
|
||||
'interfaces are: %s' % (
|
||||
interface, ", ".join(valid_interfaces)))
|
||||
|
||||
def _validate_default_net_interface(self):
|
||||
net_iface = self.config["default-network-interface"]
|
||||
if net_iface not in self.enabled_network_interfaces:
|
||||
raise ValueError(
|
||||
"default-network-interface (%s) is not enabled "
|
||||
"in enabled-network-interfaces: %s" % ", ".join(
|
||||
self.enabled_network_interfaces))
|
||||
|
||||
def _validate_deploy_interfaces(self, interfaces):
|
||||
valid_interfaces = ["direct", "iscsi"]
|
||||
has_secret = reactive.is_flag_set("leadership.set.temp_url_secret")
|
||||
for interface in interfaces:
|
||||
if interface not in valid_interfaces:
|
||||
raise ValueError(
|
||||
"Deploy interface %s is not valid. Valid "
|
||||
"interfaces are: %s" % (
|
||||
interface, ", ".join(valid_interfaces)))
|
||||
if reactive.is_flag_set("config.complete"):
|
||||
if "direct" in interfaces and has_secret is False:
|
||||
raise ValueError(
|
||||
'run "set-temp-url-secret" action on leader to '
|
||||
'enable "direct" deploy method')
|
||||
|
||||
def _validate_default_deploy_interface(self):
|
||||
iface = self.config["default-deploy-interface"]
|
||||
if iface not in self.enabled_deploy_interfaces:
|
||||
raise ValueError(
|
||||
"default-deploy-interface (%s) is not enabled "
|
||||
"in enabled-deploy-interfaces: %s" % ", ".join(
|
||||
self.enabled_deploy_interfaces))
|
||||
|
||||
@property
|
||||
def enabled_network_interfaces(self):
|
||||
network_interfaces = self.config.get(
|
||||
'enabled-network-interfaces', "").replace(" ", "")
|
||||
return network_interfaces.split(",")
|
||||
|
||||
@property
|
||||
def enabled_deploy_interfaces(self):
|
||||
network_interfaces = self.config.get(
|
||||
'enabled-deploy-interfaces', "").replace(" ", "")
|
||||
return network_interfaces.split(",")
|
||||
|
||||
def custom_assess_status_check(self):
|
||||
try:
|
||||
self._validate_network_interfaces(self.enabled_network_interfaces)
|
||||
except Exception as err:
|
||||
msg = ("invalid enabled-network-interfaces config: %s" % err)
|
||||
return ('blocked', msg)
|
||||
|
||||
try:
|
||||
self._validate_default_net_interface()
|
||||
except Exception as err:
|
||||
msg = ("invalid default-network-interface config: %s" % err)
|
||||
return ('blocked', msg)
|
||||
|
||||
try:
|
||||
self._validate_deploy_interfaces(
|
||||
self.enabled_deploy_interfaces)
|
||||
except Exception as err:
|
||||
msg = ("invalid enabled-deploy-interfaces config: %s" % err)
|
||||
return ('blocked', msg)
|
||||
|
||||
try:
|
||||
self._validate_default_deploy_interface()
|
||||
except Exception as err:
|
||||
msg = ("invalid default-deploy-interface config: %s" % err)
|
||||
return ('blocked', msg)
|
||||
|
||||
return (None, None)
|
|
@ -2,12 +2,10 @@ from __future__ import absolute_import
|
|||
|
||||
import charms.reactive as reactive
|
||||
import charmhelpers.core.hookenv as hookenv
|
||||
import charms.leadership as leadership
|
||||
|
||||
import charms_openstack.charm as charm
|
||||
import charm.openstack.ironic.ironic as ironic # noqa
|
||||
|
||||
from charmhelpers.core.templating import render
|
||||
|
||||
import charm.openstack.ironic.ironic as ironic
|
||||
|
||||
# Use the charms.openstack defaults for common states and hooks
|
||||
charm.use_defaults(
|
||||
|
|
|
@ -9,7 +9,9 @@ tftp_root={{tftpboot}}
|
|||
# value)
|
||||
tftp_server = {{ options.deployment_interface_ip }}
|
||||
|
||||
pxe_append_params = nofb nomodeset vga=normal console=tty0 console=ttyS0,115200n8 {{ options.extra_pxe_params }}
|
||||
{% if options.pxe_append_params -%}
|
||||
pxe_append_params = {{ options.pxe_append_params }}
|
||||
{% endif -%}
|
||||
|
||||
{% if options.use_ipxe -%}
|
||||
# Enable iPXE boot. (boolean value)
|
||||
|
|
|
@ -4,7 +4,7 @@ verbose = {{ options.verbose }}
|
|||
auth_strategy=keystone
|
||||
my_ip = {{ options.internal_interface_ip }}
|
||||
|
||||
enabled_deploy_interfaces = iscsi,direct
|
||||
enabled_deploy_interfaces = {{ options.enabled_deploy_interfaces }}
|
||||
enabled_hardware_types = ipmi,ilo,idrac,redfish,irmc
|
||||
{% if options.use_ipxe -%}
|
||||
enabled_boot_interfaces = pxe,ipxe,ilo-pxe,ilo-ipxe,irmc-pxe
|
||||
|
@ -13,15 +13,15 @@ enabled_boot_interfaces = pxe,ilo-pxe,irmc-pxe
|
|||
{% endif -%}
|
||||
enabled_management_interfaces = ipmitool,redfish,ilo,irmc,idrac,noop
|
||||
enabled_inspect_interfaces = idrac,ilo,irmc,redfish,no-inspect
|
||||
enabled_network_interfaces = flat,neutron,noop
|
||||
enabled_network_interfaces = {{ options.enabled_network_interfaces }}
|
||||
enabled_power_interfaces = ipmitool,redfish,ilo,irmc,idrac
|
||||
enabled_storage_interfaces = cinder,noop
|
||||
enabled_console_interfaces = ipmitool-socat,ipmitool-shellinabox,no-console
|
||||
enabled_raid_interfaces = agent,idrac,irmc,no-raid
|
||||
enabled_vendor_interfaces = ipmitool,idrac,ilo,no-vendor
|
||||
|
||||
default_deploy_interface = iscsi
|
||||
default_network_interface = flat
|
||||
default_deploy_interface = {{ options.default_deploy_interface }}
|
||||
default_network_interface = {{ options.default_network_interface }}
|
||||
|
||||
transport_url = {{ amqp.transport_url }}
|
||||
|
||||
|
@ -44,10 +44,10 @@ provisioning_network = {{ options.provisioning_network }}
|
|||
|
||||
[glance]
|
||||
{% include "parts/service-auth" %}
|
||||
# swift_container = {{ swift_container }}
|
||||
# swift_temp_url_key = {{ tmp_url_key }}
|
||||
swift_container = glance
|
||||
swift_temp_url_key = secret
|
||||
{% if options.temp_url_secret -%}
|
||||
swift_temp_url_key = {{ options.temp_url_secret }}
|
||||
{% endif %}
|
||||
|
||||
[swift]
|
||||
{% include "parts/service-auth" %}
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
# Several dependencies now require setuptools-scm>=3.0,<=3.4.1 which requires toml
|
||||
setuptools-scm>=3.0,<=3.4.1
|
||||
toml
|
||||
keystoneauth1
|
||||
pbr
|
||||
python-glanceclient
|
||||
python-swiftclient
|
||||
python-keystoneclient
|
||||
zipp < 2.0.0
|
Loading…
Reference in New Issue