Add new kube_cmd_versions table and API endpoint
In the DB, a new "kube_cmd_versions" table will be created, aside from the boilerplate stuff, the important columns will be "kubeadm_version" and "kubelet_version". We want to default these to the highest-available validated version of kubernetes in the load at the time. There will be only 1 row here and the default will be created in the DB migration script. In the API a new endpoint is created '/v1/kube_cmd_versions', and with this we can get and modify the kubeadm/kubelet version. Story: 2008972 Task: 42895 Change-Id: Ic848ea777fecab5bda7488df225c2c3e924c2fd5 Signed-off-by: Mihnea Saracin <Mihnea.Saracin@windriver.com>
This commit is contained in:
parent
63798939c1
commit
ca990c5a0d
|
@ -55,6 +55,7 @@ from cgtsclient.v1 import istor
|
|||
from cgtsclient.v1 import isystem
|
||||
from cgtsclient.v1 import iuser
|
||||
from cgtsclient.v1 import kube_cluster
|
||||
from cgtsclient.v1 import kube_cmd_version
|
||||
from cgtsclient.v1 import kube_host_upgrade
|
||||
from cgtsclient.v1 import kube_upgrade
|
||||
from cgtsclient.v1 import kube_version
|
||||
|
@ -167,6 +168,7 @@ class Client(http.HTTPClient):
|
|||
self.host_fs = host_fs.HostFsManager(self)
|
||||
self.kube_cluster = kube_cluster.KubeClusterManager(self)
|
||||
self.kube_version = kube_version.KubeVersionManager(self)
|
||||
self.kube_cmd_version = kube_cmd_version.KubeCmdVersionManager(self)
|
||||
self.kube_upgrade = kube_upgrade.KubeUpgradeManager(self)
|
||||
self.kube_host_upgrade = kube_host_upgrade.KubeHostUpgradeManager(self)
|
||||
self.device_image = device_image.DeviceImageManager(self)
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
#
|
||||
# Copyright (c) 2021 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
from cgtsclient.common import base
|
||||
|
||||
|
||||
class KubeCmdVersion(base.Resource):
|
||||
def __repr__(self):
|
||||
return "<kube_cmd_version %s>" % self._info
|
||||
|
||||
|
||||
class KubeCmdVersionManager(base.Manager):
|
||||
resource_class = KubeCmdVersion
|
||||
|
||||
@staticmethod
|
||||
def _path():
|
||||
return '/v1/kube_cmd_versions'
|
||||
|
||||
def get(self):
|
||||
try:
|
||||
return self._list(self._path())[0]
|
||||
except IndexError:
|
||||
return None
|
||||
|
||||
def update(self, patch):
|
||||
return self._update(self._path(), patch)
|
|
@ -46,6 +46,7 @@ from sysinv.api.controllers.v1 import kube_host_upgrade
|
|||
from sysinv.api.controllers.v1 import kube_rootca_update
|
||||
from sysinv.api.controllers.v1 import kube_upgrade
|
||||
from sysinv.api.controllers.v1 import kube_version
|
||||
from sysinv.api.controllers.v1 import kube_cmd_version
|
||||
from sysinv.api.controllers.v1 import label
|
||||
from sysinv.api.controllers.v1 import interface
|
||||
from sysinv.api.controllers.v1 import interface_network
|
||||
|
@ -260,6 +261,9 @@ class V1(base.APIBase):
|
|||
kube_versions = [link.Link]
|
||||
"Links to the kube_version resource"
|
||||
|
||||
kube_cmd_versions = [link.Link]
|
||||
"Links to the kube_cmd_version resource"
|
||||
|
||||
kube_upgrade = [link.Link]
|
||||
"Links to the kube_upgrade resource"
|
||||
|
||||
|
@ -815,6 +819,13 @@ class V1(base.APIBase):
|
|||
'kube_versions', '',
|
||||
bookmark=True)]
|
||||
|
||||
v1.kube_cmd_versions = [link.Link.make_link('self', pecan.request.host_url,
|
||||
'kube_cmd_versions', ''),
|
||||
link.Link.make_link('bookmark',
|
||||
pecan.request.host_url,
|
||||
'kube_cmd_versions', '',
|
||||
bookmark=True)]
|
||||
|
||||
v1.kube_upgrade = [link.Link.make_link('self', pecan.request.host_url,
|
||||
'kube_upgrade', ''),
|
||||
link.Link.make_link('bookmark',
|
||||
|
@ -935,6 +946,7 @@ class Controller(rest.RestController):
|
|||
host_fs = host_fs.HostFsController()
|
||||
kube_clusters = kube_cluster.KubeClusterController()
|
||||
kube_versions = kube_version.KubeVersionController()
|
||||
kube_cmd_versions = kube_cmd_version.KubeCmdVersionController()
|
||||
kube_upgrade = kube_upgrade.KubeUpgradeController()
|
||||
kube_rootca_update = kube_rootca_update.KubeRootCAUpdateController()
|
||||
kube_host_upgrades = kube_host_upgrade.KubeHostUpgradeController()
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
#
|
||||
# Copyright (c) 2021 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
import jsonpatch
|
||||
import pecan
|
||||
from pecan import rest
|
||||
import wsme
|
||||
from wsme import types as wtypes
|
||||
import wsmeext.pecan as wsme_pecan
|
||||
|
||||
from oslo_log import log
|
||||
from sysinv._i18n import _
|
||||
from sysinv.api.controllers.v1 import base
|
||||
from sysinv.api.controllers.v1 import types
|
||||
from sysinv.api.controllers.v1 import utils
|
||||
from sysinv.common import exception
|
||||
from sysinv.common import utils as cutils
|
||||
from sysinv import objects
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
LOCK_NAME = 'KubeCmdVersionController'
|
||||
|
||||
|
||||
class KubeCmdVersionPatchType(types.JsonPatchType):
|
||||
|
||||
@staticmethod
|
||||
def mandatory_attrs():
|
||||
return ['/kubeadm_version', '/kubelet_version']
|
||||
|
||||
|
||||
class KubeCmdVersion(base.APIBase):
|
||||
"""API representation of a k8s cmd version."""
|
||||
|
||||
kubeadm_version = wtypes.text
|
||||
"Kubeadm version for this entry"
|
||||
|
||||
kubelet_version = wtypes.text
|
||||
"Kubelet version for this entry"
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self.fields = objects.kube_cmd_version.fields
|
||||
for k in self.fields:
|
||||
if not hasattr(self, k):
|
||||
continue
|
||||
setattr(self, k, kwargs.get(k, wtypes.Unset))
|
||||
|
||||
@classmethod
|
||||
def convert_with_links(cls, rpc_kube_cmd_version):
|
||||
kube_version = KubeCmdVersion(**rpc_kube_cmd_version.as_dict())
|
||||
return kube_version
|
||||
|
||||
|
||||
class KubeCmdVersionController(rest.RestController):
|
||||
"""REST controller for Kubernetes Cmd Versions."""
|
||||
|
||||
@wsme_pecan.wsexpose(KubeCmdVersion)
|
||||
def get(self):
|
||||
"""Get the kube cmd version object"""
|
||||
kube_cmd_version = objects.kube_cmd_version.get(pecan.request.context)
|
||||
return KubeCmdVersion.convert_with_links(kube_cmd_version)
|
||||
|
||||
@cutils.synchronized(LOCK_NAME)
|
||||
@wsme_pecan.wsexpose(KubeCmdVersion, body=[KubeCmdVersionPatchType])
|
||||
def patch(self, patch):
|
||||
"""Modify the kube cmd version object"""
|
||||
try:
|
||||
utils.validate_patch(patch)
|
||||
patch_obj = jsonpatch.JsonPatch(patch)
|
||||
kube_cmd_version = objects.kube_cmd_version.get(pecan.request.context)
|
||||
kube_cmd_version_patched = KubeCmdVersion(**jsonpatch.apply_patch(
|
||||
kube_cmd_version.as_dict(),
|
||||
patch_obj))
|
||||
# Update only the fields that have changed
|
||||
for field in objects.kube_cmd_version.fields:
|
||||
if kube_cmd_version[field] != getattr(kube_cmd_version_patched, field):
|
||||
kube_cmd_version[field] = getattr(kube_cmd_version_patched, field)
|
||||
kube_cmd_version.save()
|
||||
|
||||
except utils.JSONPATCH_EXCEPTIONS as e:
|
||||
raise exception.PatchError(patch=patch, reason=e)
|
||||
except Exception as e:
|
||||
LOG.exception(e)
|
||||
raise wsme.exc.ClientSideError(_(
|
||||
"Unable modify the KubeCmdVersion object."))
|
||||
return KubeCmdVersion.convert_with_links(kube_cmd_version)
|
|
@ -110,6 +110,9 @@ KUBE_ROOTCA_UPDATING_HOST_TRUSTNEWCA = 'updating-host-trustNewCA'
|
|||
KUBE_ROOTCA_UPDATED_HOST_TRUSTNEWCA = 'updated-host-trustNewCA'
|
||||
KUBE_ROOTCA_UPDATING_HOST_TRUSTNEWCA_FAILED = 'updating-host-trustNewCA-failed'
|
||||
|
||||
# Kubeadm and Kubelet default versions
|
||||
KUBERNETES_DEFAULT_VERSION = '1.18.1'
|
||||
|
||||
# Kubernetes constants
|
||||
MANIFEST_APPLY_TIMEOUT = 60 * 15
|
||||
MANIFEST_APPLY_INTERVAL = 10
|
||||
|
|
|
@ -4691,3 +4691,14 @@ class Connection(object):
|
|||
|
||||
:param rootca_update_id: id of the kubernetes rootca update entry to be deleted from database.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def kube_cmd_version_get(self):
|
||||
""" Get the kubernetes cmd version entry"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def kube_cmd_version_update(self, values):
|
||||
""" Update the kubernetes cmd version entry.
|
||||
|
||||
:param values: a dictionary with the respective fields and values to be updated in the db entry.
|
||||
"""
|
||||
|
|
|
@ -8941,3 +8941,20 @@ class Connection(api.Connection):
|
|||
except NoResultFound:
|
||||
raise exception.KubeRootCAUpdateNotFound(rootca_update_id=rootca_update_id)
|
||||
query.delete()
|
||||
|
||||
@objects.objectify(objects.kube_cmd_version)
|
||||
def kube_cmd_version_get(self):
|
||||
query = model_query(models.KubeCmdVersions)
|
||||
try:
|
||||
return query.one()
|
||||
except NoResultFound:
|
||||
raise exception.NotFound()
|
||||
|
||||
@objects.objectify(objects.kube_cmd_version)
|
||||
def kube_cmd_version_update(self, values):
|
||||
with _session_for_write() as session:
|
||||
query = model_query(models.KubeCmdVersions, session=session)
|
||||
count = query.update(values)
|
||||
if count != 1:
|
||||
raise exception.NotFound()
|
||||
return query.one()
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
#
|
||||
# Copyright (c) 2021 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
from migrate.changeset import UniqueConstraint
|
||||
from sqlalchemy import Column
|
||||
from sqlalchemy import DateTime
|
||||
from sqlalchemy import Integer
|
||||
from sqlalchemy import MetaData
|
||||
from sqlalchemy import String
|
||||
from sqlalchemy import Table
|
||||
|
||||
from sysinv.common import kubernetes
|
||||
|
||||
ENGINE = 'InnoDB'
|
||||
CHARSET = 'utf8'
|
||||
|
||||
|
||||
def _insert_default_kube_cmd_version(kube_cmd_versions):
|
||||
kube_cmd_versions_insert = kube_cmd_versions.insert()
|
||||
values = {
|
||||
'kubeadm_version': kubernetes.KUBERNETES_DEFAULT_VERSION,
|
||||
'kubelet_version': kubernetes.KUBERNETES_DEFAULT_VERSION
|
||||
}
|
||||
kube_cmd_versions_insert.execute(values)
|
||||
|
||||
|
||||
def upgrade(migrate_engine):
|
||||
"""
|
||||
This database upgrade creates a new kube_cmd_versions table
|
||||
"""
|
||||
|
||||
meta = MetaData()
|
||||
meta.bind = migrate_engine
|
||||
|
||||
# Define and create the kube_cmd_versions table.
|
||||
kube_cmd_versions = Table(
|
||||
'kube_cmd_versions',
|
||||
meta,
|
||||
Column('created_at', DateTime),
|
||||
Column('updated_at', DateTime),
|
||||
Column('deleted_at', DateTime),
|
||||
Column('id', Integer, primary_key=True,
|
||||
unique=True, nullable=False),
|
||||
Column('kubeadm_version', String(255), nullable=False),
|
||||
Column('kubelet_version', String(255), nullable=False),
|
||||
UniqueConstraint('kubeadm_version', 'kubelet_version',
|
||||
name='u_kubeadm_version_kubelet_version'),
|
||||
|
||||
mysql_engine=ENGINE,
|
||||
mysql_charset=CHARSET,
|
||||
)
|
||||
kube_cmd_versions.create()
|
||||
|
||||
_insert_default_kube_cmd_version(kube_cmd_versions)
|
||||
|
||||
|
||||
def downgrade(migrate_engine):
|
||||
# Downgrade is unsupported in this release.
|
||||
raise NotImplementedError('SysInv database downgrade is unsupported.')
|
|
@ -1958,3 +1958,13 @@ class KubeRootCAHostUpdate(Base):
|
|||
reserved_3 = Column(String(255))
|
||||
|
||||
host = relationship("ihost", lazy="joined", join_depth=1)
|
||||
|
||||
|
||||
class KubeCmdVersions(Base):
|
||||
__tablename__ = 'kube_cmd_versions'
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
kubeadm_version = Column(String(255), nullable=False)
|
||||
kubelet_version = Column(String(255), nullable=False)
|
||||
UniqueConstraint('kubeadm_version', 'kubelet_version',
|
||||
name='u_kubeadm_version_kubelet_version')
|
||||
|
|
|
@ -45,6 +45,7 @@ from sysinv.objects import kube_app_releases
|
|||
from sysinv.objects import kube_host_upgrade
|
||||
from sysinv.objects import kube_upgrade
|
||||
from sysinv.objects import kube_version
|
||||
from sysinv.objects import kube_cmd_version
|
||||
from sysinv.objects import interface
|
||||
from sysinv.objects import interface_ae
|
||||
from sysinv.objects import interface_ethernet
|
||||
|
@ -199,6 +200,7 @@ kube_app_releases = kube_app_releases.KubeAppReleases
|
|||
kube_host_upgrade = kube_host_upgrade.KubeHostUpgrade
|
||||
kube_upgrade = kube_upgrade.KubeUpgrade
|
||||
kube_version = kube_version.KubeVersion
|
||||
kube_cmd_version = kube_cmd_version.KubeCmdVersion
|
||||
datanetwork = datanetwork.DataNetwork
|
||||
host_fs = host_fs.HostFS
|
||||
device_image = device_image.DeviceImage
|
||||
|
@ -278,6 +280,7 @@ __all__ = ("system",
|
|||
"kube_host_upgrade",
|
||||
"kube_upgrade",
|
||||
"kube_version",
|
||||
"kube_cmd_version",
|
||||
"datanetwork",
|
||||
"interface_network",
|
||||
"host_fs",
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
#
|
||||
# Copyright (c) 2021 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
from sysinv.db import api as db_api
|
||||
from sysinv.objects import base
|
||||
from sysinv.objects import utils
|
||||
|
||||
|
||||
class KubeCmdVersion(base.SysinvObject):
|
||||
|
||||
dbapi = db_api.get_instance()
|
||||
|
||||
fields = {
|
||||
'kubeadm_version': utils.str_or_none,
|
||||
'kubelet_version': utils.str_or_none,
|
||||
}
|
||||
|
||||
@base.remotable_classmethod
|
||||
def get(cls, context):
|
||||
return cls.dbapi.kube_cmd_version_get()
|
||||
|
||||
def save_changes(self, context, updates):
|
||||
self.dbapi.kube_cmd_version_update(updates)
|
|
@ -0,0 +1,61 @@
|
|||
#
|
||||
# Copyright (c) 2021 Wind River Systems, Inc.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
from six.moves import http_client
|
||||
from sysinv.tests.api import base
|
||||
from sysinv.common import kubernetes
|
||||
|
||||
|
||||
class TestKubeCmdVersion(base.FunctionalTest):
|
||||
API_HEADERS = {'User-Agent': 'sysinv-test'}
|
||||
API_PREFIX = '/kube_cmd_versions'
|
||||
expected_api_fields = ['kubeadm_version',
|
||||
'kubelet_version']
|
||||
|
||||
def setUp(self):
|
||||
super(TestKubeCmdVersion, self).setUp()
|
||||
|
||||
def assert_fields(self, api_object):
|
||||
# Verify that expected attributes are returned
|
||||
for field in self.expected_api_fields:
|
||||
self.assertIn(field, api_object)
|
||||
|
||||
def test_show_kube_cmd_version_success(self):
|
||||
response = self.get_json(self.API_PREFIX,
|
||||
headers=self.API_HEADERS)
|
||||
self.assert_fields(response)
|
||||
self.assertEqual(response['kubeadm_version'],
|
||||
kubernetes.KUBERNETES_DEFAULT_VERSION)
|
||||
self.assertEqual(response['kubelet_version'],
|
||||
kubernetes.KUBERNETES_DEFAULT_VERSION)
|
||||
|
||||
def test_patch_kube_cmd_version_success(self):
|
||||
values = {
|
||||
'kubeadm_version': '1.5.1',
|
||||
'kubelet_version': '1.5.2'
|
||||
}
|
||||
response = self.patch_dict_json(self.API_PREFIX,
|
||||
headers=self.API_HEADERS,
|
||||
**values)
|
||||
self.assertEqual(http_client.OK, response.status_int)
|
||||
self.assert_fields(response.json)
|
||||
for k in values:
|
||||
self.assertEqual(values[k], response.json[k])
|
||||
get_response = self.get_json(self.API_PREFIX,
|
||||
headers=self.API_HEADERS)
|
||||
for k in values:
|
||||
self.assertEqual(values[k], get_response[k])
|
||||
|
||||
def test_patch_kube_cmd_version_failure(self):
|
||||
wrong_value = {
|
||||
'kube_version': '1.5.1'
|
||||
}
|
||||
response = self.patch_dict_json(self.API_PREFIX,
|
||||
headers=self.API_HEADERS,
|
||||
expect_errors=True,
|
||||
**wrong_value)
|
||||
self.assertEqual(http_client.BAD_REQUEST, response.status_int)
|
||||
self.assertTrue(response.json.get('error_message'))
|
Loading…
Reference in New Issue