Fix validate error when k8s resource init
Since the k8s version has been upgraded from v22.6.0 to v23.3.0, the initial value of some fields must be the specified string, which causes the initialization of the current k8s resource to fail. This patch fixes the issue and skips the validation of k8s object initialization by setting the `client_side_validation` parameter. In order to pass the validation, the must_param variable was added to set the initialized value. This modification skips the validation and no longer uses the variable, so the related processing of the variable is deleted. At the same time, even if the initialization validation is skipped, the fields in the yaml file will still be verified when the create method is called, and an exception will be thrown and output to the log if the fields are missing. At the same time, due to the rapid iteration of the k8s version, the must_param variable needs to be repaired in each iteration to adapt to the new validation, which requires repeated maintenance and high maintenance costs, so it is no longer used. In kubernetes v23.3.0, 'available_replicas' must be set into status of `StatefulSet`, so this patch add a kuryr-kubernetes versioned parameter temporarily to .zuul.yaml to make the response returned by kubernetes correct. Closes-Bug: #1968103 Change-Id: I9495ce0f0893e5f9a1d6c52b98c3db3928bd95a3
This commit is contained in:
parent
acf84a168a
commit
c52343a974
|
@ -439,6 +439,11 @@
|
|||
KURYR_K8S_API_URL: "https://{{ hostvars['controller-k8s']['nodepool']['private_ipv4'] }}:${KURYR_K8S_API_PORT}"
|
||||
KURYR_K8S_CONTAINERIZED_DEPLOYMENT: false
|
||||
KURYR_NEUTRON_DEFAULT_SUBNETPOOL_ID: shared-default-subnetpool-v4
|
||||
# TODO(YiFeng): At present, the version of kubernetes should be 1.23.3, and the returned response can
|
||||
# pass the verification of kubernetes-client (1.23.3). This configuration will be removed after
|
||||
# kuryr-kubernetes fixes the following bug.
|
||||
# https://bugs.launchpad.net/kuryr-kubernetes/+bug/1968960
|
||||
KURYR_KUBERNETES_VERSION: 1.23.3
|
||||
MYSQL_HOST: "{{ hostvars['controller']['nodepool']['private_ipv4'] }}"
|
||||
OCTAVIA_AMP_IMAGE_FILE: "/tmp/test-only-amphora-x64-haproxy-ubuntu-bionic.qcow2"
|
||||
OCTAVIA_AMP_IMAGE_NAME: "test-only-amphora-x64-haproxy-ubuntu-bionic"
|
||||
|
|
|
@ -290,7 +290,7 @@ def fake_pc():
|
|||
|
||||
|
||||
def fake_persistent_volume(
|
||||
name='curry-sc-pv', phase='UnAvailable'):
|
||||
name='curry-sc-pv', phase='Pending'):
|
||||
return client.V1PersistentVolume(
|
||||
api_version='v1',
|
||||
kind='PersistentVolume',
|
||||
|
@ -395,6 +395,8 @@ def fake_rq():
|
|||
|
||||
|
||||
def fake_stateful_set(ready_replicas=0):
|
||||
client_config = client.Configuration.get_default_copy()
|
||||
client_config.client_side_validation = False
|
||||
return client.V1StatefulSet(
|
||||
api_version='apps/v1',
|
||||
kind='StatefulSet',
|
||||
|
@ -424,7 +426,8 @@ def fake_stateful_set(ready_replicas=0):
|
|||
),
|
||||
status=client.V1StatefulSetStatus(
|
||||
replicas=2,
|
||||
ready_replicas=ready_replicas
|
||||
ready_replicas=ready_replicas,
|
||||
local_vars_configuration=client_config
|
||||
),
|
||||
)
|
||||
|
||||
|
|
|
@ -845,7 +845,7 @@ class TestKubernetes(base.BaseTestCase):
|
|||
|
||||
mock_node.return_value = fakes.fake_node(status='False')
|
||||
mock_read_node.side_effect = [
|
||||
fakes.fake_node(type='UnReady'),
|
||||
fakes.fake_node(type='NetworkUnavailable'),
|
||||
fakes.fake_node(), fakes.fake_none()]
|
||||
|
||||
self._normal_execute_procedure(req)
|
||||
|
|
|
@ -238,7 +238,7 @@ def fake_pvc_false():
|
|||
name='curry-sc-pvc'
|
||||
),
|
||||
status=client.V1PersistentVolumeClaimStatus(
|
||||
phase='UnBound'
|
||||
phase='Pending'
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -286,7 +286,7 @@ def fake_namespace_false():
|
|||
name='curry-ns'
|
||||
),
|
||||
status=client.V1NamespaceStatus(
|
||||
phase='NotActive'
|
||||
phase='Terminating'
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -658,6 +658,8 @@ def fake_v1_volume_attachment_error():
|
|||
|
||||
|
||||
def fake_v1_stateful_set():
|
||||
client_config = client.Configuration.get_default_copy()
|
||||
client_config.client_side_validation = False
|
||||
return client.V1StatefulSet(
|
||||
api_version='apps/v1',
|
||||
kind='StatefulSet',
|
||||
|
@ -687,12 +689,15 @@ def fake_v1_stateful_set():
|
|||
),
|
||||
status=client.V1StatefulSetStatus(
|
||||
replicas=1,
|
||||
ready_replicas=1
|
||||
ready_replicas=1,
|
||||
local_vars_configuration=client_config
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def fake_v1_stateful_set_error():
|
||||
client_config = client.Configuration.get_default_copy()
|
||||
client_config.client_side_validation = False
|
||||
return client.V1StatefulSet(
|
||||
api_version='apps/v1',
|
||||
kind='StatefulSet',
|
||||
|
@ -722,7 +727,8 @@ def fake_v1_stateful_set_error():
|
|||
),
|
||||
status=client.V1StatefulSetStatus(
|
||||
replicas=2,
|
||||
ready_replicas=1
|
||||
ready_replicas=1,
|
||||
local_vars_configuration=client_config
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -750,7 +756,7 @@ def fake_v1_persistent_volume_claim_error():
|
|||
namespace='curryns'
|
||||
),
|
||||
status=client.V1PersistentVolumeClaimStatus(
|
||||
phase='Bound1'
|
||||
phase='Pending'
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -800,7 +806,7 @@ def fake_pod_error():
|
|||
namespace='curryns'
|
||||
),
|
||||
status=client.V1PodStatus(
|
||||
phase='Terminated',
|
||||
phase='Failed',
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -850,7 +856,7 @@ def fake_persistent_volume_error():
|
|||
namespace='curryns'
|
||||
),
|
||||
status=client.V1PersistentVolumeStatus(
|
||||
phase='UnBound',
|
||||
phase='Pending',
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -1017,7 +1023,7 @@ def fake_pod_list():
|
|||
name="fake-name"
|
||||
),
|
||||
status=client.V1PodStatus(
|
||||
phase="Successed"
|
||||
phase="Succeeded"
|
||||
)
|
||||
)]
|
||||
)
|
||||
|
|
|
@ -684,7 +684,6 @@ class TestTransformer(base.TestCase):
|
|||
self.assertEqual(k8s_obj.api_version, 'v1')
|
||||
# V1LimitRangeSpec
|
||||
self.assertIsNotNone(k8s_obj.spec.limits)
|
||||
self.assertIsNotNone(k8s_obj.spec.limits[0].type)
|
||||
|
||||
def test_pod_template(self):
|
||||
k8s_objs = self.transfromer.get_k8s_objs_from_yaml(
|
||||
|
|
|
@ -161,168 +161,11 @@ class Transformer(object):
|
|||
return kubernetes_objects
|
||||
|
||||
def _create_k8s_object(self, kind, file_content_dict):
|
||||
# must_param referring K8s official object page
|
||||
# *e.g:https://github.com/kubernetes-client/python/blob/master/kubernetes/docs/V1Service.md
|
||||
# initiating k8s object, you need to
|
||||
# give the must param an empty value.
|
||||
must_param = {
|
||||
'V1LocalSubjectAccessReview': '(spec="")',
|
||||
'V1HTTPGetAction': '(port="")',
|
||||
'V1DeploymentSpec': '(selector="", template="")',
|
||||
'V1PodSpec': '(containers=[])',
|
||||
'V1ConfigMapKeySelector': '(key="")',
|
||||
'V1Container': '(name="")',
|
||||
'V1EnvVar': '(name="")',
|
||||
'V1SecretKeySelector': '(key="")',
|
||||
'V1ContainerPort': '(container_port="")',
|
||||
'V1VolumeMount': '(mount_path="", name="")',
|
||||
'V1PodCondition': '(status="", type="")',
|
||||
'V1ContainerStatus': '('
|
||||
'image="", image_id="", '
|
||||
'name="", ready="", '
|
||||
'restart_count="")',
|
||||
'V1ServicePort': '(port=80)',
|
||||
'V1TypedLocalObjectReference': '(kind="", name="")',
|
||||
'V1LabelSelectorRequirement': '(key="", operator="")',
|
||||
'V1PersistentVolumeClaimCondition': '(status="", type="")',
|
||||
'V1AWSElasticBlockStoreVolumeSource': '(volume_id="")',
|
||||
'V1AzureDiskVolumeSource': '(disk_name="", disk_uri="")',
|
||||
'V1AzureFileVolumeSource': '(secret_name="", share_name="")',
|
||||
'V1CephFSVolumeSource': '(monitors=[])',
|
||||
'V1CinderVolumeSource': '(volume_id="")',
|
||||
'V1KeyToPath': '(key="", path="")',
|
||||
'V1CSIVolumeSource': '(driver="")',
|
||||
'V1DownwardAPIVolumeFile': '(path="")',
|
||||
'V1ObjectFieldSelector': '(field_path="")',
|
||||
'V1ResourceFieldSelector': '(resource="")',
|
||||
'V1FlexVolumeSource': '(driver="")',
|
||||
'V1GCEPersistentDiskVolumeSource': '(pd_name="")',
|
||||
'V1GitRepoVolumeSource': '(repository="")',
|
||||
'V1GlusterfsVolumeSource': '(endpoints="", path="")',
|
||||
'V1HostPathVolumeSource': '(path="")',
|
||||
'V1ISCSIVolumeSource': '(iqn="", lun=0, target_portal="")',
|
||||
'V1Volume': '(name="")',
|
||||
'V1NFSVolumeSource': '(path="", server="")',
|
||||
'V1PersistentVolumeClaimVolumeSource': '(claim_name="")',
|
||||
'V1PhotonPersistentDiskVolumeSource': '(pd_id="")',
|
||||
'V1PortworxVolumeSource': '(volume_id="")',
|
||||
'V1ProjectedVolumeSource': '(sources=[])',
|
||||
'V1ServiceAccountTokenProjection': '(path="")',
|
||||
'V1QuobyteVolumeSource': '(registry="", volume="")',
|
||||
'V1RBDVolumeSource': '(image="", monitors=[])',
|
||||
'V1ScaleIOVolumeSource': '('
|
||||
'gateway="", secret_ref="", '
|
||||
'system="")',
|
||||
'V1VsphereVirtualDiskVolumeSource': '(volume_path="")',
|
||||
'V1LimitRangeSpec': '(limits=[])',
|
||||
'V1Binding': '(target="")',
|
||||
'V1ComponentCondition': '(status="", type="")',
|
||||
'V1NamespaceCondition': '(status="", type="")',
|
||||
'V1ConfigMapNodeConfigSource': '(kubelet_config_key="", '
|
||||
'name="", namespace="")',
|
||||
'V1Taint': '(effect="", key="")',
|
||||
'V1NodeAddress': '(address="", type="")',
|
||||
'V1NodeCondition': '(status="", type="")',
|
||||
'V1DaemonEndpoint': '(port=0)',
|
||||
'V1ContainerImage': '(names=[])',
|
||||
'V1NodeSystemInfo': '(architecture="", boot_id="", '
|
||||
'container_runtime_version="",'
|
||||
'kernel_version="", '
|
||||
'kube_proxy_version="", '
|
||||
'kubelet_version="",'
|
||||
'machine_id="", operating_system="", '
|
||||
'os_image="", system_uuid="")',
|
||||
'V1AttachedVolume': '(device_path="", name="")',
|
||||
'V1ScopedResourceSelectorRequirement':
|
||||
'(operator="", scope_name="")',
|
||||
'V1APIServiceSpec': '(group_priority_minimum=0, '
|
||||
'service="", '
|
||||
'version_priority=0)',
|
||||
'V1APIServiceCondition': '(status="", type="")',
|
||||
'V1DaemonSetSpec': '(selector="", template="")',
|
||||
'V1ReplicaSetSpec': '(selector="")',
|
||||
'V1StatefulSetSpec': '(selector="", '
|
||||
'service_name="", template="")',
|
||||
'V1StatefulSetCondition': '(status="", type="")',
|
||||
'V1StatefulSetStatus': '(replicas=0)',
|
||||
'V1ControllerRevision': '(revision=0)',
|
||||
'V1TokenReview': '(spec="")',
|
||||
'V1SubjectAccessReviewStatus': '(allowed=True)',
|
||||
'V1SelfSubjectAccessReview': '(spec="")',
|
||||
'V1SelfSubjectRulesReview': '(spec="")',
|
||||
'V1SubjectRulesReviewStatus': '(incomplete=True, '
|
||||
'non_resource_rules=[], '
|
||||
'resource_rules=[])',
|
||||
'V1NonResourceRule': '(verbs=[])',
|
||||
'V1SubjectAccessReview': '(spec="")',
|
||||
'V1HorizontalPodAutoscalerSpec':
|
||||
'(max_replicas=0, scale_target_ref="")',
|
||||
'V1CrossVersionObjectReference': '(kind="", name="")',
|
||||
'V1HorizontalPodAutoscalerStatus':
|
||||
'(current_replicas=0, desired_replicas=0)',
|
||||
'V1JobSpec': '(template="")',
|
||||
'V1NetworkPolicySpec': '(pod_selector="")',
|
||||
'V1PolicyRule': '(verbs=[])',
|
||||
'V1ClusterRoleBinding': '(role_ref="")',
|
||||
'V1RoleRef': '(api_group="", kind="", name="")',
|
||||
'V1Subject': '(kind="", name="")',
|
||||
'V1RoleBinding': '(role_ref="")',
|
||||
'V1PriorityClass': '(value=0)',
|
||||
'V1StorageClass': '(provisioner="")',
|
||||
'V1TopologySelectorLabelRequirement': '(key="", values=[])',
|
||||
'V1VolumeAttachment': '(spec="")',
|
||||
'V1VolumeAttachmentSpec':
|
||||
'(attacher="", node_name="", source="")',
|
||||
'V1VolumeAttachmentStatus': '(attached=True)',
|
||||
'V1NodeSelector': '(node_selector_terms=[])',
|
||||
'V1NodeSelectorRequirement': '(key="", operator="")',
|
||||
'V1PreferredSchedulingTerm': '(preference="", weight=1)',
|
||||
'V1PodAffinityTerm': '(topology_key="")',
|
||||
'V1WeightedPodAffinityTerm': '(pod_affinity_term="", weight=1)',
|
||||
'V1OwnerReference': '(api_version="", kind="", name="", uid="")',
|
||||
'V1HTTPHeader': '(name="", value="")',
|
||||
'V1TCPSocketAction': '(port="")',
|
||||
'V1VolumeDevice': '(device_path="", name="")',
|
||||
'V1PodReadinessGate': '(condition_type="")',
|
||||
'V1Sysctl': '(name="", value="")',
|
||||
'V1ContainerStateTerminated': '(exit_code=0)',
|
||||
'V1AzureFilePersistentVolumeSource': '(secret_name="",'
|
||||
' share_name="")',
|
||||
'V1CephFSPersistentVolumeSource': '(monitors=[])',
|
||||
'V1CinderPersistentVolumeSource': '(volume_id="")',
|
||||
'V1CSIPersistentVolumeSource': '(driver="", volume_handle="")',
|
||||
'V1FlexPersistentVolumeSource': '(driver="")',
|
||||
'V1GlusterfsPersistentVolumeSource': '(endpoints="", path="")',
|
||||
'V1ISCSIPersistentVolumeSource': '(iqn="", lun=0,'
|
||||
' target_portal="")',
|
||||
'V1LocalVolumeSource': '(path="")',
|
||||
'V1RBDPersistentVolumeSource': '(image="", monitors=[])',
|
||||
'V1ScaleIOPersistentVolumeSource': '('
|
||||
'gateway="",'
|
||||
' secret_ref="",'
|
||||
' system="")',
|
||||
'V1DaemonSetStatus': '(current_number_scheduled=0, '
|
||||
'desired_number_scheduled=0, '
|
||||
'number_misscheduled=0, '
|
||||
'number_ready=0)',
|
||||
'V1DaemonSetCondition': '(status="", type="")',
|
||||
'V1DeploymentCondition': '(status="", type="")',
|
||||
'V1ReplicaSetStatus': '(replicas=0)',
|
||||
'V1ReplicaSetCondition': '(status="", type="")',
|
||||
'V1ResourceRule': '(verbs=[])',
|
||||
'V1JobCondition': '(status="", type="")',
|
||||
'V1IPBlock': '(cidr="")',
|
||||
'V1EphemeralContainer': '(name="")',
|
||||
'V1TopologySpreadConstraint': '(max_skew=0, topology_key="",'
|
||||
' when_unsatisfiable="")',
|
||||
'V1LimitRangeItem': '(type="")'
|
||||
}
|
||||
whole_kind = 'V1' + kind
|
||||
if whole_kind in must_param.keys():
|
||||
k8s_obj = eval('client.V1' + kind + must_param.get(whole_kind))
|
||||
else:
|
||||
k8s_obj = eval('client.V1' + kind + '()')
|
||||
self._init_k8s_obj(k8s_obj, file_content_dict, must_param)
|
||||
client_config = client.Configuration.get_default_copy()
|
||||
client_config.client_side_validation = False
|
||||
k8s_obj = eval(
|
||||
'client.V1' + kind + '(local_vars_configuration=client_config)')
|
||||
self._init_k8s_obj(k8s_obj, file_content_dict)
|
||||
return k8s_obj
|
||||
|
||||
def _get_k8s_obj_from_file_content_dict(self, file_content_dict,
|
||||
|
@ -499,7 +342,9 @@ class Transformer(object):
|
|||
name = name.strip()
|
||||
return re.sub('([a-z0-9])([A-Z])', r'\1_\2', name).lower()
|
||||
|
||||
def _init_k8s_obj(self, obj, content, must_param):
|
||||
def _init_k8s_obj(self, obj, content):
|
||||
client_config = client.Configuration.get_default_copy()
|
||||
client_config.client_side_validation = False
|
||||
for key, value in content.items():
|
||||
param_value = self._get_lower_case_name(key)
|
||||
if hasattr(obj, param_value) and \
|
||||
|
@ -511,12 +356,10 @@ class Transformer(object):
|
|||
if obj_name == 'dict(str, str)':
|
||||
setattr(obj, param_value, value)
|
||||
else:
|
||||
if obj_name in must_param.keys():
|
||||
rely_obj = eval('client.' + obj_name +
|
||||
must_param.get(obj_name))
|
||||
else:
|
||||
rely_obj = eval('client.' + obj_name + '()')
|
||||
self._init_k8s_obj(rely_obj, value, must_param)
|
||||
rely_obj = eval(
|
||||
'client.' + obj_name +
|
||||
'(local_vars_configuration=client_config)')
|
||||
self._init_k8s_obj(rely_obj, value)
|
||||
setattr(obj, param_value, rely_obj)
|
||||
elif isinstance(value, list):
|
||||
obj_name = obj.openapi_types.get(param_value)
|
||||
|
@ -527,13 +370,10 @@ class Transformer(object):
|
|||
rely_obj_name = \
|
||||
re.findall(r".*\[([^\[\]]*)\].*", obj_name)[0]
|
||||
for v in value:
|
||||
if rely_obj_name in must_param.keys():
|
||||
rely_obj = eval('client.' + rely_obj_name +
|
||||
must_param.get(rely_obj_name))
|
||||
else:
|
||||
rely_obj = \
|
||||
eval('client.' + rely_obj_name + '()')
|
||||
self._init_k8s_obj(rely_obj, v, must_param)
|
||||
rely_obj = \
|
||||
eval('client.' + rely_obj_name +
|
||||
'(local_vars_configuration=client_config)')
|
||||
self._init_k8s_obj(rely_obj, v)
|
||||
rely_objs.append(rely_obj)
|
||||
setattr(obj, param_value, rely_objs)
|
||||
|
||||
|
@ -553,9 +393,8 @@ class Transformer(object):
|
|||
return sorted_k8s_objs
|
||||
|
||||
def get_object_meta(self, content):
|
||||
must_param = {}
|
||||
v1_object_meta = client.V1ObjectMeta()
|
||||
self._init_k8s_obj(v1_object_meta, content, must_param)
|
||||
self._init_k8s_obj(v1_object_meta, content)
|
||||
return v1_object_meta
|
||||
|
||||
# config_labels configures label
|
||||
|
|
Loading…
Reference in New Issue