New system service-parameter sysinv_api_workers

The new system service-parameter will allow a user to specify the
number of sysinv api workers for horizontal scaling
The maximum value is capped at the number of physical cores.

The values
- service -> platform
- section -> config
- name -> sysinv_api_workers
- value -> [1 .. n ]
- personality -> None
- resource -> ::platform::sysinv::params::sysinv_api_workers

CGTS-CLIENT
- add --format arg to cli
- update service-parameter Unit Tests

SYSINV REST API
- add validation for sysinv_api_workers parameter
  ( min 1, max core count)

SYSINV Conductor
- update config to include sysinv_api_workers in puppet config hierdata

Test plan:

PASS - Unit testing

PASS - AIO-SX:
               verify default sysinv_api_workers_value
               verify system service-parameter-add
               verify system service-parameter-modify
               verify system service-parameter-delete

PASS - AIO-DX:
               verify default sysinv_api_workers_value
               verify system service-parameter-add
               verify system service-parameter-modify
               verify system service-parameter-delete

PASS - AIO-SX system controller:
               verify default sysinv_api_workers value

PASS - AIO-SX/DX:
               verify max sysinv_api_workers <= physical cores
               compare to system host-cpu-list <controller>

               ----------------
               Example error:
               ----------------
               Parameter 'sysinv_api_workers' must be between 1 and 6.

Story: 2011106
Task: 50065

