novajoin/scripts/novajoin-install

317 lines
11 KiB
Python
Executable File

#!/usr/bin/python
# Copyright 2016 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 argparse
import logging
import os
import pwd
import shutil
import sys
import time
import getpass
from ipapython.ipautil import run, user_input
from ipalib import api
from ipalib import errors
from novajoin.errors import ConfigurationError
from novajoin import configure_ipa
from six.moves.configparser import SafeConfigParser, NoOptionError
from urllib3.util import parse_url
IPACONF = '/etc/ipa/default.conf'
NOVACONF = '/etc/nova/nova.conf'
NOVACPUCONF = '/etc/nova/nova-cpu.conf'
NEUTRONCONF = '/etc/neutron/neutron.conf'
JOINCONF = '/etc/novajoin/join.conf'
LOGFILE = '/var/log/novajoin-install.log'
logger = logging.getLogger()
def openlogs():
global logger # pylint: disable=W0603
if os.path.isfile(LOGFILE):
try:
created = '%s' % time.strftime(
'%Y%m%d%H%M%SZ', time.gmtime(os.path.getctime(LOGFILE)))
shutil.move(LOGFILE, '%s.%s' % (LOGFILE, created))
except IOError:
pass
logger = logging.getLogger()
try:
lh = logging.FileHandler(LOGFILE)
except IOError as e:
print >> sys.stderr, 'Unable to open %s (%s)' % (LOGFILE, str(e))
lh = logging.StreamHandler(sys.stderr)
formatter = logging.Formatter('[%(asctime)s] %(message)s')
lh.setFormatter(formatter)
lh.setLevel(logging.DEBUG)
logger.addHandler(lh)
logger.propagate = False
ch = logging.StreamHandler(sys.stdout)
formatter = logging.Formatter('%(message)s')
ch.setFormatter(formatter)
ch.setLevel(logging.INFO)
logger.addHandler(ch)
def install(opts):
logger.info('Installation initiated')
if not os.path.exists(opts.ipa_conf):
raise ConfigurationError('Must be enrolled in IPA')
try:
os.environ['OS_PASSWORD']
os.environ['OS_USERNAME']
os.environ['OS_AUTH_URL']
except KeyError as e:
raise ConfigurationError('%s environment variable not set.'
% e.message)
try:
pwd.getpwnam(opts.user)
except KeyError:
raise ConfigurationError('User: %s not found on the system' %
opts.user)
api.bootstrap(context='novajoin')
api.finalize()
novajoin = configure_ipa.NovajoinRole(user=opts.user)
if not opts.no_kinit:
novajoin.kinit(opts.principal, api.env.realm, opts.password)
try:
api.Backend.rpcclient.connect()
except errors.CCacheError:
raise ConfigurationError("No Kerberos credentials")
logger.info('Installing default config files')
keystone_url = parse_url(opts.keystone_auth_url)
config = SafeConfigParser()
config.read(opts.novajoin_conf)
config.set('DEFAULT', 'domain', api.env.domain) # pylint: disable=no-member
config.set('DEFAULT',
'api_paste_config',
'/etc/novajoin/join-api-paste.ini')
config.set('DEFAULT',
'log_dir',
'/var/log/novajoin')
if not config.has_section('service_credentials'):
config.add_section('service_credentials')
config.set('service_credentials', 'auth_url', opts.keystone_auth_url)
config.set('service_credentials', 'password', opts.nova_password)
config.set('service_credentials', 'username', 'nova')
config.set('service_credentials', 'auth_type', 'password')
config.set('service_credentials', 'project_domain_name', 'default')
config.set('service_credentials', 'project_name', opts.project_name)
config.set('service_credentials', 'user_domain_id', 'default')
if not config.has_section('keystone_authtoken'):
config.add_section('keystone_authtoken')
config.set('keystone_authtoken', 'memcached_servers',
'%s:11211' % keystone_url.hostname)
config.set('keystone_authtoken', 'project_name', opts.project_name)
config.set('keystone_authtoken', 'password', opts.nova_password)
config.set('keystone_authtoken', 'username', 'nova')
config.set('keystone_authtoken', 'auth_url', opts.keystone_auth_url)
config.set('keystone_authtoken', 'auth_type', 'password')
config.set('keystone_authtoken', 'project_domain_name', 'default')
config.set('keystone_authtoken', 'user_domain_id', 'default')
with open(opts.novajoin_conf, 'w') as f:
config.write(f)
config = SafeConfigParser()
config.read(opts.nova_conf)
config.set('DEFAULT',
'vendordata_jsonfile_path',
'/etc/novajoin/cloud-config-novajoin.json')
# set the default domain to the IPA domain. This is added to the
# instance name to set the hostname.
config.set('DEFAULT',
'dhcp_domain',
api.env.domain)
# Novajoin service
config.set('DEFAULT',
'vendordata_providers',
'StaticJSON, DynamicJSON')
config.set('DEFAULT',
'vendordata_dynamic_targets',
'join@http://127.0.0.1:9090/v1/')
if not config.has_section('vendordata_dynamic_auth'):
config.add_section('vendordata_dynamic_auth')
config.set('vendordata_dynamic_auth', 'project_name', opts.project_name)
config.set('vendordata_dynamic_auth', 'password', opts.nova_password)
config.set('vendordata_dynamic_auth', 'username', 'nova')
config.set('vendordata_dynamic_auth', 'auth_url', opts.keystone_auth_url)
config.set('vendordata_dynamic_auth', 'auth_type', 'password')
config.set('vendordata_dynamic_auth', 'project_domain_name', 'default')
config.set('vendordata_dynamic_auth', 'user_domain_id', 'default')
try:
transport_url = config.get('DEFAULT', 'transport_url')
except NoOptionError:
transport_url = None
with open(opts.nova_conf, 'w') as f:
config.write(f)
# Notifications
for conf in set([opts.nova_conf, opts.nova_cpu_conf]):
config = SafeConfigParser()
config.read(conf)
if not config.has_section('notifications'):
config.add_section('notifications')
config.set('notifications',
'notify_on_state_change',
'vm_state')
config.set('notifications',
'notification_format',
'unversioned')
config.set('oslo_messaging_notifications',
'topics',
'notifications,novajoin_notifications')
with open(conf, 'w') as f:
config.write(f)
config = SafeConfigParser()
config.read(opts.neutron_conf)
config.set('oslo_messaging_notifications',
'driver',
'messagingv2')
config.set('oslo_messaging_notifications',
'topics',
'notifications,novajoin_notifications')
with open(opts.neutron_conf, 'w') as f:
config.write(f)
if transport_url:
join_config = SafeConfigParser()
join_config.read(opts.novajoin_conf)
join_config.set('DEFAULT', 'transport_url', transport_url)
with open(opts.novajoin_conf, 'w') as f:
join_config.write(f)
logger.info('Importing IPA metadata')
(stdout, stderr, returncode) = run(
['glance',
'--os-image-api-version',
'2',
'md-namespace-import',
'--file',
'/usr/share/novajoin/freeipa.json'], raiseonerr=False)
if returncode != 0:
logger.error('Adding IPA metadata failed: %s' % stderr)
logger.info('Creating IPA permissions')
novajoin.configure_ipa(precreate=False)
def parse_args():
parser = argparse.ArgumentParser(description='Nova join Install Options')
parser.add_argument('--keystone-auth-url', dest='keystone_auth_url',
help='Keystone auth URL', default=None)
parser.add_argument('--nova-password', dest='nova_password',
help='Nova service user password', default=None)
parser.add_argument('--project', dest='project_name',
help='Keystone project', default='service')
parser.add_argument('--ipa-conf', dest='ipa_conf',
help='IPA configuration file', default=IPACONF)
parser.add_argument('--nova-conf', dest='nova_conf',
help='nova configuration file', default=NOVACONF)
parser.add_argument('--nova-cpu-conf', dest='nova_cpu_conf',
help='nova compute configuration file',
default=NOVACPUCONF)
parser.add_argument('--neutron-conf', dest='neutron_conf',
help='neutron configuration file',
default=NEUTRONCONF)
parser.add_argument('--novajoin-conf', dest='novajoin_conf',
help='novajoin configuration file',
default=JOINCONF)
parser = configure_ipa.ipa_options(parser)
opts = parser.parse_args()
configure_ipa.validate_options(opts)
if not opts.keystone_auth_url:
opts.keystone_auth_url = user_input("Keystone auth URL", "",
allow_empty=False)
if not opts.nova_password:
try:
opts.nova_password = getpass.getpass("nova service Password: ")
except EOFError:
opts.nova_password = None
if not opts.nova_password:
raise ConfigurationError('nova service user password required.')
try:
pwd.getpwnam(opts.user)
except KeyError:
raise ConfigurationError('User: %s not found on the system' %
opts.user)
return opts
if __name__ == '__main__':
opts = []
out = 0
openlogs()
logger.setLevel(logging.DEBUG)
try:
opts = parse_args()
logger.debug('Installation arguments:')
logger.debug(opts)
install(opts)
except Exception as e: # pylint: disable=broad-except
logger.info(str(e)) # emit message to console
logger.debug(e, exc_info=1) # add backtrace information to logfile
logger.info('Installation aborted.')
logger.info('See log file %s for details' % LOGFILE)
out = 1
except SystemExit:
out = 1
raise
finally:
if out == 0:
logger.info('Installation complete.')
logger.info(
'Please restart nova-api to enable the join service.')
sys.exit(out)