diff --git a/sysinv/cgts-client/cgts-client/cgtsclient/v1/cluster_shell.py b/sysinv/cgts-client/cgts-client/cgtsclient/v1/cluster_shell.py index 80714d3559..5ff7468608 100644 --- a/sysinv/cgts-client/cgts-client/cgtsclient/v1/cluster_shell.py +++ b/sysinv/cgts-client/cgts-client/cgtsclient/v1/cluster_shell.py @@ -42,9 +42,9 @@ def _tier_formatter(values): def _print_cluster_show(obj): - fields = ['uuid', 'cluster_uuid', 'type', 'name', 'peers', 'tiers'] + fields = ['uuid', 'cluster_uuid', 'type', 'name', 'peers', 'tiers', 'deployment_model'] labels = ['uuid', 'cluster_uuid', 'type', 'name', 'replication_groups', - 'storage_tiers'] + 'storage_tiers', 'deployment_model'] data = [(f, getattr(obj, f, '')) for f in fields] utils.print_tuple_list( data, labels, formatters={'peers': _peer_formatter, @@ -65,7 +65,7 @@ def do_cluster_list(cc, args): """List Clusters.""" clusters = cc.cluster.list() - fields = ['uuid', 'cluster_uuid', 'type', 'name'] + fields = ['uuid', 'cluster_uuid', 'type', 'name', 'deployment_model'] utils.print_list(clusters, fields, fields, sortby=1) diff --git a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/ceph_mon.py b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/ceph_mon.py index e07a0c97b8..a2a203f1d9 100644 --- a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/ceph_mon.py +++ b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/ceph_mon.py @@ -131,8 +131,6 @@ class CephMon(base.APIBase): 'ceph_mon_gib', 'state', 'task', - 'ceph_mon_dev_ctrl0', - 'ceph_mon_dev_ctrl1', 'hostname']) if ceph_mon.device_path: diff --git a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/cluster.py b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/cluster.py index 90a81c7c01..345c0d3538 100644 --- a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/cluster.py +++ b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/cluster.py @@ -35,6 +35,7 @@ from sysinv.api.controllers.v1 import types from sysinv.api.controllers.v1 import utils from sysinv.api.controllers.v1 import storage_tier as storage_tier_api from sysinv.api.controllers.v1.query import Query +from sysinv.common import ceph from sysinv.common import constants from sysinv.common import exception from sysinv.common import utils as cutils @@ -98,6 +99,9 @@ class Cluster(base.APIBase): name = wtypes.text "User defined name of the cluster" + deployment_model = wtypes.text + "Deployment model used by cluster" + peers = types.MultiType([list]) "List of peers info in the cluster" @@ -132,7 +136,18 @@ class Cluster(base.APIBase): if not expand: cluster.unset_fields_except(['uuid', 'cluster_uuid', 'type', 'name', 'peers', - 'tiers']) + 'tiers', 'deployment_model']) + + # All Ceph type clusters have the same storage model + if cluster.type == constants.CLUSTER_TYPE_CEPH: + try: + # Storage model is defined dynamically, displayed by CLI + # and used by Horizon. + cluster.deployment_model = ceph.get_ceph_storage_model() + except Exception: + cluster.deployment_model = constants.CEPH_UNDEFINED_MODEL + else: + cluster.deployment_model = None cluster.links = [link.Link.make_link('self', pecan.request.host_url, 'clusters', cluster.uuid), diff --git a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/profile.py b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/profile.py index 3cddb8a4ea..e38e431ec5 100644 --- a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/profile.py +++ b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/profile.py @@ -46,6 +46,7 @@ from sysinv.api.controllers.v1 import cpu_utils from sysinv.api.controllers.v1 import types from sysinv.api.controllers.v1 import port as port_api from sysinv.api.controllers.v1 import ethernet_port as ethernet_port_api +from sysinv.common import ceph from sysinv.common import constants from sysinv.common import exception from sysinv.common import utils as cutils @@ -898,29 +899,25 @@ class ProfileController(rest.RestController): if 'profiletype' in profile_dict and profile_dict['profiletype']: profiletype = profile_dict['profiletype'] if profiletype == constants.PROFILE_TYPE_STORAGE: + stor_model = ceph.get_ceph_storage_model() if constants.WORKER in from_ihost.subfunctions: # combo has no ceph profiletype = constants.PROFILE_TYPE_LOCAL_STORAGE LOG.info("No ceph backend for stor profile, assuming " "%s" % profiletype) - elif constants.CONTROLLER in from_ihost.subfunctions: + elif not StorageBackendConfig.has_backend_configured( + pecan.request.dbapi, + constants.CINDER_BACKEND_CEPH + ): raise wsme.exc.ClientSideError(_("Storage profiles " - "not applicable for %s with subfunctions %s." % - (from_ihost.hostname, from_ihost.subfunctions))) - elif constants.STORAGE in from_ihost.subfunctions: - if not StorageBackendConfig.has_backend_configured( - pecan.request.dbapi, - constants.CINDER_BACKEND_CEPH - ): - raise wsme.exc.ClientSideError(_("Storage profiles " - "not applicable for %s with subfunctions %s " - "and non Ceph backend." % - (from_ihost.hostname, from_ihost.subfunctions))) - else: + "not applicable for %s with non Ceph backend." % + from_ihost.hostname)) + elif (from_ihost.personality == constants.CONTROLLER and + stor_model != constants.CEPH_CONTROLLER_MODEL): raise wsme.exc.ClientSideError(_("Storage profiles " - "not applicable for %s with unsupported " - "subfunctions %s." % - (from_ihost.hostname, from_ihost.subfunctions))) + "not applicable for %s as storage deployment " + "model is: %s" % + (from_ihost.hostname, stor_model))) # Create profile LOG.debug("iprofileihost is: %s " % profile_dict) diff --git a/sysinv/sysinv/sysinv/sysinv/common/ceph.py b/sysinv/sysinv/sysinv/sysinv/common/ceph.py index da71c620a7..a2e5a7cf1e 100644 --- a/sysinv/sysinv/sysinv/sysinv/common/ceph.py +++ b/sysinv/sysinv/sysinv/sysinv/common/ceph.py @@ -370,7 +370,8 @@ class CephApiOperator(object): def crushmap_tiers_add(self): """Add all custom storage tiers to the crushmap. """ - cluster = pecan.request.dbapi.clusters_get_all(name='ceph_cluster') + ceph_cluster_name = constants.CLUSTER_CEPH_DEFAULT_NAME + cluster = pecan.request.dbapi.clusters_get_all(name=ceph_cluster_name) # get the list of tiers tiers = pecan.request.dbapi.storage_tier_get_by_cluster( @@ -404,7 +405,8 @@ class CephApiOperator(object): def _crushmap_tiers_bucket_add(self, bucket_name, bucket_type): """Add a new bucket to all the tiers in the crushmap. """ - cluster = pecan.request.dbapi.clusters_get_all(name='ceph_cluster') + ceph_cluster_name = constants.CLUSTER_CEPH_DEFAULT_NAME + cluster = pecan.request.dbapi.clusters_get_all(name=ceph_cluster_name) tiers = pecan.request.dbapi.storage_tier_get_by_cluster( cluster[0].uuid) for t in tiers: @@ -418,7 +420,8 @@ class CephApiOperator(object): def _crushmap_tiers_bucket_remove(self, bucket_name): """Remove an existing bucket from all the tiers in the crushmap. """ - cluster = pecan.request.dbapi.clusters_get_all(name='ceph_cluster') + ceph_cluster_name = constants.CLUSTER_CEPH_DEFAULT_NAME + cluster = pecan.request.dbapi.clusters_get_all(name=ceph_cluster_name) tiers = pecan.request.dbapi.storage_tier_get_by_cluster( cluster[0].uuid) for t in tiers: @@ -433,7 +436,8 @@ class CephApiOperator(object): ancestor_name): """Move common bucket in all the tiers in the crushmap. """ - cluster = pecan.request.dbapi.clusters_get_all(name='ceph_cluster') + ceph_cluster_name = constants.CLUSTER_CEPH_DEFAULT_NAME + cluster = pecan.request.dbapi.clusters_get_all(name=ceph_cluster_name) tiers = pecan.request.dbapi.storage_tier_get_by_cluster( cluster[0].uuid) for t in tiers: @@ -769,8 +773,6 @@ def get_ceph_storage_model(dbapi=None): for chost in controller_hosts: istors = dbapi.istor_get_by_ihost(chost['uuid']) if len(istors): - LOG.info("Controller host %s has OSDs configured. System has ceph " - "controller storage." % chost['hostname']) is_controller_model = True break diff --git a/sysinv/sysinv/sysinv/sysinv/common/constants.py b/sysinv/sysinv/sysinv/sysinv/common/constants.py index 87e072f82f..f5209939b2 100644 --- a/sysinv/sysinv/sysinv/sysinv/common/constants.py +++ b/sysinv/sysinv/sysinv/sysinv/common/constants.py @@ -383,6 +383,10 @@ GLANCE_BACKEND_RBD = 'rbd' GLANCE_BACKEND_HTTP = 'http' GLANCE_BACKEND_GLANCE = 'glance' +# Clusters +CLUSTER_TYPE_CEPH = "ceph" +CLUSTER_CEPH_DEFAULT_NAME = "ceph_cluster" + # Storage Tiers: types (aligns with polymorphic backends) SB_TIER_TYPE_CEPH = SB_TYPE_CEPH SB_TIER_SUPPORTED = [SB_TIER_TYPE_CEPH] @@ -438,8 +442,8 @@ SB_CONFIGURATION_TIMEOUT = 1200 # Controller model: OSDs are on controllers, no storage nodes can # be defined. # Storage model: OSDs are on dedicated storage nodes. -CEPH_STORAGE_MODEL = 'storage' -CEPH_CONTROLLER_MODEL = 'controller' +CEPH_STORAGE_MODEL = 'storage-nodes' +CEPH_CONTROLLER_MODEL = 'controller-nodes' CEPH_AIO_SX_MODEL = 'aio-sx' CEPH_UNDEFINED_MODEL = 'undefined' diff --git a/sysinv/sysinv/sysinv/sysinv/tests/db/sqlalchemy/test_migrations.py b/sysinv/sysinv/sysinv/sysinv/tests/db/sqlalchemy/test_migrations.py index 5a15633607..ce2c40fefb 100644 --- a/sysinv/sysinv/sysinv/sysinv/tests/db/sqlalchemy/test_migrations.py +++ b/sysinv/sysinv/sysinv/sysinv/tests/db/sqlalchemy/test_migrations.py @@ -1463,8 +1463,6 @@ class TestMigrations(BaseMigrationTestCase, WalkVersionsMixin): 'state': 'String', 'task': 'String', 'ceph_mon_gib': 'Integer', - 'ceph_mon_dev_ctrl0': 'String', - 'ceph_mon_dev_ctrl1': 'String', } for col, coltype in storconfigs_cols.items(): self.assertTrue(isinstance(storconfigs.c[col].type,