Ejemplo n.º 1
0
    def _validate_kubernetes_secrets(
        self, node_id: str, node_label: str, secrets: List[KubernetesSecret], response: ValidationResponse
    ) -> None:
        """
        Checks the format of Kubernetes secrets to ensure they're in the correct form
        e.g. FOO=SECRET_NAME:KEY
        :param node_id: the unique ID of the node
        :param node_label: the given node name or user customized name/label of the node
        :param secrets: a KeyValueList of secrets to check
        :param response: ValidationResponse containing the issue list to be updated
        """
        for secret in secrets:
            if not secret.name or not secret.key:
                response.add_message(
                    severity=ValidationSeverity.Error,
                    message_type="invalidKubernetesSecret",
                    message=f"Environment variable '{secret.env_var}' has an improperly formatted representation of "
                    f"secret name and key.",
                    data={
                        "nodeID": node_id,
                        "nodeName": node_label,
                        "propertyName": KUBERNETES_SECRETS,
                        "value": KeyValueList.to_str(secret.env_var, f"{(secret.name or '')}:{(secret.key or '')}"),
                    },
                )
                continue

            # Ensure the secret name is syntactically a valid Kubernetes resource name
            if not is_valid_kubernetes_resource_name(secret.name):
                response.add_message(
                    severity=ValidationSeverity.Error,
                    message_type="invalidKubernetesSecret",
                    message=f"Secret name '{secret.name}' is not a valid Kubernetes resource name.",
                    data={
                        "nodeID": node_id,
                        "nodeName": node_label,
                        "propertyName": KUBERNETES_SECRETS,
                        "value": KeyValueList.to_str(secret.env_var, f"{secret.name}:{secret.key}"),
                    },
                )
            # Ensure the secret key is a syntactically valid Kubernetes key
            if not is_valid_kubernetes_key(secret.key):
                response.add_message(
                    severity=ValidationSeverity.Error,
                    message_type="invalidKubernetesSecret",
                    message=f"Key '{secret.key}' is not a valid Kubernetes secret key.",
                    data={
                        "nodeID": node_id,
                        "nodeName": node_label,
                        "propertyName": KUBERNETES_SECRETS,
                        "value": KeyValueList.to_str(secret.env_var, f"{secret.name}:{secret.key}"),
                    },
                )
Ejemplo n.º 2
0
 def _validate_mounted_volumes(
     self, node_id: str, node_label: str, volumes: List[VolumeMount], response: ValidationResponse
 ) -> None:
     """
     Checks the format of mounted volumes to ensure they're in the correct form
     e.g. foo/path=pvc_name
     :param node_id: the unique ID of the node
     :param node_label: the given node name or user customized name/label of the node
     :param volumes: a KeyValueList of volumes to check
     :param response: ValidationResponse containing the issue list to be updated
     """
     for volume in volumes:
         # Ensure the PVC name is syntactically a valid Kubernetes resource name
         if not is_valid_kubernetes_resource_name(volume.pvc_name):
             response.add_message(
                 severity=ValidationSeverity.Error,
                 message_type="invalidVolumeMount",
                 message=f"PVC name '{volume.pvc_name}' is not a valid Kubernetes resource name.",
                 data={
                     "nodeID": node_id,
                     "nodeName": node_label,
                     "propertyName": MOUNTED_VOLUMES,
                     "value": KeyValueList.to_str(volume.path, volume.pvc_name),
                 },
             )
Ejemplo n.º 3
0
def test_envs_to_dict():
    test_list = [
        "TEST= one", "TEST_TWO=two ", "TEST_THREE =", " TEST_FOUR=1",
        "TEST_FIVE = fi=ve "
    ]
    test_dict_correct = {
        "TEST": "one",
        "TEST_TWO": "two",
        "TEST_FOUR": "1",
        "TEST_FIVE": "fi=ve"
    }
    assert KeyValueList(test_list).to_dict() == test_dict_correct
Ejemplo n.º 4
0
 def remove_env_vars_with_matching_secrets(self):
     """
     In the case of a matching key between env vars and kubernetes secrets,
     prefer the Kubernetes Secret and remove the matching env var.
     """
     env_vars = self.get_component_parameter(ENV_VARIABLES)
     secrets = self.get_component_parameter(KUBERNETES_SECRETS)
     if isinstance(env_vars, KeyValueList) and isinstance(
             secrets, KeyValueList):
         new_list = KeyValueList.difference(minuend=env_vars,
                                            subtrahend=secrets)
         self.set_component_parameter(ENV_VARIABLES, new_list)