Change-Id: I7fa0407a747def9bf66060a1b6622029a00ba5a8
Signed-off-by: Kyale, Eliud <Eliud.Kyale@windriver.com>
This commit is contained in:
Kyale, Eliud 2024-05-01 16:25:57 -04:00
parent 180ac1df30
commit ed952d898a
10 changed files with 619 additions and 41 deletions

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2013-2019 Wind River Systems, Inc.
# Copyright (c) 2013-2019,2024 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@ -17,7 +17,6 @@ import keystoneauth1
from cgtsclient import exc
from cgtsclient import shell as cgts_shell
from cgtsclient.tests import utils
from cgtsclient.v1.ihost import ihost
FAKE_ENV = {'OS_USERNAME': 'username',
'OS_PASSWORD': 'password',
@ -62,9 +61,22 @@ class ShellTest(utils.BaseTestCase):
return out
class ShellBaseTest(ShellTest):
def test_help_unknown_command(self):
self.assertRaises(exc.CommandError, self.shell, 'help foofoo')
def test_help_on_network_addrpool_subcommand(self):
self.shell("help network-addrpool-list")
self.shell("help network-addrpool-show")
self.shell("help network-addrpool-assign")
self.shell("help network-addrpool-remove")
def test_auth_param(self):
self.make_env(exclude='OS_USERNAME')
self.test_help()
def test_debug(self):
httplib2.debuglevel = 0
self.shell('--debug help')
@ -101,28 +113,3 @@ class ShellTest(utils.BaseTestCase):
for r in required:
self.assertThat(help_text,
matchers.MatchesRegex(r, self.re_options))
def test_auth_param(self):
self.make_env(exclude='OS_USERNAME')
self.test_help()
@mock.patch('cgtsclient.v1.ihost.ihostManager.list')
def test_host_list(self, mock_list):
# This unit test mocks returning a single controller-0 host through host-list
fake_controller = {'id': '0',
'hostname': 'controller-0',
'personality': 'controller',
'administrative': 'unlocked',
'operational': 'enabled',
'availability': 'available'}
mock_list.return_value = [ihost(None, fake_controller, True)]
self.make_env()
host_results = self.shell("host-list")
self.assertIn('controller-0', host_results)
self.assertNotIn('controller-1', host_results)
def test_help_on_network_addrpool_subcommand(self):
self.shell("help network-addrpool-list")
self.shell("help network-addrpool-show")
self.shell("help network-addrpool-assign")
self.shell("help network-addrpool-remove")

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2019-2023 Wind River Systems, Inc.
# Copyright (c) 2019-2024 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@ -193,6 +193,21 @@ class HostTest(test_shell.ShellTest):
self.assertIn(str(FAKE_KUBE_HOST_UPGRADE_2['status']),
results)
@mock.patch('cgtsclient.v1.ihost.ihostManager.list')
def test_host_list(self, mock_list):
# This unit test mocks returning a single controller-0 host through host-list
fake_controller = {'id': '0',
'hostname': 'controller-0',
'personality': 'controller',
'administrative': 'unlocked',
'operational': 'enabled',
'availability': 'available'}
mock_list.return_value = [ihost(None, fake_controller, True)]
self.make_env()
host_results = self.shell("host-list")
self.assertIn('controller-0', host_results)
self.assertNotIn('controller-1', host_results)
def test_kube_host_upgrade_kubelet(self):
self.make_env()
self.ihost_manager_list_result = [ihost(None, FAKE_IHOST_2, True)]

View File

@ -0,0 +1,302 @@
#
# Copyright (c) 2024 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
import copy
import testtools
import uuid
from cgtsclient.tests import utils
import cgtsclient.v1.service_parameter
CREATE_PARAMETER_1 = {
'service': 'platform',
'section': 'config',
'parameters': {
'sysinv_api_workers': 10
},
'personality': None,
'resource': None,
}
PARAMETER_1 = {
'uuid': str(uuid.uuid4()),
'service': 'platform',
'section': 'config',
'name': 'sysinv_api_workers',
'value': 10,
'personality': None,
'resource': None,
}
CREATE_PARAMETER_2 = {
'service': 'docker',
'section': 'docker-registry',
'parameters': {
'url': 'oldregistry:5000/starlingx/docker.io'
},
'personality': None,
'resource': None,
}
PARAMETER_2 = {
'uuid': str(uuid.uuid4()),
'service': 'docker',
'section': 'docker-registry',
'name': 'url',
'value': 'oldregistry:5000/starlingx/docker.io',
'personality': None,
'resource': None,
}
UPDATED_PARAMETER_1 = copy.deepcopy(PARAMETER_1)
NEW_VALUE_PARAMETER_1 = 15
UPDATED_PARAMETER_1['value'] = NEW_VALUE_PARAMETER_1
UPDATED_PARAMETER_2 = copy.deepcopy(PARAMETER_2)
NEW_VALUE_PARAMETER_2 = 'newregistry:5000/starlingx/docker.io'
UPDATED_PARAMETER_2['value'] = NEW_VALUE_PARAMETER_2
PARAMETERS = {
"parameters": [PARAMETER_1, PARAMETER_2]
}
fixtures_default = {
'/v1/service_parameter':
{
'GET': (
{},
PARAMETERS,
),
'POST': (
{},
PARAMETER_1,
),
},
'/v1/service_parameter/%s' % PARAMETER_1['uuid']:
{
'GET': (
{},
PARAMETER_1,
),
'DELETE': (
{},
None,
),
'PATCH': (
{},
UPDATED_PARAMETER_1,
),
},
'/v1/service_parameter/%s' % PARAMETER_2['uuid']:
{
'GET': (
{},
PARAMETER_2,
),
'DELETE': (
{},
None,
),
'PATCH': (
{},
UPDATED_PARAMETER_2,
),
},
'/v1/service_parameter/apply':
{
'POST': (
{},
None,
)
},
}
class ServiceParameterManagerTest(testtools.TestCase):
def setUp(self):
super(ServiceParameterManagerTest, self).setUp()
self.api = utils.FakeAPI(fixtures_default)
self.mgr = \
cgtsclient.v1.service_parameter.ServiceParameterManager(self.api)
def test_service_parameter_list(self):
parameters = self.mgr.list()
expect = [
# (method , url , headers , body )
('GET', '/v1/service_parameter', {}, None)
]
self.assertEqual(self.api.calls, expect)
self.assertEqual(len(parameters), 2)
def test_service_parameter_get(self):
parameter_1 = self.mgr.get(PARAMETER_1['uuid'])
expect = [
('GET',
'/v1/service_parameter/%s' % PARAMETER_1['uuid'],
{},
None),
]
self.assertEqual(self.api.calls, expect)
self.assertTrue(
isinstance(parameter_1,
cgtsclient.v1.service_parameter.ServiceParameter))
self.assertEqual(parameter_1.uuid, PARAMETER_1['uuid'])
self.assertEqual(parameter_1.service, PARAMETER_1['service'])
self.assertEqual(parameter_1.section, PARAMETER_1['section'])
self.assertEqual(parameter_1.name, PARAMETER_1['name'])
self.assertEqual(parameter_1.value, PARAMETER_1['value'])
parameter_2 = self.mgr.get(UPDATED_PARAMETER_2['uuid'])
expect = [
('GET',
'/v1/service_parameter/%s' % PARAMETER_1['uuid'],
{},
None),
('GET',
'/v1/service_parameter/%s' % PARAMETER_2['uuid'],
{},
None)
]
self.assertEqual(self.api.calls, expect)
self.assertTrue(
isinstance(parameter_2,
cgtsclient.v1.service_parameter.ServiceParameter))
self.assertEqual(parameter_2.uuid, PARAMETER_2['uuid'])
self.assertEqual(parameter_2.service, PARAMETER_2['service'])
self.assertEqual(parameter_2.section, PARAMETER_2['section'])
self.assertEqual(parameter_2.name, PARAMETER_2['name'])
self.assertEqual(parameter_2.value, PARAMETER_2['value'])
def test_service_parameter_create(self):
parameter_1 = self.mgr.create(
PARAMETER_1['service'],
PARAMETER_1['section'],
PARAMETER_1['personality'],
PARAMETER_1['resource'],
{
PARAMETER_1['name']: PARAMETER_1['value'],
}
)
self.api.fixtures['/v1/service_parameter']['POST'] = (
{},
PARAMETER_2,
)
parameter_2 = self.mgr.create(
PARAMETER_2['service'],
PARAMETER_2['section'],
PARAMETER_2['personality'],
PARAMETER_2['resource'],
{
PARAMETER_2['name']: PARAMETER_2['value'],
}
)
expect = [
('POST',
'/v1/service_parameter',
{},
CREATE_PARAMETER_1),
('POST',
'/v1/service_parameter',
{},
CREATE_PARAMETER_2),
]
self.assertEqual(self.api.calls, expect)
isinstance(
parameter_1,
cgtsclient.v1.service_parameter.ServiceParameter)
isinstance(
parameter_2,
cgtsclient.v1.service_parameter.ServiceParameter)
self.assertEqual(parameter_1.uuid, PARAMETER_1['uuid'])
self.assertEqual(parameter_1.service, PARAMETER_1['service'])
self.assertEqual(parameter_1.section, PARAMETER_1['section'])
self.assertEqual(parameter_1.name, PARAMETER_1['name'])
self.assertEqual(parameter_1.value, PARAMETER_1['value'])
self.assertEqual(parameter_2.uuid, PARAMETER_2['uuid'])
self.assertEqual(parameter_2.service, PARAMETER_2['service'])
self.assertEqual(parameter_2.section, PARAMETER_2['section'])
self.assertEqual(parameter_2.name, PARAMETER_2['name'])
self.assertEqual(parameter_2.value, PARAMETER_2['value'])
def test_service_parameter_delete(self):
parameter = self.mgr.delete(PARAMETER_1['uuid'])
expect = [
('DELETE',
'/v1/service_parameter/%s' % PARAMETER_1['uuid'],
{},
None),
]
self.assertEqual(self.api.calls, expect)
self.assertTrue(parameter is None)
def test_service_parameter_apply(self):
_, body = self.mgr.apply(
PARAMETER_1['service'],
PARAMETER_1['section'],
)
expect = [
(
'POST',
'/v1/service_parameter/apply',
{},
{
"service": PARAMETER_1['service'],
"section": PARAMETER_1['section'],
}
),
]
self.assertEqual(self.api.calls, expect)
self.assertTrue(body is None)
def test_service_parameter_update(self):
patch_1 = [
{
'op': 'replace',
'path': '/name',
'value': PARAMETER_1['name'],
},
{
'op': 'replace',
'path': '/value',
'value': PARAMETER_1['value']
},
]
patch_2 = [
{
'op': 'replace',
'path': '/name',
'value': PARAMETER_2['name'],
},
{
'op': 'replace',
'path': '/value',
'value': PARAMETER_2['value']
},
]
parameter_1 = self.mgr.update(PARAMETER_1['uuid'], patch_1)
parameter_2 = self.mgr.update(PARAMETER_2['uuid'], patch_2)
expect = [
('PATCH',
'/v1/service_parameter/%s' % PARAMETER_1['uuid'],
{},
patch_1),
('PATCH',
'/v1/service_parameter/%s' % PARAMETER_2['uuid'],
{},
patch_2),
]
self.assertEqual(self.api.calls, expect)
self.assertEqual(parameter_1.value, NEW_VALUE_PARAMETER_1)
self.assertEqual(parameter_2.value, NEW_VALUE_PARAMETER_2)

View File

@ -0,0 +1,215 @@
#
# Copyright (c) 2024 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
import mock
import uuid
import yaml
from cgtsclient import exc
from cgtsclient.tests import test_shell
from cgtsclient.v1.service_parameter import ServiceParameter
from http import HTTPStatus
from testtools import ExpectedException
FAKE_SERVICE_PARAMETER_1 = {
'uuid': str(uuid.uuid4()),
'service': 'platform',
'section': 'config',
'name': 'sysinv_api_workers',
'value': 10,
'personality': None,
'resource': None,
}
FAKE_SERVICE_PARAMETER_2 = {
'uuid': str(uuid.uuid4()),
'service': 'docker',
'section': 'docker-registry',
'name': 'url',
'value': 'myregistry:5000/starlingx/docker.io',
'personality': None,
'resource': None,
}
class MockResponse:
def __init__(self, status_code, json_data) -> None:
self.json_data = json_data
self.status_code = status_code
def json(self):
return self.json_data
class ServiceParameterTest(test_shell.ShellTest):
def setUp(self):
super(ServiceParameterTest, self).setUp()
self.make_env()
@mock.patch('cgtsclient.v1.service_parameter.ServiceParameterManager.list')
def test_service_parameter_list(self, mock_list):
mock_list.return_value = [
ServiceParameter(None, FAKE_SERVICE_PARAMETER_1, True),
ServiceParameter(None, FAKE_SERVICE_PARAMETER_2, True),
]
results_str = self.shell("service-parameter-list --format yaml")
results_list = yaml.safe_load(results_str)
self.assertTrue(isinstance(results_list, list),
"service-parameter-list should return a list")
expected_list = [FAKE_SERVICE_PARAMETER_2, FAKE_SERVICE_PARAMETER_1]
self.assertCountEqual(expected_list, results_list)
@mock.patch('cgtsclient.v1.service_parameter.ServiceParameterManager.get')
def test_service_parameter_show(self, mock_get):
mock_get.return_value = ServiceParameter(None,
FAKE_SERVICE_PARAMETER_1,
True)
results = self.shell("service-parameter-show --format yaml "
f"{FAKE_SERVICE_PARAMETER_1['uuid']}")
service_parameter = yaml.safe_load(results)
self.assertEqual(service_parameter['service'],
FAKE_SERVICE_PARAMETER_1['service'])
self.assertEqual(service_parameter['section'],
FAKE_SERVICE_PARAMETER_1['section'])
self.assertEqual(service_parameter['name'],
FAKE_SERVICE_PARAMETER_1['name'])
self.assertEqual(service_parameter['value'],
FAKE_SERVICE_PARAMETER_1['value'])
@mock.patch(
'cgtsclient.v1.service_parameter.ServiceParameterManager.apply'
)
def test_service_parameter_apply(self, mock_apply):
resp = MockResponse(HTTPStatus.OK, {})
mock_apply.return_value = (resp, resp.json())
self.shell("service-parameter-apply"
f" --section {FAKE_SERVICE_PARAMETER_1['section']}"
f" {FAKE_SERVICE_PARAMETER_1['service']}")
mock_apply.assert_called_once()
@mock.patch(
'cgtsclient.v1.service_parameter.ServiceParameterManager.apply'
)
def test_service_parameter_apply_invalid(self, mock_apply):
mock_apply.side_effect = exc.HTTPNotFound()
exception_str = 'Failed to apply service parameters'
with ExpectedException(exc.CommandError, exception_str):
self.shell("service-parameter-apply --section invalid_section"
" invalid_service")
@mock.patch(
'cgtsclient.v1.service_parameter.ServiceParameterManager.delete'
)
def test_service_parameter_delete(self, mock_delete):
self.shell(f"service-parameter-delete"
f" {FAKE_SERVICE_PARAMETER_1['uuid']}")
mock_delete.assert_called_once()
@mock.patch(
'cgtsclient.v1.service_parameter.ServiceParameterManager.get'
)
@mock.patch(
'cgtsclient.v1.service_parameter.ServiceParameterManager.create'
)
def test_service_parameter_add(self, mock_create, mock_get):
body = {
'parameters': [
FAKE_SERVICE_PARAMETER_1
]
}
mock_create.return_value = ServiceParameter(None,
body,
True)
mock_get.return_value = ServiceParameter(None,
FAKE_SERVICE_PARAMETER_1,
True)
self.shell("service-parameter-add"
f" {FAKE_SERVICE_PARAMETER_1['service']}"
f" {FAKE_SERVICE_PARAMETER_1['section']}"
f" {FAKE_SERVICE_PARAMETER_1['name']}="
f" {FAKE_SERVICE_PARAMETER_1['value']}")
mock_create.assert_called_once()
mock_get.assert_called_once()
def test_service_parameter_add_invalid_parameters(self):
custom_resource = "::platform::config::params::custom"
keyvaluepairs = "param1=true param2=disabled param3=10"
exception_str =\
"Cannot specify multiple parameters with custom resource."
with ExpectedException(exc.CommandError, exception_str):
self.shell("service-parameter-add platform config "
f" {keyvaluepairs} "
f"--resource {custom_resource}")
@mock.patch(
'cgtsclient.v1.service_parameter.ServiceParameterManager.create'
)
def test_service_parameter_add_failed(self, mock_create):
mock_create.side_effect = exc.HTTPNotFound()
attributes =\
{
FAKE_SERVICE_PARAMETER_1['name']:
str(FAKE_SERVICE_PARAMETER_1['value'])
}
exception_str = \
f'Failed to create Service parameters: {attributes} '
with ExpectedException(exc.CommandError, exception_str):
self.shell("service-parameter-add"
f" {FAKE_SERVICE_PARAMETER_1['service']}"
f" {FAKE_SERVICE_PARAMETER_1['section']}"
f" {FAKE_SERVICE_PARAMETER_1['name']}="
f"{FAKE_SERVICE_PARAMETER_1['value']}")
@mock.patch(
'cgtsclient.v1.service_parameter.ServiceParameterManager.list'
)
@mock.patch(
'cgtsclient.v1.service_parameter.ServiceParameterManager.update')
def test_service_parameter_modify(self, mock_update, mock_list):
FAKE_SERVICE_PARAMETER_1_MODIFIED = FAKE_SERVICE_PARAMETER_1
FAKE_SERVICE_PARAMETER_1_MODIFIED['value'] = 15
mock_list.return_value = [
ServiceParameter(None, FAKE_SERVICE_PARAMETER_1, True),
ServiceParameter(None, FAKE_SERVICE_PARAMETER_2, True),
]
mock_update.return_value = \
ServiceParameter(None, FAKE_SERVICE_PARAMETER_1_MODIFIED, True)
r = self.shell("service-parameter-modify"
f" {FAKE_SERVICE_PARAMETER_1['service']}"
f" {FAKE_SERVICE_PARAMETER_1['section']}"
f" {FAKE_SERVICE_PARAMETER_1['name']}="
f"{FAKE_SERVICE_PARAMETER_1_MODIFIED['value']}"
" --format yaml")
mock_list.assert_called_once()
mock_update.assert_called_once()
service_parameter = yaml.safe_load(r)
self.assertEqual(service_parameter['service'],
FAKE_SERVICE_PARAMETER_1['service'])
self.assertEqual(service_parameter['section'],
FAKE_SERVICE_PARAMETER_1['section'])
self.assertEqual(service_parameter['name'],
FAKE_SERVICE_PARAMETER_1['name'])
self.assertEqual(service_parameter['value'],
FAKE_SERVICE_PARAMETER_1_MODIFIED['value'])
def test_service_parameter_modify_invalid_parameters(self):
custom_resource = "::platform::config::params::custom"
keyvaluepairs = "param1=true param2=disabled param3=10"
exception_str = \
"Cannot specify multiple parameters with custom resource."
with ExpectedException(exc.CommandError, exception_str):
self.shell("service-parameter-modify platform config "
f" {keyvaluepairs} "
f"--resource {custom_resource}")

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2013-2019 Wind River Systems, Inc.
# Copyright (c) 2013-2019,2024 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@ -13,20 +13,24 @@ from cgtsclient import exc
from cgtsclient.v1 import options
def _print_service_parameter_show(obj):
def _print_service_parameter_show(service_parameter, output_format=None):
fields = ['uuid', 'service', 'section', 'name', 'value',
'personality', 'resource']
data = [(f, getattr(obj, f, '')) for f in fields]
utils.print_tuple_list(data)
data_list = [(f, getattr(service_parameter, f, '')) for f in fields]
data = dict(data_list)
utils.print_dict_with_format(data, wrap=72, output_format=output_format)
@utils.arg('uuid',
metavar='<uuid>',
help="UUID of service parameter")
@utils.arg('--format',
choices=['table', 'yaml', 'value'],
help="Specify the output format, defaults to table")
def do_service_parameter_show(cc, args):
"""Show Service parameter."""
service_parameter = cc.service_parameter.get(args.uuid)
_print_service_parameter_show(service_parameter)
_print_service_parameter_show(service_parameter, args.format)
@utils.arg('--service',
@ -107,12 +111,14 @@ def _find_service_parameter(cc, service, section, name):
metavar='<resource>',
default=None,
help="Custom resource to be updated")
@utils.arg('--format',
choices=['table', 'yaml', 'value'],
help="specify the output format, defaults to table")
def do_service_parameter_modify(cc, args):
"""Modify Service Parameter attributes."""
patch = []
attributes = utils.extract_keypairs(args)
if len(attributes) > 1 \
and (args.resource is not None or args.personality is not None):
raise exc.CommandError("Cannot specify multiple parameters with custom resource.")
@ -129,7 +135,7 @@ def do_service_parameter_modify(cc, args):
if args.resource:
patch.append({'op': 'replace', 'path': '/resource', 'value': args.resource})
parameter = cc.service_parameter.update(service_parameter.uuid, patch)
_print_service_parameter_show(parameter)
_print_service_parameter_show(parameter, output_format=args.format)
@utils.arg('service',

View File

@ -1,4 +1,4 @@
# Copyright (c) 2015-2023 Wind River Systems, Inc.
# Copyright (c) 2015-2024 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@ -658,7 +658,7 @@ class ServiceParameterController(rest.RestController):
try:
# Pass name to update_service_config only in case the parameters are the Intel
# NIC driver version and intel_pstate.
# NIC driver version, intel_pstate or sysinv_api_workers.
new_name = None
if section == constants.SERVICE_PARAM_SECTION_PLATFORM_CONFIG and \
name == constants.SERVICE_PARAM_NAME_PLAT_CONFIG_INTEL_NIC_DRIVER_VERSION:
@ -668,6 +668,10 @@ class ServiceParameterController(rest.RestController):
name == constants.SERVICE_PARAM_NAME_PLAT_CONFIG_INTEL_PSTATE:
new_name = name
elif section == constants.SERVICE_PARAM_SECTION_PLATFORM_CONFIG and \
name == constants.SERVICE_PARAM_NAME_PLATFORM_SYSINV_API_WORKERS:
new_name = name
pecan.request.rpcapi.update_service_config(
pecan.request.context, service, section=section, name=new_name)
except rpc_common.RemoteError as e:
@ -815,8 +819,8 @@ class ServiceParameterController(rest.RestController):
delete_k8s_configmap(parameter.as_dict(), self.kube_operator)
try:
# Pass name to update_service_config only in case the parameter is the Intel
# NIC driver version
# Pass name to update_service_config only in case the parameter is
# the Intel NIC driver version, intel_pstate or sysinv_api_workers
name = None
if parameter.section == constants.SERVICE_PARAM_SECTION_PLATFORM_CONFIG and \
parameter.name == constants.SERVICE_PARAM_NAME_PLAT_CONFIG_INTEL_NIC_DRIVER_VERSION:
@ -826,6 +830,10 @@ class ServiceParameterController(rest.RestController):
parameter.name == constants.SERVICE_PARAM_NAME_PLAT_CONFIG_INTEL_PSTATE:
name = parameter.name
elif parameter.section == constants.SERVICE_PARAM_SECTION_PLATFORM_CONFIG and \
parameter.name == constants.SERVICE_PARAM_NAME_PLATFORM_SYSINV_API_WORKERS:
name = parameter.name
pecan.request.rpcapi.update_service_config(
pecan.request.context,
parameter.service,

View File

@ -1383,6 +1383,9 @@ SERVICE_PARAM_NAME_CEPH_MONITOR_AUTH_ID_RECLAIM = 'auth_id_reclaim'
SERVICE_PARAM_NAME_PLATFORM_MAX_CPU_PERCENTAGE = 'cpu_max_freq_min_percentage'
SERVICE_PARAM_PLATFORM_MAX_CPU_PERCENTAGE_DEFAULT = 80
# The number of sysinv-api workers
SERVICE_PARAM_NAME_PLATFORM_SYSINV_API_WORKERS = 'sysinv_api_workers'
# DNS host record Service Parameters
SERVICE_PARAM_SECTION_DNS_HOST_RECORD = 'host-record'
SERVICE_PARAM_NAME_DNS_HOST_RECORD_HOSTS = 'hosts'

View File

@ -1,4 +1,4 @@
# Copyright (c) 2017-2023 Wind River Systems, Inc.
# Copyright (c) 2017-2024 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
@ -608,6 +608,13 @@ def _validate_max_cpu_min_percentage(name, value):
return _validate_range(name, value, 60, 100)
def _validate_sysinv_api_workers(name, value):
"""Check if sysinv_api_workers value is valid"""
MAX_WORKERS = cutils.get_platform_core_count(pecan.request.dbapi)
MIN_WORKERS = 1
return _validate_range(name, value, MIN_WORKERS, MAX_WORKERS)
def parse_volume_string_to_dict(parameter):
"""
Parse volume string value from parameter to dictionary.
@ -801,6 +808,7 @@ PLATFORM_CONFIG_PARAMETER_OPTIONAL = [
constants.SERVICE_PARAM_NAME_PLATFORM_MAX_CPU_PERCENTAGE,
constants.SERVICE_PARAM_NAME_PLAT_CONFIG_INTEL_NIC_DRIVER_VERSION,
constants.SERVICE_PARAM_NAME_PLAT_CONFIG_INTEL_PSTATE,
constants.SERVICE_PARAM_NAME_PLATFORM_SYSINV_API_WORKERS,
]
PLATFORM_CONFIG_PARAMETER_READONLY = [
@ -816,14 +824,19 @@ PLATFORM_CONFIG_PARAMETER_VALIDATOR = {
_validate_intel_nic_driver_version,
constants.SERVICE_PARAM_NAME_PLAT_CONFIG_INTEL_PSTATE:
_validate_intel_pstate,
constants.SERVICE_PARAM_NAME_PLATFORM_SYSINV_API_WORKERS:
_validate_sysinv_api_workers,
}
PLATFORM_CONFIG_PARAMETER_RESOURCE = {
constants.SERVICE_PARAM_NAME_PLAT_CONFIG_VIRTUAL: 'platform::params::virtual_system',
constants.SERVICE_PARAM_NAME_PLAT_CONFIG_VIRTUAL:
'platform::params::virtual_system',
constants.SERVICE_PARAM_NAME_PLAT_CONFIG_INTEL_NIC_DRIVER_VERSION:
'platform::compute::grub::params::g_intel_nic_driver_version',
constants.SERVICE_PARAM_NAME_PLAT_CONFIG_INTEL_PSTATE:
'platform::compute::grub::params::g_intel_pstate',
constants.SERVICE_PARAM_NAME_PLATFORM_SYSINV_API_WORKERS:
'platform::sysinv::params::sysinv_api_workers',
}
IDENTITY_LDAP_PARAMETER_OPTIONAL = [

View File

@ -1018,6 +1018,30 @@ def is_virtual_worker(ihost):
return False
def get_platform_core_count(dbapi):
"""
Determine the number of platform cores available
Returns the minimum of the 2 controllers or 1
"""
core_list = []
controllers = dbapi.ihost_get_by_personality(constants.CONTROLLER)
platform_functions = [
constants.PLATFORM_FUNCTION,
constants.SHARED_FUNCTION
]
for controller in controllers:
number_platform_cores = 0
cpu_list = dbapi.icpu_get_by_ihost(controller.uuid)
for cpu in cpu_list:
if int(cpu['thread']) == 0:
if cpu['allocated_function'] in platform_functions:
number_platform_cores += 1
if number_platform_cores > 0:
core_list.append(number_platform_cores)
return min(core_list, default=1)
def is_low_core_system(ihost, dba):
"""
Determine if the hosts core count is less than or equal to a xeon-d cpu

View File

@ -12047,6 +12047,11 @@ class ConductorManager(service.PeriodicService):
# _config_update_hosts() above. Node needs a reboot to clear it.
config_uuid = self._config_clear_reboot_required(config_uuid)
self._config_apply_runtime_manifest(context, config_uuid, config_dict, force=True)
elif section == constants.SERVICE_PARAM_SECTION_PLATFORM_CONFIG and \
name == constants.SERVICE_PARAM_NAME_PLATFORM_SYSINV_API_WORKERS:
reboot = True
personalities = [constants.CONTROLLER]
config_uuid = self._config_update_hosts(context, personalities, reboot=True)
elif section == constants.SERVICE_PARAM_SECTION_PLATFORM_COREDUMP:
personalities = [constants.CONTROLLER,
constants.WORKER,