From 42f6086beab8b0ee0f3400a37264e07c555f5ce7 Mon Sep 17 00:00:00 2001
From: Li Zhu
Date: Mon, 29 May 2023 10:15:03 -0400
Subject: [PATCH] Update Horizon to support prestage orchestration
Support the operations of create/delete prestage orchestration strategy
on Horizon.
Test Plan:
PASS: Successfully create and apply prestage strategy with specified
21.12/22.12 release.
PASS: Successfully create and apply prestage strategy with 22.12 release
(the system controller active release) when the release field
is absent.
PASS: Successfully abort or delete the prestage strategy.
PASS: Verify no broken functionalities of existing orchestration
strategies.
Story: 2010611
Task: 48144
Change-Id: Ia560e6b9e8f3fa8f27e9864b204335cd0c6935f1
Signed-off-by: lzhu1
---
.../starlingx_dashboard/api/sysinv.py | 31 +++++++++
.../dc_admin/dc_orchestration/forms.py | 65 ++++++++++++++++++-
.../_cloud_strategy_orchestration.html | 11 +++-
.../_create_cloud_strategy.html | 3 +
.../_30_stx_local_settings.py | 4 +-
5 files changed, 108 insertions(+), 6 deletions(-)
diff --git a/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/api/sysinv.py b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/api/sysinv.py
index 3761cdf0..f5ca0528 100644
--- a/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/api/sysinv.py
+++ b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/api/sysinv.py
@@ -111,6 +111,11 @@ HOST_BM_TYPE_IPMI = "ipmi"
HOST_BM_TYPE_REDFISH = "redfish"
HOST_BM_TYPE_DYNAMIC = "dynamic"
+# Load states
+ACTIVE_LOAD_STATE = 'active'
+INACTIVE_LOAD_STATE = 'inactive'
+IMPORTED_LOAD_STATE = 'imported'
+
LOG = logging.getLogger(__name__)
@@ -2533,3 +2538,29 @@ class KubeVersion(base.APIResourceWrapper):
def kube_version_list(request):
kube_versions = cgtsclient(request).kube_version.list()
return [KubeVersion(n) for n in kube_versions]
+
+
+class Load(base.APIResourceWrapper):
+ """Wrapper for Load"""
+
+ _attrs = ['software_version', 'compatible_version', 'required_patches',
+ 'state']
+
+ def __init__(self, apiresource):
+ super(Load, self).__init__(apiresource)
+
+
+def load_list(request):
+ loads = cgtsclient(request).load.list()
+ return [Load(n) for n in loads]
+
+
+def get_sw_versions_for_prestage(request):
+ valid_states = [
+ ACTIVE_LOAD_STATE,
+ IMPORTED_LOAD_STATE,
+ INACTIVE_LOAD_STATE
+ ]
+ loads = load_list(request)
+ return [load.software_version for load in loads
+ if load.state in valid_states]
diff --git a/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_orchestration/forms.py b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_orchestration/forms.py
index 3480021b..a1a103a1 100644
--- a/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_orchestration/forms.py
+++ b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_orchestration/forms.py
@@ -4,6 +4,7 @@
# SPDX-License-Identifier: Apache-2.0
#
+import base64
import logging
from dcmanagerclient import exceptions as exc
@@ -40,6 +41,8 @@ class ApplyCloudStrategyForm(forms.SelfHandlingForm):
class CreateCloudStrategyForm(forms.SelfHandlingForm):
+ FIELD_LABEL_RELEASE = _("Release")
+ FIELD_LABEL_SYSADMIN_PASSWORD = _("sysadmin password")
failure_url = 'horizon:dc_admin:dc_orchestration:index'
SUBCLOUD_APPLY_TYPES = (
@@ -52,6 +55,7 @@ class CreateCloudStrategyForm(forms.SelfHandlingForm):
('upgrade', _("Upgrade")),
('kubernetes', _("Kubernetes")),
('firmware', _("Firmware")),
+ ('prestage', _("Prestage")),
)
SUBCLOUD_TYPES = (
@@ -186,7 +190,7 @@ class CreateCloudStrategyForm(forms.SelfHandlingForm):
initial=False,
required=False,
help_text=_('Force Kube upgrade to a subcloud '
- 'which is in-sync with system controller'),
+ 'which is in-sync with System Controller'),
widget=forms.CheckboxInput(
attrs={
'class': 'switched',
@@ -210,6 +214,37 @@ class CreateCloudStrategyForm(forms.SelfHandlingForm):
)
)
+ release = forms.ChoiceField(
+ label=FIELD_LABEL_RELEASE,
+ required=False,
+ help_text=_("Select a version for the strategy to apply. \
+ Otherwise, the System Controller active version \
+ will be used."),
+ widget=forms.Select(
+ attrs={
+ 'class': 'switched',
+ 'data-switch-on': 'strategy_types',
+ 'data-strategy_types-prestage': FIELD_LABEL_RELEASE,
+ 'data-slug': 'release'
+ }
+ )
+ )
+
+ sysadmin_password = forms.CharField(
+ label=FIELD_LABEL_SYSADMIN_PASSWORD,
+ required=False,
+ widget=forms.PasswordInput(
+ attrs={
+ 'autocomplete': 'off',
+ 'class': 'switched',
+ 'data-switch-on': 'strategy_types',
+ 'data-strategy_types-prestage':
+ FIELD_LABEL_SYSADMIN_PASSWORD,
+ 'data-required-when-shown': 'true'
+ }
+ )
+ )
+
def __init__(self, request, *args, **kwargs):
super(CreateCloudStrategyForm, self).__init__(request, *args,
**kwargs)
@@ -232,6 +267,27 @@ class CreateCloudStrategyForm(forms.SelfHandlingForm):
kube_versions.extend(version)
self.fields['to_version'].choices = kube_versions
+ release_list = []
+ sw_versions = api.sysinv.get_sw_versions_for_prestage(self.request)
+ for version in sw_versions:
+ release_list.extend([(version, version)])
+ empty_release = [('', '--')]
+ release_list[:0] = empty_release
+ self.fields['release'].choices = release_list
+
+ def clean(self):
+ cleaned_data = super(CreateCloudStrategyForm, self).clean()
+ if cleaned_data['type'] == 'prestage':
+ if (('sysadmin_password' not in cleaned_data) or
+ (not cleaned_data['sysadmin_password'])):
+ raise forms.ValidationError(
+ {'sysadmin_password':
+ forms.ValidationError('sysadmin password is required')})
+ else:
+ cleaned_data.pop('release', None)
+ cleaned_data.pop('sysadmin_password', None)
+ return cleaned_data
+
def handle(self, request, data):
try:
# convert keys to use dashes
@@ -268,6 +324,13 @@ class CreateCloudStrategyForm(forms.SelfHandlingForm):
else:
del data['upload-only']
+ if data['type'] == 'prestage':
+ if data['release'] == '':
+ data.pop('release', None)
+ data['sysadmin_password'] = base64.b64encode(
+ data['sysadmin-password'].encode("utf-8")).decode("utf-8")
+ data.pop('sysadmin-password', None)
+
response = api.dc_manager.strategy_create(request, data)
if not response:
messages.error(request, "Strategy creation failed")
diff --git a/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_orchestration/templates/dc_orchestration/_cloud_strategy_orchestration.html b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_orchestration/templates/dc_orchestration/_cloud_strategy_orchestration.html
index 08aa24c1..29a6d7ce 100644
--- a/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_orchestration/templates/dc_orchestration/_cloud_strategy_orchestration.html
+++ b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_orchestration/templates/dc_orchestration/_cloud_strategy_orchestration.html
@@ -17,9 +17,14 @@
{{ strategy.max_parallel_subclouds }}
{% trans "Stop On Failure" %}
{{ strategy.stop_on_failure }}
- {% if strategy.strategy_type == 'patch' and strategy.extra_args %}
- {% trans "Upload Only" %}
- {{ strategy.extra_args|get_value:"upload-only" }}
+ {% if strategy.extra_args %}
+ {% if strategy.strategy_type == 'patch' %}
+ {% trans "Upload Only" %}
+ {{ strategy.extra_args|get_value:"upload-only" }}
+ {% elif strategy.strategy_type == 'prestage' %}
+ {% trans "Prestage Software Version" %}
+ {{ strategy.extra_args|get_value:"prestage-software-version" }}
+ {% endif %}
{% endif %}
{% trans "State" %}
{{ strategy.state }}
diff --git a/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_orchestration/templates/dc_orchestration/_create_cloud_strategy.html b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_orchestration/templates/dc_orchestration/_create_cloud_strategy.html
index 13e497e9..3431aeaa 100644
--- a/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_orchestration/templates/dc_orchestration/_create_cloud_strategy.html
+++ b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/dashboards/dc_admin/dc_orchestration/templates/dc_orchestration/_create_cloud_strategy.html
@@ -28,6 +28,9 @@
{% trans "Firmware: specify how the firmware should be updated." %}
+
+ {% trans "Prestage: specify how the software should be prestaged." %}
+
{% endblock %}
diff --git a/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/local/local_settings.d/_30_stx_local_settings.py b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/local/local_settings.d/_30_stx_local_settings.py
index cdca901e..47951e1c 100644
--- a/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/local/local_settings.d/_30_stx_local_settings.py
+++ b/starlingx-dashboard/starlingx-dashboard/starlingx_dashboard/local/local_settings.d/_30_stx_local_settings.py
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2019-2021 Wind River Systems, Inc.
+# Copyright (c) 2019-2023 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@@ -99,7 +99,7 @@ OPERATION_LOG_ENABLED = True
OPERATION_LOG_OPTIONS = {
'mask_fields': ['password', 'bm_password', 'bm_confirm_password',
'current_password', 'confirm_password', 'new_password',
- 'fake_password'],
+ 'fake_password', 'sysadmin_password'],
'ignore_urls': [],
'target_methods': ['POST', 'PUT', 'DELETE'],
'format': ("[%(project_name)s %(project_id)s] [%(user_name)s %(user_id)s]"