Ejemplo n.º 5
0
def test_remove_env_vars_with_matching_secrets():
    pipeline_json = _read_pipeline_resource(
        "resources/sample_pipelines/pipeline_valid_with_pipeline_default.json")
    pipeline_definition = PipelineDefinition(pipeline_definition=pipeline_json)
    node = pipeline_definition.primary_pipeline.nodes.pop()

    # Set kubernetes_secret property to have all the same keys as those in the env_vars property
    kubernetes_secrets = KeyValueList(
        ["var1=name1:key1", "var2=name2:key2", "var3=name3:key3"])
    node.set_component_parameter(KUBERNETES_SECRETS, kubernetes_secrets)

    node.remove_env_vars_with_matching_secrets()
    assert node.get_component_parameter(ENV_VARIABLES) == []
Ejemplo n.º 6
0
    def convert_kv_properties(self, kv_properties: List[str]):
        """
        Convert pipeline defaults-level list properties that have been identified
        as sets of key-value pairs from a plain list type to the KeyValueList type.
        """
        pipeline_defaults = self.get_property(PIPELINE_DEFAULTS, {})
        for property_name, value in pipeline_defaults.items():
            if property_name not in kv_properties:
                continue

            # Replace plain list with KeyValueList
            pipeline_defaults[property_name] = KeyValueList(value)

        if pipeline_defaults:
            self.set_property(PIPELINE_DEFAULTS, pipeline_defaults)
Ejemplo n.º 7
0
    def convert_kv_properties(self, kv_properties: List[str]):
        """
        Convert node-level list properties that have been identified as sets of
        key-value pairs from a plain list type to the KeyValueList type. If any
        k-v property has already been converted to a KeyValueList, all k-v
        properties are assumed to have already been converted.
        """
        for kv_property in kv_properties:
            value = self.get_component_parameter(kv_property)
            if not value:
                continue

            if isinstance(value,
                          KeyValueList) or not isinstance(value[0], str):
                # A KeyValueList instance implies all relevant properties have already been converted
                # Similarly, if KeyValueList items aren't strings, this implies they have already been
                # converted to the appropriate data class objects
                return

            # Convert plain list to KeyValueList
            self.set_component_parameter(kv_property, KeyValueList(value))
Ejemplo n.º 8
0
    def propagate_pipeline_default_properties(self):
        """
        For any default pipeline properties set (e.g. runtime image, volume), propagate
        the values to any nodes that do not set their own value for that property.
        """
        # Convert any key-value list pipeline default properties to the KeyValueList type
        kv_properties = PipelineDefinition.get_kv_properties()
        self.primary_pipeline.convert_kv_properties(kv_properties)

        pipeline_default_properties = self.primary_pipeline.get_property(
            PIPELINE_DEFAULTS, {})
        for node in self.pipeline_nodes:
            if not Operation.is_generic_operation(node.op):
                continue

            # Convert any key-value list node properties to the KeyValueList type if not done already
            node.convert_kv_properties(kv_properties)

            for property_name, pipeline_default_value in pipeline_default_properties.items(
            ):
                if not pipeline_default_value:
                    continue

                node_value = node.get_component_parameter(property_name)
                if not node_value:
                    node.set_component_parameter(property_name,
                                                 pipeline_default_value)
                    continue

                if isinstance(pipeline_default_value,
                              KeyValueList) and isinstance(
                                  node_value, KeyValueList):
                    merged_list = KeyValueList.merge(node_value,
                                                     pipeline_default_value)
                    node.set_component_parameter(property_name, merged_list)

            if self.primary_pipeline.runtime_config != "local":
                node.remove_env_vars_with_matching_secrets()

            node.convert_data_class_properties()
Ejemplo n.º 9
0
def test_env_dict_to_list():
    test_dict = {"TEST": "one", "TEST_TWO": "two", "TEST_FOUR": "1"}
    test_list_correct = ["TEST=one", "TEST_TWO=two", "TEST_FOUR=1"]
    assert KeyValueList.from_dict(test_dict) == test_list_correct