diff --git a/dcmanager/cmd/api.py b/dcmanager/cmd/api.py index 2f3bba76f..d62912fa3 100644 --- a/dcmanager/cmd/api.py +++ b/dcmanager/cmd/api.py @@ -27,6 +27,8 @@ import sys import eventlet +eventlet.monkey_patch(os=False) + from oslo_config import cfg from oslo_log import log as logging from oslo_service import systemd @@ -43,7 +45,6 @@ from dcorch.common import messaging as dcorch_messaging CONF = cfg.CONF config.register_options() LOG = logging.getLogger('dcmanager.api') -eventlet.monkey_patch(os=False) def main(): diff --git a/dcmanager/db/api.py b/dcmanager/db/api.py index f8804e679..87b35d7ad 100644 --- a/dcmanager/db/api.py +++ b/dcmanager/db/api.py @@ -63,6 +63,7 @@ def subcloud_db_model_to_dict(subcloud): "management-start-ip": subcloud.management_start_ip, "management-end-ip": subcloud.management_end_ip, "management-gateway-ip": subcloud.management_gateway_ip, + "openstack-installed": subcloud.openstack_installed, "systemcontroller-gateway-ip": subcloud.systemcontroller_gateway_ip, "created-at": subcloud.created_at, @@ -73,13 +74,15 @@ def subcloud_db_model_to_dict(subcloud): def subcloud_create(context, name, description, location, software_version, management_subnet, management_gateway_ip, management_start_ip, management_end_ip, - systemcontroller_gateway_ip, deploy_status): + systemcontroller_gateway_ip, deploy_status, + openstack_installed): """Create a subcloud.""" return IMPL.subcloud_create(context, name, description, location, software_version, management_subnet, management_gateway_ip, management_start_ip, management_end_ip, - systemcontroller_gateway_ip, deploy_status) + systemcontroller_gateway_ip, deploy_status, + openstack_installed) def subcloud_get(context, subcloud_id): @@ -110,12 +113,12 @@ def subcloud_get_all_with_status(context): def subcloud_update(context, subcloud_id, management_state=None, availability_status=None, software_version=None, description=None, location=None, audit_fail_count=None, - deploy_status=None): + deploy_status=None, openstack_installed=None): """Update a subcloud or raise if it does not exist.""" return IMPL.subcloud_update(context, subcloud_id, management_state, availability_status, software_version, description, location, audit_fail_count, - deploy_status) + deploy_status, openstack_installed) def subcloud_destroy(context, subcloud_id): @@ -130,6 +133,11 @@ def subcloud_status_create(context, subcloud_id, endpoint_type): return IMPL.subcloud_status_create(context, subcloud_id, endpoint_type) +def subcloud_status_delete(context, subcloud_id, endpoint_type): + """Delete a subcloud status for an endpoint_type.""" + return IMPL.subcloud_status_delete(context, subcloud_id, endpoint_type) + + def subcloud_status_db_model_to_dict(subcloud_status): """Convert subcloud status db model to dictionary.""" if subcloud_status: diff --git a/dcmanager/db/sqlalchemy/api.py b/dcmanager/db/sqlalchemy/api.py index 36c54d9b6..25bd419f0 100644 --- a/dcmanager/db/sqlalchemy/api.py +++ b/dcmanager/db/sqlalchemy/api.py @@ -205,7 +205,8 @@ def subcloud_get_all_with_status(context): def subcloud_create(context, name, description, location, software_version, management_subnet, management_gateway_ip, management_start_ip, management_end_ip, - systemcontroller_gateway_ip, deploy_status): + systemcontroller_gateway_ip, deploy_status, + openstack_installed): with write_session() as session: subcloud_ref = models.Subcloud() subcloud_ref.name = name @@ -221,6 +222,7 @@ def subcloud_create(context, name, description, location, software_version, subcloud_ref.systemcontroller_gateway_ip = systemcontroller_gateway_ip subcloud_ref.deploy_status = deploy_status subcloud_ref.audit_fail_count = 0 + subcloud_ref.openstack_installed = openstack_installed session.add(subcloud_ref) return subcloud_ref @@ -229,7 +231,7 @@ def subcloud_create(context, name, description, location, software_version, def subcloud_update(context, subcloud_id, management_state=None, availability_status=None, software_version=None, description=None, location=None, audit_fail_count=None, - deploy_status=None): + deploy_status=None, openstack_installed=None): with write_session() as session: subcloud_ref = subcloud_get(context, subcloud_id) if management_state is not None: @@ -246,6 +248,8 @@ def subcloud_update(context, subcloud_id, management_state=None, subcloud_ref.audit_fail_count = audit_fail_count if deploy_status is not None: subcloud_ref.deploy_status = deploy_status + if openstack_installed is not None: + subcloud_ref.openstack_installed = openstack_installed subcloud_ref.save(session) return subcloud_ref @@ -304,6 +308,14 @@ def subcloud_status_create(context, subcloud_id, endpoint_type): return subcloud_status_ref +@require_admin_context +def subcloud_status_delete(context, subcloud_id, endpoint_type): + with write_session() as session: + subcloud_status_ref = subcloud_status_get(context, subcloud_id, + endpoint_type) + session.delete(subcloud_status_ref) + + @require_admin_context def subcloud_status_update(context, subcloud_id, endpoint_type, sync_status): with write_session() as session: diff --git a/dcmanager/db/sqlalchemy/migrate_repo/versions/004_add_openstack_installed_column.py b/dcmanager/db/sqlalchemy/migrate_repo/versions/004_add_openstack_installed_column.py new file mode 100644 index 000000000..65f2ce181 --- /dev/null +++ b/dcmanager/db/sqlalchemy/migrate_repo/versions/004_add_openstack_installed_column.py @@ -0,0 +1,38 @@ +# 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. +# +# Copyright (c) 2019 Wind River Systems, Inc. +# +# The right to copy, distribute, modify, or otherwise make use +# of this software may be licensed only pursuant to the terms +# of an applicable Wind River license agreement. +# + +from sqlalchemy import Column, MetaData, Table, Boolean + + +def upgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine + + subclouds = Table('subclouds', meta, autoload=True) + + # Add the 'openstack_installed' column to the subclouds table. + subclouds.create_column(Column('openstack_installed', Boolean, + nullable=False, default=False, + server_default='0')) + + return True + + +def downgrade(migrate_engine): + raise NotImplementedError('Database downgrade is unsupported.') diff --git a/dcmanager/db/sqlalchemy/models.py b/dcmanager/db/sqlalchemy/models.py index 5b3538bd2..a3cc6eb74 100644 --- a/dcmanager/db/sqlalchemy/models.py +++ b/dcmanager/db/sqlalchemy/models.py @@ -92,6 +92,7 @@ class Subcloud(BASE, DCManagerBase): management_gateway_ip = Column(String(255)) management_start_ip = Column(String(255), unique=True) management_end_ip = Column(String(255), unique=True) + openstack_installed = Column(Boolean, nullable=False, default=False) systemcontroller_gateway_ip = Column(String(255)) audit_fail_count = Column(Integer) diff --git a/dcmanager/drivers/openstack/sysinv_v1.py b/dcmanager/drivers/openstack/sysinv_v1.py index faddc5cb5..e84824e56 100644 --- a/dcmanager/drivers/openstack/sysinv_v1.py +++ b/dcmanager/drivers/openstack/sysinv_v1.py @@ -124,3 +124,9 @@ class SysinvClient(base.DriverBase): def get_loads(self): """Get a list of loads.""" return self.sysinv_client.load.list() + + def get_applications(self): + """Get a list of containerized applications""" + + # Get a list of containerized applications the system knows of + return self.sysinv_client.app.list() diff --git a/dcmanager/manager/subcloud_audit_manager.py b/dcmanager/manager/subcloud_audit_manager.py index 8e0af1a0c..0bc4eb1ae 100644 --- a/dcmanager/manager/subcloud_audit_manager.py +++ b/dcmanager/manager/subcloud_audit_manager.py @@ -22,7 +22,7 @@ from oslo_log import log as logging - +from dcorch.common import consts as dcorch_consts from dcorch.drivers.openstack.keystone_v3 import KeystoneClient from dcorch.rpc import client as dcorch_rpc_client @@ -38,6 +38,7 @@ from keystoneauth1 import exceptions as keystone_exceptions from fm_api import constants as fm_const from fm_api import fm_api +from sysinv.common import constants as sysinv_constants LOG = logging.getLogger(__name__) @@ -79,6 +80,7 @@ class SubcloudAuditManager(manager.Manager): management_state = subcloud.management_state avail_status_current = subcloud.availability_status audit_fail_count = subcloud.audit_fail_count + openstack_installed = subcloud.openstack_installed # Set defaults to None and disabled so we will still set disabled # status if we encounter an error. @@ -106,6 +108,7 @@ class SubcloudAuditManager(manager.Manager): LOG.exception(e) if sysinv_client: + # get a list of service groups in the subcloud try: svc_groups = sysinv_client.get_service_groups() except Exception as e: @@ -257,3 +260,61 @@ class SubcloudAuditManager(manager.Manager): LOG.info('Ignoring SubcloudNotFound when attempting ' 'audit_fail_count update: %s' % subcloud_name) continue + + if sysinv_client: + # get a list of installed apps in the subcloud + try: + apps = sysinv_client.get_applications() + except Exception as e: + apps = None + LOG.warn('Cannot retrieve installed apps for ' + 'subcloud:%s, %s' % (subcloud_name, e)) + + if apps: + openstack_installed_current = False + for app in apps: + if app.name == sysinv_constants.HELM_APP_OPENSTACK\ + and app.active: + # audit find openstack app is installed and active in + # the subcloud + openstack_installed_current = True + break + + dcm_update_func = None + dco_update_func = None + if openstack_installed_current and not openstack_installed: + dcm_update_func = db_api.subcloud_status_create + dco_update_func = self.dcorch_rpc_client.\ + add_subcloud_sync_endpoint_type + elif not openstack_installed_current and openstack_installed: + dcm_update_func = db_api.subcloud_status_delete + dco_update_func = self.dcorch_rpc_client.\ + remove_subcloud_sync_endpoint_type + + if dcm_update_func and dco_update_func: + endpoint_type_list = dcorch_consts.ENDPOINT_TYPES_LIST_OS + try: + # Notify dcorch to add/remove sync endpoint type list + dco_update_func(self.context, subcloud_name, + endpoint_type_list) + LOG.info('Notifying dcorch, subcloud: %s new sync' + ' endpoint: %s' % (subcloud_name, + endpoint_type_list)) + # Update subcloud status table by adding/removing + # openstack sync endpoint types. + for endpoint_type in endpoint_type_list: + dcm_update_func(self.context, subcloud_id, + endpoint_type) + # Update openstack_installed of subcloud table + db_api.subcloud_update( + self.context, subcloud_id, + openstack_installed=openstack_installed_current) + except exceptions.SubcloudNotFound: + LOG.info('Ignoring SubcloudNotFound when attempting' + ' openstack_installed update: %s' + % subcloud_name) + except Exception as e: + LOG.exception(e) + LOG.warn('Problem informing dcorch of subcloud ' + 'sync endpoint type change, subcloud: %s' + % subcloud_name) diff --git a/dcmanager/manager/subcloud_manager.py b/dcmanager/manager/subcloud_manager.py index 7fd9ca163..29f27309b 100644 --- a/dcmanager/manager/subcloud_manager.py +++ b/dcmanager/manager/subcloud_manager.py @@ -120,7 +120,8 @@ class SubcloudManager(manager.Manager): payload['management_start_address'], payload['management_end_address'], payload['systemcontroller_gateway_address'], - consts.DEPLOY_STATE_NONE) + consts.DEPLOY_STATE_NONE, + False) except Exception as e: LOG.exception(e) raise e diff --git a/dcmanager/tests/unit/db/test_subcloud_db_api.py b/dcmanager/tests/unit/db/test_subcloud_db_api.py index 9a6e6ebc4..988ee9301 100644 --- a/dcmanager/tests/unit/db/test_subcloud_db_api.py +++ b/dcmanager/tests/unit/db/test_subcloud_db_api.py @@ -86,6 +86,7 @@ class DBAPISubcloudTest(base.DCManagerTestCase): 'management_end_ip': "192.168.101.50", 'systemcontroller_gateway_ip': "192.168.204.101", 'deploy_status': "not-deployed", + 'openstack_installed': False, } values.update(kwargs) return db_api.subcloud_create(ctxt, **values) @@ -104,6 +105,7 @@ class DBAPISubcloudTest(base.DCManagerTestCase): 'systemcontroller_gateway_ip': data[ 'systemcontroller_gateway_address'], 'deploy_status': "not-deployed", + 'openstack_installed': False, } return db_api.subcloud_create(ctxt, **values)