
* Fix errors in infrastructure blueprint one-style-config 1) Update sample config - remove non-existing directory 2) Add 0.4.1 version 3) Rename config file to sample Fixes-Bug: 1270734 * Fixed issue with copy configuration files. Closes-Bug: #1271079 * Removed SysV EL6 standalone file, removed old setup scripts * Fixed typo in daemon executable name * Delete init scripts and agent config dirs so we will update then and not delete cache if murano-repository is unavaliable Closes-bug: 1274470 * Fix accessing nested-dir scripts from nested-dir agent templates. This works the following way: if path to agent template is, .g. <someHash>/template/agent/SqlServerCluster/FailoverCluster.template, nd it references script file '/ImportCoreFunctions.ps1', then it will e searched in '<someHash>/template/agent/scripts/' dir, but if it eferences 'Failover-Cluster.ps1', it will be searched in <someHash>/template/agent/scripts/SqlServerCluster/' dir. o the root-like agent dir '<someHash>/template/agent' corresponds to oot-like scripts dir '<someHash>/template/agent/scripts', and the ctual script file will be searched immediately in root-like scripts dir if it starts with '/' (absolute name), or there will be 'rest-dirs' between root-like scripts dir and the script filename if the script filename is a relative one. 'rest-dirs' is the difference between root-like agent dir and the actual parent dir of the agent template which references the script dir. As you see, the abovementioned example is much clearer than the explanation. Closes-bug: #1271578 * Add forgotten deletion in metadata folder setup * Undo init file parameter remane * Return external network id together with routerId blueprint auto-assign-floating-ip * Fix name for syslog_log_facility param * Update reqirements for a release-0.4.1 Change-Id: I2744eaeef369220c5a8dabb027ba40622be9d242
198 lines
6.8 KiB
Python
198 lines
6.8 KiB
Python
# Copyright (c) 2013 Mirantis 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 sys
|
|
import tarfile
|
|
import shutil
|
|
import tempfile
|
|
import hashlib
|
|
from glob import glob
|
|
from metadataclient.common.exceptions import CommunicationError
|
|
from muranoconductor import config
|
|
from metadataclient.v1.client import Client
|
|
import os
|
|
from keystoneclient.v2_0 import client as ksclient
|
|
from keystoneclient.exceptions import EndpointNotFound
|
|
|
|
from openstack.common import log as logging
|
|
|
|
CHUNK_SIZE = 1 << 20 # 1MB
|
|
|
|
log = logging.getLogger(__name__)
|
|
CONF = config.CONF
|
|
|
|
|
|
class MetadataException(BaseException):
|
|
# Inherited not from Exception in purpose:
|
|
# On this exception ack message would not be sent
|
|
pass
|
|
|
|
|
|
def _unpack_data_archive(task_id, hash):
|
|
archive_name = hash + '.tar.gz'
|
|
if not tarfile.is_tarfile(archive_name):
|
|
raise MetadataException('Received invalid file {0} from Metadata '
|
|
'Repository'.format(hash))
|
|
dst_dir = task_id
|
|
if not os.path.exists(dst_dir):
|
|
os.mkdir(dst_dir)
|
|
tar = tarfile.open(archive_name, 'r:gz')
|
|
try:
|
|
tar.extractall(path=dst_dir)
|
|
finally:
|
|
tar.close()
|
|
return dst_dir
|
|
|
|
|
|
def get_endpoint(token_id, tenant_id):
|
|
endpoint = CONF.murano_metadata_url
|
|
if not endpoint:
|
|
keystone_settings = CONF.keystone
|
|
|
|
client = ksclient.Client(auth_url=keystone_settings.auth_url,
|
|
token=token_id)
|
|
|
|
client.authenticate(
|
|
auth_url=keystone_settings.auth_url,
|
|
tenant_id=tenant_id,
|
|
token=token_id)
|
|
|
|
try:
|
|
endpoint = client.service_catalog.url_for(
|
|
service_type='murano-metadata')
|
|
except EndpointNotFound:
|
|
endpoint = 'http://localhost:8084/v1'
|
|
log.warning(
|
|
'Murano Metadata API location could not be found in the '
|
|
'Keystone Service Catalog, using default: {0}'.format(
|
|
endpoint))
|
|
return endpoint
|
|
|
|
|
|
def metadataclient(token_id, tenant_id):
|
|
endpoint = get_endpoint(token_id, tenant_id)
|
|
return Client(endpoint=endpoint, token=token_id)
|
|
|
|
|
|
def get_metadata(task_id, token_id, tenant_id):
|
|
hash = _check_existing_hash()
|
|
try:
|
|
log.debug('Retrieving metadata from Murano Metadata Repository')
|
|
resp, body_iter = metadataclient(token_id, tenant_id).\
|
|
metadata_client.get_conductor_data(hash)
|
|
except CommunicationError as e:
|
|
if hash:
|
|
log.warning('Metadata update failed: '
|
|
'Unable to connect Metadata Repository due to {0}. '
|
|
'Using existing version of metadata'.format(e))
|
|
else:
|
|
log.exception(e)
|
|
exc_type, exc_value, exc_traceback = sys.exc_info()
|
|
raise MetadataException('Unable to get data '
|
|
'from Metadata Repository due to {0}: '
|
|
'{1}'.format(exc_type.__name__, exc_value))
|
|
|
|
else:
|
|
if resp.status == 304:
|
|
log.debug('Metadata unmodified. Using existing archive.')
|
|
|
|
elif resp.status == 200:
|
|
with tempfile.NamedTemporaryFile(delete=False) as archive:
|
|
for chunk in body_iter:
|
|
archive.write(chunk)
|
|
hash = _get_hash(archive.name)
|
|
shutil.move(archive.name, hash + '.tar.gz')
|
|
else:
|
|
msg = 'Metadata update failed: ' \
|
|
'Got {0} status in response.'.format(resp.status)
|
|
if hash:
|
|
log.warning(msg + ' Using existing version of metadata.')
|
|
else:
|
|
raise MetadataException(msg)
|
|
return _unpack_data_archive(task_id, hash)
|
|
|
|
|
|
def release(folder):
|
|
log.debug('Deleting metadata folder {0}'.format(folder))
|
|
try:
|
|
shutil.rmtree(folder)
|
|
except Exception as e:
|
|
log.exception('Unable to delete folder {0} with '
|
|
'task metadata due to {1}'.format(folder, e))
|
|
|
|
|
|
def prepare(data_dir):
|
|
if not os.path.exists(data_dir):
|
|
os.makedirs(data_dir)
|
|
log.info("Creating directory '{0}' to store "
|
|
"conductor data".format(data_dir))
|
|
init_scripts_dst = os.path.join(data_dir,
|
|
os.path.basename(CONF.init_scripts_dir))
|
|
if os.path.exists(init_scripts_dst):
|
|
log.info("Found existing init scripts directory at"
|
|
" '{0}'. Deleting it.'".format(init_scripts_dst))
|
|
shutil.rmtree(init_scripts_dst)
|
|
log.info("Copying init scripts directory from '{0}' "
|
|
"to '{1}'".format(CONF.init_scripts_dir, init_scripts_dst))
|
|
shutil.copytree(CONF.init_scripts_dir, init_scripts_dst)
|
|
|
|
agent_config_dst = os.path.join(data_dir,
|
|
os.path.basename(CONF.agent_config_dir))
|
|
if os.path.exists(agent_config_dst):
|
|
log.info("Found existing agent config directory at"
|
|
" '{0}'. Deleting it.'".format(agent_config_dst))
|
|
shutil.rmtree(agent_config_dst)
|
|
log.info("Copying agent config directory from '{0}' "
|
|
"to '{1}'".format(CONF.agent_config_dir, agent_config_dst))
|
|
shutil.copytree(CONF.agent_config_dir, agent_config_dst)
|
|
os.chdir(data_dir)
|
|
|
|
|
|
def _get_hash(archive_path):
|
|
"""Calculate SHA1-hash of archive file.
|
|
|
|
SHA-1 take a bit more time than MD5 (see http://tinyurl.com/kpj5jy7),
|
|
but is more secure.
|
|
"""
|
|
if os.path.exists(archive_path):
|
|
sha1 = hashlib.sha1()
|
|
with open(archive_path) as f:
|
|
buf = f.read(CHUNK_SIZE)
|
|
while buf:
|
|
sha1.update(buf)
|
|
buf = f.read(CHUNK_SIZE)
|
|
hsum = sha1.hexdigest()
|
|
log.debug("Archive '{0}' has hash-sum {1}".format(archive_path, hsum))
|
|
return hsum
|
|
else:
|
|
log.info("Archive '{0}' doesn't exist, no hash to calculate".format(
|
|
archive_path))
|
|
return None
|
|
|
|
|
|
def _check_existing_hash():
|
|
hash_archives = glob('*.tar.gz')
|
|
if not hash_archives:
|
|
hash = None
|
|
else:
|
|
if len(hash_archives) > 1:
|
|
log.warning('There are to metadata archive. Deleting them both')
|
|
for item in hash_archives:
|
|
os.remove(item)
|
|
hash = None
|
|
else:
|
|
file_name, extension = hash_archives[0].split('.', 1)
|
|
hash = file_name
|
|
return hash
|