Pythonize instack-install-undercloud
-Very incomplete testing right now -Puts the password and stackrc files in the current user's home directory during the install. Given that they now have secure permissions and we recommend doing that anyway, I think it's fine, but it is a non-trivial change in behavior. This was done because it's awkward to read a root-owned file from a Python process running as a regular user. -Uses oslo.config instead of the bash-style answers file. A sample conf file created by the oslo.config generator is included (for now, although we may want to generate that dynamically at some point). Backwards compatibility with existing answers files is maintained for now, but is deprecated. -Hard-codes the image path in instack-test-overcloud to . It's difficult to extract the value from the conf file in bash (unless they overrode the default, there's nothing for ConfigParser to read), and since it's just a simple sanity test script I think that's okay, at least for now. Change-Id: I09270997dea7fdad2b40dfb303967ff425b55a9b
This commit is contained in:
parent
bf9e96920d
commit
a82f4dc363
1
.gitignore
vendored
1
.gitignore
vendored
@ -23,6 +23,7 @@ pip-log.txt
|
|||||||
# Unit test / coverage reports
|
# Unit test / coverage reports
|
||||||
.coverage
|
.coverage
|
||||||
.tox
|
.tox
|
||||||
|
.testrepository
|
||||||
nosetests.xml
|
nosetests.xml
|
||||||
|
|
||||||
# Translations
|
# Translations
|
||||||
|
4
.testr.conf
Normal file
4
.testr.conf
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
[DEFAULT]
|
||||||
|
test_command=OS_STDOUT_CAPTURE=1 OS_STDERR_CAPTURE=1 OS_TEST_TIMEOUT=60 ${PYTHON:-python} -m subunit.run discover -t ./instack_undercloud ./instack_undercloud $LISTOPT $IDOPTION
|
||||||
|
test_id_option=--load-list $IDFILE
|
||||||
|
test_list_option=--list
|
3
config-generator/undercloud.conf
Normal file
3
config-generator/undercloud.conf
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
[DEFAULT]
|
||||||
|
output_file = undercloud.conf.sample
|
||||||
|
namespace = instack-undercloud
|
@ -28,7 +28,6 @@ Installing the Undercloud
|
|||||||
|
|
||||||
sudo hostnamectl set-hostname myhost.mydomain
|
sudo hostnamectl set-hostname myhost.mydomain
|
||||||
sudo hostnamectl set-hostname --transient myhost.mydomain
|
sudo hostnamectl set-hostname --transient myhost.mydomain
|
||||||
export HOSTNAME=myhost.mydomain
|
|
||||||
|
|
||||||
An entry for the system's FQDN hostname is also needed in /etc/hosts. For
|
An entry for the system's FQDN hostname is also needed in /etc/hosts. For
|
||||||
example, if the system is named *myhost.mydomain*, /etc/hosts should have
|
example, if the system is named *myhost.mydomain*, /etc/hosts should have
|
||||||
@ -72,9 +71,9 @@ Installing the Undercloud
|
|||||||
.. admonition:: Baremetal
|
.. admonition:: Baremetal
|
||||||
:class: baremetal
|
:class: baremetal
|
||||||
|
|
||||||
Copy in the sample answers file and edit it to reflect your environment::
|
Copy in the sample configuration file and edit it to reflect your environment::
|
||||||
|
|
||||||
cp /usr/share/instack-undercloud/instack.answers.sample ~/instack.answers
|
cp /usr/share/instack-undercloud/undercloud.conf.sample ~/undercloud.conf
|
||||||
|
|
||||||
|
|
||||||
Install the undercloud::
|
Install the undercloud::
|
||||||
@ -82,12 +81,13 @@ Installing the Undercloud
|
|||||||
openstack undercloud install
|
openstack undercloud install
|
||||||
|
|
||||||
|
|
||||||
Once the install script has run to completion, you should take note of the
|
Once the install has completed, you should take note of the files ``stackrc`` and
|
||||||
files ``/root/stackrc`` and ``/root/tripleo-undercloud-passwords``. Both of
|
``undercloud-passwords.conf``. You can source ``stackrc`` to interact with the
|
||||||
these files will be needed to interact with the installed undercloud. Copy them
|
undercloud via the OpenStack command-line client. ``undercloud-passwords.conf``
|
||||||
to the home directory for easier use later::
|
contains the passwords used for each service in the undercloud. These passwords
|
||||||
|
will be automatically reused if the undercloud is reinstalled on the same system,
|
||||||
|
so it is not necessary to copy them to ``undercloud.conf``.
|
||||||
|
|
||||||
sudo cp /root/tripleo-undercloud-passwords .
|
.. note::
|
||||||
sudo chown $USER: tripleo-undercloud-passwords
|
Any passwords set in ``undercloud.conf`` will take precedence over the ones in
|
||||||
sudo cp /root/stackrc .
|
``undercloud-passwords.conf``.
|
||||||
sudo chown $USER: stackrc
|
|
||||||
|
@ -17,7 +17,7 @@ visudo -c
|
|||||||
mkdir -p /home/stack/.ssh
|
mkdir -p /home/stack/.ssh
|
||||||
cp /tmp/in_target.d/id_rsa_virt_power /home/stack/.ssh/id_rsa_virt_power
|
cp /tmp/in_target.d/id_rsa_virt_power /home/stack/.ssh/id_rsa_virt_power
|
||||||
cp /tmp/in_target.d/id_rsa_virt_power.pub /home/stack/.ssh/id_rsa_virt_power.pub
|
cp /tmp/in_target.d/id_rsa_virt_power.pub /home/stack/.ssh/id_rsa_virt_power.pub
|
||||||
cp /tmp/in_target.d/instack.answers.sample /home/stack/instack.answers
|
cp /tmp/in_target.d/undercloud.conf.sample /home/stack/undercloud.conf
|
||||||
cp /tmp/in_target.d/$TE_DATAFILE /home/stack/instackenv.json
|
cp /tmp/in_target.d/$TE_DATAFILE /home/stack/instackenv.json
|
||||||
|
|
||||||
chown -R stack:stack /home/stack
|
chown -R stack:stack /home/stack
|
||||||
|
@ -1,161 +0,0 @@
|
|||||||
# instack answers file
|
|
||||||
|
|
||||||
### DEPLOYMENT_MODE ###
|
|
||||||
# Deployment mode to setup on this Undercloud.
|
|
||||||
# Choices are poc and scale:
|
|
||||||
# poc will allow deployment of a single role to heterogenous hardware
|
|
||||||
# scale will allow deployment of a single role only to homogenous hardware.
|
|
||||||
DEPLOYMENT_MODE=poc
|
|
||||||
|
|
||||||
### IMAGE_PATH ###
|
|
||||||
# Local file path to the downloaded images.
|
|
||||||
# The path should be a directory readable by the current user that contains
|
|
||||||
# the full set of downloaded images.
|
|
||||||
IMAGE_PATH=.
|
|
||||||
|
|
||||||
### LOCAL_IP ###
|
|
||||||
# IP address to assign to the interface on the Undercloud that will
|
|
||||||
# be handling the PXE boots and DHCP for Overcloud instances.
|
|
||||||
# LOCAL_IP will be assigned to LOCAL_INTERFACE, and must be in
|
|
||||||
# IP/PREFIX format.
|
|
||||||
LOCAL_IP=192.0.2.1/24
|
|
||||||
|
|
||||||
### LOCAL_INTERFACE ###
|
|
||||||
# Network interface on the Undercloud that will be handling the PXE boots and
|
|
||||||
# DHCP for Overcloud instances.
|
|
||||||
# LOCAL_INTERFACE will be assigned the address from LOCAL_IP
|
|
||||||
LOCAL_INTERFACE=eth1
|
|
||||||
|
|
||||||
### MASQUERADE_NETWORK ###
|
|
||||||
# Network that will be masqueraded for external access if required.
|
|
||||||
MASQUERADE_NETWORK=192.0.2.0/24
|
|
||||||
|
|
||||||
### DHCP_START ###
|
|
||||||
# Start of DHCP Allocation range for PXE and DHCP of Overcloud instances
|
|
||||||
DHCP_START=192.0.2.5
|
|
||||||
|
|
||||||
### DHCP_END ###
|
|
||||||
# End of DHCP Allocation range for PXE and DHCP of Overcloud instances
|
|
||||||
DHCP_END=192.0.2.24
|
|
||||||
|
|
||||||
### NETWORK_CIDR ###
|
|
||||||
# Network cidr for neutron managed network for Overcloud instances
|
|
||||||
NETWORK_CIDR=192.0.2.0/24
|
|
||||||
|
|
||||||
### NETWORK_GATEWAY ###
|
|
||||||
# Network gateway for neturon managed network for Overcloud instances
|
|
||||||
NETWORK_GATEWAY=192.0.2.1
|
|
||||||
|
|
||||||
### DISCOVERY_INTERFACE ###
|
|
||||||
# Network interface on which discovery dnsmasq will listen
|
|
||||||
# If in doubt, do not change
|
|
||||||
DISCOVERY_INTERFACE=br-ctlplane
|
|
||||||
|
|
||||||
### DISCOVERY_IPRANGE ###
|
|
||||||
# Temporary IP range that will be given to nodes during discovery process
|
|
||||||
# Should not overlap with Neutron range, but should be in the same network
|
|
||||||
DISCOVERY_IPRANGE=192.0.2.100,192.0.2.120
|
|
||||||
|
|
||||||
### DISCOVERY_RUNBENCH ###
|
|
||||||
# Determines whether benchmarks are run when discovering nodes
|
|
||||||
# Set to 1 to enable
|
|
||||||
DISCOVERY_RUNBENCH=0
|
|
||||||
|
|
||||||
### UNDERCLOUD_DEBUG ###
|
|
||||||
# Whether to enable the debug log level for OpenStack services
|
|
||||||
UNDERCLOUD_DEBUG=true
|
|
||||||
|
|
||||||
### Database password ###
|
|
||||||
# Password used for MySQL databases
|
|
||||||
# If left unset, one will be automatically generated
|
|
||||||
UNDERCLOUD_DB_PASSWORD=
|
|
||||||
|
|
||||||
### Admin Token ###
|
|
||||||
# Keystone admin token
|
|
||||||
# If left unset, one will be automatically generated
|
|
||||||
UNDERCLOUD_ADMIN_TOKEN=
|
|
||||||
|
|
||||||
### Admin password ###
|
|
||||||
# Keystone admin password
|
|
||||||
# If left unset, one will be automatically generated
|
|
||||||
UNDERCLOUD_ADMIN_PASSWORD=
|
|
||||||
|
|
||||||
### Glance password ###
|
|
||||||
# Glance service password
|
|
||||||
# If left unset, one will be automatically generated
|
|
||||||
UNDERCLOUD_GLANCE_PASSWORD=
|
|
||||||
|
|
||||||
### Heat password ###
|
|
||||||
# Heat service password
|
|
||||||
# If left unset, one will be automatically generated
|
|
||||||
UNDERCLOUD_HEAT_PASSWORD=
|
|
||||||
|
|
||||||
### Neutron password ###
|
|
||||||
# Neutron service password
|
|
||||||
# If left unset, one will be automatically generated
|
|
||||||
UNDERCLOUD_NEUTRON_PASSWORD=
|
|
||||||
|
|
||||||
### Nova password ###
|
|
||||||
# Nova service password
|
|
||||||
# If left unset, one will be automatically generated
|
|
||||||
UNDERCLOUD_NOVA_PASSWORD=
|
|
||||||
|
|
||||||
### Ironic password ###
|
|
||||||
# Ironic service password
|
|
||||||
# If left unset, one will be automatically generated
|
|
||||||
UNDERCLOUD_IRONIC_PASSWORD=
|
|
||||||
|
|
||||||
### Tuskar password ###
|
|
||||||
# Tuskar service password
|
|
||||||
# If left unset, one will be automatically generated
|
|
||||||
UNDERCLOUD_TUSKAR_PASSWORD=
|
|
||||||
|
|
||||||
### Ceilometer password ###
|
|
||||||
# Ceilometer service password
|
|
||||||
# If left unset, one will be automatically generated
|
|
||||||
UNDERCLOUD_CEILOMETER_PASSWORD=
|
|
||||||
|
|
||||||
### Ceilometer metering secret ###
|
|
||||||
# Ceilometer metering secret
|
|
||||||
# If left unset, one will be automatically generated
|
|
||||||
UNDERCLOUD_CEILOMETER_METERING_SECRET=
|
|
||||||
|
|
||||||
### Ceilometer snmpd user ###
|
|
||||||
# Ceilometer snmpd user
|
|
||||||
# If left unset, one will be automatically generated
|
|
||||||
UNDERCLOUD_CEILOMETER_SNMPD_USER=
|
|
||||||
|
|
||||||
### Ceilometer snmpd password ###
|
|
||||||
# Ceilometer snmpd password
|
|
||||||
# If left unset, one will be automatically generated
|
|
||||||
UNDERCLOUD_CEILOMETER_SNMPD_PASSWORD=
|
|
||||||
|
|
||||||
### Swift password ###
|
|
||||||
# Swift password
|
|
||||||
# If left unset, one will be automatically generated
|
|
||||||
UNDERCLOUD_SWIFT_PASSWORD=
|
|
||||||
|
|
||||||
### Rabbit Cookie ###
|
|
||||||
# Rabbit Cookie
|
|
||||||
# If left unset, one will be automatically generated
|
|
||||||
UNDERCLOUD_RABBIT_COOKIE=
|
|
||||||
|
|
||||||
### Rabbit Password ###
|
|
||||||
# Rabbit Password
|
|
||||||
# If left unset, one will be automatically generated
|
|
||||||
UNDERCLOUD_RABBIT_PASSWORD=
|
|
||||||
|
|
||||||
### Rabbit Username ###
|
|
||||||
# Rabbit Username
|
|
||||||
# If left unset, one will be automatically generated
|
|
||||||
UNDERCLOUD_RABBIT_USERNAME=
|
|
||||||
|
|
||||||
### Heat Stack Domain Admin Password ###
|
|
||||||
# Heat Stack Domain Admin Password
|
|
||||||
# If left unset, one will be automatically generated
|
|
||||||
UNDERCLOUD_HEAT_STACK_DOMAIN_ADMIN_PASSWORD=
|
|
||||||
|
|
||||||
### Swift Hash Suffix ###
|
|
||||||
# Swift Hash Suffix
|
|
||||||
# If left unset, one will be automatically generated
|
|
||||||
UNDERCLOUD_SWIFT_HASH_SUFFIX=
|
|
0
instack_undercloud/__init__.py
Normal file
0
instack_undercloud/__init__.py
Normal file
0
instack_undercloud/tests/__init__.py
Normal file
0
instack_undercloud/tests/__init__.py
Normal file
98
instack_undercloud/tests/test_undercloud.py
Normal file
98
instack_undercloud/tests/test_undercloud.py
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
# Copyright 2015 Red Hat Inc.
|
||||||
|
#
|
||||||
|
# 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 io
|
||||||
|
|
||||||
|
import fixtures
|
||||||
|
import mock
|
||||||
|
from oslotest import base
|
||||||
|
|
||||||
|
from instack_undercloud import undercloud
|
||||||
|
|
||||||
|
# TODO(bnemec): Test all the things
|
||||||
|
# TODO(bnemec): Stop the code from logging to the real log file during tests
|
||||||
|
|
||||||
|
|
||||||
|
class TestUndercloud(base.BaseTestCase):
|
||||||
|
@mock.patch('instack_undercloud.undercloud._check_hostname')
|
||||||
|
@mock.patch('instack_undercloud.undercloud._run_command')
|
||||||
|
@mock.patch('instack_undercloud.undercloud._configure_ssh_keys')
|
||||||
|
@mock.patch('instack_undercloud.undercloud._run_orc')
|
||||||
|
@mock.patch('instack_undercloud.undercloud._run_instack')
|
||||||
|
@mock.patch('instack_undercloud.undercloud._generate_environment')
|
||||||
|
@mock.patch('instack_undercloud.undercloud._load_config')
|
||||||
|
def test_install(self, mock_load_config, mock_generate_environment,
|
||||||
|
mock_run_instack, mock_run_orc, mock_configure_ssh_keys,
|
||||||
|
mock_run_command, mock_check_hostname):
|
||||||
|
fake_env = mock.MagicMock()
|
||||||
|
mock_generate_environment.return_value = fake_env
|
||||||
|
undercloud.install('.')
|
||||||
|
mock_generate_environment.assert_called_with('.')
|
||||||
|
mock_run_instack.assert_called_with(fake_env)
|
||||||
|
mock_run_orc.assert_called_with(fake_env)
|
||||||
|
mock_run_command.assert_called_with(
|
||||||
|
['sudo', 'rm', '-f', '/tmp/svc-map-services'], None, 'rm')
|
||||||
|
|
||||||
|
|
||||||
|
class TestCheckHostname(base.BaseTestCase):
|
||||||
|
@mock.patch('instack_undercloud.undercloud._run_command')
|
||||||
|
def test_correct(self, mock_run_command):
|
||||||
|
mock_run_command.side_effect = ['test-hostname', 'test-hostname']
|
||||||
|
self.useFixture(fixtures.EnvironmentVariable('HOSTNAME',
|
||||||
|
'test-hostname'))
|
||||||
|
fake_hosts = io.StringIO(u'127.0.0.1 test-hostname\n')
|
||||||
|
with mock.patch('instack_undercloud.undercloud.open',
|
||||||
|
return_value=fake_hosts, create=True):
|
||||||
|
undercloud._check_hostname()
|
||||||
|
|
||||||
|
@mock.patch('instack_undercloud.undercloud._run_command')
|
||||||
|
def test_static_transient_mismatch(self, mock_run_command):
|
||||||
|
mock_run_command.side_effect = ['test-hostname', 'other-hostname']
|
||||||
|
self.useFixture(fixtures.EnvironmentVariable('HOSTNAME',
|
||||||
|
'test-hostname'))
|
||||||
|
fake_hosts = io.StringIO(u'127.0.0.1 test-hostname\n')
|
||||||
|
with mock.patch('instack_undercloud.undercloud.open',
|
||||||
|
return_value=fake_hosts, create=True):
|
||||||
|
self.assertRaises(RuntimeError, undercloud._check_hostname)
|
||||||
|
|
||||||
|
@mock.patch('instack_undercloud.undercloud._run_command')
|
||||||
|
def test_missing_entry(self, mock_run_command):
|
||||||
|
mock_run_command.side_effect = ['test-hostname', 'test-hostname']
|
||||||
|
self.useFixture(fixtures.EnvironmentVariable('HOSTNAME',
|
||||||
|
'test-hostname'))
|
||||||
|
fake_hosts = io.StringIO(u'127.0.0.1 other-hostname\n')
|
||||||
|
with mock.patch('instack_undercloud.undercloud.open',
|
||||||
|
return_value=fake_hosts, create=True):
|
||||||
|
self.assertRaises(RuntimeError, undercloud._check_hostname)
|
||||||
|
|
||||||
|
@mock.patch('instack_undercloud.undercloud._run_command')
|
||||||
|
def test_no_substring_match(self, mock_run_command):
|
||||||
|
mock_run_command.side_effect = ['test-hostname', 'test-hostname']
|
||||||
|
self.useFixture(fixtures.EnvironmentVariable('HOSTNAME',
|
||||||
|
'test-hostname'))
|
||||||
|
fake_hosts = io.StringIO(u'127.0.0.1 test-hostname-bad\n')
|
||||||
|
with mock.patch('instack_undercloud.undercloud.open',
|
||||||
|
return_value=fake_hosts, create=True):
|
||||||
|
self.assertRaises(RuntimeError, undercloud._check_hostname)
|
||||||
|
|
||||||
|
@mock.patch('instack_undercloud.undercloud._run_command')
|
||||||
|
def test_commented(self, mock_run_command):
|
||||||
|
mock_run_command.side_effect = ['test-hostname', 'test-hostname']
|
||||||
|
self.useFixture(fixtures.EnvironmentVariable('HOSTNAME',
|
||||||
|
'test-hostname'))
|
||||||
|
fake_hosts = io.StringIO(u""" #127.0.0.1 test-hostname\n
|
||||||
|
127.0.0.1 other-hostname\n""")
|
||||||
|
with mock.patch('instack_undercloud.undercloud.open',
|
||||||
|
return_value=fake_hosts, create=True):
|
||||||
|
self.assertRaises(RuntimeError, undercloud._check_hostname)
|
511
instack_undercloud/undercloud.py
Normal file
511
instack_undercloud/undercloud.py
Normal file
@ -0,0 +1,511 @@
|
|||||||
|
# Copyright 2015 Red Hat Inc.
|
||||||
|
#
|
||||||
|
# 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 ConfigParser
|
||||||
|
import copy
|
||||||
|
import errno
|
||||||
|
import getpass
|
||||||
|
import hashlib
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import platform
|
||||||
|
import socket
|
||||||
|
import StringIO
|
||||||
|
import subprocess
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
from novaclient import client as novaclient
|
||||||
|
from novaclient import exceptions
|
||||||
|
from oslo_config import cfg
|
||||||
|
import six
|
||||||
|
|
||||||
|
|
||||||
|
CONF_PATH = os.path.expanduser('~/undercloud.conf')
|
||||||
|
# NOTE(bnemec): Deprecated
|
||||||
|
ANSWERS_PATH = os.path.expanduser('~/instack.answers')
|
||||||
|
PASSWORD_PATH = os.path.expanduser('~/undercloud-passwords.conf')
|
||||||
|
LOG_FILE = os.path.expanduser('~/.instack/install-undercloud.log')
|
||||||
|
DEFAULT_LOG_LEVEL = logging.DEBUG
|
||||||
|
DEFAULT_LOG_FORMAT = '%(asctime)s %(levelname)s: %(message)s'
|
||||||
|
try:
|
||||||
|
os.makedirs(os.path.dirname(LOG_FILE))
|
||||||
|
except OSError as e:
|
||||||
|
if e.errno != errno.EEXIST:
|
||||||
|
raise
|
||||||
|
logging.basicConfig(filename=LOG_FILE,
|
||||||
|
format=DEFAULT_LOG_FORMAT,
|
||||||
|
level=DEFAULT_LOG_LEVEL)
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
LOG.addHandler(logging.StreamHandler())
|
||||||
|
CONF = cfg.CONF
|
||||||
|
COMPLETION_MESSAGE = """
|
||||||
|
#############################################################################
|
||||||
|
instack-install-undercloud complete.
|
||||||
|
|
||||||
|
The file containing this installation's passwords is at
|
||||||
|
%(password_path)s.
|
||||||
|
|
||||||
|
There is also a stackrc file at %(stackrc_path)s.
|
||||||
|
|
||||||
|
These files are needed to interact with the OpenStack services, and should be
|
||||||
|
secured.
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
# When adding new options to the lists below, make sure to regenerate the
|
||||||
|
# sample config by running "tox -e genconfig" in the project root.
|
||||||
|
_opts = [
|
||||||
|
cfg.StrOpt('deployment_mode',
|
||||||
|
default='poc',
|
||||||
|
choices=['poc', 'scale'],
|
||||||
|
help=('Deployment mode for this undercloud. "poc" will allow '
|
||||||
|
'deployment of a single role to heterogenous hardware. '
|
||||||
|
'"scale" will allow deployment of a single role only to '
|
||||||
|
'homogenous hardware.'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
cfg.StrOpt('image_path',
|
||||||
|
default='.',
|
||||||
|
help=('Local file path to the necessary images. The path '
|
||||||
|
'should be a directory readable by the current user '
|
||||||
|
'that contains the full set of images.'),
|
||||||
|
),
|
||||||
|
cfg.StrOpt('local_ip',
|
||||||
|
default='192.0.2.1/24',
|
||||||
|
help=('IP information for the interface on the Undercloud '
|
||||||
|
'that will be handling the PXE boots and DHCP for '
|
||||||
|
'Overcloud instances. The IP portion of the value will '
|
||||||
|
'be assigned to the network interface defined by '
|
||||||
|
'local_interface, with the netmask defined by the '
|
||||||
|
'prefix portion of the value.')
|
||||||
|
),
|
||||||
|
cfg.StrOpt('local_interface',
|
||||||
|
default='eth1',
|
||||||
|
help=('Network interface on the Undercloud that will be '
|
||||||
|
'handling the PXE boots and DHCP for Overcloud '
|
||||||
|
'instances.')
|
||||||
|
),
|
||||||
|
cfg.StrOpt('masquerade_network',
|
||||||
|
default='192.0.2.0/24',
|
||||||
|
help=('Network that will be masqueraded for external access, '
|
||||||
|
'if required.')
|
||||||
|
),
|
||||||
|
cfg.StrOpt('dhcp_start',
|
||||||
|
default='192.0.2.5',
|
||||||
|
help=('Start of DHCP allocation range for PXE and DHCP of '
|
||||||
|
'Overcloud instances.')
|
||||||
|
),
|
||||||
|
cfg.StrOpt('dhcp_end',
|
||||||
|
default='192.0.2.24',
|
||||||
|
help=('End of DHCP allocation range for PXE and DHCP of '
|
||||||
|
'Overcloud instances.')
|
||||||
|
),
|
||||||
|
cfg.StrOpt('network_cidr',
|
||||||
|
default='192.0.2.0/24',
|
||||||
|
help=('Network CIDR for the Neutron-managed network for '
|
||||||
|
'Overcloud instances.')
|
||||||
|
),
|
||||||
|
cfg.StrOpt('network_gateway',
|
||||||
|
default='192.0.2.1',
|
||||||
|
help=('Network gateway for the Neutron-managed network for '
|
||||||
|
'Overcloud instances.')
|
||||||
|
),
|
||||||
|
cfg.StrOpt('discovery_interface',
|
||||||
|
default='br-ctlplane',
|
||||||
|
help=('Network interface on which discovery dnsmasq will '
|
||||||
|
'listen. If in doubt, use the default value.')
|
||||||
|
),
|
||||||
|
cfg.StrOpt('discovery_iprange',
|
||||||
|
default='192.0.2.100,192.0.2.120',
|
||||||
|
help=('Temporary IP range that will be given to nodes during '
|
||||||
|
'the discovery process. Should not overlap with the '
|
||||||
|
'range defined by dhcp_start and dhcp_end, but should '
|
||||||
|
'be in the same network.')
|
||||||
|
),
|
||||||
|
cfg.BoolOpt('discovery_runbench',
|
||||||
|
default=False,
|
||||||
|
help='Whether to run benchmarks when discovering nodes.'
|
||||||
|
),
|
||||||
|
cfg.BoolOpt('undercloud_debug',
|
||||||
|
default=True,
|
||||||
|
help=('Whether to enable the debug log level for Undercloud '
|
||||||
|
'OpenStack services.')
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
# Passwords, tokens, hashes
|
||||||
|
_auth_opts = [
|
||||||
|
cfg.StrOpt('undercloud_db_password',
|
||||||
|
help=('Password used for MySQL databases. '
|
||||||
|
'If left unset, one will be automatically generated.')
|
||||||
|
),
|
||||||
|
cfg.StrOpt('undercloud_admin_token',
|
||||||
|
help=('Keystone admin token. '
|
||||||
|
'If left unset, one will be automatically generated.')
|
||||||
|
),
|
||||||
|
cfg.StrOpt('undercloud_admin_password',
|
||||||
|
help=('Keystone admin password. '
|
||||||
|
'If left unset, one will be automatically generated.')
|
||||||
|
),
|
||||||
|
cfg.StrOpt('undercloud_glance_password',
|
||||||
|
help=('Glance service password. '
|
||||||
|
'If left unset, one will be automatically generated.')
|
||||||
|
),
|
||||||
|
cfg.StrOpt('undercloud_heat_password',
|
||||||
|
help=('Heat service password. '
|
||||||
|
'If left unset, one will be automatically generated.')
|
||||||
|
),
|
||||||
|
cfg.StrOpt('undercloud_neutron_password',
|
||||||
|
help=('Neutron service password. '
|
||||||
|
'If left unset, one will be automatically generated.')
|
||||||
|
),
|
||||||
|
cfg.StrOpt('undercloud_nova_password',
|
||||||
|
help=('Nova service password. '
|
||||||
|
'If left unset, one will be automatically generated.')
|
||||||
|
),
|
||||||
|
cfg.StrOpt('undercloud_ironic_password',
|
||||||
|
help=('Ironic service password. '
|
||||||
|
'If left unset, one will be automatically generated.')
|
||||||
|
),
|
||||||
|
cfg.StrOpt('undercloud_tuskar_password',
|
||||||
|
help=('Tuskar service password. '
|
||||||
|
'If left unset, one will be automatically generated.')
|
||||||
|
),
|
||||||
|
cfg.StrOpt('undercloud_ceilometer_password',
|
||||||
|
help=('Ceilometer service password. '
|
||||||
|
'If left unset, one will be automatically generated.')
|
||||||
|
),
|
||||||
|
cfg.StrOpt('undercloud_ceilometer_metering_secret',
|
||||||
|
help=('Ceilometer metering secret. '
|
||||||
|
'If left unset, one will be automatically generated.')
|
||||||
|
),
|
||||||
|
cfg.StrOpt('undercloud_ceilometer_snmpd_user',
|
||||||
|
help=('Ceilometer snmpd user. '
|
||||||
|
'If left unset, one will be automatically generated.')
|
||||||
|
),
|
||||||
|
cfg.StrOpt('undercloud_ceilometer_snmpd_password',
|
||||||
|
help=('Ceilometer snmpd password. '
|
||||||
|
'If left unset, one will be automatically generated.')
|
||||||
|
),
|
||||||
|
cfg.StrOpt('undercloud_swift_password',
|
||||||
|
help=('Swift service password. '
|
||||||
|
'If left unset, one will be automatically generated.')
|
||||||
|
),
|
||||||
|
cfg.StrOpt('undercloud_rabbit_cookie',
|
||||||
|
help=('Rabbitmq cookie. '
|
||||||
|
'If left unset, one will be automatically generated.')
|
||||||
|
),
|
||||||
|
cfg.StrOpt('undercloud_rabbit_password',
|
||||||
|
default='guest',
|
||||||
|
help='Rabbitmq password.'
|
||||||
|
),
|
||||||
|
cfg.StrOpt('undercloud_rabbit_username',
|
||||||
|
default='guest',
|
||||||
|
help='Rabbitmq username.'
|
||||||
|
),
|
||||||
|
cfg.StrOpt('undercloud_heat_stack_domain_admin_password',
|
||||||
|
help=('Heat stack domain admin password. '
|
||||||
|
'If left unset, one will be automatically generated.')
|
||||||
|
),
|
||||||
|
cfg.StrOpt('undercloud_swift_hash_suffix',
|
||||||
|
help=('Swift hash suffix. '
|
||||||
|
'If left unset, one will be automatically generated.')
|
||||||
|
),
|
||||||
|
]
|
||||||
|
CONF.register_opts(_opts)
|
||||||
|
CONF.register_opts(_auth_opts, group='auth')
|
||||||
|
|
||||||
|
|
||||||
|
def list_opts():
|
||||||
|
return [(None, copy.deepcopy(_opts)),
|
||||||
|
('auth', copy.deepcopy(_auth_opts)),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def _load_config():
|
||||||
|
conf_params = []
|
||||||
|
if os.path.isfile(PASSWORD_PATH):
|
||||||
|
conf_params += ['--config-file', PASSWORD_PATH]
|
||||||
|
if os.path.isfile(CONF_PATH):
|
||||||
|
conf_params += ['--config-file', CONF_PATH]
|
||||||
|
CONF(conf_params)
|
||||||
|
|
||||||
|
|
||||||
|
def _run_command(args, env=None, name=None):
|
||||||
|
"""Run the command defined by args and return its output
|
||||||
|
|
||||||
|
:param args: List of arguments for the command to be run.
|
||||||
|
:param env: Dict defining the environment variables. Pass None to use
|
||||||
|
the current environment.
|
||||||
|
:param name: User-friendly name for the command being run. A value of
|
||||||
|
None will cause args[0] to be used.
|
||||||
|
"""
|
||||||
|
if name is None:
|
||||||
|
name = args[0]
|
||||||
|
try:
|
||||||
|
return subprocess.check_output(args,
|
||||||
|
stderr=subprocess.STDOUT,
|
||||||
|
env=env)
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
LOG.error('%s failed: %s', name, e.output)
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
def _run_live_command(args, env=None, name=None):
|
||||||
|
"""Run the command defined by args and log its output
|
||||||
|
|
||||||
|
Takes the same arguments as _run_command, but runs the process
|
||||||
|
asynchronously so the output can be logged while the process is still
|
||||||
|
running.
|
||||||
|
"""
|
||||||
|
process = subprocess.Popen(args, env=env,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.STDOUT)
|
||||||
|
while True:
|
||||||
|
line = process.stdout.readline()
|
||||||
|
if line:
|
||||||
|
LOG.info(line.rstrip())
|
||||||
|
if line == '' and process.poll() is not None:
|
||||||
|
break
|
||||||
|
if process.returncode != 0:
|
||||||
|
raise RuntimeError('%s failed. See log for details.', name)
|
||||||
|
|
||||||
|
|
||||||
|
def _check_hostname():
|
||||||
|
"""Check system hostname configuration
|
||||||
|
|
||||||
|
Rabbit requires a pretty specific hostname configuration. This attempts
|
||||||
|
to verify the configuration is correct before continuing with
|
||||||
|
installation.
|
||||||
|
"""
|
||||||
|
LOG.info('Checking for a FQDN hostname...')
|
||||||
|
args = ['sudo', 'hostnamectl', '--static']
|
||||||
|
detected_static_hostname = _run_command(args, name='hostnamectl').rstrip()
|
||||||
|
LOG.info('Static hostname detected as %s', detected_static_hostname)
|
||||||
|
args = ['sudo', 'hostnamectl', '--transient']
|
||||||
|
detected_transient_hostname = _run_command(args,
|
||||||
|
name='hostnamectl').rstrip()
|
||||||
|
LOG.info('Transient hostname detected as %s', detected_transient_hostname)
|
||||||
|
if detected_static_hostname != detected_transient_hostname:
|
||||||
|
LOG.error('Static hostname "%s" does not match transient hostname '
|
||||||
|
'"%s".', detected_static_hostname,
|
||||||
|
detected_transient_hostname)
|
||||||
|
LOG.error('Use hostnamectl to set matching hostnames.')
|
||||||
|
raise RuntimeError('Static and transient hostnames do not match')
|
||||||
|
with open('/etc/hosts') as hosts_file:
|
||||||
|
for line in hosts_file:
|
||||||
|
if (not line.lstrip().startswith('#') and
|
||||||
|
detected_static_hostname in line.split()):
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
LOG.error('Static hostname not set in /etc/hosts.')
|
||||||
|
LOG.error('Please add a line to /etc/hosts for the static '
|
||||||
|
'hostname.')
|
||||||
|
raise RuntimeError('Static hostname not set in /etc/hosts')
|
||||||
|
|
||||||
|
|
||||||
|
def _generate_password():
|
||||||
|
"""Create a random password
|
||||||
|
|
||||||
|
Copied from rdomanager-oscplugin. This should eventually live in
|
||||||
|
tripleo-common.
|
||||||
|
"""
|
||||||
|
uuid_str = six.text_type(uuid.uuid1()).encode("UTF-8")
|
||||||
|
return hashlib.sha1(uuid_str).hexdigest()
|
||||||
|
|
||||||
|
|
||||||
|
def _generate_environment(instack_root):
|
||||||
|
"""Generate an environment dict for instack
|
||||||
|
|
||||||
|
The returned dict will have the necessary values for use as the env
|
||||||
|
parameter when calling instack via the subprocess module.
|
||||||
|
|
||||||
|
:param instack_root: The path containing the instack-undercloud elements
|
||||||
|
and json files.
|
||||||
|
"""
|
||||||
|
instack_env = os.environ
|
||||||
|
# Rabbit uses HOSTNAME, so we need to make sure it's right
|
||||||
|
instack_env['HOSTNAME'] = socket.gethostname()
|
||||||
|
|
||||||
|
# Find the paths we need
|
||||||
|
json_file_dir = '/usr/share/instack-undercloud/json-files'
|
||||||
|
if not os.path.isdir(json_file_dir):
|
||||||
|
json_file_dir = os.path.join(instack_root, 'json-files')
|
||||||
|
instack_undercloud_elements = '/usr/share/instack-undercloud'
|
||||||
|
if not os.path.isdir(instack_undercloud_elements):
|
||||||
|
instack_undercloud_elements = os.path.join(instack_root, 'elements')
|
||||||
|
tripleo_puppet_elements = '/usr/share/tripleo-puppet-elements'
|
||||||
|
if not os.path.isdir(tripleo_puppet_elements):
|
||||||
|
tripleo_puppet_elements = os.path.join(os.getcwd(),
|
||||||
|
'tripleo-puppet-elements',
|
||||||
|
'elements')
|
||||||
|
if 'ELEMENTS_PATH' in os.environ:
|
||||||
|
instack_env['ELEMENTS_PATH'] = os.environ['ELEMENTS_PATH']
|
||||||
|
else:
|
||||||
|
instack_env['ELEMENTS_PATH'] = (
|
||||||
|
'%s:%s:'
|
||||||
|
'/usr/share/tripleo-image-elements:'
|
||||||
|
'/usr/share/diskimage-builder/elements'
|
||||||
|
) % (tripleo_puppet_elements, instack_undercloud_elements)
|
||||||
|
|
||||||
|
# Distro-specific values
|
||||||
|
distro = platform.linux_distribution()[0]
|
||||||
|
if distro.startswith('Red Hat Enterprise Linux'):
|
||||||
|
instack_env['NODE_DIST'] = os.environ.get('NODE_DIST') or 'rhel7'
|
||||||
|
instack_env['JSONFILE'] = (
|
||||||
|
os.environ.get('JSONFILE') or
|
||||||
|
os.path.join(json_file_dir, 'rhel-7-undercloud-packages.json')
|
||||||
|
)
|
||||||
|
instack_env['REG_METHOD'] = 'disable'
|
||||||
|
instack_env['REG_HALT_UNREGISTER'] = '1'
|
||||||
|
elif distro.startswith('CentOS'):
|
||||||
|
instack_env['NODE_DIST'] = os.environ.get('NODE_DIST') or 'centos7'
|
||||||
|
instack_env['JSONFILE'] = (
|
||||||
|
os.environ.get('JSONFILE') or
|
||||||
|
os.path.join(json_file_dir, 'centos-7-undercloud-packages.json')
|
||||||
|
)
|
||||||
|
elif distro.startswith('Fedora'):
|
||||||
|
instack_env['NODE_DIST'] = os.environ.get('NODE_DIST') or 'fedora'
|
||||||
|
raise Exception('Fedora is not currently supported')
|
||||||
|
else:
|
||||||
|
raise Exception('%s is not supported' % distro)
|
||||||
|
|
||||||
|
# Do some fiddling to retain answers file support for now
|
||||||
|
answers_parser = ConfigParser.ConfigParser()
|
||||||
|
if os.path.isfile(ANSWERS_PATH):
|
||||||
|
config_answers = StringIO.StringIO()
|
||||||
|
config_answers.write('[answers]\n')
|
||||||
|
with open(ANSWERS_PATH) as f:
|
||||||
|
config_answers.write(f.read())
|
||||||
|
config_answers.seek(0)
|
||||||
|
answers_parser.readfp(config_answers)
|
||||||
|
|
||||||
|
# Convert conf opts to env values
|
||||||
|
for opt in _opts:
|
||||||
|
env_name = opt.name.upper()
|
||||||
|
if answers_parser.has_option('answers', env_name):
|
||||||
|
LOG.warning('Using value for %s from instack.answers. This '
|
||||||
|
'behavior is deprecated. undercloud.conf should '
|
||||||
|
'now be used for configuration.', env_name)
|
||||||
|
instack_env[env_name] = answers_parser.get('answers', env_name)
|
||||||
|
else:
|
||||||
|
instack_env[env_name] = six.text_type(CONF[opt.name])
|
||||||
|
# Opts that needs extra processing
|
||||||
|
if instack_env['DISCOVERY_RUNBENCH'] not in ['0', '1']:
|
||||||
|
instack_env['DISCOVERY_RUNBENCH'] = ('1' if CONF.discovery_runbench
|
||||||
|
else '0')
|
||||||
|
instack_env['PUBLIC_INTERFACE_IP'] = instack_env['LOCAL_IP']
|
||||||
|
instack_env['LOCAL_IP'] = instack_env['LOCAL_IP'].split('/')[0]
|
||||||
|
with open(PASSWORD_PATH, 'w') as password_file:
|
||||||
|
password_file.write('[auth]\n')
|
||||||
|
for opt in _auth_opts:
|
||||||
|
env_name = opt.name.upper()
|
||||||
|
if answers_parser.has_option('answers', env_name):
|
||||||
|
LOG.warning('Using value for %s from instack.answers. This '
|
||||||
|
'behavior is deprecated. undercloud.conf should '
|
||||||
|
'now be used for configuration.', env_name)
|
||||||
|
value = answers_parser.get('answers', env_name)
|
||||||
|
else:
|
||||||
|
value = CONF.auth[opt.name]
|
||||||
|
if not value:
|
||||||
|
value = _generate_password()
|
||||||
|
LOG.info('Generated new password for %s', opt.name)
|
||||||
|
instack_env[env_name] = value
|
||||||
|
password_file.write('%s=%s\n' % (opt.name, value))
|
||||||
|
|
||||||
|
return instack_env
|
||||||
|
|
||||||
|
|
||||||
|
def _run_instack(instack_env):
|
||||||
|
args = ['sudo', '-E', 'instack', '-p', instack_env['ELEMENTS_PATH'],
|
||||||
|
'-j', instack_env['JSONFILE'],
|
||||||
|
]
|
||||||
|
LOG.info('Running instack')
|
||||||
|
_run_live_command(args, instack_env, 'instack')
|
||||||
|
LOG.info('Instack completed successfully')
|
||||||
|
|
||||||
|
|
||||||
|
def _run_orc(instack_env):
|
||||||
|
args = ['sudo', 'os-refresh-config']
|
||||||
|
LOG.info('Running os-refresh-config')
|
||||||
|
_run_live_command(args, instack_env, 'os-refresh-config')
|
||||||
|
LOG.info('os-refresh-config completed successfully')
|
||||||
|
|
||||||
|
|
||||||
|
def _extract_from_stackrc(name):
|
||||||
|
"""Extract authentication values from stackrc
|
||||||
|
|
||||||
|
:param name: The value to be extracted. For example: OS_USERNAME or
|
||||||
|
OS_AUTH_URL.
|
||||||
|
"""
|
||||||
|
with open(os.path.expanduser('~/stackrc')) as f:
|
||||||
|
for line in f:
|
||||||
|
if name in line:
|
||||||
|
parts = line.split('=')
|
||||||
|
return parts[1].rstrip()
|
||||||
|
|
||||||
|
|
||||||
|
def _configure_ssh_keys():
|
||||||
|
"""Configure default ssh keypair in Nova
|
||||||
|
|
||||||
|
Generates a new ssh key for the current user if one does not already
|
||||||
|
exist, then uploads that to Nova as the 'default' keypair.
|
||||||
|
"""
|
||||||
|
id_path = os.path.expanduser('~/.ssh/id_rsa')
|
||||||
|
if not os.path.isfile(id_path):
|
||||||
|
args = ['ssh-keygen', '-t', 'rsa', '-N', '', '-f', id_path]
|
||||||
|
_run_command(args)
|
||||||
|
LOG.info('Generated new ssh key in ~/.ssh/id_rsa')
|
||||||
|
|
||||||
|
args = ['sudo', 'cp', '/root/stackrc', os.path.expanduser('~')]
|
||||||
|
_run_command(args, name='Copy stackrc')
|
||||||
|
args = ['sudo', 'chown', getpass.getuser() + ':',
|
||||||
|
os.path.expanduser('~/stackrc')]
|
||||||
|
_run_command(args, name='Chown stackrc')
|
||||||
|
password = _run_command(['hiera', 'admin_password']).rstrip()
|
||||||
|
user = _extract_from_stackrc('OS_USERNAME')
|
||||||
|
auth_url = _extract_from_stackrc('OS_AUTH_URL')
|
||||||
|
tenant = _extract_from_stackrc('OS_TENANT')
|
||||||
|
nova = novaclient.Client(2, user, password, tenant, auth_url)
|
||||||
|
try:
|
||||||
|
nova.keypairs.get('default')
|
||||||
|
except exceptions.NotFound:
|
||||||
|
with open(id_path + '.pub') as pubkey:
|
||||||
|
nova.keypairs.create('default', pubkey.read().rstrip())
|
||||||
|
|
||||||
|
|
||||||
|
def install(instack_root):
|
||||||
|
"""Install the undercloud
|
||||||
|
|
||||||
|
:param instack_root: The path containing the instack-undercloud elements
|
||||||
|
and json files.
|
||||||
|
"""
|
||||||
|
LOG.info('Logging to %s', LOG_FILE)
|
||||||
|
_load_config()
|
||||||
|
_check_hostname()
|
||||||
|
instack_env = _generate_environment(instack_root)
|
||||||
|
_run_instack(instack_env)
|
||||||
|
# NOTE(bnemec): I removed the conditional running of os-refresh-config.
|
||||||
|
# To my knowledge it wasn't really being used anymore, and if we do still
|
||||||
|
# need it, it should be reimplemented as a client parameter instead of
|
||||||
|
# an input env var.
|
||||||
|
# TODO(bnemec): Do we still need INSTACK_ROOT?
|
||||||
|
instack_env['INSTACK_ROOT'] = os.environ.get('INSTACK_ROOT') or ''
|
||||||
|
_run_orc(instack_env)
|
||||||
|
_configure_ssh_keys()
|
||||||
|
_run_command(['sudo', 'rm', '-f', '/tmp/svc-map-services'], None, 'rm')
|
||||||
|
LOG.info(COMPLETION_MESSAGE, {'password_path': PASSWORD_PATH,
|
||||||
|
'stackrc_path': os.path.expanduser('~/stackrc')})
|
3
requirements.txt
Normal file
3
requirements.txt
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
six>=1.9.0
|
||||||
|
python-novaclient
|
||||||
|
oslo.config
|
@ -13,9 +13,6 @@ export TRIPLEO_ROOT=${TRIPLEO_ROOT:-"/etc/tripleo"}
|
|||||||
export NODES_JSON=${NODES_JSON:-"instackenv.json"}
|
export NODES_JSON=${NODES_JSON:-"instackenv.json"}
|
||||||
export TE_DATAFILE=$NODES_JSON
|
export TE_DATAFILE=$NODES_JSON
|
||||||
|
|
||||||
echo "Sourcing answers file from instack.answers..."
|
|
||||||
source ~/instack.answers
|
|
||||||
|
|
||||||
source tripleo-overcloud-passwords
|
source tripleo-overcloud-passwords
|
||||||
|
|
||||||
OVERCLOUD_ENDPOINT=$(heat output-show overcloud KeystoneURL|sed 's/^"\(.*\)"$/\1/')
|
OVERCLOUD_ENDPOINT=$(heat output-show overcloud KeystoneURL|sed 's/^"\(.*\)"$/\1/')
|
||||||
|
@ -74,9 +74,9 @@ fi
|
|||||||
|
|
||||||
source tripleo-overcloud-passwords
|
source tripleo-overcloud-passwords
|
||||||
|
|
||||||
# Undercloud passwords must all be sourced into this script since we make use
|
# NOTE(bnemec): Hopefully this script will eventually be converted to
|
||||||
# of $UNDERCLOUD_CEILOMETER_SNMPD_PASSWORD below
|
# Python and then we can kill this sort of hackery.
|
||||||
source tripleo-undercloud-passwords
|
UNDERCLOUD_CEILOMETER_SNMPD_PASSWORD=$(python -c "import ConfigParser; p = ConfigParser.ConfigParser(); p.read('undercloud-passwords.conf'); print(p.get('auth', 'undercloud_ceilometer_snmpd_password'))")
|
||||||
|
|
||||||
NeutronFlatNetworks=${NeutronFlatNetworks:-'datacentre'}
|
NeutronFlatNetworks=${NeutronFlatNetworks:-'datacentre'}
|
||||||
NeutronPhysicalBridge=${NeutronPhysicalBridge:-'br-ex'}
|
NeutronPhysicalBridge=${NeutronPhysicalBridge:-'br-ex'}
|
||||||
|
@ -1,170 +1,3 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
set -eu
|
python -c "from instack_undercloud import undercloud; undercloud.install('$(dirname $0)/..')"
|
||||||
|
|
||||||
mkdir -p ~/.instack
|
|
||||||
LOGFILE=~/.instack/install-undercloud.log
|
|
||||||
|
|
||||||
exec > >(tee $LOGFILE)
|
|
||||||
exec 2>&1
|
|
||||||
|
|
||||||
echo "Running $0"
|
|
||||||
|
|
||||||
echo "Checking for a FQDN hostname..."
|
|
||||||
detected_static_hostname=$(sudo hostnamectl --static)
|
|
||||||
echo "static hostname detected as...$detected_static_hostname"
|
|
||||||
detected_transient_hostname=$(sudo hostnamectl --transient)
|
|
||||||
echo "transient hostname detected as...$detected_transient_hostname"
|
|
||||||
echo "\$HOSTNAME detected as...$HOSTNAME"
|
|
||||||
|
|
||||||
if [ ! "$detected_static_hostname" = "$detected_transient_hostname" ]; then
|
|
||||||
echo "static hostname does not match transient hostname"
|
|
||||||
echo "Use hostnamectl to set matching hostnames."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ ! "$detected_static_hostname" = "$HOSTNAME" ]; then
|
|
||||||
echo "static hostname does not match \$HOSTNAME"
|
|
||||||
echo "Set \$HOSTNAME to match or relogin so $HOSTNAME is redefined."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! grep -E "\s+$detected_static_hostname(\s|$)+" /etc/hosts; then
|
|
||||||
echo "static hostname not set in /etc/hosts"
|
|
||||||
echo "Please add a line to /etc/hosts for the static hostname."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Attempt to be smart about detecting the path to the json files.
|
|
||||||
JSONFILEDIR=/usr/share/instack-undercloud/json-files
|
|
||||||
if [ ! -d "$JSONFILEDIR" ]; then
|
|
||||||
JSONFILEDIR=$(dirname $0)/../json-files
|
|
||||||
fi
|
|
||||||
|
|
||||||
if $(grep -Eqs 'Red Hat Enterprise Linux' /etc/redhat-release); then
|
|
||||||
export NODE_DIST=${NODE_DIST:-rhel7}
|
|
||||||
export JSONFILE=${JSONFILE:-$JSONFILEDIR/rhel-7-undercloud-packages.json}
|
|
||||||
export REG_METHOD=disable
|
|
||||||
export REG_HALT_UNREGISTER=1
|
|
||||||
elif $(grep -Eqs 'CentOS' /etc/redhat-release); then
|
|
||||||
export NODE_DIST=${NODE_DIST:-centos7}
|
|
||||||
export JSONFILE=${JSONFILE:-$JSONFILEDIR/centos-7-undercloud-packages.json}
|
|
||||||
elif $(grep -Eqs 'Fedora' /etc/redhat-release); then
|
|
||||||
export NODE_DIST=${NODE_DIST:-fedora}
|
|
||||||
echo "Fedora not currently supported"
|
|
||||||
exit 1
|
|
||||||
else
|
|
||||||
echo "Could not detect distritubion from /etc/redhat-release!"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Attempt to be smart about detecting the patch to the instack-undercloud
|
|
||||||
# elements
|
|
||||||
INSTACKUNDERCLOUDELEMENTS=/usr/share/instack-undercloud
|
|
||||||
if [ ! -d $INSTACKUNDERCLOUDELEMENTS ]; then
|
|
||||||
INSTACKUNDERCLOUDELEMENTS=$(dirname $0)/../elements
|
|
||||||
fi
|
|
||||||
|
|
||||||
TRIPLEOPUPPETELEMENTS=/usr/share/tripleo-puppet-elements
|
|
||||||
if [ ! -d $TRIPLEOPUPPETELEMENTS ]; then
|
|
||||||
# Assume it's checked out in the current directory
|
|
||||||
TRIPLEOPUPPETELEMENTS=$PWD/tripleo-puppet-elements/elements
|
|
||||||
fi
|
|
||||||
|
|
||||||
export ELEMENTS_PATH=${ELEMENTS_PATH:-"\
|
|
||||||
$TRIPLEOPUPPETELEMENTS:\
|
|
||||||
$INSTACKUNDERCLOUDELEMENTS:\
|
|
||||||
/usr/share/tripleo-image-elements:\
|
|
||||||
/usr/share/diskimage-builder/elements"}
|
|
||||||
|
|
||||||
echo "Sourcing answers file from instack.answers..."
|
|
||||||
source ~/instack.answers
|
|
||||||
|
|
||||||
# Munge up LOCAL_IP.
|
|
||||||
export PUBLIC_INTERFACE_IP="$LOCAL_IP"
|
|
||||||
export LOCAL_IP="${LOCAL_IP%/*}"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export IMAGE_PATH
|
|
||||||
export LOCAL_INTERFACE
|
|
||||||
export MASQUERADE_NETWORK
|
|
||||||
export DHCP_START
|
|
||||||
export DHCP_END
|
|
||||||
export NETWORK_CIDR
|
|
||||||
export NETWORK_GATEWAY
|
|
||||||
export DISCOVERY_INTERFACE
|
|
||||||
export DISCOVERY_IPRANGE
|
|
||||||
export DISCOVERY_RUNBENCH
|
|
||||||
export UNDERCLOUD_DEBUG
|
|
||||||
|
|
||||||
# Reuse any existing defined passwords. This is important since any users
|
|
||||||
# defined in Keystone already have passwords set. So we don't want to generate
|
|
||||||
# new ones that end up as values in configuration files.
|
|
||||||
if sudo bash -c '[[ -f /root/tripleo-undercloud-passwords ]]'; then
|
|
||||||
source <(sudo cat /root/tripleo-undercloud-passwords)
|
|
||||||
fi
|
|
||||||
|
|
||||||
export UNDERCLOUD_HEAT_STACK_DOMAIN_ADMIN_PASSWORD=${UNDERCLOUD_HEAT_STACK_DOMAIN_ADMIN_PASSWORD:-$(tripleo os-make-password)}
|
|
||||||
export UNDERCLOUD_RABBIT_COOKIE=${UNDERCLOUD_RABBIT_COOKIE:-$(tripleo os-make-password)}
|
|
||||||
export UNDERCLOUD_RABBIT_PASSWORD=${UNDERCLOUD_RABBIT_PASSWORD:-guest}
|
|
||||||
export UNDERCLOUD_RABBIT_USERNAME=${UNDERCLOUD_RABBIT_USERNAME:-guest}
|
|
||||||
export UNDERCLOUD_SWIFT_HASH_SUFFIX=${UNDERCLOUD_SWIFT_HASH_SUFFIX:-$(tripleo os-make-password)}
|
|
||||||
export UNDERCLOUD_ADMIN_PASSWORD=${UNDERCLOUD_ADMIN_PASSWORD:-$(tripleo os-make-password)}
|
|
||||||
export UNDERCLOUD_ADMIN_TOKEN=${UNDERCLOUD_ADMIN_TOKEN:-$(tripleo os-make-password)}
|
|
||||||
export UNDERCLOUD_CEILOMETER_METERING_SECRET=${UNDERCLOUD_CEILOMETER_METERING_SECRET:-$(tripleo os-make-password)}
|
|
||||||
export UNDERCLOUD_CEILOMETER_PASSWORD=${UNDERCLOUD_CEILOMETER_PASSWORD:-$(tripleo os-make-password)}
|
|
||||||
export UNDERCLOUD_CEILOMETER_SNMPD_PASSWORD=${UNDERCLOUD_CEILOMETER_SNMPD_PASSWORD:-$(tripleo os-make-password)}
|
|
||||||
export UNDERCLOUD_CEILOMETER_SNMPD_USER=${UNDERCLOUD_CEILOMETER_SNMPD_USER:-$(tripleo os-make-password)}
|
|
||||||
export UNDERCLOUD_GLANCE_PASSWORD=${UNDERCLOUD_GLANCE_PASSWORD:-$(tripleo os-make-password)}
|
|
||||||
export UNDERCLOUD_HEAT_PASSWORD=${UNDERCLOUD_HEAT_PASSWORD:-$(tripleo os-make-password)}
|
|
||||||
export UNDERCLOUD_HORIZON_SECRET_KEY=${UNDERCLOUD_HORIZON_SECRET_KEY:-$(tripleo os-make-password)}
|
|
||||||
export UNDERCLOUD_IRONIC_PASSWORD=${UNDERCLOUD_IRONIC_PASSWORD:-$(tripleo os-make-password)}
|
|
||||||
export UNDERCLOUD_NEUTRON_PASSWORD=${UNDERCLOUD_NEUTRON_PASSWORD:-$(tripleo os-make-password)}
|
|
||||||
export UNDERCLOUD_NOVA_PASSWORD=${UNDERCLOUD_NOVA_PASSWORD:-$(tripleo os-make-password)}
|
|
||||||
export UNDERCLOUD_SWIFT_PASSWORD=${UNDERCLOUD_SWIFT_PASSWORD:-$(tripleo os-make-password)}
|
|
||||||
export UNDERCLOUD_TUSKAR_PASSWORD=${UNDERCLOUD_TUSKAR_PASSWORD:-$(tripleo os-make-password)}
|
|
||||||
|
|
||||||
sudo -E instack \
|
|
||||||
-p $ELEMENTS_PATH \
|
|
||||||
-j $JSONFILE
|
|
||||||
|
|
||||||
RUN_ORC=${RUN_ORC:-"1"}
|
|
||||||
export INSTACK_ROOT=${INSTACK_ROOT:-""}
|
|
||||||
if [ "$RUN_ORC" = "1" ]; then
|
|
||||||
sudo INSTACK_ROOT=$INSTACK_ROOT IMAGE_PATH=$IMAGE_PATH os-refresh-config
|
|
||||||
|
|
||||||
# generate ssh authentication keys if they don't exist
|
|
||||||
if [ ! -f ~/.ssh/id_rsa ]; then
|
|
||||||
ssh-keygen -t rsa -N "" -f ~/.ssh/id_rsa
|
|
||||||
fi
|
|
||||||
|
|
||||||
source <(sudo cat /root/stackrc)
|
|
||||||
if ! nova keypair-show default 2>/dev/null; then
|
|
||||||
tripleo user-config
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# This is owned by root, which can break later image builds as a regular user
|
|
||||||
sudo rm -f /tmp/svc-map-services
|
|
||||||
|
|
||||||
export COMPLETION_MESSAGE=${COMPLETION_MESSAGE:-"\
|
|
||||||
#############################################################################
|
|
||||||
instack-install-undercloud complete.
|
|
||||||
|
|
||||||
The file containing this installation's passwords is at
|
|
||||||
/root/tripleo-undercloud-passwords.
|
|
||||||
|
|
||||||
There is also a stackrc file at /root/stackrc.
|
|
||||||
|
|
||||||
These files are needed to interact with the OpenStack services, and should be
|
|
||||||
secured. For convenience, they can be copied to the current directory:
|
|
||||||
|
|
||||||
sudo cp /root/tripleo-undercloud-passwords .
|
|
||||||
sudo chown $USER: tripleo-undercloud-passwords
|
|
||||||
sudo cp /root/stackrc .
|
|
||||||
sudo chown $USER: stackrc
|
|
||||||
|
|
||||||
#############################################################################"}
|
|
||||||
|
|
||||||
echo "$COMPLETION_MESSAGE"
|
|
||||||
|
@ -2,9 +2,10 @@
|
|||||||
|
|
||||||
set -eux
|
set -eux
|
||||||
|
|
||||||
instack-create-overcloudrc
|
|
||||||
source ~/overcloudrc
|
source ~/overcloudrc
|
||||||
source ~/instack.answers
|
# TODO(bnemec): Hard-coding this to . for now because it's tricky to extract
|
||||||
|
# the value from the new conf file when not using oslo.config.
|
||||||
|
IMAGE_PATH='.'
|
||||||
|
|
||||||
# tripleo os-adduser -p $OVERCLOUD_DEMO_PASSWORD demo demo@example.com
|
# tripleo os-adduser -p $OVERCLOUD_DEMO_PASSWORD demo demo@example.com
|
||||||
|
|
||||||
|
@ -11,11 +11,11 @@ export LIBVIRT_DEFAULT_URI="qemu:///system"
|
|||||||
|
|
||||||
if [ ! -d "/usr/share/instack-undercloud" ]; then
|
if [ ! -d "/usr/share/instack-undercloud" ]; then
|
||||||
DEVTEST_VARIABLES=/usr/libexec/openstack-tripleo/devtest_variables.sh
|
DEVTEST_VARIABLES=/usr/libexec/openstack-tripleo/devtest_variables.sh
|
||||||
export ANSWERSFILE=$(dirname $0)/../instack.answers.sample
|
export ANSWERSFILE=$(dirname $0)/../undercloud.conf.sample
|
||||||
export ELEMENTS_PATH="$(realpath $(dirname $0)/../elements):/usr/share/tripleo-image-elements:/usr/share/diskimage-builder/elements"
|
export ELEMENTS_PATH="$(realpath $(dirname $0)/../elements):/usr/share/tripleo-image-elements:/usr/share/diskimage-builder/elements"
|
||||||
else
|
else
|
||||||
DEVTEST_VARIABLES=/usr/libexec/openstack-tripleo/devtest_variables.sh
|
DEVTEST_VARIABLES=/usr/libexec/openstack-tripleo/devtest_variables.sh
|
||||||
export ANSWERSFILE=/usr/share/instack-undercloud/instack.answers.sample
|
export ANSWERSFILE=/usr/share/instack-undercloud/undercloud.conf.sample
|
||||||
export ELEMENTS_PATH="/usr/share/instack-undercloud:/usr/share/tripleo-image-elements:/usr/share/diskimage-builder/elements"
|
export ELEMENTS_PATH="/usr/share/instack-undercloud:/usr/share/tripleo-image-elements:/usr/share/diskimage-builder/elements"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -20,6 +20,9 @@ classifier =
|
|||||||
Programming Language :: Python :: 3.3
|
Programming Language :: Python :: 3.3
|
||||||
|
|
||||||
[files]
|
[files]
|
||||||
|
packages =
|
||||||
|
instack_undercloud
|
||||||
|
|
||||||
scripts =
|
scripts =
|
||||||
scripts/instack-build-images
|
scripts/instack-build-images
|
||||||
scripts/instack-create-overcloudrc
|
scripts/instack-create-overcloudrc
|
||||||
@ -35,5 +38,9 @@ data_files =
|
|||||||
share/instack-undercloud/heat-templates = heat-templates/*
|
share/instack-undercloud/heat-templates = heat-templates/*
|
||||||
share/instack-undercloud/json-files = json-files/*
|
share/instack-undercloud/json-files = json-files/*
|
||||||
share/instack-undercloud/jenkins-jobs = jenkins-jobs/*
|
share/instack-undercloud/jenkins-jobs = jenkins-jobs/*
|
||||||
share/instack-undercloud/ = instack.answers.sample
|
share/instack-undercloud/ = undercloud.conf.sample
|
||||||
share/instack-undercloud/ = deploy-baremetal-overcloudrc
|
share/instack-undercloud/ = deploy-baremetal-overcloudrc
|
||||||
|
|
||||||
|
[entry_points]
|
||||||
|
oslo.config.opts =
|
||||||
|
instack-undercloud = instack_undercloud.undercloud:list_opts
|
||||||
|
@ -2,3 +2,15 @@
|
|||||||
sphinx>=1.1.2,!=1.2.0,!=1.3b1,<1.3
|
sphinx>=1.1.2,!=1.2.0,!=1.3b1,<1.3
|
||||||
oslosphinx>=2.2.0 # Apache-2.0
|
oslosphinx>=2.2.0 # Apache-2.0
|
||||||
sphinx_rtd_theme==0.1.7
|
sphinx_rtd_theme==0.1.7
|
||||||
|
|
||||||
|
hacking>=0.10.0,<0.11
|
||||||
|
|
||||||
|
discover
|
||||||
|
fixtures>=0.3.14
|
||||||
|
python-subunit>=0.0.18
|
||||||
|
testrepository>=0.0.18
|
||||||
|
testscenarios>=0.4
|
||||||
|
testtools>=0.9.36,!=1.2.0
|
||||||
|
mock>=1.0
|
||||||
|
oslotest>=1.5.1 # Apache-2.0
|
||||||
|
bashate
|
||||||
|
16
tox.ini
16
tox.ini
@ -1,12 +1,14 @@
|
|||||||
[tox]
|
[tox]
|
||||||
minversion = 1.6
|
minversion = 1.6
|
||||||
skipsdist = True
|
skipsdist = True
|
||||||
|
envlist = py34,py27,pep8
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
usedevelop = True
|
usedevelop = True
|
||||||
install_command = pip install {opts} {packages}
|
|
||||||
setenv = VIRTUAL_ENV={envdir}
|
setenv = VIRTUAL_ENV={envdir}
|
||||||
deps = -r{toxinidir}/test-requirements.txt
|
deps = -r{toxinidir}/test-requirements.txt
|
||||||
|
-r{toxinidir}/requirements.txt
|
||||||
|
commands = python setup.py testr --slowest --testr-args='{posargs}'
|
||||||
|
|
||||||
[testenv:venv]
|
[testenv:venv]
|
||||||
commands = {posargs}
|
commands = {posargs}
|
||||||
@ -16,10 +18,16 @@ commands = sphinx-build -a -t external doc/source/ build/sphinx/html
|
|||||||
sphinx-build -a -t internal doc/source/ build/sphinx/internal-html
|
sphinx-build -a -t internal doc/source/ build/sphinx/internal-html
|
||||||
|
|
||||||
[testenv:pep8]
|
[testenv:pep8]
|
||||||
deps = bashate
|
|
||||||
whitelist_externals = bash
|
whitelist_externals = bash
|
||||||
commands = bash -c "find scripts -type f | xargs bashate -v"
|
# We fail pretty horribly on bashate right now
|
||||||
|
#commands = bash -c "find scripts -type f | xargs bashate -v"
|
||||||
|
# flake8
|
||||||
|
commands = flake8
|
||||||
|
|
||||||
[flake8]
|
[flake8]
|
||||||
ignore = H803
|
ignore = H803
|
||||||
exclude = .tox
|
show-source = True
|
||||||
|
exclude = .tox,dist,doc,*.egg,build
|
||||||
|
|
||||||
|
[testenv:genconfig]
|
||||||
|
commands = oslo-config-generator --config-file config-generator/undercloud.conf
|
||||||
|
145
undercloud.conf.sample
Normal file
145
undercloud.conf.sample
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
[DEFAULT]
|
||||||
|
|
||||||
|
#
|
||||||
|
# From instack-undercloud
|
||||||
|
#
|
||||||
|
|
||||||
|
# Deployment mode for this undercloud. "poc" will allow deployment of
|
||||||
|
# a single role to heterogenous hardware. "scale" will allow
|
||||||
|
# deployment of a single role only to homogenous hardware. (string
|
||||||
|
# value)
|
||||||
|
# Allowed values: poc, scale
|
||||||
|
#deployment_mode = poc
|
||||||
|
|
||||||
|
# Local file path to the necessary images. The path should be a
|
||||||
|
# directory readable by the current user that contains the full set of
|
||||||
|
# images. (string value)
|
||||||
|
#image_path = .
|
||||||
|
|
||||||
|
# IP information for the interface on the Undercloud that will be
|
||||||
|
# handling the PXE boots and DHCP for Overcloud instances. The IP
|
||||||
|
# portion of the value will be assigned to the network interface
|
||||||
|
# defined by local_interface, with the netmask defined by the prefix
|
||||||
|
# portion of the value. (string value)
|
||||||
|
#local_ip = 192.0.2.1/24
|
||||||
|
|
||||||
|
# Network interface on the Undercloud that will be handling the PXE
|
||||||
|
# boots and DHCP for Overcloud instances. (string value)
|
||||||
|
#local_interface = eth1
|
||||||
|
|
||||||
|
# Network that will be masqueraded for external access, if required.
|
||||||
|
# (string value)
|
||||||
|
#masquerade_network = 192.0.2.0/24
|
||||||
|
|
||||||
|
# Start of DHCP allocation range for PXE and DHCP of Overcloud
|
||||||
|
# instances. (string value)
|
||||||
|
#dhcp_start = 192.0.2.5
|
||||||
|
|
||||||
|
# End of DHCP allocation range for PXE and DHCP of Overcloud
|
||||||
|
# instances. (string value)
|
||||||
|
#dhcp_end = 192.0.2.24
|
||||||
|
|
||||||
|
# Network CIDR for the Neutron-managed network for Overcloud
|
||||||
|
# instances. (string value)
|
||||||
|
#network_cidr = 192.0.2.0/24
|
||||||
|
|
||||||
|
# Network gateway for the Neutron-managed network for Overcloud
|
||||||
|
# instances. (string value)
|
||||||
|
#network_gateway = 192.0.2.1
|
||||||
|
|
||||||
|
# Network interface on which discovery dnsmasq will listen. If in
|
||||||
|
# doubt, use the default value. (string value)
|
||||||
|
#discovery_interface = br-ctlplane
|
||||||
|
|
||||||
|
# Temporary IP range that will be given to nodes during the discovery
|
||||||
|
# process. Should not overlap with the range defined by dhcp_start
|
||||||
|
# and dhcp_end, but should be in the same network. (string value)
|
||||||
|
#discovery_iprange = 192.0.2.100,192.0.2.120
|
||||||
|
|
||||||
|
# Whether to run benchmarks when discovering nodes. (boolean value)
|
||||||
|
#discovery_runbench = false
|
||||||
|
|
||||||
|
# Whether to enable the debug log level for Undercloud OpenStack
|
||||||
|
# services. (boolean value)
|
||||||
|
#undercloud_debug = true
|
||||||
|
|
||||||
|
|
||||||
|
[auth]
|
||||||
|
|
||||||
|
#
|
||||||
|
# From instack-undercloud
|
||||||
|
#
|
||||||
|
|
||||||
|
# Password used for MySQL databases. If left unset, one will be
|
||||||
|
# automatically generated. (string value)
|
||||||
|
#undercloud_db_password = <None>
|
||||||
|
|
||||||
|
# Keystone admin token. If left unset, one will be automatically
|
||||||
|
# generated. (string value)
|
||||||
|
#undercloud_admin_token = <None>
|
||||||
|
|
||||||
|
# Keystone admin password. If left unset, one will be automatically
|
||||||
|
# generated. (string value)
|
||||||
|
#undercloud_admin_password = <None>
|
||||||
|
|
||||||
|
# Glance service password. If left unset, one will be automatically
|
||||||
|
# generated. (string value)
|
||||||
|
#undercloud_glance_password = <None>
|
||||||
|
|
||||||
|
# Heat service password. If left unset, one will be automatically
|
||||||
|
# generated. (string value)
|
||||||
|
#undercloud_heat_password = <None>
|
||||||
|
|
||||||
|
# Neutron service password. If left unset, one will be automatically
|
||||||
|
# generated. (string value)
|
||||||
|
#undercloud_neutron_password = <None>
|
||||||
|
|
||||||
|
# Nova service password. If left unset, one will be automatically
|
||||||
|
# generated. (string value)
|
||||||
|
#undercloud_nova_password = <None>
|
||||||
|
|
||||||
|
# Ironic service password. If left unset, one will be automatically
|
||||||
|
# generated. (string value)
|
||||||
|
#undercloud_ironic_password = <None>
|
||||||
|
|
||||||
|
# Tuskar service password. If left unset, one will be automatically
|
||||||
|
# generated. (string value)
|
||||||
|
#undercloud_tuskar_password = <None>
|
||||||
|
|
||||||
|
# Ceilometer service password. If left unset, one will be
|
||||||
|
# automatically generated. (string value)
|
||||||
|
#undercloud_ceilometer_password = <None>
|
||||||
|
|
||||||
|
# Ceilometer metering secret. If left unset, one will be automatically
|
||||||
|
# generated. (string value)
|
||||||
|
#undercloud_ceilometer_metering_secret = <None>
|
||||||
|
|
||||||
|
# Ceilometer snmpd user. If left unset, one will be automatically
|
||||||
|
# generated. (string value)
|
||||||
|
#undercloud_ceilometer_snmpd_user = <None>
|
||||||
|
|
||||||
|
# Ceilometer snmpd password. If left unset, one will be automatically
|
||||||
|
# generated. (string value)
|
||||||
|
#undercloud_ceilometer_snmpd_password = <None>
|
||||||
|
|
||||||
|
# Swift service password. If left unset, one will be automatically
|
||||||
|
# generated. (string value)
|
||||||
|
#undercloud_swift_password = <None>
|
||||||
|
|
||||||
|
# Rabbitmq cookie. If left unset, one will be automatically generated.
|
||||||
|
# (string value)
|
||||||
|
#undercloud_rabbit_cookie = <None>
|
||||||
|
|
||||||
|
# Rabbitmq password. (string value)
|
||||||
|
#undercloud_rabbit_password = guest
|
||||||
|
|
||||||
|
# Rabbitmq username. (string value)
|
||||||
|
#undercloud_rabbit_username = guest
|
||||||
|
|
||||||
|
# Heat stack domain admin password. If left unset, one will be
|
||||||
|
# automatically generated. (string value)
|
||||||
|
#undercloud_heat_stack_domain_admin_password = <None>
|
||||||
|
|
||||||
|
# Swift hash suffix. If left unset, one will be automatically
|
||||||
|
# generated. (string value)
|
||||||
|
#undercloud_swift_hash_suffix = <None>
|
Loading…
Reference in New Issue
Block a user