Esempio n. 1
0
def _raise_error_if_unsupported_payload_version(payload_version: str):
    input_rde_version = rde_constants.MAP_INPUT_PAYLOAD_VERSION_TO_RDE_VERSION.get(
        payload_version,
        rde_constants.RDEVersion.RDE_1_0_0.value)  # noqa: E501
    supported_rde_version = rde_utils.get_rde_version_introduced_at_api_version(
        _SUPPORTED_API_VERSION)  # noqa: E501
    if semantic_version.Version(input_rde_version) > semantic_version.Version(
            supported_rde_version):  # noqa: E501
        raise exceptions.BadRequestError(
            f"Unsupported payload version: {payload_version}")  # noqa: E501
Esempio n. 2
0
def create_cluster(behavior_ctx: BehaviorRequestContext):
    entity_id: str = behavior_ctx.entity_id
    entity: dict = behavior_ctx.entity
    cloudapi_client: CloudApiClient = behavior_ctx.op_ctx.cloudapi_client
    api_version: float = behavior_ctx.api_version

    # Validate the input
    rde_version_introduced_at_api_version = rde_utils.get_rde_version_introduced_at_api_version(
        api_version)  # noqa: E501
    rde_validator_factory.get_validator(
        rde_version=rde_version_introduced_at_api_version). \
        validate(cloudapi_client=cloudapi_client, entity=entity)

    # TODO Based on the rde_in_use, convert the entity if necessary.

    # Call the backend to initiate the cluster creation.
    rde_in_use = server_utils.get_rde_version_in_use()
    svc = cluster_service_factory.ClusterServiceFactory(
        behavior_ctx).get_cluster_service(rde_in_use)  # noqa: E501
    NativeEntityClass: AbstractNativeEntity = rde_factory.get_rde_model(
        rde_in_use)  # noqa: E501
    input_entity: AbstractNativeEntity = NativeEntityClass(**entity)
    return svc.create_cluster(entity_id=entity_id,
                              input_native_entity=input_entity)  # noqa: E501
    def validate(self,
                 cloudapi_client: CloudApiClient,
                 entity_id: str = None,
                 entity: dict = None,
                 operation: BehaviorOperation = None) -> bool:  # noqa: E501
        """Validate the input request.

        This method performs
        1. Basic validation of the entity by simply casting the input entity
        dict to the model class dictated by the api_version specified in the
        request. This is usually performed for the "create" operation.
        2. Operation (create, update, delete) specific validation.
        - create: "entity" is the only required parameter.
        - update: both "entity" and "entity_id" are required parameters.
        - delete: "entity_id" is the only required parameter.
        - kubeconfig: "entity_id" is the only required parameter.

        :param cloudapi_client: cloud api client
        :param dict entity: dict form of the native entity to be validated
        :param entity_id: entity id to be validated
        :param BehaviorOperation operation: CSE operation key
        :return: is validation successful or failure
        :rtype: bool
        """
        if not entity_id and not entity:
            raise ValueError(
                'Either entity_id or entity is required to validate.'
            )  # noqa: E501
        entity_svc = DefEntityService(cloudapi_client=cloudapi_client)

        api_version: str = cloudapi_client.get_api_version()
        rde_version_introduced_at_api_version: str = rde_utils.get_rde_version_introduced_at_api_version(
            api_version)  # noqa: E501

        # TODO Reject the request if payload_version does not match with
        #  either rde_in_use (or) rde_version_introduced_at_api_version

        # Cast the entity to the model class based on the user-specified
        # api_version. This can be considered as a basic request validation.
        # Any operation specific validation is handled further down
        NativeEntityClass: AbstractNativeEntity = rde_factory. \
            get_rde_model(rde_version_introduced_at_api_version)
        input_entity = None
        if entity:
            try:
                input_entity: AbstractNativeEntity = NativeEntityClass.from_dict(
                    entity)  # noqa: E501
            except Exception as err:
                msg = f"Failed to parse request body: {err}"
                raise BadRequestError(msg)

        # Return True if the operation is not specified.
        if not operation:
            return True

        # TODO: validators for rest of the CSE operations in V36 will be
        #  implemented as and when v36/def_cluster_handler.py get other handler
        #  functions
        if operation == BehaviorOperation.UPDATE_CLUSTER:
            if not entity_id or not entity:
                raise ValueError(
                    'Both entity_id and entity are required to validate the Update operation.'
                )  # noqa: E501
            current_entity: AbstractNativeEntity = entity_svc.get_entity(
                entity_id).entity  # noqa: E501
            input_entity_spec: rde_2_0_0.ClusterSpec = input_entity.spec
            current_entity_status: rde_2_0_0.Status = current_entity.status
            current_entity_spec = \
                rde_utils.construct_cluster_spec_from_entity_status(
                    current_entity_status, rde_constants.RDEVersion.RDE_2_0_0.value)  # noqa: E501
            return validate_cluster_update_request_and_check_cluster_upgrade(
                input_entity_spec, current_entity_spec)

        # TODO check the reason why there was an unreachable raise statement
        raise NotImplementedError(f"Validator for {operation.name} not found")
    def validate(
            self,
            cloudapi_client: CloudApiClient,
            sysadmin_client: Client,
            entity_id: str = None,
            entity: dict = None,
            operation: BehaviorOperation = BehaviorOperation.CREATE_CLUSTER,
            **kwargs) -> bool:
        """Validate the input request.

        This method performs
        1. Basic validation of the entity by simply casting the input entity
        dict to the model class dictated by the api_version specified in the
        request. This is usually performed for the "create" operation.
        2. Operation (create, update, delete) specific validation.
        - create: "entity" is the only required parameter.
        - update: both "entity" and "entity_id" are required parameters.
        - delete: "entity_id" is the only required parameter.
        - kubeconfig: "entity_id" is the only required parameter.

        :param cloudapi_client: cloud api client
        :param sysadmin_client:
        :param dict entity: dict form of the native entity to be validated
        :param entity_id: entity id to be validated
        :param BehaviorOperation operation: CSE operation key
        :return: is validation successful or failure
        :rtype: bool
        """
        is_tkgm_cluster = kwargs.get('is_tkgm_cluster', False)
        if not entity_id and not entity:
            raise ValueError(
                'Either entity_id or entity is required to validate.'
            )  # noqa: E501
        entity_svc = DefEntityService(cloudapi_client=cloudapi_client)

        api_version: str = cloudapi_client.get_api_version()
        rde_version_introduced_at_api_version: str = rde_utils.get_rde_version_introduced_at_api_version(
            api_version)  # noqa: E501

        # TODO Reject the request if payload_version does not match with
        #  either rde_in_use (or) rde_version_introduced_at_api_version

        # Cast the entity to the model class based on the user-specified
        # api_version. This can be considered as a basic request validation.
        # Any operation specific validation is handled further down
        native_entity_class: AbstractNativeEntity = rde_factory. \
            get_rde_model(rde_version_introduced_at_api_version)
        input_entity = None
        if entity:
            try:
                input_entity: AbstractNativeEntity = native_entity_class.from_dict(
                    entity)  # noqa: E501
            except Exception as err:
                msg = f"Failed to parse request body: {err}"
                raise BadRequestError(msg)

        # Need to ensure that sizing class along with cpu/memory is not
        # present in the request
        if isinstance(input_entity, rde_2_1_0.NativeEntity):
            # cpu and mem are properties of only rde 2.0.0
            bad_request_msg = ""
            if input_entity.spec.topology.workers.sizing_class and \
                    (input_entity.spec.topology.workers.cpu or input_entity.spec.topology.workers.memory):  # noqa: E501
                bad_request_msg = "Cannot specify both sizing class and cpu/memory for Workers nodes."  # noqa: E501
            if input_entity.spec.topology.control_plane.sizing_class and (
                    input_entity.spec.topology.control_plane.cpu
                    or input_entity.spec.topology.control_plane.memory
            ):  # noqa: E501
                bad_request_msg = "Cannot specify both sizing class and cpu/memory for Control Plane nodes."  # noqa: E501
            if bad_request_msg:
                raise BadRequestError(bad_request_msg)
        # Return True if the operation is not specified.
        if operation == BehaviorOperation.CREATE_CLUSTER:
            return True

        # TODO: validators for rest of the CSE operations in V36 will be
        #  implemented as and when v36/def_cluster_handler.py get other handler
        #  functions
        if operation == BehaviorOperation.UPDATE_CLUSTER:
            if not entity_id or not entity:
                raise ValueError(
                    'Both entity_id and entity are required to validate the Update operation.'
                )  # noqa: E501
            current_entity: AbstractNativeEntity = entity_svc.get_entity(
                entity_id).entity  # noqa: E501
            input_entity_spec: rde_2_1_0.ClusterSpec = input_entity.spec
            current_entity_status: rde_2_1_0.Status = current_entity.status
            is_tkgm_with_default_sizing_in_control_plane = False
            is_tkgm_with_default_sizing_in_workers = False
            if is_tkgm_cluster:
                # NOTE: Since for TKGm cluster, if cluster is created without
                # a sizing class, default sizing class is assigned by VCD,
                # If we find the default sizing policy in the status section,
                # validate cpu/memory and sizing policy.
                # Also note that at this point in code, we are sure that only
                # one of sizing class or cpu/mem will be associated with
                # control plane and workers.
                vdc: VDC = get_vdc(
                    sysadmin_client,
                    vdc_name=current_entity_status.cloud_properties.
                    virtual_data_center_name,  # noqa: E501
                    org_name=current_entity_status.cloud_properties.org_name)
                vdc_resource = vdc.get_resource_admin()
                default_cp_name = vdc_resource.DefaultComputePolicy.get('name')
                control_plane_sizing_class = current_entity_status.nodes.control_plane.sizing_class  # noqa: E501
                is_tkgm_with_default_sizing_in_control_plane = \
                    (control_plane_sizing_class == default_cp_name)
                is_tkgm_with_default_sizing_in_workers = \
                    (len(current_entity_status.nodes.workers) > 0
                     and current_entity_status.nodes.workers[0].sizing_class == default_cp_name)  # noqa: E501
            current_entity_spec = \
                rde_utils.construct_cluster_spec_from_entity_status(
                    current_entity_status,
                    rde_constants.RDEVersion.RDE_2_1_0.value,
                    is_tkgm_with_default_sizing_in_control_plane=is_tkgm_with_default_sizing_in_control_plane,  # noqa: E501
                    is_tkgm_with_default_sizing_in_workers=is_tkgm_with_default_sizing_in_workers)  # noqa: E501
            return validate_cluster_update_request_and_check_cluster_upgrade(
                input_entity_spec, current_entity_spec, is_tkgm_cluster)

        # TODO check the reason why there was an unreachable raise statement
        raise NotImplementedError(f"Validator for {operation.name} not found")