From 5781af9f4fe2a4ff9ca5eddefeaef45b48ea398c Mon Sep 17 00:00:00 2001 From: Ovidiu Poncea Date: Fri, 25 Jan 2019 20:19:27 +0200 Subject: [PATCH] Ceph for standard: Enable Ceph for a standard configuration This commit enables StarlingX Dashboard to display and allow configuration of Ceph on a standard 2 controllers and 2 computes configuration. For this to work we use deployment_model in the 'cluster' API of System Inventory and show or hide specific panels and options from view. Change-Id: I998bc8083720425bdca10c6876e1c2ed99235bf9 Implements: containerization-2002844-CEPH-persistent-storage-backend-for-Kubernetes Story: 2002844 Task: 29113 Depends-On: https://review.openstack.org/633257 Signed-off-by: Ovidiu Poncea --- starlingx-dashboard/centos/build_srpm.data | 2 +- .../starlingx_dashboard/api/sysinv.py | 83 +++++++++++++++---- .../admin/inventory/storages/tables.py | 9 +- .../dashboards/admin/inventory/tabs.py | 9 +- .../templates/inventory/_detail_storages.html | 3 +- .../dashboards/admin/inventory/workflows.py | 7 +- 6 files changed, 86 insertions(+), 27 deletions(-) diff --git a/starlingx-dashboard/centos/build_srpm.data b/starlingx-dashboard/centos/build_srpm.data index f94364dd..e077606c 100644 --- a/starlingx-dashboard/centos/build_srpm.data +++ b/starlingx-dashboard/centos/build_srpm.data @@ -1,2 +1,2 @@ SRC_DIR="starlingx-dashboard" -TIS_PATCH_VER=25 +TIS_PATCH_VER=26 diff --git a/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/api/sysinv.py b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/api/sysinv.py index a868aa5f..f5396af4 100644 --- a/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/api/sysinv.py +++ b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/api/sysinv.py @@ -1338,7 +1338,7 @@ def extoam_list(request): class Cluster(base.APIResourceWrapper): """...""" - _attrs = ['uuid', 'cluster_uuid', 'type', 'name'] + _attrs = ['uuid', 'cluster_uuid', 'type', 'name', 'deployment_model'] def __init__(self, apiresource): super(Cluster, self).__init__(apiresource) @@ -1347,6 +1347,7 @@ class Cluster(base.APIResourceWrapper): self._uuid = self.uuid self._name = self.name self._type = self.type + self._deployment_model = self.deployment_model self._cluster_uuid = self.cluster_uuid else: self._uuid = None @@ -1366,11 +1367,23 @@ class Cluster(base.APIResourceWrapper): def type(self): return self._type + @property + def deployment_model(self): + return self._deployment_model + @property def cluster_uuid(self): return self._cluster_uuid +def cluster_get(request, name): + clusters = cgtsclient(request).cluster.list() + for c in clusters: + if name == c.name: + return Cluster(c) + return None + + def cluster_list(request): clusters = cgtsclient(request).cluster.list() @@ -1554,7 +1567,8 @@ class ControllerFS(base.APIResourceWrapper): class CephMon(base.APIResourceWrapper): """...""" - _attrs = ['device_path', 'ceph_mon_gib', 'hostname', 'uuid', 'link'] + _attrs = ['device_path', 'ceph_mon_gib', 'hostname', + 'ihost_uuid', 'uuid', 'link'] def __init__(self, apiresource): super(CephMon, self).__init__(apiresource) @@ -1563,10 +1577,12 @@ class CephMon(base.APIResourceWrapper): self._device_path = self.device_path self._ceph_mon_gib = self.ceph_mon_gib self._hostname = self.hostname + self._ihost_uuid = self.ihost_uuid else: self._device_path = None self._ceph_mon_gib = None self._hostname = None + self._ihost_uuid = None @property def device_path(self): @@ -1580,6 +1596,10 @@ class CephMon(base.APIResourceWrapper): def hostname(self): return self._hostname + @property + def ihost_uuid(self): + return self._ihost_uuid + class STORAGE(base.APIResourceWrapper): """...""" @@ -1736,20 +1756,38 @@ def storagefs_list(request): # so the first element is enough for obtaining the needed data. controllerfs_obj = None - ceph_mon_obj = None + mon_obj = None if ceph_mon_list: - ceph_mon_obj = ceph_mon_list[0] + # Get storage-0 configuration + for mon_obj in ceph_mon_list: + if mon_obj.hostname == constants.STORAGE_0_HOSTNAME: + break + else: + mon_obj = ceph_mon_list[0] - return [STORAGE(controllerfs_obj, ceph_mon_obj)] + return [STORAGE(controllerfs_obj, mon_obj)] def controllerfs_list(request): controllerfs = cgtsclient(request).controller_fs.list() ceph_mon_list = cgtsclient(request).ceph_mon.list() + hosts = cgtsclient(request).ihost.list() - if ceph_mon_list and not is_system_k8s_aio(request): - controllerfs.append(ceph_mon_list[0]) + if ceph_mon_list: + host = None + for host in hosts: + # Get any unlocked controller, + # both have the same configuration + if (host.personality == constants.CONTROLLER and + host.administrative == constants.ADMIN_UNLOCKED): + break + + if host and is_host_with_storage(request, host.uuid): + for mon in ceph_mon_list: + if mon.hostname == host.hostname: + controllerfs.append(mon) + break return [ControllerFS(n) for n in controllerfs] @@ -2570,18 +2608,33 @@ def is_kubernetes_config(request): return False -def is_system_k8s_aio(request): - system_type = get_system_type(request) - - if (system_type == SYSTEM_TYPE_AIO and - is_kubernetes_config(request)): - return True - return False +def get_ceph_storage_model(request): + cluster = cluster_get(request, constants.CLUSTER_CEPH_DEFAULT_NAME) + return cluster.deployment_model def is_host_with_storage(request, host_id): + storage_model = get_ceph_storage_model(request) + + if storage_model == constants.CEPH_AIO_SX_MODEL: + # We have a single host, no need to query further + return True + host = host_get(request, host_id) - return 'storage' in host.subfunctions or is_system_k8s_aio(request) + + if storage_model == constants.CEPH_STORAGE_MODEL: + if host._personality == constants.STORAGE: + return True + else: + return False + elif storage_model == constants.CEPH_CONTROLLER_MODEL: + if host._personality == constants.CONTROLLER: + return True + else: + return False + else: + # Storage model is undefined + return False class DataNetwork(base.APIResourceWrapper): diff --git a/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/admin/inventory/storages/tables.py b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/admin/inventory/storages/tables.py index 23bcb5dd..cbbc550d 100644 --- a/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/admin/inventory/storages/tables.py +++ b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/admin/inventory/storages/tables.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2013-2015, 2017 Wind River Systems, Inc. +# Copyright (c) 2013-2019 Wind River Systems, Inc. # # SPDX-License-Identifier: Apache-2.0 # @@ -33,18 +33,19 @@ class CreateStorageVolume(tables.LinkAction): return reverse(self.url, args=(host_id,)) def allowed(self, request, datum): - is_system_k8s_aio = sysinv.is_system_k8s_aio(request) + host_id = self.table.kwargs['host_id'] + is_host_with_storage = sysinv.is_host_with_storage(request, host_id) host = self.table.kwargs['host'] self.verbose_name = _("Assign Storage Function") classes = [c for c in self.classes if c != "disabled"] self.classes = classes - if host._personality != 'storage' and not is_system_k8s_aio: + if not is_host_with_storage: return False if host._administrative == 'unlocked': - if 'storage' in host._subfunctions or is_system_k8s_aio: + if is_host_with_storage: if "disabled" not in self.classes: self.classes = [c for c in self.classes] + ['disabled'] self.verbose_name = string_concat(self.verbose_name, ' ', diff --git a/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/admin/inventory/tabs.py b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/admin/inventory/tabs.py index ad736c21..79206e0d 100755 --- a/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/admin/inventory/tabs.py +++ b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/admin/inventory/tabs.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2013-2018 Wind River Systems, Inc. +# Copyright (c) 2013-2019 Wind River Systems, Inc. # # SPDX-License-Identifier: Apache-2.0 # @@ -489,8 +489,9 @@ class StorageTab(tabs.TableTab): def get_context_data(self, request): context = super(StorageTab, self).get_context_data(request) + host = self.tab_group.kwargs['host'] try: - context['host'] = self.tab_group.kwargs['host'] + context['host'] = host except Exception: redirect = reverse('horizon:admin:inventory:index') exceptions.handle(self.request, @@ -498,8 +499,8 @@ class StorageTab(tabs.TableTab): redirect=redirect) context['cinder_backend'] = stx_api.sysinv.get_cinder_backend(request) - context['is_system_k8s_aio'] = \ - stx_api.sysinv.is_system_k8s_aio(request) + context['is_host_with_storage'] = \ + stx_api.sysinv.is_host_with_storage(request, host.uuid) return context diff --git a/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/admin/inventory/templates/inventory/_detail_storages.html b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/admin/inventory/templates/inventory/_detail_storages.html index c2e0addc..967416a6 100755 --- a/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/admin/inventory/templates/inventory/_detail_storages.html +++ b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/admin/inventory/templates/inventory/_detail_storages.html @@ -9,8 +9,7 @@
{{ partitions_table.render }}
- - {% if host.personality == "Storage" or is_system_k8s_aio %} + {% if is_host_with_storage %}
{{ storagevolumes_table.render }}
diff --git a/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/admin/inventory/workflows.py b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/admin/inventory/workflows.py index 4c05dc62..42576361 100755 --- a/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/admin/inventory/workflows.py +++ b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/admin/inventory/workflows.py @@ -1,5 +1,5 @@ # -# Copyright (c) 2013-2018 Wind River Systems, Inc. +# Copyright (c) 2013-2019 Wind River Systems, Inc. # # SPDX-License-Identifier: Apache-2.0 # @@ -9,6 +9,7 @@ import logging import cpu_functions.utils as icpu_utils +import sysinv.common.constants as sysinv_const from cgtsclient.common import constants from cgtsclient import exc @@ -23,6 +24,7 @@ from horizon.utils import validators from horizon import workflows from starlingx_dashboard import api as stx_api +from starlingx_dashboard.api import sysinv LOG = logging.getLogger(__name__) @@ -392,7 +394,10 @@ class UpdateHostInfoAction(workflows.Action): self.fields[ 'interfaceProfile'].widget = forms.widgets.HiddenInput() + stor_model = sysinv.get_ceph_storage_model(request) if ((personality == 'storage' or + (personality == 'controller' and + stor_model == sysinv_const.CEPH_CONTROLLER_MODEL) or 'worker' in host._subfunctions) and host.disks): # Populate Available Disk Profile Choices try: