Add initial charm code
This commit is contained in:
parent
6e0c703cde
commit
82102ccf3e
|
@ -0,0 +1,62 @@
|
|||
options:
|
||||
openstack-origin:
|
||||
default: distro
|
||||
type: string
|
||||
description: |
|
||||
Repository from which to install. May be one of the following:
|
||||
distro (default), ppa:somecustom/ppa, a deb url sources entry,
|
||||
or a supported Ubuntu Cloud Archive e.g.
|
||||
.
|
||||
cloud:<series>-<openstack-release>
|
||||
cloud:<series>-<openstack-release>/updates
|
||||
cloud:<series>-<openstack-release>/staging
|
||||
cloud:<series>-<openstack-release>/proposed
|
||||
.
|
||||
See https://wiki.ubuntu.com/OpenStack/CloudArchive for info on which
|
||||
cloud archives are available and supported.
|
||||
rabbit-user:
|
||||
default: ironic
|
||||
type: string
|
||||
description: Username used to access rabbitmq queue
|
||||
rabbit-vhost:
|
||||
default: openstack
|
||||
type: string
|
||||
description: Rabbitmq vhost
|
||||
database-user:
|
||||
default: ironic
|
||||
type: string
|
||||
description: Username for Magnum database access
|
||||
database:
|
||||
default: ironic
|
||||
type: string
|
||||
description: Database name for Magnum
|
||||
debug:
|
||||
default: False
|
||||
type: boolean
|
||||
description: Enable debug logging
|
||||
verbose:
|
||||
default: False
|
||||
type: boolean
|
||||
description: Enable verbose logging
|
||||
region:
|
||||
default: RegionOne
|
||||
type: string
|
||||
description: OpenStack Region
|
||||
use-ipxe:
|
||||
default: false
|
||||
type: boolean
|
||||
description: |
|
||||
Use iPXE instead of PXE. This option will install an aditional
|
||||
HTTP server with a root in /httpboot.
|
||||
ipxe-http-port:
|
||||
default: "8080"
|
||||
type: string
|
||||
description: |
|
||||
The port used for the HTTP server used to serve iPXE resources.
|
||||
api-port:
|
||||
default: "6385"
|
||||
type: string
|
||||
description: |
|
||||
The API port ironic-api will listen on.
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
After Width: | Height: | Size: 81 KiB |
|
@ -0,0 +1,11 @@
|
|||
includes:
|
||||
- layer:openstack
|
||||
- layer:openstack-api
|
||||
- interface:mysql-shared
|
||||
- interface:rabbitmq
|
||||
- interface:keystone
|
||||
repo: https://github.com/gabriel-samfira/charm-ironic-api
|
||||
options:
|
||||
basic:
|
||||
use_venv: true
|
||||
include_system_packages: true
|
|
@ -0,0 +1,148 @@
|
|||
import os
|
||||
import shutil
|
||||
|
||||
from charmhelpers.core.templating import render
|
||||
from charmhelpers.core.host import get_distrib_codename
|
||||
import charmhelpers.fetch as fetch
|
||||
|
||||
_IRONIC_USER = "ironic"
|
||||
_IRONIC_GROUP = "ironic"
|
||||
|
||||
|
||||
class PXEBootBase(object):
|
||||
|
||||
TFTP_ROOT = "/tftproot"
|
||||
HTTP_ROOT = "/httproot"
|
||||
IPXE_BOOT = os.path.join(HTTP_ROOT, "boot.ipxe")
|
||||
GRUB_DIR = os.path.join(TFTP_ROOT, "grub")
|
||||
MAP_FILE = os.path.join(TFTP_ROOT, "map-file")
|
||||
TFTP_CONFIG = "/etc/default/tftpd-hpa"
|
||||
|
||||
# This is a file map of source to destination. The destination is
|
||||
# relative to self.TFTP_ROOT
|
||||
FILE_MAP = {
|
||||
"/usr/lib/PXELINUX/pxelinux.0": "pxelinux.0",
|
||||
"/usr/lib/syslinux/modules/bios/chain.c32": "chain.c32",
|
||||
"/usr/lib/syslinux/modules/bios/ldlinux.c32": "ldlinux.c32",
|
||||
"/usr/lib/grub/x86_64-efi-signed/grubnetx64.efi.signed": "grubx64.efi",
|
||||
"/usr/lib/shim/shim.efi.signed": "bootx64.efi",
|
||||
"/usr/lib/ipxe/undionly.kpxe": "undionly.kpxe",
|
||||
"/usr/lib/ipxe/ipxe.efi": "ipxe.efi",
|
||||
}
|
||||
|
||||
TFTP_PACKAGES = ["tftp-hpa"]
|
||||
PACKAGES = [
|
||||
'syslinux-common',
|
||||
'pxelinux',
|
||||
'grub-efi-amd64-signed',
|
||||
'shim-signed',
|
||||
'ipxe',
|
||||
]
|
||||
|
||||
def __init__(self, charm_config):
|
||||
self._config = charm_config
|
||||
|
||||
def _copy_resources(self):
|
||||
self._ensure_folders()
|
||||
for f in self.FILE_MAP:
|
||||
if os.path.isfile(f) is False:
|
||||
raise ValueError(
|
||||
"Missing required file %s. Package not installes?" % f)
|
||||
shutil.copy(
|
||||
f, os.path.join(self.TFTP_ROOT, self.FILE_MAP[f]),
|
||||
follow_symlinks=True)
|
||||
self._recursive_chown(
|
||||
self.TFTP_ROOT, user=_IRONIC_USER, group=_IRONIC_GROUP)
|
||||
|
||||
def _recursive_chown(self, path, user=None, group=None):
|
||||
for root, _, files in os.walk(path):
|
||||
shutil.chown(root, user=user, group=group)
|
||||
for f in files:
|
||||
shutil.chown(
|
||||
os.path.join(root, f), user=user, group=group)
|
||||
|
||||
def _ensure_folders(self):
|
||||
if os.path.isdir(self.TFTP_ROOT) is False:
|
||||
os.makedirs(self.TFTP_ROOT)
|
||||
|
||||
if os.path.isdir(self.HTTP_ROOT) is False:
|
||||
os.makedirs(self.HTTP_ROOT)
|
||||
|
||||
if os.path.isdir(self.IPXE_BOOT) is False:
|
||||
os.makedirs(self.IPXE_BOOT)
|
||||
|
||||
if os.path.isdir(self.GRUB_DIR) is False:
|
||||
os.makedirs(self.GRUB_DIR)
|
||||
|
||||
self._recursive_chown(
|
||||
self.TFTP_ROOT, user=_IRONIC_USER, group=_IRONIC_GROUP)
|
||||
self._recursive_chown(
|
||||
self.HTTP_ROOT, user=_IRONIC_USER, group=_IRONIC_GROUP)
|
||||
|
||||
def _create_file_map(self):
|
||||
self._ensure_folders()
|
||||
render(source='tftp-file-map',
|
||||
target=self.MAP_FILE,
|
||||
owner=_IRONIC_USER,
|
||||
perms=0o664,
|
||||
context={})
|
||||
|
||||
def _create_grub_cfg(self):
|
||||
self._ensure_folders()
|
||||
render(source='grub-efi',
|
||||
target=os.path.join(self.GRUB_DIR, "grub.cfg"),
|
||||
owner="root",
|
||||
perms=0o644,
|
||||
context={
|
||||
"tftpboot": self.TFTP_ROOT,
|
||||
})
|
||||
|
||||
def _create_tftp_config(self):
|
||||
cfg_dir = os.path.dirname(self.TFTP_CONFIG)
|
||||
if os.path.isdir(cfg_dir) is False:
|
||||
raise Exception("Could not find %s" % cfg_dir)
|
||||
render(source='tftp-hpa',
|
||||
target=self.TFTP_CONFIG,
|
||||
owner="root",
|
||||
perms=0o644,
|
||||
context={
|
||||
"tftpboot": self.TFTP_ROOT,
|
||||
})
|
||||
|
||||
def configure_resources(self):
|
||||
# On Ubuntu 20.04, if IPv6 is not available on the system,
|
||||
# the tftp-hpa package fails to install properly. We create the
|
||||
# config beforehand, forcing IPv4.
|
||||
self._create_tftp_config()
|
||||
fetch.apt_install(self.TFTP_PACKAGES, fatal=True)
|
||||
fetch.apt_install(self.PACKAGES, fatal=True)
|
||||
self._copy_resources()
|
||||
self._create_file_map()
|
||||
self._create_grub_cfg()
|
||||
|
||||
|
||||
class PXEBootBionic(PXEBootBase):
|
||||
|
||||
# This is a file map of source to destination. The destination is
|
||||
# relative to self.TFTP_ROOT
|
||||
FILE_MAP = {
|
||||
"/usr/lib/PXELINUX/pxelinux.0": "pxelinux.0",
|
||||
"/usr/lib/syslinux/modules/bios/chain.c32": "chain.c32",
|
||||
"/usr/lib/syslinux/modules/bios/ldlinux.c32": "ldlinux.c32",
|
||||
"/usr/lib/grub/x86_64-efi-signed/grubnetx64.efi.signed": "grubx64.efi",
|
||||
"/usr/lib/shim/shimx64.efi.signed": "bootx64.efi",
|
||||
"/usr/lib/ipxe/undionly.kpxe": "undionly.kpxe",
|
||||
"/usr/lib/ipxe/ipxe.efi": "ipxe.efi",
|
||||
}
|
||||
|
||||
|
||||
def get_pxe_config_class(charm_config):
|
||||
# In the future, we may need to make slight adjustments to package
|
||||
# names and/or configuration files, based on the version of Ubuntu
|
||||
# we are installing on. This function serves as a factory which will
|
||||
# return an instance of the proper class to the charm. For now we only
|
||||
# have one class.
|
||||
series = get_distrib_codename()
|
||||
if series == "bionic":
|
||||
return PXEBootBionic(charm_config)
|
||||
return PXEBootBase(charm_config)
|
|
@ -0,0 +1,137 @@
|
|||
# Copyright 2020 Cloudbase Solutions
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
import collections
|
||||
|
||||
import charms_openstack.charm
|
||||
import charms_openstack.adapters
|
||||
import charms_openstack.ip as os_ip
|
||||
|
||||
import charm.openstack.ironic.controller_utils as controller_utils
|
||||
|
||||
PACKAGES = [
|
||||
'ironic-api',
|
||||
'ironic-conductor',
|
||||
'python-mysqldb',
|
||||
'python3-dracclient',
|
||||
'python3-sushy',
|
||||
'python3-ironicclient',
|
||||
'python3-scciclient',
|
||||
'shellinabox',
|
||||
'openssl',
|
||||
'socat',
|
||||
'open-iscsi',
|
||||
'qemu-utils',
|
||||
'ipmitool']
|
||||
|
||||
IRONIC_DIR = "/etc/ironic/"
|
||||
IRONIC_CONF = IRONIC_DIR + "ironic.conf"
|
||||
TFTP_CONF = "/etc/default/tftpd-hpa"
|
||||
|
||||
OPENSTACK_RELEASE_KEY = 'ironic-charm.openstack-release-version'
|
||||
|
||||
|
||||
# select the default release function
|
||||
charms_openstack.charm.use_defaults('charm.default-select-release')
|
||||
|
||||
|
||||
def db_sync_done():
|
||||
return IronicAPICharm.singleton.db_sync_done()
|
||||
|
||||
|
||||
def restart_all():
|
||||
IronicAPICharm.singleton.restart_all()
|
||||
|
||||
|
||||
def db_sync():
|
||||
IronicAPICharm.singleton.db_sync()
|
||||
|
||||
|
||||
def configure_ha_resources(hacluster):
|
||||
IronicAPICharm.singleton.configure_ha_resources(hacluster)
|
||||
|
||||
|
||||
def assess_status():
|
||||
IronicAPICharm.singleton.assess_status()
|
||||
|
||||
|
||||
def setup_endpoint(keystone):
|
||||
charm = IronicAPICharm.singleton
|
||||
public_ep = '{}/v1'.format(charm.public_url)
|
||||
internal_ep = '{}/v1'.format(charm.internal_url)
|
||||
admin_ep = '{}/v1'.format(charm.admin_url)
|
||||
keystone.register_endpoints(charm.service_type,
|
||||
charm.region,
|
||||
public_ep,
|
||||
internal_ep,
|
||||
admin_ep)
|
||||
|
||||
|
||||
class IronicAPICharm(charms_openstack.charm.HAOpenStackCharm):
|
||||
|
||||
abstract_class = False
|
||||
release = 'train'
|
||||
name = 'ironic'
|
||||
packages = PACKAGES
|
||||
api_ports = {
|
||||
'ironic-api': {
|
||||
os_ip.PUBLIC: 6385,
|
||||
os_ip.ADMIN: 6385,
|
||||
os_ip.INTERNAL: 6385,
|
||||
}
|
||||
}
|
||||
service_type = 'ironic'
|
||||
default_service = 'ironic-api'
|
||||
services = ['ironic-api', 'ironic-conductor']
|
||||
sync_cmd = ['ironic-dbsync', 'upgrade']
|
||||
|
||||
required_relations = [
|
||||
'shared-db', 'amqp', 'identity-service']
|
||||
|
||||
restart_map = {
|
||||
IRONIC_CONF: services,
|
||||
TFTP_CONF: ["tftp-hpa"]
|
||||
}
|
||||
|
||||
ha_resources = ['vips', 'haproxy']
|
||||
|
||||
# Package for release version detection
|
||||
release_pkg = 'ironic-common'
|
||||
|
||||
# Package codename map for ironic-common
|
||||
package_codenames = {
|
||||
'ironic-common': collections.OrderedDict([
|
||||
('14', 'train'),
|
||||
('15', 'ussuri'),
|
||||
]),
|
||||
}
|
||||
|
||||
group = "ironic"
|
||||
|
||||
def __init__(self, **kw):
|
||||
super().__init__(**kw)
|
||||
self.pxe_config = controller_utils.get_pxe_config_class(
|
||||
self.config)
|
||||
|
||||
def get_amqp_credentials(self):
|
||||
"""Provide the default amqp username and vhost as a tuple.
|
||||
|
||||
:returns (username, host): two strings to send to the amqp provider.
|
||||
"""
|
||||
return (self.config['rabbit-user'], self.config['rabbit-vhost'])
|
||||
|
||||
def get_database_setup(self):
|
||||
return [
|
||||
dict(
|
||||
database=self.config['database'],
|
||||
username=self.config['database-user'], )
|
||||
]
|
||||
|
||||
def install(self):
|
||||
super().install()
|
||||
self.pxe_config.configure_resources()
|
||||
|
||||
# def configue_tls(self, certificates_instance=None):
|
||||
# # TODO(gsamfira): add tls support
|
||||
# pass
|
|
@ -0,0 +1,27 @@
|
|||
name: ironic-api
|
||||
summary: Openstack bare metal component
|
||||
maintainer: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
|
||||
description: |
|
||||
OpenStack bare metal provisioning a.k.a Ironic is an integrated OpenStack
|
||||
program which aims to provision bare metal machines instead of virtual
|
||||
machines, forked from the Nova baremetal driver. It is best thought of
|
||||
as a bare metal hypervisor API and a set of plugins which interact with
|
||||
the bare metal hypervisors. By default, it will use PXE and IPMI in order
|
||||
to provision and turn on/off machines, but Ironic also supports
|
||||
vendor-specific plugins which may implement additional functionality.
|
||||
tags:
|
||||
- openstack
|
||||
- baremetal
|
||||
series:
|
||||
- bionic
|
||||
- focal
|
||||
extra-bindings:
|
||||
deployment:
|
||||
subordinate: false
|
||||
requires:
|
||||
shared-db:
|
||||
interface: mysql-shared
|
||||
amqp:
|
||||
interface: rabbitmq
|
||||
identity-service:
|
||||
interface: keystone
|
|
@ -0,0 +1,64 @@
|
|||
# Copyright 2018 Cloudbase Solutions
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
import charms.reactive as reactive
|
||||
import charmhelpers.core.hookenv as hookenv
|
||||
|
||||
import charms_openstack.charm as charm
|
||||
import charm.openstack.ironic.ironic as ironic # noqa
|
||||
|
||||
from charmhelpers.core.templating import render
|
||||
import charmhelpers.contrib.network.ip as ch_ip
|
||||
import charms_openstack.adapters as adapters
|
||||
|
||||
|
||||
# Use the charms.openstack defaults for common states and hooks
|
||||
charm.use_defaults(
|
||||
'charm.installed',
|
||||
'amqp.connected',
|
||||
'shared-db.connected',
|
||||
'identity-service.available', # enables SSL support
|
||||
'config.changed',
|
||||
'update-status')
|
||||
|
||||
|
||||
@reactive.when('shared-db.available')
|
||||
@reactive.when('identity-service.available')
|
||||
@reactive.when('amqp.available')
|
||||
def render_stuff(*args):
|
||||
hookenv.log("about to call the render_configs with {}".format(args))
|
||||
with charm.provide_charm_instance() as ironic_charm:
|
||||
ironic_charm.render_with_interfaces(
|
||||
charm.optional_interfaces(args))
|
||||
ironic_charm.assess_status()
|
||||
reactive.set_state('config.complete')
|
||||
|
||||
|
||||
@reactive.when('identity-service.connected')
|
||||
def setup_endpoint(keystone):
|
||||
ironic.setup_endpoint(keystone)
|
||||
ironic.assess_status()
|
||||
|
||||
|
||||
@reactive.when('config.complete')
|
||||
@reactive.when_not('db.synced')
|
||||
def run_db_migration():
|
||||
ironic.db_sync()
|
||||
ironic.restart_all()
|
||||
reactive.set_state('db.synced')
|
||||
ironic.assess_status()
|
||||
|
||||
|
||||
@reactive.when('ha.connected')
|
||||
def cluster_connected(hacluster):
|
||||
ironic.configure_ha_resources(hacluster)
|
||||
|
||||
|
||||
@adapters.config_property
|
||||
def deployment_interface_ip(self):
|
||||
return ch_ip.get_relation_ip("deployment")
|
||||
|
||||
@adapters.config_property
|
||||
def internal_interface_ip(self):
|
||||
return ch_ip.get_relation_ip("internal")
|
|
@ -0,0 +1,7 @@
|
|||
{% if not tftpboot -%}
|
||||
{% set tftpboot = "/tftpboot" -%}
|
||||
{% endif -%}
|
||||
TFTP_USERNAME="root"
|
||||
TFTP_DIRECTORY="{{ tftpboot }}"
|
||||
TFTP_ADDRESS=":69"
|
||||
TFTP_OPTIONS="--secure -4 -v -v -v -v -v --map-file {{tftpboot}}/map-file"
|
|
@ -0,0 +1,35 @@
|
|||
{% if identity_service.auth_host -%}
|
||||
{% if identity_service.api_version and identity_service.api_version == "3" %}
|
||||
{% set auth_ver = "v3" %}
|
||||
{% else %}
|
||||
{% set auth_ver = "v2.0" %}
|
||||
{% endif %}
|
||||
[keystone_authtoken]
|
||||
auth_version = {{auth_ver}}
|
||||
www_authenticate_uri = {{ identity_service.service_protocol }}://{{ identity_service.service_host }}:{{ identity_service.service_port }}/{{auth_ver}}
|
||||
auth_url = {{ identity_service.auth_protocol }}://{{ identity_service.auth_host }}:{{ identity_service.auth_port }}
|
||||
auth_type = password
|
||||
|
||||
{% if identity_service.service_domain -%}
|
||||
project_domain_name = {{ identity_service.service_domain }}
|
||||
user_domain_name = {{ identity_service.service_domain }}
|
||||
{% else %}
|
||||
project_domain_name = default
|
||||
user_domain_name = default
|
||||
{% endif -%}
|
||||
|
||||
username = {{ identity_service.service_username }}
|
||||
password = {{ identity_service.service_password }}
|
||||
project_name = {{identity_service.service_tenant}}
|
||||
|
||||
admin_user = {{ identity_service.service_username }}
|
||||
admin_password = {{ identity_service.service_password }}
|
||||
admin_tenant_name = {{identity_service.service_tenant}}
|
||||
|
||||
{% if identity_service.signing_dir -%}
|
||||
signing_dir = {{ identity_service.signing_dir }}
|
||||
{% endif -%}
|
||||
{% if options.use_memcache == true -%}
|
||||
memcached_servers = {{ options.memcache_url }}
|
||||
{% endif -%}
|
||||
{% endif -%}
|
|
@ -0,0 +1,8 @@
|
|||
[deploy]
|
||||
{% if options.use_ipxe -%}
|
||||
# Ironic compute node's http root path. (string value)
|
||||
http_root=/httpboot
|
||||
|
||||
# Ironic compute node's HTTP server URL (string value)
|
||||
http_url=http://{{ options.deployment_interface_ip }}:{{ options.ipxe_http_port}}
|
||||
{% endif -%}
|
|
@ -0,0 +1,27 @@
|
|||
[pxe]
|
||||
# Ironic compute node's tftp root path. (string value)
|
||||
tftp_root=/tftpboot
|
||||
|
||||
# IP address of Ironic compute node's tftp server. (string
|
||||
# value)
|
||||
tftp_server = {{ options.deployment_interface_ip }}
|
||||
|
||||
pxe_append_params = nofb nomodeset vga=normal console=tty0 console=ttyS0,115200n8
|
||||
|
||||
{% if options.use_ipxe -%}
|
||||
# Enable iPXE boot. (boolean value)
|
||||
ipxe_enabled=True
|
||||
|
||||
# Neutron bootfile DHCP parameter. (string value)
|
||||
pxe_bootfile_name=undionly.kpxe
|
||||
|
||||
# Bootfile DHCP parameter for UEFI boot mode. (string value)
|
||||
uefi_pxe_bootfile_name=ipxe.efi
|
||||
|
||||
# Template file for PXE configuration. (string value)
|
||||
pxe_config_template=$pybasedir/drivers/modules/ipxe_config.template
|
||||
|
||||
# Template file for PXE configuration for UEFI boot loader.
|
||||
# (string value)
|
||||
uefi_pxe_config_template=$pybasedir/drivers/modules/ipxe_config.template
|
||||
{% endif -%}
|
|
@ -0,0 +1,31 @@
|
|||
# Authentication type to load (string value)
|
||||
auth_type = password
|
||||
|
||||
# Authentication URL (string value)
|
||||
auth_url = {{ identity_service.auth_protocol }}://{{ identity_service.auth_host }}:{{ identity_service.auth_port }}
|
||||
|
||||
# Username (string value)
|
||||
username = {{ identity_service.service_username }}
|
||||
|
||||
# User's password (string value)
|
||||
password = {{ identity_service.service_password }}
|
||||
|
||||
# Project name to scope to (string value)
|
||||
project_name = {{identity_service.service_tenant}}
|
||||
|
||||
|
||||
{% if identity_service.service_domain -%}
|
||||
project_domain_name = {{ identity_service.service_domain }}
|
||||
user_domain_name = {{ identity_service.service_domain }}
|
||||
{% else -%}
|
||||
project_domain_name = default
|
||||
user_domain_name = default
|
||||
{% endif -%}
|
||||
|
||||
{% if options.ca_cert_path -%}
|
||||
# PEM encoded Certificate Authority to use when verifying
|
||||
# HTTPs connections. (string value)
|
||||
cafile = {{ options.ca_cert_path }}
|
||||
{% endif -%}
|
||||
|
||||
region_name = {{ options.region }}
|
|
@ -0,0 +1,10 @@
|
|||
{% if not tftpboot -%}
|
||||
{% set tftpboot = "/tftpboot" -%}
|
||||
{% endif -%}
|
||||
set default=master
|
||||
set timeout=5
|
||||
set hidden_timeout_quiet=false
|
||||
|
||||
menuentry "master" {
|
||||
configfile {{tftpboot}}/$net_default_ip.conf
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
re ^(/tftpboot/) /tftpboot/\2
|
||||
re ^/tftpboot/ /tftpboot/
|
||||
re ^(^/) /tftpboot/\1
|
||||
re ^([^/]) /tftpboot/\1
|
|
@ -0,0 +1,57 @@
|
|||
[DEFAULT]
|
||||
auth_strategy=keystone
|
||||
my_ip = {{ options.internal_interface_ip }}
|
||||
|
||||
enabled_deploy_interfaces = iscsi
|
||||
enabled_hardware_types = ipmi,ilo,idrac,redfish,irmc
|
||||
{% if options.use_ipxe -%}
|
||||
enabled_boot_interfaces = pxe,ipxe,ilo-pxe,ilo-ipxe,irmc-pxe
|
||||
{% else -%}
|
||||
enabled_boot_interfaces = pxe,ilo-pxe,irmc-pxe
|
||||
{% endif -%}
|
||||
enabled_management_interfaces = ipmitool,redfish,ilo,irmc,idrac
|
||||
enabled_inspect_interfaces = idrac,ilo,irmc,redfish,no-inspect
|
||||
enabled_network_interfaces = flat,neutron
|
||||
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 = neutron
|
||||
|
||||
transport_url = {{ amqp.transport_url }}
|
||||
|
||||
{% include "parts/keystone-authtoken" %}
|
||||
|
||||
[api]
|
||||
port = {{ options.service_listen_info.ironic_api.port }}
|
||||
|
||||
[database]
|
||||
{% include "parts/database" %}
|
||||
|
||||
[neutron]
|
||||
{% include "parts/service-auth" %}
|
||||
# {% if options.cleaning_network %}
|
||||
# cleaning_network = {{ options.cleaning_network }}
|
||||
# {% endif %}
|
||||
# {% if options.provisioning_network %}
|
||||
# provisioning_network = {{ options.provisioning_network }}
|
||||
# {% endif %}
|
||||
|
||||
cleaning_network = 512147a6-37ed-4ab4-ac4c-c55bb845de8e
|
||||
provisioning_network = 512147a6-37ed-4ab4-ac4c-c55bb845de8e
|
||||
|
||||
[glance]
|
||||
{% include "parts/service-auth" %}
|
||||
|
||||
[cinder]
|
||||
{% include "parts/service-auth" %}
|
||||
|
||||
[service_catalog]
|
||||
{% include "parts/service-auth" %}
|
||||
|
||||
{% include "parts/section-pxe" %}
|
||||
|
||||
{% include "parts/section-deploy" %}
|
|
@ -0,0 +1,5 @@
|
|||
#!/bin/bash
|
||||
|
||||
sudo add-apt-repository ppa:juju/stable -y
|
||||
sudo apt-get update
|
||||
sudo apt-get install amulet python-requests -y
|
|
@ -0,0 +1,35 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
import amulet
|
||||
import requests
|
||||
import unittest
|
||||
|
||||
|
||||
class TestCharm(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.d = amulet.Deployment()
|
||||
|
||||
self.d.add('charm-ironic')
|
||||
self.d.expose('charm-ironic')
|
||||
|
||||
self.d.setup(timeout=900)
|
||||
self.d.sentry.wait()
|
||||
|
||||
self.unit = self.d.sentry['charm-ironic'][0]
|
||||
|
||||
def test_service(self):
|
||||
# test we can access over http
|
||||
page = requests.get('http://{}'.format(self.unit.info['public-address']))
|
||||
self.assertEqual(page.status_code, 200)
|
||||
# Now you can use self.d.sentry[SERVICE][UNIT] to address each of the units and perform
|
||||
# more in-depth steps. Each self.d.sentry[SERVICE][UNIT] has the following methods:
|
||||
# - .info - An array of the information of that unit from Juju
|
||||
# - .file(PATH) - Get the details of a file on that unit
|
||||
# - .file_contents(PATH) - Get plain text output of PATH file from that unit
|
||||
# - .directory(PATH) - Get details of directory
|
||||
# - .directory_contents(PATH) - List files and folders in PATH on that unit
|
||||
# - .relation(relation, service:rel) - Get relation data from return service
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
Loading…
Reference in New Issue