kubernetes rootca pods update
API for pods rollout restart to update pods to receive certificates signed by the new root CA. Respective to phases trustBothCAs and trustNewCA - kube rootca pods update phase trustBothCAs API and conductor implementation. - API unit tests for pods update phase trustBothCAs. - kube rootca pods update phase trustNewCA API and conductor implementation. - API unit tests for pods update phase trustNewCA. Story: 2008675 Task: 42703 Depends-on: https://review.opendev.org/c/starlingx/stx-puppet/+/798306 Change-Id: I34fe51dd1dca401864d165b04186ebe1fab178c7 Signed-off-by: Andy Ning <andy.ning@windriver.com>
This commit is contained in:
parent
a2e0edab01
commit
6eb997aefe
|
@ -183,11 +183,81 @@ class KubeRootCAHostUpdate(base.APIBase):
|
|||
return kube_rootca_host_update
|
||||
|
||||
|
||||
class KubeRootCAPodsUpdateController(rest.RestController):
|
||||
|
||||
def _precheck_trustbothcas(self, cluster_update):
|
||||
# Pre checking if conditions met for phase trustBothCAs
|
||||
if cluster_update.state not in \
|
||||
[kubernetes.KUBE_ROOTCA_UPDATED_HOST_TRUSTBOTHCAS,
|
||||
kubernetes.KUBE_ROOTCA_UPDATING_PODS_TRUSTBOTHCAS_FAILED]:
|
||||
raise wsme.exc.ClientSideError(_(
|
||||
"kube-rootca-pods-update phase trust-both-cas rejected: "
|
||||
"not allowed when cluster update is in state: %s. "
|
||||
"(only allowed when in state: %s or %s)"
|
||||
% (cluster_update.state,
|
||||
kubernetes.KUBE_ROOTCA_UPDATED_HOST_TRUSTBOTHCAS,
|
||||
kubernetes.KUBE_ROOTCA_UPDATING_PODS_TRUSTBOTHCAS_FAILED)))
|
||||
|
||||
def _precheck_trustnewca(self, cluster_update):
|
||||
# Pre checking if conditions met for phase trustNewCA
|
||||
if cluster_update.state not in \
|
||||
[kubernetes.KUBE_ROOTCA_UPDATED_HOST_TRUSTNEWCA,
|
||||
kubernetes.KUBE_ROOTCA_UPDATING_PODS_TRUSTNEWCA_FAILED]:
|
||||
raise wsme.exc.ClientSideError(_(
|
||||
"kube-rootca-pods-update phase trust-new-ca rejected: "
|
||||
"not allowed when cluster update is in state: %s. "
|
||||
"(only allowed when in state: %s or %s)"
|
||||
% (cluster_update.state,
|
||||
kubernetes.KUBE_ROOTCA_UPDATED_HOST_TRUSTNEWCA,
|
||||
kubernetes.KUBE_ROOTCA_UPDATING_PODS_TRUSTNEWCA_FAILED)))
|
||||
|
||||
@cutils.synchronized(LOCK_KUBE_ROOTCA_CONTROLLER)
|
||||
@wsme_pecan.wsexpose(KubeRootCAUpdate, body=six.text_type)
|
||||
def post(self, body):
|
||||
# Check cluster update status
|
||||
try:
|
||||
update = pecan.request.dbapi.kube_rootca_update_get_one()
|
||||
except exception.NotFound:
|
||||
raise wsme.exc.ClientSideError(_(
|
||||
"kube-rootca-pods-update rejected: No update in progress."))
|
||||
|
||||
phase = body['phase'].lower()
|
||||
|
||||
if phase == constants.KUBE_CERT_UPDATE_TRUSTBOTHCAS:
|
||||
# kube root CA update for pods phase trustBothCAs
|
||||
self._precheck_trustbothcas(update)
|
||||
update_state = kubernetes.KUBE_ROOTCA_UPDATING_PODS_TRUSTBOTHCAS
|
||||
elif phase == constants.KUBE_CERT_UPDATE_TRUSTNEWCA:
|
||||
# kube root CA update for pods phase trustNewCA
|
||||
self._precheck_trustnewca(update)
|
||||
update_state = kubernetes.KUBE_ROOTCA_UPDATING_PODS_TRUSTNEWCA
|
||||
else:
|
||||
raise wsme.exc.ClientSideError(_(
|
||||
"kube-rootca-pods-update rejected: phase %s not supported."
|
||||
% (phase)))
|
||||
|
||||
# Update the cluster update state
|
||||
values = dict()
|
||||
values['state'] = update_state
|
||||
update = \
|
||||
pecan.request.dbapi.kube_rootca_update_update(update.id, values)
|
||||
|
||||
# perform rpc to conductor to perform config apply
|
||||
pecan.request.rpcapi.kube_certificate_update_for_pods(
|
||||
pecan.request.context, phase)
|
||||
|
||||
return KubeRootCAUpdate.convert_with_links(update)
|
||||
|
||||
|
||||
class KubeRootCAUpdateController(rest.RestController):
|
||||
"""REST controller for kubernetes rootCA updates."""
|
||||
|
||||
# Controller for /kube_rootca_update/upload, upload new root CA
|
||||
# certificate.
|
||||
upload = KubeRootCAUploadController()
|
||||
generate_cert = KubeRootCAGenerateController()
|
||||
# Controller for /kube_rootca_update/pods, update pods certificates.
|
||||
pods = KubeRootCAPodsUpdateController()
|
||||
|
||||
def __init__(self):
|
||||
self.fm_api = fm_api.FaultAPIs()
|
||||
|
|
|
@ -7513,7 +7513,7 @@ class ConductorManager(service.PeriodicService):
|
|||
LOG.error("No match for sysinv-agent manifest application reported! "
|
||||
"reported_cfg: %(cfg)s status: %(status)s "
|
||||
"iconfig: %(iconfig)s" % args)
|
||||
# Kubernetes root CA update
|
||||
# Kubernetes root CA host update
|
||||
elif reported_cfg in [puppet_common.REPORT_KUBE_CERT_UPDATE_TRUSTBOTHCAS,
|
||||
puppet_common.REPORT_KUBE_CERT_UPDATE_UPDATECERTS,
|
||||
puppet_common.REPORT_KUBE_CERT_UPDATE_TRUSTNEWCA]:
|
||||
|
@ -7531,6 +7531,23 @@ class ConductorManager(service.PeriodicService):
|
|||
LOG.error("No match for sysinv-agent manifest application reported! "
|
||||
"reported_cfg: %(cfg)s status: %(status)s "
|
||||
"iconfig: %(iconfig)s" % args)
|
||||
# Kubernetes root CA pods update
|
||||
elif reported_cfg in \
|
||||
[puppet_common.REPORT_KUBE_CERT_UPDATE_PODS_TRUSTBOTHCAS,
|
||||
puppet_common.REPORT_KUBE_CERT_UPDATE_PODS_TRUSTNEWCA]:
|
||||
if status == puppet_common.REPORT_SUCCESS:
|
||||
# Update action was successful
|
||||
success = True
|
||||
self.report_kube_rootca_pods_update_success(reported_cfg)
|
||||
elif status == puppet_common.REPORT_FAILURE:
|
||||
# Update action has failed
|
||||
self.report_kube_rootca_pods_update_failure(reported_cfg,
|
||||
error)
|
||||
else:
|
||||
args = {'cfg': reported_cfg, 'status': status, 'iconfig': iconfig}
|
||||
LOG.error("No match for sysinv-agent manifest application reported! "
|
||||
"reported_cfg: %(cfg)s status: %(status)s "
|
||||
"iconfig: %(iconfig)s" % args)
|
||||
else:
|
||||
LOG.error("Reported configuration '%(cfg)s' is not handled by"
|
||||
" report_config_status! iconfig: %(iconfig)s" %
|
||||
|
@ -8392,6 +8409,50 @@ class ConductorManager(service.PeriodicService):
|
|||
c_update = self.dbapi.kube_rootca_update_get_one()
|
||||
self.dbapi.kube_rootca_update_update(c_update.id, {'state': state})
|
||||
|
||||
def report_kube_rootca_pods_update_success(self, reported_cfg):
|
||||
"""
|
||||
Callback for Sysinv Agent on kube root CA pods update success
|
||||
"""
|
||||
LOG.info("Kube root CA update phase '%s' succeeded for pods"
|
||||
% (reported_cfg))
|
||||
|
||||
if reported_cfg == \
|
||||
puppet_common.REPORT_KUBE_CERT_UPDATE_PODS_TRUSTBOTHCAS:
|
||||
state = kubernetes.KUBE_ROOTCA_UPDATED_PODS_TRUSTBOTHCAS
|
||||
elif reported_cfg == \
|
||||
puppet_common.REPORT_KUBE_CERT_UPDATE_PODS_TRUSTNEWCA:
|
||||
state = kubernetes.KUBE_ROOTCA_UPDATED_PODS_TRUSTNEWCA
|
||||
else:
|
||||
LOG.info("Not supported reported_cfg: %s" % reported_cfg)
|
||||
raise exception.SysinvException(_(
|
||||
"Not supported reported_cfg: %s" % reported_cfg))
|
||||
|
||||
# Update cluster 'update state'
|
||||
c_update = self.dbapi.kube_rootca_update_get_one()
|
||||
self.dbapi.kube_rootca_update_update(c_update.id, {'state': state})
|
||||
|
||||
def report_kube_rootca_pods_update_failure(self, reported_cfg, error):
|
||||
"""
|
||||
Callback for Sysinv Agent on kube root CA pods update failure
|
||||
"""
|
||||
LOG.info("Kube root CA update phase '%s' failed for pods, error: %s"
|
||||
% (reported_cfg, error))
|
||||
|
||||
if reported_cfg == \
|
||||
puppet_common.REPORT_KUBE_CERT_UPDATE_PODS_TRUSTBOTHCAS:
|
||||
state = kubernetes.KUBE_ROOTCA_UPDATING_PODS_TRUSTBOTHCAS_FAILED
|
||||
elif reported_cfg == \
|
||||
puppet_common.REPORT_KUBE_CERT_UPDATE_PODS_TRUSTNEWCA:
|
||||
state = kubernetes.KUBE_ROOTCA_UPDATING_PODS_TRUSTNEWCA_FAILED
|
||||
else:
|
||||
LOG.info("Not supported reported_cfg: %s" % reported_cfg)
|
||||
raise exception.SysinvException(_(
|
||||
"Not supported reported_cfg: %s" % reported_cfg))
|
||||
|
||||
# Update cluster 'update state'
|
||||
c_update = self.dbapi.kube_rootca_update_get_one()
|
||||
self.dbapi.kube_rootca_update_update(c_update.id, {'state': state})
|
||||
|
||||
def create_controller_filesystems(self, context, rootfs_device):
|
||||
""" Create the storage config based on disk size for database, platform,
|
||||
extension, rabbit, etcd, docker-distribution, dc-vault(SC)
|
||||
|
@ -14231,6 +14292,41 @@ class ConductorManager(service.PeriodicService):
|
|||
config_uuid,
|
||||
config_dict)
|
||||
|
||||
def kube_certificate_update_for_pods(self, context, phase):
|
||||
"""Update the kube certificate for pods"""
|
||||
|
||||
# Updating pods' certificates is only needed to run once on active
|
||||
# controller
|
||||
host = self.dbapi.ihost_get(self.host_uuid)
|
||||
config_uuid = self._config_update_hosts(context,
|
||||
personalities=host.personality,
|
||||
host_uuids=[host.uuid])
|
||||
|
||||
LOG.info("kube_certificate_update_for_pods config_uuid=%s"
|
||||
% config_uuid)
|
||||
|
||||
phase = phase.lower()
|
||||
if phase not in [constants.KUBE_CERT_UPDATE_TRUSTBOTHCAS,
|
||||
constants.KUBE_CERT_UPDATE_TRUSTNEWCA]:
|
||||
raise exception.SysinvException(_(
|
||||
"Invalid phase %s to update kube certificate for pods." %
|
||||
phase))
|
||||
|
||||
puppet_class = [
|
||||
'platform::kubernetes::master::rootca::pods::' + phase.replace('-', '') + '::runtime',
|
||||
]
|
||||
|
||||
config_dict = {
|
||||
"personalities": host.personality,
|
||||
"classes": puppet_class,
|
||||
"host_uuids": [host.uuid],
|
||||
puppet_common.REPORT_STATUS_CFG: 'pods_' + phase,
|
||||
}
|
||||
|
||||
self._config_apply_runtime_manifest(context,
|
||||
config_uuid,
|
||||
config_dict)
|
||||
|
||||
|
||||
def device_image_state_sort_key(dev_img_state):
|
||||
if dev_img_state.bitstream_type == dconstants.BITSTREAM_TYPE_ROOT_KEY:
|
||||
|
|
|
@ -2254,3 +2254,17 @@ class ConductorAPI(sysinv.openstack.common.rpc.proxy.RpcProxy):
|
|||
phase=phase
|
||||
)
|
||||
)
|
||||
|
||||
def kube_certificate_update_for_pods(self, context, phase):
|
||||
"""
|
||||
Asynchronously, have the conductor update certificates for pods.
|
||||
|
||||
:param context: request context.
|
||||
:param phase: the phase of the update.
|
||||
"""
|
||||
return self.cast(
|
||||
context, self.make_msg(
|
||||
'kube_certificate_update_for_pods',
|
||||
phase=phase
|
||||
)
|
||||
)
|
||||
|
|
|
@ -41,9 +41,15 @@ REPORT_PCI_SRIOV_CONFIG = 'pci_sriov_config'
|
|||
REPORT_CEPH_OSD_CONFIG = 'ceph_osd'
|
||||
REPORT_CEPH_RADOSGW_CONFIG = 'ceph_radosgw'
|
||||
REPORT_CEPH_ROOK_CONFIG = 'ceph_rook_config'
|
||||
# puppet report configs for hosts cert update
|
||||
REPORT_KUBE_CERT_UPDATE_TRUSTBOTHCAS = constants.KUBE_CERT_UPDATE_TRUSTBOTHCAS
|
||||
REPORT_KUBE_CERT_UPDATE_UPDATECERTS = constants.KUBE_CERT_UPDATE_UPDATECERTS
|
||||
REPORT_KUBE_CERT_UPDATE_TRUSTNEWCA = constants.KUBE_CERT_UPDATE_TRUSTNEWCA
|
||||
# puppet report configs for pods cert update
|
||||
REPORT_KUBE_CERT_UPDATE_PODS_TRUSTBOTHCAS = \
|
||||
'pods_' + constants.KUBE_CERT_UPDATE_TRUSTBOTHCAS
|
||||
REPORT_KUBE_CERT_UPDATE_PODS_TRUSTNEWCA = \
|
||||
'pods_' + constants.KUBE_CERT_UPDATE_TRUSTNEWCA
|
||||
|
||||
|
||||
def puppet_apply_manifest(ip_address, personality,
|
||||
|
|
|
@ -67,6 +67,9 @@ class FakeConductorAPI(object):
|
|||
def kube_certificate_update_by_host(self, context, host_uuid, phase):
|
||||
return
|
||||
|
||||
def kube_certificate_update_for_pods(self, context, phase):
|
||||
return
|
||||
|
||||
|
||||
class TestKubeRootCAUpdate(base.FunctionalTest):
|
||||
|
||||
|
@ -292,6 +295,94 @@ class TestKubeRootCAGenerate(TestKubeRootCAUpdate,
|
|||
self.assertFalse(resp.get('error'))
|
||||
|
||||
|
||||
class TestKubeRootCAPodsUpdateTrustBothCAs(TestKubeRootCAUpdate,
|
||||
dbbase.ProvisionedControllerHostTestCase):
|
||||
def setUp(self):
|
||||
super(TestKubeRootCAPodsUpdateTrustBothCAs, self).setUp()
|
||||
self.phase = constants.KUBE_CERT_UPDATE_TRUSTBOTHCAS
|
||||
self.post_url = '/kube_rootca_update/pods'
|
||||
self.headers = {'User-Agent': 'sysinv-test'}
|
||||
|
||||
def test_rootca_update_pods(self):
|
||||
# Test kube root CA update for pods
|
||||
create_dict = {'phase': self.phase}
|
||||
|
||||
dbutils.create_test_kube_rootca_update(
|
||||
state=kubernetes.KUBE_ROOTCA_UPDATED_HOST_TRUSTBOTHCAS)
|
||||
|
||||
result = self.post_json(self.post_url, create_dict,
|
||||
headers=self.headers)
|
||||
|
||||
# Verify that the rootca update pods has the expected attributes
|
||||
self.assertEqual(result.json['state'],
|
||||
kubernetes.KUBE_ROOTCA_UPDATING_PODS_TRUSTBOTHCAS)
|
||||
|
||||
def test_rootca_update_pods_reject_wrong_state(self):
|
||||
# Test kube root CA update for pods - rejected, not in right state
|
||||
create_dict = {'phase': self.phase}
|
||||
|
||||
# The cluster update state is in updating hosts
|
||||
dbutils.create_test_kube_rootca_update(
|
||||
state=kubernetes.KUBE_ROOTCA_UPDATING_HOST_TRUSTBOTHCAS)
|
||||
|
||||
result = self.post_json(self.post_url, create_dict,
|
||||
headers=self.headers,
|
||||
expect_errors=True)
|
||||
|
||||
self.assertEqual(http_client.BAD_REQUEST, result.status_int)
|
||||
self.assertIn("kube-rootca-pods-update phase trust-both-cas rejected: "
|
||||
"not allowed when cluster update is in state: %s. "
|
||||
"(only allowed when in state: %s or %s)"
|
||||
% (kubernetes.KUBE_ROOTCA_UPDATING_HOST_TRUSTBOTHCAS,
|
||||
kubernetes.KUBE_ROOTCA_UPDATED_HOST_TRUSTBOTHCAS,
|
||||
kubernetes.KUBE_ROOTCA_UPDATING_PODS_TRUSTBOTHCAS_FAILED),
|
||||
result.json['error_message'])
|
||||
|
||||
|
||||
class TestKubeRootCAPodsUpdateTrustNewCA(TestKubeRootCAUpdate,
|
||||
dbbase.ProvisionedControllerHostTestCase):
|
||||
def setUp(self):
|
||||
super(TestKubeRootCAPodsUpdateTrustNewCA, self).setUp()
|
||||
self.phase = constants.KUBE_CERT_UPDATE_TRUSTNEWCA
|
||||
self.post_url = '/kube_rootca_update/pods'
|
||||
self.headers = {'User-Agent': 'sysinv-test'}
|
||||
|
||||
def test_rootca_update_pods(self):
|
||||
# Test kube root CA update for pods
|
||||
create_dict = {'phase': self.phase}
|
||||
|
||||
dbutils.create_test_kube_rootca_update(
|
||||
state=kubernetes.KUBE_ROOTCA_UPDATED_HOST_TRUSTNEWCA)
|
||||
|
||||
result = self.post_json(self.post_url, create_dict,
|
||||
headers=self.headers)
|
||||
|
||||
# Verify that the rootca update pods has the expected attributes
|
||||
self.assertEqual(result.json['state'],
|
||||
kubernetes.KUBE_ROOTCA_UPDATING_PODS_TRUSTNEWCA)
|
||||
|
||||
def test_rootca_update_pods_reject_wrong_state(self):
|
||||
# Test kube root CA update for pods - rejected, not in right state
|
||||
create_dict = {'phase': self.phase}
|
||||
|
||||
# The cluster update state is in updating hosts
|
||||
dbutils.create_test_kube_rootca_update(
|
||||
state=kubernetes.KUBE_ROOTCA_UPDATING_PODS_TRUSTBOTHCAS)
|
||||
|
||||
result = self.post_json(self.post_url, create_dict,
|
||||
headers=self.headers,
|
||||
expect_errors=True)
|
||||
|
||||
self.assertEqual(http_client.BAD_REQUEST, result.status_int)
|
||||
self.assertIn("kube-rootca-pods-update phase trust-new-ca rejected: "
|
||||
"not allowed when cluster update is in state: %s. "
|
||||
"(only allowed when in state: %s or %s)"
|
||||
% (kubernetes.KUBE_ROOTCA_UPDATING_PODS_TRUSTBOTHCAS,
|
||||
kubernetes.KUBE_ROOTCA_UPDATED_HOST_TRUSTNEWCA,
|
||||
kubernetes.KUBE_ROOTCA_UPDATING_PODS_TRUSTNEWCA_FAILED),
|
||||
result.json['error_message'])
|
||||
|
||||
|
||||
class TestKubeRootCAHostUpdate(base.FunctionalTest):
|
||||
# API_HEADERS are a generic header passed to most API calls
|
||||
API_HEADERS = {'User-Agent': 'sysinv-test'}
|
||||
|
|
Loading…
Reference in New Issue