Add expansion and role patching features.

1. also updated templates and confs with latest adapter conf.

Change-Id: Id261c0243e8536f7b866807359260ef482a11791
This commit is contained in:
Xicheng Chang 2015-12-07 17:33:15 -08:00
parent c1cc40fe52
commit a05ce06169
20 changed files with 418 additions and 159 deletions

59
compass/actions/patch.py Normal file
View File

@ -0,0 +1,59 @@
# Copyright 2014 Huawei Technologies Co. Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Module to patch an existing cluster
"""
import logging
from compass.actions import util
from compass.db.api import cluster as cluster_db
from compass.db.api import user as user_db
from compass.deployment.deploy_manager import Patcher
from compass.deployment.utils import constants as const
def patch(cluster_id, username=None):
"""Patch cluster.
:param cluster_id: id of the cluster
:type cluster_id: int
.. note::
The function should be called out of database session.
"""
with util.lock('serialized_action', timeout=1000) as lock:
if not lock:
raise Exception('failed to acquire lock to deploy')
user = user_db.get_user_object(username)
cluster_hosts = cluster_db.list_cluster_hosts(cluster_id, user)
hosts_id_list = [host['id'] for host in cluster_hosts]
cluster_info = util.ActionHelper.get_cluster_info(cluster_id, user)
adapter_id = cluster_info[const.ADAPTER_ID]
adapter_info = util.ActionHelper.get_adapter_info(
adapter_id, cluster_id, user)
hosts_info = util.ActionHelper.get_hosts_info(
cluster_id, hosts_id_list, user)
patch_successful = True
try:
patcher = Patcher(
adapter_info, cluster_info, hosts_info, cluster_hosts)
patched_config = patcher.patch()
except Exception as error:
logging.exception(error)
patch_successful = False
if patch_successful:
logging.info("Patch successful: %s", patched_config)

View File

@ -2044,7 +2044,7 @@ def take_cluster_action(cluster_id):
Supported actions: [
'add_hosts', 'remove_hosts', 'set_hosts',
'review', 'deploy', 'check_health'
'review', 'deploy', 'check_health', 'apply_patch'
]
"""
data = _get_request_data()
@ -2068,6 +2068,12 @@ def take_cluster_action(cluster_id):
),
202
)
patch_cluster_func = _wrap_response(
functools.partial(
cluster_api.patch_cluster, cluster_id, user=current_user,
),
202
)
check_cluster_health_func = _wrap_response(
functools.partial(
health_report_api.start_check_cluster_health,
@ -2084,6 +2090,7 @@ def take_cluster_action(cluster_id):
remove_hosts=update_cluster_hosts_func,
review=review_cluster_func,
deploy=deploy_cluster_func,
apply_patch=patch_cluster_func,
check_health=check_cluster_health_func
)

View File

@ -51,7 +51,8 @@ RESP_CLUSTERHOST_FIELDS = [
'os_name', 'os_id', 'ip',
'reinstall_os', 'reinstall_distributed_system',
'owner', 'cluster_id',
'created_at', 'updated_at'
'created_at', 'updated_at',
'patched_roles'
]
RESP_CONFIG_FIELDS = [
'os_config',
@ -285,14 +286,14 @@ def check_cluster_editable(
'cluster %s is not editable '
'when state is installing' % cluster.name
)
elif (
cluster.flavor_name and
not cluster.reinstall_distributed_system
):
raise exception.Forbidden(
'cluster %s is not editable '
'when not to be reinstalled' % cluster.name
)
# elif (
# cluster.flavor_name and
# not cluster.reinstall_distributed_system
# ):
# raise exception.Forbidden(
# 'cluster %s is not editable '
# 'when not to be reinstalled' % cluster.name
# )
if user and not user.is_admin and cluster.creator_id != user.id:
raise exception.Forbidden(
'cluster %s is not editable '
@ -759,6 +760,12 @@ def _add_clusterhost_only(
**kwargs
):
"""Get clusterhost only."""
if not cluster.state.state == "UNINITIALIZED":
cluster.state.ready = False
cluster.state.state = "UNINITIALIZED"
cluster.state.percentage = 0.0
utils.update_db_object(session, cluster.state, state="UNINITIALIZED")
return utils.add_db_object(
session, models.ClusterHost, exception_when_existing,
cluster.id, host.id, **kwargs
@ -780,6 +787,7 @@ def _add_clusterhost(
machine_id, cluster, session=session,
user=user, **kwargs
)
return _add_clusterhost_only(
cluster, host, exception_when_existing=exception_when_existing,
session=session, user=user, **kwargs
@ -1060,12 +1068,14 @@ def patch_cluster_host(
session=None, **kwargs
):
"""Patch clusterhost by cluster id and host id."""
logging.info("kwargs are %s", kwargs)
clusterhost = _get_cluster_host(
cluster_id, host_id, session=session
)
return _update_clusterhost(
updated_clusterhost = _update_clusterhost(
clusterhost, session=session, user=user, **kwargs
)
return updated_clusterhost
# replace roles to patched_roles in kwargs.
@ -1848,6 +1858,33 @@ def deploy_cluster(
}
@utils.supported_filters(optional_support_keys=['apply_patch'])
@database.run_in_session()
@user_api.check_user_permission(
permission.PERMISSION_DEPLOY_CLUSTER
)
@utils.wrap_to_dict(
RESP_DEPLOY_FIELDS,
cluster=RESP_CONFIG_FIELDS,
hosts=RESP_CLUSTERHOST_FIELDS
)
def patch_cluster(cluster_id, user=None, session=None, **kwargs):
from compass.tasks import client as celery_client
cluster = _get_cluster(cluster_id, session=session)
celery_client.celery.send_task(
'compass.tasks.patch_cluster',
(
user.email, cluster_id,
)
)
return {
'status': 'patch action sent',
'cluster': cluster
}
@utils.supported_filters([])
@database.run_in_session()
@user_api.check_user_permission(

View File

@ -319,6 +319,9 @@ def validate_host(host):
def _update_host(host_id, session=None, user=None, **kwargs):
"""Update a host internal."""
host = _get_host(host_id, session=session)
if host.state.state == "SUCCESSFUL" and not host.reinstall_os:
logging.info("ignoring successful host: %s", host_id)
return {}
check_host_editable(
host, user=user,
check_in_installing=kwargs.get('reinstall_os', False)
@ -752,6 +755,13 @@ def update_host_network(
host_id, host_network_id, user=None, session=None, **kwargs
):
"""Update a host network by host id and host network id."""
host = _get_host(
host_id, session=session
)
if host.state.state == "SUCCESSFUL" and not host.reinstall_os:
logging.info("ignoring updating request for successful hosts")
return {}
host_network = _get_host_network(
host_id, host_network_id, session=session
)

View File

@ -383,6 +383,7 @@ class ClusterHost(BASE, TimestampMixin, HelperMixin):
)
# the list of role names.
_roles = Column('roles', JSONEncoded, default=[])
_patched_roles = Column('patched_roles', JSONEncoded, default=[])
config_step = Column(String(80), default='')
package_config = Column(JSONEncoded, default={})
config_validated = Column(Boolean, default=False)
@ -556,7 +557,17 @@ class ClusterHost(BASE, TimestampMixin, HelperMixin):
@property
def patched_roles(self):
return self.roles
patched_role_names = list(self._patched_roles)
if not patched_role_names:
return []
cluster_roles = self.cluster.flavor['roles']
if not cluster_roles:
return []
roles = []
for cluster_role in cluster_roles:
if cluster_role['name'] in patched_role_names:
roles.append(cluster_role)
return roles
@patched_roles.setter
def patched_roles(self, value):
@ -564,6 +575,9 @@ class ClusterHost(BASE, TimestampMixin, HelperMixin):
roles = list(self._roles)
roles.extend(value)
self._roles = roles
patched_roles = list(self._patched_roles)
patched_roles.extend(value)
self._patched_roles = patched_roles
self.config_validated = False
@hybrid_property
@ -621,6 +635,7 @@ class ClusterHost(BASE, TimestampMixin, HelperMixin):
'state': state_dict['state']
})
dict_info['roles'] = self.roles
dict_info['patched_roles'] = self.patched_roles
return dict_info

View File

@ -174,6 +174,38 @@ class DeployManager(object):
self.pk_installer.cluster_ready()
class Patcher(DeployManager):
"""Patcher Module."""
def __init__(self, adapter_info, cluster_info, hosts_info, cluster_hosts):
self.pk_installer = None
self.cluster_info = cluster_info
registered_roles = cluster_info['flavor']['roles']
pk_info = adapter_info.setdefault(const.PK_INSTALLER, {})
if pk_info:
pk_installer_name = pk_info[const.NAME]
self.pk_installer = Patcher._get_installer(PKInstaller,
pk_installer_name,
adapter_info,
cluster_info,
hosts_info)
patched_role_mapping = {}
for role in registered_roles:
patched_role_mapping[role] = []
for host in cluster_hosts:
if len(host['patched_roles']) == 0:
continue
for role in host['patched_roles']:
patched_role_mapping[role['name']].append(host)
self.patched_role_mapping = patched_role_mapping
def patch(self):
patched_config = self.pk_installer.patch(self.patched_role_mapping)
return patched_config
class PowerManager(object):
"""Manage host to power on, power off, and reset."""

View File

@ -138,6 +138,14 @@ class ClusterInfo(object):
return dict(mapping)
def _get_cluster_patched_roles_mapping(self):
mapping = defaultdict(list)
for host in self.hosts:
for role, value in host.patched_roles_mapping.iteritems():
mapping[role].append(value)
return dict(mapping)
@property
def base_info(self):
return {
@ -160,6 +168,7 @@ class HostInfo(object):
self.package_config = self.host_info.setdefault(const.PK_CONFIG, {})
self.roles = self.host_info.setdefault(const.ROLES, [])
self.patched_roles = self.host_info.setdefault(const.PATCHED_ROLES, [])
self.ipmi = deepcopy(self.host_info.setdefault(const.IPMI, {}))
self.reinstall_os_flag = self.host_info.get(const.REINSTALL_OS_FLAG)
self.deployed_os_config = self.host_info.setdefault(
@ -197,6 +206,8 @@ class HostInfo(object):
self.roles_mapping = \
self.deployed_package_config[const.ROLES_MAPPING]
self.patched_roles_mapping = self._get_host_patched_roles_mapping()
self.cluster_info.add_host(self)
def valid_interface(self, interface):
@ -241,6 +252,25 @@ class HostInfo(object):
return mapping
def _get_host_patched_roles_mapping(self):
if not self.network_mapping:
return {}
net_info = {const.HOSTNAME: self.hostname}
for k, v in self.network_mapping.items():
try:
net_info[k] = self.networks[v[const.NIC]]
net_info[k][const.NIC] = v[const.NIC]
except Exception:
pass
mapping = {}
for role in self.patched_roles:
role = role['name'].replace("-", "_")
mapping[role] = net_info
return mapping
@property
def baseinfo(self):
return {
@ -332,6 +362,9 @@ class BaseConfigManager(object):
def get_cluster_roles_mapping(self):
return self.cluster_info.roles_mapping
def get_cluster_patched_roles_mapping(self):
return self.cluster_info._get_cluster_patched_roles_mapping()
def validate_host(self, host_id):
if host_id not in self.hosts_info:
raise RuntimeError("host_id %s is invalid" % host_id)

View File

@ -48,6 +48,7 @@ def byteify(input):
class AnsibleInstaller(PKInstaller):
INVENTORY_TMPL_DIR = 'inventories'
GROUPVARS_TMPL_DIR = 'vars'
INVENTORY_PATCH_TEMPALTE_DIR = 'inventories'
# keywords in package installer settings
ANSIBLE_DIR = 'ansible_dir'
@ -256,8 +257,7 @@ class AnsibleInstaller(PKInstaller):
tmpl = Template(file=tmpl_path, searchList=searchList)
return tmpl.respond()
def _create_ansible_run_env(self, env_name):
ansible_run_destination = os.path.join(self.ansible_run_dir, env_name)
def _create_ansible_run_env(self, env_name, ansible_run_destination):
os.mkdir(ansible_run_destination)
# copy roles to run env
@ -288,7 +288,9 @@ class AnsibleInstaller(PKInstaller):
def prepare_ansible(self, env_name, global_vars_dict):
ansible_run_destination = os.path.join(self.ansible_run_dir, env_name)
self._create_ansible_run_env(env_name)
if os.path.exists(ansible_run_destination):
ansible_run_destination += "-expansion"
self._create_ansible_run_env(env_name, ansible_run_destination)
inv_config = self._generate_inventory_attributes(global_vars_dict)
inventory_dir = os.path.join(ansible_run_destination, 'inventories')
@ -353,11 +355,39 @@ class AnsibleInstaller(PKInstaller):
# Create ansible related files
self.prepare_ansible(env_name, global_vars_dict)
def patch(self, patched_role_mapping):
adapter_name = self.config_manager.get_adapter_name()
cluster_name = self.config_manager.get_clustername()
env_name = self.get_env_name(adapter_name, cluster_name)
ansible_run_destination = os.path.join(self.ansible_run_dir, env_name)
inventory_dir = os.path.join(ansible_run_destination, 'inventories')
patched_global_vars_dict = self._get_cluster_tmpl_vars()
mapping = self.config_manager.get_cluster_patched_roles_mapping()
patched_global_vars_dict['roles_mapping'] = mapping
patched_inv = self._generate_inventory_attributes(
patched_global_vars_dict)
inv_file = os.path.join(inventory_dir, 'patched_inventory.yml')
self.serialize_config(patched_inv, inv_file)
config_file = os.path.join(
ansible_run_destination, self.ansible_config
)
playbook_file = os.path.join(ansible_run_destination, self.playbook)
log_file = os.path.join(ansible_run_destination, 'patch.log')
cmd = "ANSIBLE_CONFIG=%s ansible-playbook -i %s %s" % (config_file,
inv_file,
playbook_file)
with open(log_file, 'w') as logfile:
subprocess.Popen(cmd, shell=True, stdout=logfile, stderr=logfile)
return patched_role_mapping
def cluster_os_ready(self):
adapter_name = self.config_manager.get_adapter_name()
cluster_name = self.config_manager.get_clustername()
env_name = self.get_env_name(adapter_name, cluster_name)
ansible_run_destination = os.path.join(self.ansible_run_dir, env_name)
expansion_dir = ansible_run_destination + "-expansion"
if os.path.exists(expansion_dir):
ansible_run_destination = expansion_dir
inventory_dir = os.path.join(ansible_run_destination, 'inventories')
inventory_file = os.path.join(inventory_dir, self.inventory)
playbook_file = os.path.join(ansible_run_destination, self.playbook)

View File

@ -78,6 +78,7 @@ OS_CONFIG = 'os_config'
OS_CONFIG_GENERAL = 'general'
PK_CONFIG = 'package_config'
ROLES = 'roles'
PATCHED_ROLES = 'patched_roles'
ROLES_MAPPING = 'roles_mapping'
SERVER_CREDS = 'server_credentials'
TMPL_VARS_DICT = 'vars_dict'

View File

@ -25,6 +25,7 @@ from compass.actions import clean
from compass.actions import delete
from compass.actions import deploy
from compass.actions import install_callback
from compass.actions import patch
from compass.actions import poll_switch
from compass.actions import update_progress
from compass.db.api import adapter_holder as adapter_api
@ -112,6 +113,19 @@ def deploy_cluster(deployer_email, cluster_id, clusterhost_ids):
logging.exception(error)
@celery.task(name='compass.tasks.patch_cluster')
def patch_cluster(patcher_email, cluster_id):
"""Patch the existing cluster.
:param cluster_id: id of the cluster
:type cluster_id: int
"""
try:
patch.patch(cluster_id, patcher_email)
except Exception as error:
logging.exception(error)
@celery.task(name='compass.tasks.reinstall_cluster')
def reinstall_cluster(installer_email, cluster_id, clusterhost_ids):
"""reinstall the given cluster.

View File

@ -396,28 +396,14 @@ class TestUpdateCluster(ClusterTestCase):
)
def test_is_cluster_editable(self):
# state is INSTALLING
# cluster should be editable for expansion purposes.
raised = False
cluster.update_cluster_state(
self.cluster_id,
user=self.user_object,
state='INSTALLING'
)
self.assertRaises(
exception.Forbidden,
cluster.update_cluster,
self.cluster_id,
user=self.user_object,
name='cluster_editable'
)
# reinstall
self.assertRaises(
exception.Forbidden,
cluster.update_cluster,
self.cluster_id,
user=self.user_object,
reinstall_distributed_system=True
)
self.assertFalse(raised, exception.Forbidden)
class TestDelCluster(ClusterTestCase):
@ -443,18 +429,14 @@ class TestDelCluster(ClusterTestCase):
self.assertNotEqual(1, del_cluster['id'])
def test_is_cluster_editable(self):
# state is INSTALLING
# cluster should be editable for expansion purposes.
raised = False
cluster.update_cluster_state(
self.cluster_id,
user=self.user_object,
state='INSTALLING'
)
self.assertRaises(
exception.Forbidden,
cluster.del_cluster,
self.cluster_id,
user=self.user_object,
)
self.assertFalse(raised, exception.Forbidden)
class TestGetClusterConfig(ClusterTestCase):
@ -630,17 +612,14 @@ class TestDelClusterConfig(ClusterTestCase):
self.assertEqual(config, {})
def test_cluster_editable(self):
# cluster should be editable for expansion purposes.
raised = False
cluster.update_cluster_state(
self.cluster_id,
user=self.user_object,
state='INSTALLING'
)
self.assertRaises(
exception.Forbidden,
cluster.del_cluster_config,
self.cluster_id,
user=self.user_object,
)
self.assertFalse(raised, exception.Forbidden)
class TestListClusterHosts(ClusterTestCase):
@ -774,19 +753,14 @@ class TestAddClusterHost(ClusterTestCase):
)
def test_is_cluster_editable(self):
# installing
# cluster should be editable for expansion purposes.
raised = False
cluster.update_cluster_state(
self.cluster_id,
user=self.user_object,
state='INSTALLING'
)
self.assertRaises(
exception.Forbidden,
cluster.add_cluster_host,
self.cluster_id,
user=self.user_object,
machine_id=self.add_machine_id
)
self.assertFalse(raised, exception.Forbidden)
class TestUpdateClusterHost(ClusterTestCase):
@ -836,19 +810,14 @@ class TestUpdateClusterHost(ClusterTestCase):
)
def test_is_cluster_editable(self):
# state is INSTALLING
# cluster should be editable for expansion purposes.
raised = False
cluster.update_cluster_state(
self.cluster_id,
user=self.user_object,
state='INSTALLING'
)
self.assertRaises(
exception.Forbidden,
cluster.update_cluster_host,
self.cluster_id,
self.host_id[0],
user=self.user_object,
)
self.assertFalse(raised, exception.Forbidden)
class TestUpdateClusterhost(ClusterTestCase):
@ -895,18 +864,14 @@ class TestUpdateClusterhost(ClusterTestCase):
)
def test_is_cluster_editable(self):
# state is INSTALLING
# cluster should be editable for expansion purposes.
raised = False
cluster.update_cluster_state(
self.cluster_id,
user=self.user_object,
state='INSTALLING'
)
self.assertRaises(
exception.Forbidden,
cluster.update_clusterhost,
self.clusterhost_id[0],
user=self.user_object,
)
self.assertFalse(raised, exception.Forbidden)
class TestPatchClusterHost(ClusterTestCase):
@ -935,18 +900,14 @@ class TestPatchClusterHost(ClusterTestCase):
self.assertEqual(result, 'all in one compute')
def test_is_cluster_editable(self):
# cluster should be editable for expansion purposes.
raised = False
cluster.update_cluster_state(
self.cluster_id,
user=self.user_object,
state='INSTALLING'
)
self.assertRaises(
exception.Forbidden,
cluster.patch_cluster_host,
self.cluster_id,
self.host_id[0],
user=self.user_object,
)
self.assertFalse(raised, exception.Forbidden)
class TestPatchClusterhost(ClusterTestCase):
@ -972,18 +933,15 @@ class TestPatchClusterhost(ClusterTestCase):
result = role['display_name']
self.assertEqual(result, 'all in one compute')
def testi_is_cluster_editable(self):
def test_is_cluster_editable(self):
# cluster should be editable for expansion purposes.
raised = False
cluster.update_cluster_state(
self.cluster_id,
user=self.user_object,
state='INSTALLING'
)
self.assertRaises(
exception.Forbidden,
cluster.patch_clusterhost,
self.clusterhost_id[0],
user=self.user_object,
)
self.assertFalse(raised, exception.Forbidden)
class TestDelClusterHost(ClusterTestCase):
@ -1011,18 +969,14 @@ class TestDelClusterHost(ClusterTestCase):
self.assertNotEqual(del_cluster_host['id'], 1)
def test_is_cluster_editable(self):
# cluster should be editable for expansion purposes.
raised = False
cluster.update_cluster_state(
self.cluster_id,
user=self.user_object,
state='INSTALLING'
)
self.assertRaises(
exception.Forbidden,
cluster.del_cluster_host,
self.cluster_id,
self.host_id[0],
user=self.user_object,
)
self.assertFalse(raised, exception.Forbidden)
class TestDelClusterhost(ClusterTestCase):
@ -1048,17 +1002,14 @@ class TestDelClusterhost(ClusterTestCase):
self.assertNotEqual(del_clusterhost['id'], 1)
def test_is_cluster_editable(self):
# cluster should be editable for expansion purposes.
raised = False
cluster.update_cluster_state(
self.cluster_id,
user=self.user_object,
state='INSTALLING'
)
self.assertRaises(
exception.Forbidden,
cluster.del_clusterhost,
self.clusterhost_id[0],
user=self.user_object,
)
self.assertFalse(raised, exception.Forbidden)
class TestGetClusterHostConfig(ClusterTestCase):
@ -1234,20 +1185,14 @@ class TestUpdateClusterHostConfig(ClusterTestCase):
self.assertItemsEqual(os_configs, self.os_configs)
def test_is_cluster_editable(self):
# cluster should be editable for expansion purposes.
raised = False
cluster.update_cluster_state(
self.cluster_id,
user=self.user_object,
state='INSTALLING'
)
self.assertRaises(
exception.Forbidden,
cluster.update_cluster_host_config,
self.cluster_id,
self.host_id[0],
user=self.user_object,
os_config=self.os_configs,
package_config=self.package_configs
)
self.assertFalse(raised, exception.Forbidden)
class TestUpdateClusterHostDeployedConfig(ClusterTestCase):
@ -1323,19 +1268,14 @@ class TestUpdateClusterhostConfig(ClusterTestCase):
self.assertItemsEqual(os_config, self.os_configs)
def test_id_cluster_editable(self):
# cluster should be editable for expansion purposes.
raised = False
cluster.update_cluster_state(
self.cluster_id,
user=self.user_object,
state='INSTALLING'
)
self.assertRaises(
exception.Forbidden,
cluster.update_clusterhost_config,
self.clusterhost_id[0],
user=self.user_object,
os_config=self.os_configs,
package_config=self.package_configs
)
self.assertFalse(raised, exception.Forbidden)
class TestUpdateClusterhostDeployedConfig(ClusterTestCase):
@ -1411,20 +1351,14 @@ class TestPatchClusterHostConfig(ClusterTestCase):
self.assertItemsEqual(os_config, self.os_configs)
def test_is_cluster_editable(self):
# cluster should be editable for expansion purposes.
raised = False
cluster.update_cluster_state(
self.cluster_id,
user=self.user_object,
state='INSTALLING'
)
self.assertRaises(
exception.Forbidden,
cluster.patch_cluster_host_config,
self.cluster_id,
self.host_id[0],
user=self.user_object,
os_config=self.os_configs,
package_config=self.package_configs
)
self.assertFalse(raised, exception.Forbidden)
class TestPatchClusterhostConfig(ClusterTestCase):
@ -1453,19 +1387,14 @@ class TestPatchClusterhostConfig(ClusterTestCase):
self.assertItemsEqual(os_config, self.os_configs)
def test_is_cluster_editable(self):
# cluster should be editable for expansion purposes.
raised = False
cluster.update_cluster_state(
self.cluster_id,
user=self.user_object,
state='INSTALLING'
)
self.assertRaises(
exception.Forbidden,
cluster.patch_clusterhost_config,
self.clusterhost_id[0],
user=self.user_object,
os_config=self.os_configs,
package_config=self.package_configs
)
self.assertFalse(raised, exception.Forbidden)
class TestDeleteClusterHostConfig(ClusterTestCase):
@ -1503,18 +1432,14 @@ class TestDeleteClusterHostConfig(ClusterTestCase):
self.assertEqual(config, {})
def test_is_cluster_editable(self):
# cluster should be editable for expansion purposes.
raised = False
cluster.update_cluster_state(
self.cluster_id,
user=self.user_object,
state='INSTALLING'
)
self.assertRaises(
exception.Forbidden,
cluster.delete_cluster_host_config,
self.cluster_id,
self.host_id[0],
user=self.user_object,
)
self.assertFalse(raised, exception.Forbidden)
class TestDeleteClusterhostConfig(ClusterTestCase):
@ -1549,17 +1474,14 @@ class TestDeleteClusterhostConfig(ClusterTestCase):
self.assertEqual(config, {})
def test_is_cluster_editable(self):
# cluster should be editable for expansion purposes.
raised = False
cluster.update_cluster_state(
self.cluster_id,
user=self.user_object,
state='INSTALLING'
)
self.assertRaises(
exception.Forbidden,
cluster.delete_clusterhost_config,
self.clusterhost_id[0],
user=self.user_object,
)
self.assertFalse(raised, exception.Forbidden)
class TestUpdateClusterHosts(ClusterTestCase):

View File

@ -25,7 +25,7 @@ FLAVORS = [{
'display_name': 'HA-ansible-multinodes-juno',
'template': 'HA-ansible-multinodes.tmpl',
'roles': [
'controller', 'compute', 'ha', 'odl', 'onos', 'ceph'
'controller', 'compute', 'ha', 'odl', 'onos', 'ceph', 'ceph-adm', 'ceph-mon', 'ceph-osd', 'sec-patch', 'ceph-osd-node'
],
}]

View File

@ -22,10 +22,10 @@ FLAVORS = [{
],
}, {
'flavor': 'HA-ansible-multinodes-kilo',
'display_name': 'HA-ansible-multinodes',
'display_name': 'HA-ansible-multinodes-kilo',
'template': 'HA-ansible-multinodes.tmpl',
'roles': [
'controller', 'compute', 'ha', 'odl', 'onos', 'ceph'
'controller', 'compute', 'ha', 'odl', 'onos', 'ceph', 'ceph-adm', 'ceph-mon', 'ceph-osd'
],
}]

8
conf/flavor_mapping/HA-ansible-multinodes-juno.conf Executable file → Normal file
View File

@ -42,6 +42,10 @@ CONFIG_MAPPING = {
"volume": {
"username": "cinder",
"password": "cinder"
},
"heat": {
"username": "heat",
"password": "heat"
}
}
}
@ -82,6 +86,10 @@ CONFIG_MAPPING = {
"username": "swift",
"password": "swift"
},
"heat": {
"username": "heat",
"password": "heat"
},
"volume": {
"username": "cinder",
"password": "cinder"

0
conf/flavor_mapping/HA-ansible-multinodes-kilo.conf Executable file → Normal file
View File

View File

@ -8,7 +8,7 @@ METADATA = {
'_self': {
'required_in_whole_config': True,
'key_extensions': {
'$service': ['image', 'compute', 'dashboard', 'identity', 'metering', 'rabbitmq', 'volume', 'mysql']
'$service': ['image', 'compute', 'dashboard', 'identity', 'metering', 'rabbitmq', 'volume', 'mysql', 'heat']
},
'mapping_to': 'service_credentials'
},
@ -37,7 +37,7 @@ METADATA = {
'_self': {
'required_in_whole_config': True,
'key_extensions': {
'$console': ['admin', 'compute', 'dashboard', 'image', 'metering', 'network', 'object-store', 'volume']
'$console': ['admin', 'compute', 'dashboard', 'image', 'metering', 'network', 'object-store', 'volume', 'heat']
},
'mapping_to': 'console_credentials'
},

View File

@ -77,9 +77,34 @@ ROLES = [{
'role': 'ha',
'display': 'Cluster with HA',
'description': 'Cluster with HA node'
}, {
'role': 'ceph-adm',
'display': 'Ceph Admin Node',
'description': 'Ceph Admin Node',
'optional': True
}, {
'role': 'ceph-mon',
'display': 'Ceph Monitor Node',
'description': 'Ceph Monitor Node',
'optional': True
}, {
'role': 'ceph-osd',
'display': 'Ceph Storage Node',
'description': 'Ceph Storage Node',
'optional': True
}, {
'role': 'ceph-osd-node',
'display': 'Ceph osd install from node',
'description': '',
'optional': True
}, {
'role': 'ceph',
'display': 'Ceph storage',
'description': 'Ceph storage',
'display': 'ceph node',
'description': 'ceph node',
'optional': True
}, {
'role': 'sec-patch',
'display': 'sec-patch node',
'description': 'Security Patch Node',
'optional': True
}]

View File

@ -77,9 +77,24 @@ ROLES = [{
'role': 'ha',
'display': 'Cluster with HA',
'description': 'Cluster with HA node'
}, {
'role': 'ceph-adm',
'display': 'Ceph Admin Node',
'description': 'Ceph Admin Node',
'optional': True
}, {
'role': 'ceph-mon',
'display': 'Ceph Monitor Node',
'description': 'Ceph Monitor Node',
'optional': True
}, {
'role': 'ceph-osd',
'display': 'Ceph Storage Node',
'description': 'Ceph Storage Node',
'optional': True
}, {
'role': 'ceph',
'display': 'Ceph storage',
'description': 'Ceph storage',
'display': 'ceph node',
'description': 'ceph node',
'optional': True
}]

View File

@ -3,7 +3,12 @@
#set has = $getVar('ha', [])
#set odls = $getVar('odl', [])
#set onoss = $getVar('onos', [])
#set cephs = $getVar('ceph',[])
#set ceph_adm_list = $getVar('ceph_adm',[])
#set ceph_mon_list = $getVar('ceph_mon',[])
#set ceph_osd_list = $getVar('ceph_osd',[])
#set sec_patch_list = $getVar('sec_patch',[])
#set ceph_osd_node_list = $getVar('ceph_osd_node',[])
#if not $isinstance($controllers, list)
#set controllers = [$controllers]
#end if
@ -19,9 +24,22 @@
#if not $isinstance(onoss, list)
#set onoss = [onoss]
#end if
#if not $isinstance(cephs, list)
#set cephs = [cephs]
#if not $isinstance(ceph_adm_list, list)
#set ceph_adm_list = [ceph_adm_list]
#end if
#if not $isinstance(ceph_mon_list, list)
#set ceph_mon_list = [ceph_mon_list]
#end if
#if not $isinstance(ceph_osd_list, list)
#set ceph_osd_list = [ceph_osd_list]
#end if
#if not $isinstance(sec_patch_list, list)
#set sec_patch_list = [sec_patch_list]
#end if
#if not $isinstance(ceph_osd_node_list, list)
#set ceph_osd_node_list = [ceph_osd_node_list]
#end if
#set credentials = $getVar('server_credentials', {})
#set username = $credentials.get('username', 'root')
#set password = $credentials.get('password', 'root')
@ -55,9 +73,33 @@ $odl_hostname ansible_ssh_host=$odl_ip ansible_ssh_user=$username ansible_ssh_pa
#set onos_hostname = $onos.hostname
$onos_hostname ansible_ssh_host=$onos_ip ansible_ssh_user=$username ansible_ssh_password=$password
#end for
[ceph]
#for ceph in $cephs
#set ceph_ip = $ceph.install.ip
#set ceph_hostname = $ceph.hostname
$ceph_hostname ansible_ssh_host=$ceph_ip ansible_ssh_user=$username ansible_ssh_password=$password
[ceph_adm]
#for ceph_adm in $ceph_adm_list
#set ceph_adm_ip = $ceph_adm.install.ip
#set ceph_adm_hostname = $ceph_adm.hostname
$ceph_adm_hostname ansible_ssh_host=$ceph_adm_ip ansible_ssh_user=$username ansible_ssh_password=$password
#end for
[ceph_mon]
#for ceph_mon in $ceph_mon_list
#set ceph_mon_ip = $ceph_mon.install.ip
#set ceph_mon_hostname = $ceph_mon.hostname
$ceph_mon_hostname ansible_ssh_host=$ceph_mon_ip ansible_ssh_user=$username ansible_ssh_password=$password
#end for
[ceph_osd]
#for ceph_osd in $ceph_osd_list
#set ceph_osd_ip = $ceph_osd.install.ip
#set ceph_osd_hostname = $ceph_osd.hostname
$ceph_osd_hostname ansible_ssh_host=$ceph_osd_ip ansible_ssh_user=$username ansible_ssh_password=$password
#end for
[sec_patch]
#for sec_patch in $sec_patch_list
#set sec_patch_ip = $sec_patch.install.ip
#set sec_patch_hostname = $sec_patch.hostname
$sec_patch_hostname ansible_ssh_host=$sec_patch_ip ansible_ssh_user=$username ansible_ssh_password=$password
#end for
[ceph_osd_node]
#for ceph_osd_node in $ceph_osd_node_list
#set ceph_osd_node_ip = $ceph_osd_node.install.ip
#set ceph_osd_node_hostname = $ceph_osd_node.hostname
$ceph_osd_node_hostname ansible_ssh_host=$ceph_osd_node_ip ansible_ssh_user=$username ansible_ssh_password=$password
#end for

View File

@ -80,6 +80,11 @@ haproxy_hosts:
$hostname: $ip_settings[$hostname]["mgmt"]["ip"]
#end for
host_index:
#for $index, $item in enumerate($has)
$item["hostname"]: $index
#end for
ERLANG_TOKEN: YOWSJSJIGGAUFZTIBRAD
#set credentials = $getVar('service_credentials', {})
#set console_credentials = $getVar('console_credentials', {})
@ -95,6 +100,8 @@ ERLANG_TOKEN: YOWSJSJIGGAUFZTIBRAD
#set dash_dbpass = $credentials.dashboard.password
#set cinder_dbpass = $credentials.volume.password
#set cinder_pass = $console_credentials.volume.password
#set heat_dbpass = $credentials.heat.password
#set heat_pass = $console_credentials.heat.password
#set admin_pass = $console_credentials.admin.password
#set neutron_pass = $console_credentials.network.password
@ -130,6 +137,8 @@ CINDER_DBPASS: $cinder_dbpass
CINDER_PASS: $cinder_pass
NEUTRON_DBPASS: $neutron_pass
NEUTRON_PASS: $neutron_pass
HEAT_DBPASS: $heat_dbpass
HEAT_PASS: $heat_pass
#set neutron_service_plugins=['router']