def nfs_node_delete(data, op_ctx: ctx.OperationContext):
    """Request handler for node delete operation.

    Required data: cluster_name, node_names_list
    Optional data and default values: org_name=None, ovdc_name=None

    (data validation handled in broker)

    :return: Dict
    """
    rde_in_use = server_utils.get_rde_version_in_use()
    svc = cluster_service_factory.ClusterServiceFactory(op_ctx). \
        get_cluster_service(rde_in_use)
    cluster_id = data[RequestKey.CLUSTER_ID]
    node_name = data[RequestKey.NODE_NAME]

    telemetry_handler.record_user_action_details(
        cse_operation=telemetry_constants.CseOperation.V36_NODE_DELETE,
        cse_params={
            telemetry_constants.PayloadKey.CLUSTER_ID:
            cluster_id,
            telemetry_constants.PayloadKey.NODE_NAME:
            node_name,
            telemetry_constants.PayloadKey.SOURCE_DESCRIPTION:
            thread_local_data.get_thread_local_data(
                server_constants.ThreadLocalData.USER_AGENT)  # noqa: E501
        })

    return svc.delete_nodes(cluster_id, [node_name]).to_dict()
Ejemplo n.º 2
0
def cluster_delete(data: dict, op_ctx: ctx.OperationContext):
    """Request handler for cluster delete operation.

    Required data: cluster_name
    Optional data and default values: org_name=None, ovdc_name=None

    (data validation handled in broker)

    :return: Dict
    """
    cluster_id = data[RequestKey.CLUSTER_ID]
    def_entity_service = entity_service.DefEntityService(
        op_ctx.cloudapi_client)  # noqa: E501
    def_entity: common_models.DefEntity = def_entity_service.get_entity(
        cluster_id)  # noqa: E501
    telemetry_handler.record_user_action_details(
        cse_operation=telemetry_constants.CseOperation.V36_CLUSTER_DELETE,
        cse_params={
            server_constants.CLUSTER_ENTITY:
            def_entity,
            telemetry_constants.PayloadKey.SOURCE_DESCRIPTION:
            thread_local_data.get_thread_local_data(
                ThreadLocalData.USER_AGENT)  # noqa: E501
        })
    _, task_href = def_entity_service.delete_entity(
        cluster_id, invoke_hooks=True, is_request_async=True)  # noqa: E501
    def_entity.entity.status.task_href = task_href
    return def_entity.to_dict()
Ejemplo n.º 3
0
def cluster_config(data: dict, op_ctx: ctx.OperationContext):
    """Request handler for cluster config operation.

    Required data: cluster_id

    :return: Dict
    """
    cluster_id = data[RequestKey.CLUSTER_ID]
    def_entity_service = entity_service.DefEntityService(
        op_ctx.cloudapi_client)  # noqa: E501
    def_entity: common_models.DefEntity = def_entity_service.get_entity(
        cluster_id)  # noqa: E501
    telemetry_handler.record_user_action_details(
        cse_operation=telemetry_constants.CseOperation.V36_CLUSTER_CONFIG,
        cse_params={
            server_constants.CLUSTER_ENTITY:
            def_entity,
            telemetry_constants.PayloadKey.SOURCE_DESCRIPTION:
            thread_local_data.get_thread_local_data(
                ThreadLocalData.USER_AGENT)  # noqa: E501
        })

    op_ctx.entity_id = cluster_id  # hack for passing entity id
    svc = cluster_service_factory.ClusterServiceFactory(
        _get_request_context(op_ctx)).get_cluster_service()  # noqa: E501
    config_dict = svc.get_cluster_config(cluster_id)

    config: str = config_dict.get(
        server_constants.BEHAVIOR_TASK_RESPONSE_RESULT_MESSAGE_KEY, {}).get(
            server_constants.BEHAVIOR_TASK_RESPONSE_RESULT_CONTENT_MESSAGE_KEY
        )  # noqa: E501
    return_dict = {"message": config}
    return return_dict
Ejemplo n.º 4
0
def cluster_list(request_data, op_ctx: ctx.OperationContext):
    """Request handler for cluster list operation.

    All brokers in the org do 'list cluster' operation.
    Post-process the result returned by the broker.
    Aggregate all the results into a list.

    Optional data and default values: org_name=None, ovdc_name=None

    (data validation handled in broker)

    :return: List
    """
    _raise_error_if_pks_not_enabled()

    cse_params = copy.deepcopy(request_data)
    cse_params[PayloadKey.
               SOURCE_DESCRIPTION] = thread_local_data.get_thread_local_data(
                   ThreadLocalData.USER_AGENT)  # noqa: E501
    telemetry_handler.record_user_action_details(
        cse_operation=CseOperation.PKS_CLUSTER_LIST, cse_params=cse_params)

    pks_clusters_info = pks_broker_manager.list_clusters(request_data, op_ctx)
    common_cluster_properties = [
        'name', 'vdc', 'status', 'org_name', 'k8s_version', K8S_PROVIDER_KEY
    ]

    result = []
    for cluster_info in pks_clusters_info:
        filtered_cluster_info = \
            {k: cluster_info.get(k) for k in common_cluster_properties}
        result.append(filtered_cluster_info)

    return result
Ejemplo n.º 5
0
def nfs_node_delete(data, op_ctx: ctx.OperationContext):
    """Request handler for node delete operation.

    Required data: cluster_name, node_names_list
    Optional data and default values: org_name=None, ovdc_name=None

    (data validation handled in broker)

    :return: Dict
    """
    cluster_id = data[RequestKey.CLUSTER_ID]
    node_name = data[RequestKey.NODE_NAME]
    behavior_svc = BehaviorService(cloudapi_client=op_ctx.cloudapi_client)
    telemetry_handler.record_user_action_details(
        cse_operation=telemetry_constants.CseOperation.V36_NODE_DELETE,
        cse_params={
            telemetry_constants.PayloadKey.CLUSTER_ID:
            cluster_id,
            telemetry_constants.PayloadKey.NODE_NAME:
            node_name,
            telemetry_constants.PayloadKey.SOURCE_DESCRIPTION:
            thread_local_data.get_thread_local_data(
                server_constants.ThreadLocalData.USER_AGENT)  # noqa: E501
        })
    delete_nfs_node_task = behavior_svc.invoke_behavior(
        entity_id=cluster_id,
        behavior_interface_id=DELETE_NFS_NODE_BEHAVIOR_ID,
        arguments={RequestKey.NODE_NAME.value: node_name})
    def_entity_service = entity_service.DefEntityService(
        op_ctx.cloudapi_client)  # noqa: E501
    cluster_def_entity: common_models.DefEntity = def_entity_service.get_entity(
        cluster_id)  # noqa: E501
    cluster_def_entity.entity.status.task_href = delete_nfs_node_task

    return cluster_def_entity.to_dict()
Ejemplo n.º 6
0
def get_ovdc(operation_context: ctx.OperationContext, ovdc_id: str) -> dict:
    """Get ovdc info for a particular ovdc.

    :param ctx.OperationContext operation_context: context for the request
    :param str ovdc_id: ID of the ovdc
    :return: dictionary containing the ovdc information
    :rtype: dict
    """
    # NOTE: For CSE 3.0, if `enable_tkg_plus` flag in config is set to false,
    # Prevent showing information about TKG+ by skipping TKG+ from the result.
    cse_params = {
        RequestKey.OVDC_ID:
        ovdc_id,
        PayloadKey.SOURCE_DESCRIPTION:
        thread_local_data.get_thread_local_data(
            ThreadLocalData.USER_AGENT)  # noqa: E501
    }
    telemetry_handler.record_user_action_details(
        cse_operation=CseOperation.OVDC_INFO,  # noqa: E501
        cse_params=cse_params)
    config = server_utils.get_server_runtime_config()
    log_wire = utils.str_to_bool(config.get('service', {}).get('log_wire'))
    result = asdict(
        get_ovdc_k8s_runtime_details(
            operation_context.sysadmin_client,  # noqa: E501
            ovdc_id=ovdc_id,
            log_wire=log_wire))
    # TODO: Find a better way to avoid sending remove_cp_from_vms_on_disable
    # flag
    if ClusterEntityKind.TKG_PLUS.value in result['k8s_runtime'] \
            and not server_utils.is_tkg_plus_enabled():
        result['k8s_runtime'].remove(ClusterEntityKind.TKG_PLUS.value)
    del result['remove_cp_from_vms_on_disable']
    return result
Ejemplo n.º 7
0
def list_org_vdcs(operation_context: ctx.OperationContext,
                  page_number=CSE_PAGINATION_FIRST_PAGE_NUMBER,
                  page_size=CSE_PAGINATION_DEFAULT_PAGE_SIZE) -> dict:
    """Fetch org VDCs and their k8s runtimes.

    :param ctx.OperationContext operation_context: context for the request
    :param int page_number: page_number to fetch
    :param int page_size: size of each page to return
    :return: dictionary containing list of details about the ovdc
    :rtype: dict
    """
    # NOTE: The response sent out by this function needs to be
    # paginated
    # Record telemetry
    telemetry_handler.record_user_action_details(
        cse_operation=CseOperation.OVDC_LIST,
        cse_params={
            PayloadKey.SOURCE_DESCRIPTION:
            thread_local_data.get_thread_local_data(
                ThreadLocalData.USER_AGENT)  # noqa: E501
        })
    result = cloudapi_utils.get_vdcs_by_page(operation_context.cloudapi_client,
                                             page_number=page_number,
                                             page_size=page_size)
    num_results = result[PaginationKey.RESULT_TOTAL]
    ovdcs = _get_cse_ovdc_list(operation_context.sysadmin_client,
                               result[PaginationKey.VALUES])
    return {
        PaginationKey.RESULT_TOTAL: num_results,
        PaginationKey.VALUES: ovdcs
    }
Ejemplo n.º 8
0
def cluster_create(data: dict, op_ctx: ctx.OperationContext):
    """Request handler for cluster create operation.

    :return: Defined entity of the native cluster
    :rtype: container_service_extension.def_.models.DefEntity
    """
    input_entity: dict = data[RequestKey.INPUT_SPEC]
    payload_version = input_entity.get(
        rde_constants.PayloadKey.PAYLOAD_VERSION)  # noqa: E501
    rde_utils.raise_error_if_unsupported_payload_version(payload_version)

    # Validate the Input payload based on the (Operation, payload_version).
    # Get the validator based on the payload_version
    # ToDo : Don't use default cloudapi_client. Use the specific versioned one
    rde_validator_factory.get_validator(
        rde_version=rde_constants.
        MAP_INPUT_PAYLOAD_VERSION_TO_RDE_VERSION[payload_version]).validate(
            cloudapi_client=op_ctx.cloudapi_client,
            sysadmin_client=op_ctx.sysadmin_client,
            entity=input_entity)

    def_entity_service = entity_service.DefEntityService(
        op_ctx.cloudapi_client)  # noqa: E501
    entity_type = server_utils.get_registered_def_entity_type()
    converted_entity: AbstractNativeEntity = rde_utils.convert_input_rde_to_runtime_rde_format(
        input_entity)  # noqa: E501
    def_entity = common_models.DefEntity(
        entity=converted_entity, entityType=entity_type.id)  # noqa: E501

    # No need to set org context for non sysadmin users
    org_context = None
    if op_ctx.client.is_sysadmin():
        org_resource = pyvcloud_utils.get_org(
            op_ctx.client,
            org_name=converted_entity.metadata.org_name)  # noqa: E501
        org_context = org_resource.href.split('/')[-1]

    _, task_href = def_entity_service.create_entity(
        entity_type_id=entity_type.id,
        entity=def_entity,
        tenant_org_context=org_context,
        is_request_async=True)

    task_resource = op_ctx.sysadmin_client.get_resource(task_href)
    entity_id = task_resource.Owner.get('id')
    def_entity = def_entity_service.get_entity(entity_id)
    def_entity.entity.status.task_href = task_href
    telemetry_handler.record_user_action_details(
        cse_operation=telemetry_constants.CseOperation.V36_CLUSTER_APPLY,
        cse_params={
            server_constants.CLUSTER_ENTITY:
            def_entity,
            telemetry_constants.PayloadKey.SOURCE_DESCRIPTION:
            thread_local_data.get_thread_local_data(
                ThreadLocalData.USER_AGENT)  # noqa: E501
        })
    return def_entity.to_dict()
def org_vdc_list(request_data, op_ctx: ctx.OperationContext):
    """Request handler for orgvdc list operation.

    This handler returns a paginated response.
    :return: Dictionary containing list of org VDC K8s provider metadata
    :rtype: dict
    """
    # NOTE: Response sent out by this function should be paginated
    data = req_utils.flatten_request_data(request_data,
                                          [RequestKey.QUERY_PARAMS])

    defaults = {
        PaginationKey.PAGE_NUMBER: CSE_PAGINATION_FIRST_PAGE_NUMBER,
        PaginationKey.PAGE_SIZE: CSE_PAGINATION_DEFAULT_PAGE_SIZE
    }
    validated_data = {**defaults, **data}

    page_number = int(validated_data[PaginationKey.PAGE_NUMBER])
    page_size = int(validated_data[PaginationKey.PAGE_SIZE])

    # Record telemetry data
    # TODO: enhance telemetry to record the page number and page size data.
    cse_params = copy.deepcopy(validated_data)
    cse_params[PayloadKey.
               SOURCE_DESCRIPTION] = thread_local_data.get_thread_local_data(
                   ThreadLocalData.USER_AGENT)  # noqa: E501
    record_user_action_details(cse_operation=CseOperation.OVDC_LIST,
                               cse_params=cse_params)
    client_v33 = op_ctx.get_client(api_version=DEFAULT_API_VERSION)
    result = vcd_utils.get_ovdcs_by_page(client_v33,
                                         page=page_number,
                                         page_size=page_size)
    org_vdcs = result[PaginationKey.VALUES]
    result_total = result[PaginationKey.RESULT_TOTAL]
    next_page_uri = result.get(PaginationKey.NEXT_PAGE_URI)
    prev_page_uri = result.get(PaginationKey.PREV_PAGE_URI)

    sysadmin_client_v33 = \
        op_ctx.get_sysadmin_client(api_version=DEFAULT_API_VERSION)
    ovdcs = _get_cse_ovdc_list(sysadmin_client_v33, org_vdcs)

    api_path = CseServerOperationInfo.ORG_VDC_LIST.api_path_format
    next_page_uri = vcd_utils.create_cse_page_uri(client_v33,
                                                  api_path,
                                                  vcd_uri=next_page_uri)
    prev_page_uri = vcd_utils.create_cse_page_uri(client_v33,
                                                  api_path,
                                                  vcd_uri=prev_page_uri)
    return server_utils.construct_paginated_response(
        values=ovdcs,
        result_total=result_total,
        page_number=page_number,
        page_size=page_size,
        next_page_uri=next_page_uri,
        prev_page_uri=prev_page_uri)
Ejemplo n.º 10
0
def cluster_update(data: dict, op_ctx: ctx.OperationContext):
    """Request handler for cluster resize operation.

    :return: Defined entity of the native cluster
    :rtype: container_service_extension.def_.models.DefEntity
    """
    cluster_id = data[RequestKey.CLUSTER_ID]
    input_entity: dict = data[RequestKey.INPUT_SPEC]
    payload_version = input_entity.get(
        rde_constants.PayloadKey.PAYLOAD_VERSION)  # noqa: E501
    rde_utils.raise_error_if_unsupported_payload_version(payload_version)

    # Validate the Input payload based on the (Operation, payload_version).
    # Get the validator based on the payload_version
    # ToDo : Don't use default cloudapi_client. Use the specific versioned one
    kind = input_entity['kind']
    is_tkgm_cluster = (kind == ClusterEntityKind.TKG_M.value)
    sysadmin_client = op_ctx.sysadmin_client
    rde_validator_factory.get_validator(
        rde_version=rde_constants.MAP_INPUT_PAYLOAD_VERSION_TO_RDE_VERSION[
            payload_version]). \
        validate(cloudapi_client=op_ctx.cloudapi_client,
                 sysadmin_client=sysadmin_client, entity_id=cluster_id,
                 entity=input_entity,
                 operation=BehaviorOperation.UPDATE_CLUSTER,
                 is_tkgm_cluster=is_tkgm_cluster)

    # Convert the input entity to runtime rde format.
    # Based on the runtime rde, call the appropriate backend method.
    def_entity_service = entity_service.DefEntityService(
        op_ctx.cloudapi_client)  # noqa: E501
    converted_native_entity: AbstractNativeEntity = rde_utils.convert_input_rde_to_runtime_rde_format(
        input_entity)  # noqa: E501

    changes = {'entity.spec': converted_native_entity.spec}
    updated_def_entity, task_href = def_entity_service.update_entity(
        entity_id=cluster_id,
        invoke_hooks=True,
        is_request_async=True,
        changes=changes)
    updated_def_entity.entity.status.task_href = task_href
    telemetry_handler.record_user_action_details(
        cse_operation=telemetry_constants.CseOperation.V36_CLUSTER_APPLY,
        cse_params={
            server_constants.CLUSTER_ENTITY:
            updated_def_entity,
            telemetry_constants.PayloadKey.SOURCE_DESCRIPTION:
            thread_local_data.get_thread_local_data(
                ThreadLocalData.USER_AGENT)  # noqa: E501
        })
    # TODO: Response RDE must be compatible with the request RDE.
    #  Conversions may be needed especially if there is a major version
    #  difference in the input RDE and runtime RDE.
    return updated_def_entity.to_dict()
def ovdc_list(request_data, op_ctx: ctx.OperationContext):
    """Request handler for ovdc list operation.

    :return: List of dictionaries with org VDC k8s provider metadata.
    """
    # NOTE: Response sent out by this function should not be
    # paginated
    # Record telemetry data
    cse_params = copy.deepcopy(request_data)
    record_user_action_details(cse_operation=CseOperation.OVDC_LIST,
                               cse_params=cse_params)

    org_vdcs = vcd_utils.get_all_ovdcs(op_ctx.client)
    return _get_cse_ovdc_list(op_ctx.sysadmin_client, org_vdcs)
def ovdc_update(request_data, op_ctx: ctx.OperationContext):
    """Request handler for ovdc enable, disable operations.

    Required data: org_name, ovdc_name, k8s_provider
    Conditional data:
        if k8s_provider is 'ent-pks': pks_plan_name, pks_cluster_domain

    :return: Dictionary with org VDC update task href.
    """
    # TODO the data flow here should be better understood.
    # org_name and ovdc_name seem redundant if we already have ovdc_id
    data = req_utils.flatten_request_data(
        request_data, [RequestKey.INPUT_SPEC, RequestKey.QUERY_PARAMS])

    required = [
        RequestKey.ORG_NAME, RequestKey.OVDC_NAME, RequestKey.K8S_PROVIDER,
        RequestKey.OVDC_ID
    ]
    validated_data = data
    req_utils.validate_payload(validated_data, required)

    k8s_provider = validated_data[RequestKey.K8S_PROVIDER]
    k8s_provider_info = {K8S_PROVIDER_KEY: k8s_provider}

    # Record the telemetry data
    cse_params = copy.deepcopy(validated_data)
    cse_params[PayloadKey.
               SOURCE_DESCRIPTION] = thread_local_data.get_thread_local_data(
                   ThreadLocalData.USER_AGENT)  # noqa: E501
    cse_operation = CseOperation.OVDC_DISABLE if k8s_provider == K8sProvider.NONE else CseOperation.OVDC_ENABLE  # noqa: E501
    record_user_action_details(cse_operation=cse_operation,
                               cse_params=cse_params)  # noqa: E501

    try:
        sysadmin_client_v33 = \
            op_ctx.get_sysadmin_client(api_version=DEFAULT_API_VERSION)
        task = ovdc_utils.update_ovdc_k8s_provider_metadata(
            sysadmin_client_v33,
            validated_data[RequestKey.OVDC_ID],
            k8s_provider_data=k8s_provider_info,
            k8s_provider=k8s_provider)

        # Telemetry - Record successful enabling/disabling of ovdc
        record_user_action(cse_operation, status=OperationStatus.SUCCESS)

        return {'task_href': task.get('href')}
    except Exception as err:
        # Telemetry - Record failed enabling/disabling of ovdc
        record_user_action(cse_operation, status=OperationStatus.FAILED)
        raise err
Ejemplo n.º 13
0
def cluster_info(request_data, op_ctx: ctx.OperationContext):
    """Request handler for cluster info operation.

    Required data: cluster_name
    Optional data and default values: org_name=None, ovdc_name=None

    (data validation handled in broker)

    :return: Dict
    """
    _raise_error_if_pks_not_enabled()
    cluster, _ = _get_cluster_info(request_data, op_ctx)  # noqa: E501
    telemetry_handler.record_user_action_details(
        cse_operation=CseOperation.PKS_CLUSTER_INFO,
        cse_params=_get_telemetry_data(request_data, cluster))
    return cluster
def cluster_create(request_data, op_ctx: ctx.OperationContext):
    """Request handler for cluster create operation.

    Required data: org_name, ovdc_name, cluster_name

    (data validation handled in broker)

    :return: Dict
    """
    _raise_error_if_pks_not_enabled()

    data = req_utils.flatten_request_data(request_data,
                                          [RequestKey.INPUT_SPEC])

    required = [RequestKey.CLUSTER_NAME]
    req_utils.validate_payload(data, required)

    cluster_name = data[RequestKey.CLUSTER_NAME]
    data['is_org_admin_search'] = True

    try:
        _get_cluster_and_broker(data, op_ctx, telemetry=False)
        raise ClusterAlreadyExistsError(f"Cluster {cluster_name} "
                                        f"already exists.")
    except ClusterNotFoundError:
        pass

    sysadmin_client_v33 = op_ctx.get_sysadmin_client(
        api_version=DEFAULT_API_VERSION)
    k8s_metadata = \
        ovdc_utils.get_ovdc_k8s_provider_metadata(
            sysadmin_client_v33,
            org_name=data[RequestKey.ORG_NAME],
            ovdc_name=data[RequestKey.OVDC_NAME],
            include_credentials=True,
            include_nsxt_info=True)
    broker = _get_broker_from_k8s_metadata(k8s_metadata, op_ctx)
    data[RequestKey.PKS_PLAN_NAME] = k8s_metadata[PKS_PLANS_KEY][0]
    data[RequestKey.PKS_EXT_HOST] = \
        f"{cluster_name}.{k8s_metadata[PKS_CLUSTER_DOMAIN_KEY]}"
    cluster = broker.create_cluster(data=data)
    # Record telemetry data
    telemetry_handler.record_user_action_details(
        cse_operation=CseOperation.PKS_CLUSTER_CREATE,
        cse_params=_get_telemetry_data(data, cluster))
    return cluster
Ejemplo n.º 15
0
def nfs_node_delete(data, op_ctx: ctx.OperationContext):
    """Request handler for node delete operation.

    Required data: cluster_name, node_names_list
    Optional data and default values: org_name=None, ovdc_name=None

    (data validation handled in broker)

    :return: Dict
    """
    rde_in_use = server_utils.get_rde_version_in_use()
    if semantic_version.Version(rde_in_use) >= semantic_version.Version(
            rde_constants.RDEVersion.RDE_2_0_0.value):  # noqa: E501
        cluster_dict = cluster_handler.nfs_node_delete(
            data=data, op_ctx=op_ctx)  # noqa: E501
        # NOTE: cluster_handler is always expected to return RDE version
        #   2.0.0 or more. Hence a convertion to 1.0 is needed
        rde_class = rde_factory.get_rde_model(rde_in_use)
        cluster_entity: AbstractNativeEntity = rde_class.from_dict(
            cluster_dict['entity'])  # noqa: E501
        new_native_entity: AbstractNativeEntity = rde_utils.convert_runtime_rde_to_input_rde_version_format(  # noqa: E501
            cluster_entity, rde_constants.RDEVersion.RDE_1_0_0)
        cluster_dict['entity'] = new_native_entity.to_dict()
        cluster_dict[
            'entityType'] = common_models.EntityType.NATIVE_ENTITY_TYPE_1_0_0.value.id  # noqa: E501
        return cluster_dict

    svc = cluster_service_factory.ClusterServiceFactory(op_ctx). \
        get_cluster_service(rde_in_use)
    cluster_id = data[RequestKey.CLUSTER_ID]
    node_name = data[RequestKey.NODE_NAME]

    telemetry_handler.record_user_action_details(
        cse_operation=telemetry_constants.CseOperation.V35_NODE_DELETE,
        cse_params={
            telemetry_constants.PayloadKey.CLUSTER_ID:
            cluster_id,
            telemetry_constants.PayloadKey.NODE_NAME:
            node_name,
            telemetry_constants.PayloadKey.SOURCE_DESCRIPTION:
            thread_local_data.get_thread_local_data(
                ThreadLocalData.USER_AGENT)  # noqa: E501
        })

    return svc.delete_nodes(cluster_id, [node_name]).to_dict()
Ejemplo n.º 16
0
def cluster_resize(request_data, op_ctx: ctx.OperationContext):
    """Request handler for cluster resize operation.

    Required data: cluster_name, num_nodes
    Optional data and default values: org_name=None, ovdc_name=None

    (data validation handled in broker)

    :return: Dict
    """
    _raise_error_if_pks_not_enabled()
    cluster, broker = _get_cluster_info(request_data, op_ctx,
                                        telemetry=False)  # noqa: E501
    # Record telemetry data
    telemetry_handler.record_user_action_details(
        cse_operation=CseOperation.PKS_CLUSTER_RESIZE,
        cse_params=_get_telemetry_data(request_data, cluster))
    return broker.resize_cluster(data=request_data)
def ovdc_info(request_data, op_ctx: ctx.OperationContext):
    """Request handler for ovdc info operation.

    Required data: org_name, ovdc_name

    :return: Dictionary with org VDC k8s provider metadata.
    """
    required = [RequestKey.OVDC_ID]
    req_utils.validate_payload(request_data, required)

    # Record telemetry data
    cse_params = copy.deepcopy(request_data)
    cse_params[PayloadKey.
               SOURCE_DESCRIPTION] = thread_local_data.get_thread_local_data(
                   ThreadLocalData.USER_AGENT)  # noqa: E501
    record_user_action_details(cse_operation=CseOperation.OVDC_INFO,
                               cse_params=cse_params)

    return ovdc_utils.get_ovdc_k8s_provider_metadata(
        op_ctx.sysadmin_client, ovdc_id=request_data[RequestKey.OVDC_ID])
Ejemplo n.º 18
0
def ovdc_list(request_data, op_ctx: ctx.OperationContext):
    """Request handler for ovdc list operation.

    :return: List of dictionaries with org VDC k8s provider metadata.
    """
    # NOTE: Response sent out by this function should not be
    # paginated

    data = req_utils.flatten_request_data(
        request_data, [RequestKey.QUERY_PARAMS])

    # Record telemetry data
    cse_params = copy.deepcopy(data)
    record_user_action_details(cse_operation=CseOperation.OVDC_LIST,
                               cse_params=cse_params)

    client_v33 = op_ctx.get_client(api_version=DEFAULT_API_VERSION)
    sysadmin_client_v33 = \
        op_ctx.get_sysadmin_client(api_version=DEFAULT_API_VERSION)
    org_vdcs = vcd_utils.get_all_ovdcs(client_v33)
    return _get_cse_ovdc_list(sysadmin_client_v33, org_vdcs)
Ejemplo n.º 19
0
def list_ovdc(operation_context: ctx.OperationContext) -> list:
    """List all ovdc and their k8s runtimes.

    :param ctx.OperationContext operation_context: context for the request
    :return: list of org vdcs
    :rtype: list
    """
    # NOTE: Response sent out by this function should not be
    # paginated. The purpose of this handler is to maintain
    # backward compatibility
    # TODO: Deprecate handler once support for CSE 3.0 is removed
    # Record telemetry
    telemetry_handler.record_user_action_details(
        cse_operation=CseOperation.OVDC_LIST,
        cse_params={
            PayloadKey.SOURCE_DESCRIPTION:
            thread_local_data.get_thread_local_data(
                ThreadLocalData.USER_AGENT)  # noqa: E501
        })
    # send un-paginated response
    org_vdcs = vcd_utils.get_all_ovdcs(operation_context.client)
    return _get_cse_ovdc_list(operation_context.sysadmin_client, org_vdcs)
Ejemplo n.º 20
0
    def run(self, msg_update_callback=utils.NullPrinter()):
        sysadmin_client = None
        try:
            sysadmin_client = vcd_utils.get_sys_admin_client(api_version=None)
            verify_version_compatibility(
                sysadmin_client,
                should_cse_run_in_legacy_mode=self.config['service']
                ['legacy_mode'],  # noqa: E501
                is_mqtt_extension=server_utils.should_use_mqtt_protocol(
                    self.config))  # noqa: E501
        except Exception as err:
            logger.SERVER_LOGGER.info(err)
            raise
        finally:
            if sysadmin_client:
                sysadmin_client.logout()

        if server_utils.should_use_mqtt_protocol(self.config):
            # Store/setup MQTT extension, api filter, and token info
            try:
                sysadmin_client = \
                    vcd_utils.get_sys_admin_client(api_version=None)
                mqtt_ext_manager = MQTTExtensionManager(sysadmin_client)
                ext_info = mqtt_ext_manager.get_extension_info(
                    ext_name=server_constants.CSE_SERVICE_NAME,
                    ext_version=server_constants.MQTT_EXTENSION_VERSION,
                    ext_vendor=server_constants.MQTT_EXTENSION_VENDOR)
                ext_urn_id = ext_info[server_constants.MQTTExtKey.EXT_URN_ID]
                ext_uuid = mqtt_ext_manager.get_extension_uuid(ext_urn_id)
                api_filters_status = mqtt_ext_manager.check_api_filters_setup(
                    ext_uuid, configure_cse.API_FILTER_PATTERNS)
                if not api_filters_status:
                    msg = 'MQTT Api filter is not set up'
                    logger.SERVER_LOGGER.error(msg)
                    raise cse_exception.MQTTExtensionError(msg)

                token_info = mqtt_ext_manager.setup_extension_token(
                    token_name=server_constants.MQTT_TOKEN_NAME,
                    ext_name=server_constants.CSE_SERVICE_NAME,
                    ext_version=server_constants.MQTT_EXTENSION_VERSION,
                    ext_vendor=server_constants.MQTT_EXTENSION_VENDOR,
                    ext_urn_id=ext_urn_id)

                self.config['mqtt'].update(ext_info)
                self.config['mqtt'].update(token_info)
                self.config['mqtt'][server_constants.MQTTExtKey.EXT_UUID] = \
                    ext_uuid
            except Exception as err:
                msg = f'MQTT extension setup error: {err}'
                logger.SERVER_LOGGER.error(msg)
                raise err
            finally:
                if sysadmin_client:
                    sysadmin_client.logout()

        populate_vsphere_list(self.config['vcs'])

        # Load def entity-type and interface
        self._load_def_schema(msg_update_callback=msg_update_callback)

        # Read k8s catalog definition from catalog item metadata and append
        # the same to to server run-time config
        self._load_template_definition_from_catalog(
            msg_update_callback=msg_update_callback)

        self._load_placement_policy_details(
            msg_update_callback=msg_update_callback)

        if self.config['service']['legacy_mode']:
            # Read templates rules from config and update template definition
            # in server run-time config
            self._process_template_rules(
                msg_update_callback=msg_update_callback)

            # Make sure that all vms in templates are compliant with the
            # compute policy specified in template definition (can be affected
            # by rules).
            self._process_template_compute_policy_compliance(
                msg_update_callback=msg_update_callback)
        else:
            msg = "Template rules are not supported by CSE for vCD api " \
                  "version 35.0 or above. Skipping template rule processing."
            msg_update_callback.info(msg)
            logger.SERVER_LOGGER.debug(msg)

        if self.should_check_config:
            configure_cse.check_cse_installation(
                self.config, msg_update_callback=msg_update_callback)

        if self.config.get('pks_config'):
            pks_config = self.config.get('pks_config')
            self.pks_cache = PksCache(
                pks_servers=pks_config.get('pks_api_servers', []),
                pks_accounts=pks_config.get('pks_accounts', []),
                pvdcs=pks_config.get('pvdcs', []),
                orgs=pks_config.get('orgs', []),
                nsxt_servers=pks_config.get('nsxt_servers', []))

        num_processors = self.config['service']['processors']
        name = server_constants.MESSAGE_CONSUMER_THREAD
        try:
            self.consumer = MessageConsumer(self.config, num_processors)
            consumer_thread = Thread(name=name,
                                     target=consumer_thread_run,
                                     args=(self.consumer, ))
            consumer_thread.daemon = True
            consumer_thread.start()
            self.consumer_thread = consumer_thread
            msg = f"Started thread '{name}' ({consumer_thread.ident})"
            msg_update_callback.general(msg)
            logger.SERVER_LOGGER.info(msg)
        except KeyboardInterrupt:
            if self.consumer:
                self.consumer.stop()
            interrupt_msg = f"\nKeyboard interrupt when starting thread " \
                            f"'{name}'"
            logger.SERVER_LOGGER.debug(interrupt_msg)
            raise Exception(interrupt_msg)
        except Exception:
            if self.consumer:
                self.consumer.stop()
            logger.SERVER_LOGGER.error(traceback.format_exc())

        # Updating state to Running before starting watchdog because watchdog
        # exits when server is not Running
        self._state = ServerState.RUNNING

        # Start consumer watchdog
        name = server_constants.WATCHDOG_THREAD
        consumer_watchdog = Thread(name=name,
                                   target=watchdog_thread_run,
                                   args=(self, num_processors))
        consumer_watchdog.daemon = True
        consumer_watchdog.start()
        self._consumer_watchdog = consumer_watchdog
        msg = f"Started thread '{name}' ({consumer_watchdog.ident})"
        msg_update_callback.general(msg)
        logger.SERVER_LOGGER.info(msg)

        message = f"Container Service Extension for vCloud Director" \
                  f"\nServer running using config file: {self.config_file}" \
                  f"\nLog files: {logger.SERVER_INFO_LOG_FILEPATH}, " \
                  f"{logger.SERVER_DEBUG_LOG_FILEPATH}" \
                  f"\nwaiting for requests (ctrl+c to close)"

        signal.signal(signal.SIGINT, signal_handler)
        msg_update_callback.general_no_color(message)
        logger.SERVER_LOGGER.info(message)

        # Record telemetry on user action and details of operation.
        cse_params = {
            PayloadKey.WAS_DECRYPTION_SKIPPED:
            bool(self.skip_config_decryption),  # noqa: E501
            PayloadKey.WAS_PKS_CONFIG_FILE_PROVIDED:
            bool(self.pks_config_file),  # noqa: E501
            PayloadKey.WAS_INSTALLATION_CHECK_SKIPPED:
            bool(self.should_check_config)  # noqa: E501
        }
        record_user_action_details(cse_operation=CseOperation.SERVICE_RUN,
                                   cse_params=cse_params)
        record_user_action(cse_operation=CseOperation.SERVICE_RUN)

        while True:
            try:
                time.sleep(1)
                if self._state == ServerState.STOPPING and \
                        self.active_requests_count() == 0:
                    break
            except KeyboardInterrupt:
                break
            except Exception:
                msg_update_callback.general_no_color(traceback.format_exc())
                logger.SERVER_LOGGER.error(traceback.format_exc())
                sys.exit(1)

        logger.SERVER_LOGGER.info("Stop detected")
        logger.SERVER_LOGGER.info("Closing connections...")
        self._state = ServerState.STOPPING
        try:
            self.consumer.stop()
        except Exception:
            logger.SERVER_LOGGER.error(traceback.format_exc())

        self._state = ServerState.STOPPED
        logger.SERVER_LOGGER.info("Done")
Ejemplo n.º 21
0
def org_vdc_list(request_data, op_ctx: ctx.OperationContext):
    """Request handler for ovdc list operation.

    :return: dictionary containing list of Org VDCs
    :rtype: dict
    """
    # NOTE: Response sent out by this handler should be paginated

    data = req_utils.flatten_request_data(request_data,
                                          [RequestKey.QUERY_PARAMS])

    defaults = {
        RequestKey.LIST_PKS_PLANS: False,
        PaginationKey.PAGE_NUMBER: CSE_PAGINATION_FIRST_PAGE_NUMBER,
        PaginationKey.PAGE_SIZE: CSE_PAGINATION_DEFAULT_PAGE_SIZE
    }
    validated_data = {**defaults, **data}

    page_number = int(validated_data[PaginationKey.PAGE_NUMBER])
    page_size = int(validated_data[PaginationKey.PAGE_SIZE])
    list_pks_plans = utils.str_to_bool(
        validated_data[RequestKey.LIST_PKS_PLANS])  # noqa: E501

    # Record telemetry data
    # TODO: enhance telemetry to record the page number and page size data.
    cse_params = copy.deepcopy(validated_data)
    cse_params[RequestKey.LIST_PKS_PLANS] = list_pks_plans
    cse_params[PayloadKey.
               SOURCE_DESCRIPTION] = thread_local_data.get_thread_local_data(
                   ThreadLocalData.USER_AGENT)  # noqa: E501
    record_user_action_details(cse_operation=CseOperation.OVDC_LIST,
                               cse_params=cse_params)

    if list_pks_plans and not op_ctx.client.is_sysadmin():
        raise e.UnauthorizedRequestError(
            'Operation denied. Enterprise PKS plans visible only '
            'to System Administrators.')

    ovdcs = []
    result = \
        vcd_utils.get_ovdcs_by_page(op_ctx.client,
                                    page=page_number,
                                    page_size=page_size)
    org_vdcs = result[PaginationKey.VALUES]
    result_total = result[PaginationKey.RESULT_TOTAL]
    next_page_uri = result.get(PaginationKey.NEXT_PAGE_URI)
    prev_page_uri = result.get(PaginationKey.PREV_PAGE_URI)
    for ovdc in org_vdcs:
        ovdc_name = ovdc.get('name')
        org_name = ovdc.get('orgName')
        ovdc_id = vcd_utils.extract_id(ovdc.get('id'))
        k8s_metadata = ovdc_utils.get_ovdc_k8s_provider_metadata(
            op_ctx.sysadmin_client,
            ovdc_id=ovdc_id,
            ovdc_name=ovdc_name,
            org_name=org_name)
        k8s_provider = k8s_metadata[K8S_PROVIDER_KEY]
        ovdc_dict = {
            OvdcInfoKey.OVDC_NAME: ovdc_name,
            OvdcInfoKey.ORG_NAME: org_name,
            OvdcInfoKey.K8S_PROVIDER: k8s_provider
        }
        if list_pks_plans:
            pks_plans = ''
            pks_server = ''
            if k8s_provider == K8sProvider.PKS:
                # vc name for vdc can only be found using typed query
                qfilter = f"name=={urllib.parse.quote(ovdc_name)};" \
                          f"orgName=={urllib.parse.quote(org_name)}"
                q = op_ctx.client.get_typed_query(
                    vcd_client.ResourceType.ADMIN_ORG_VDC.value,
                    query_result_format=vcd_client.QueryResultFormat.
                    RECORDS,  # noqa: E501
                    qfilter=qfilter)
                # should only ever be one element in the generator
                ovdc_records = list(q.execute())
                if len(ovdc_records) == 0:
                    raise vcd_e.EntityNotFoundException(
                        f"Org VDC {ovdc_name} not found in org {org_name}")
                ovdc_record = None
                for record in ovdc_records:
                    ovdc_record = pyvcd_utils.to_dict(
                        record,
                        resource_type=vcd_client.ResourceType.ADMIN_ORG_VDC.
                        value)  # noqa: E501
                    break

                vc_to_pks_plans_map = {}
                pks_contexts = pksbroker_manager.create_pks_context_for_all_accounts_in_org(
                    op_ctx)  # noqa: E501

                for pks_context in pks_contexts:
                    if pks_context['vc'] in vc_to_pks_plans_map:
                        continue
                    pks_broker = pksbroker.PksBroker(pks_context, op_ctx)
                    plans = pks_broker.list_plans()
                    plan_names = [plan.get('name') for plan in plans]
                    vc_to_pks_plans_map[pks_context['vc']] = \
                        [plan_names, pks_context['host']]

                pks_plan_and_server_info = vc_to_pks_plans_map.get(
                    ovdc_record['vcName'], [])
                if len(pks_plan_and_server_info) > 0:
                    pks_plans = pks_plan_and_server_info[0]
                    pks_server = pks_plan_and_server_info[1]

            ovdc_dict[PKSOvdcInfoKey.PKS_API_SERVER] = pks_server
            ovdc_dict[PKSOvdcInfoKey.AVAILABLE_PKS_PLANS] = pks_plans
        ovdcs.append(ovdc_dict)
    api_path = CseServerOperationInfo.PKS_ORG_VDC_LIST.api_path_format
    next_page_uri = vcd_utils.create_cse_page_uri(op_ctx.client,
                                                  api_path,
                                                  vcd_uri=next_page_uri)
    prev_page_uri = vcd_utils.create_cse_page_uri(op_ctx.client,
                                                  api_path,
                                                  vcd_uri=prev_page_uri)
    return server_utils.construct_paginated_response(
        values=ovdcs,
        result_total=result_total,
        page_number=page_number,
        page_size=page_size,
        next_page_uri=next_page_uri,  # noqa: E501
        prev_page_uri=prev_page_uri)  # noqa: E501
Ejemplo n.º 22
0
def _update_ovdc_using_placement_policy_async(
        operation_context: ctx.OperationContext,  # noqa: E501
        task: vcd_task.Task,
        task_href,
        user_href,
        policy_list,
        ovdc_id,
        vdc,
        org_name,
        remove_cp_from_vms_on_disable=False):  # noqa: E501
    """Enable ovdc using placement policies.

    :param ctx.OperationContext operation_context: operation context object
    :param vcd_task.Task task: Task resource to track progress
    :param str task_href: href of the task
    :param str user_href:
    :param List[str] policy_list: The new list of policies associated with
        the ovdc
    :param str ovdc_id:
    :param pyvcloud.vcd.vdc.VDC vdc: VDC object
    :param str org_name: name of the organization that vdc provides resource
    :param bool remove_cp_from_vms_on_disable: Set to true if placement
        policies need to be removed from the vms before removing from the VDC.
    """
    operation_name = "Update OVDC with placement policies"
    k8s_runtimes_added = ''
    k8s_runtimes_deleted = ''
    try:
        config = server_utils.get_server_runtime_config()
        log_wire = utils.str_to_bool(config.get('service', {}).get('log_wire'))
        cpm = compute_policy_manager.ComputePolicyManager(
            operation_context.sysadmin_client, log_wire=log_wire)
        existing_policies = []
        for cse_policy in \
                compute_policy_manager.list_cse_placement_policies_on_vdc(cpm, ovdc_id):  # noqa: E501
            existing_policies.append(cse_policy['display_name'])

        logger.SERVER_LOGGER.debug(policy_list)
        logger.SERVER_LOGGER.debug(existing_policies)
        policies_to_add = set(policy_list) - set(existing_policies)
        policies_to_delete = set(existing_policies) - set(policy_list)

        # Telemetry for 'vcd cse ovdc enable' command
        # TODO: Update telemetry request to handle 'k8s_runtime' array
        k8s_runtimes_added = ','.join(policies_to_add)
        if k8s_runtimes_added:
            cse_params = {
                RequestKey.K8S_PROVIDER:
                k8s_runtimes_added,
                RequestKey.OVDC_ID:
                ovdc_id,
                RequestKey.ORG_NAME:
                org_name,
                PayloadKey.SOURCE_DESCRIPTION:
                thread_local_data.get_thread_local_data(
                    ThreadLocalData.USER_AGENT)  # noqa: E501
            }
            telemetry_handler.record_user_action_details(
                cse_operation=CseOperation.OVDC_ENABLE,  # noqa: E501
                cse_params=cse_params)

        # Telemetry for 'vcd cse ovdc enable' command
        # TODO: Update telemetry request to handle 'k8s_runtime' array
        k8s_runtimes_deleted = '.'.join(policies_to_delete)
        if k8s_runtimes_deleted:
            cse_params = {
                RequestKey.K8S_PROVIDER:
                k8s_runtimes_deleted,
                RequestKey.OVDC_ID:
                ovdc_id,
                RequestKey.ORG_NAME:
                org_name,
                RequestKey.REMOVE_COMPUTE_POLICY_FROM_VMS:
                remove_cp_from_vms_on_disable,  # noqa: E501
                PayloadKey.SOURCE_DESCRIPTION:
                thread_local_data.get_thread_local_data(
                    ThreadLocalData.USER_AGENT)  # noqa: E501
            }
            telemetry_handler.record_user_action_details(
                cse_operation=CseOperation.OVDC_DISABLE,  # noqa: E501
                cse_params=cse_params)

        for cp_name in policies_to_add:
            msg = f"Adding k8s provider {cp_name} to OVDC {vdc.name}"
            logger.SERVER_LOGGER.debug(msg)
            task.update(status=vcd_client.TaskStatus.RUNNING.value,
                        namespace='vcloud.cse',
                        operation=msg,
                        operation_name=operation_name,
                        details='',
                        progress=None,
                        owner_href=vdc.href,
                        owner_name=vdc.name,
                        owner_type=vcd_client.EntityType.VDC.value,
                        user_href=user_href,
                        user_name=operation_context.user.name,
                        task_href=task_href,
                        org_href=operation_context.user.org_href)
            policy = compute_policy_manager.get_cse_vdc_compute_policy(
                cpm, cp_name, is_placement_policy=True)
            cpm.add_compute_policy_to_vdc(vdc_id=ovdc_id,
                                          compute_policy_href=policy['href'])

        for cp_name in policies_to_delete:
            msg = f"Removing k8s provider {RUNTIME_INTERNAL_NAME_TO_DISPLAY_NAME_MAP[cp_name]} from OVDC {ovdc_id}"  # noqa: E501
            logger.SERVER_LOGGER.debug(msg)
            task_resource = \
                task.update(status=vcd_client.TaskStatus.RUNNING.value,
                            namespace='vcloud.cse',
                            operation=msg,
                            operation_name=operation_name,
                            details='',
                            progress=None,
                            owner_href=vdc.href,
                            owner_name=vdc.name,
                            owner_type=vcd_client.EntityType.VDC.value,
                            user_href=user_href,
                            user_name=operation_context.user.name,
                            task_href=task_href,
                            org_href=operation_context.user.org_href)
            policy = compute_policy_manager.get_cse_vdc_compute_policy(
                cpm, cp_name, is_placement_policy=True)  # noqa: E501
            cpm.remove_compute_policy_from_vdc_sync(
                vdc=vdc,
                compute_policy_href=policy['href'],  # noqa: E501
                force=remove_cp_from_vms_on_disable,  # noqa: E501
                is_placement_policy=True,
                task_resource=task_resource)  # noqa: E501
        msg = f"Successfully updated OVDC: {vdc.name}"
        logger.SERVER_LOGGER.debug(msg)
        task.update(status=vcd_client.TaskStatus.SUCCESS.value,
                    namespace='vcloud.cse',
                    operation="Operation success",
                    operation_name=operation_name,
                    details=msg,
                    progress=None,
                    owner_href=vdc.href,
                    owner_name=vdc.name,
                    owner_type=vcd_client.EntityType.VDC.value,
                    user_href=user_href,
                    user_name=operation_context.user.name,
                    task_href=task_href,
                    org_href=operation_context.user.org_href)
        # Record telemetry
        if k8s_runtimes_added:
            telemetry_handler.record_user_action(
                CseOperation.OVDC_ENABLE,
                status=OperationStatus.SUCCESS)  # noqa: E501
        if k8s_runtimes_deleted:
            telemetry_handler.record_user_action(
                CseOperation.OVDC_DISABLE,
                status=OperationStatus.SUCCESS)  # noqa: E501
    except Exception as err:
        # Record telemetry
        if k8s_runtimes_added:
            telemetry_handler.record_user_action(CseOperation.OVDC_ENABLE,
                                                 status=OperationStatus.FAILED)
        if k8s_runtimes_deleted:
            telemetry_handler.record_user_action(CseOperation.OVDC_DISABLE,
                                                 status=OperationStatus.FAILED)
        logger.SERVER_LOGGER.error(err)
        task.update(status=vcd_client.TaskStatus.ERROR.value,
                    namespace='vcloud.cse',
                    operation='Failed to update OVDC',
                    operation_name=operation_name,
                    details=f'Failed with error: {err}',
                    progress=None,
                    owner_href=vdc.href,
                    owner_name=vdc.name,
                    owner_type=vcd_client.EntityType.VDC.value,
                    user_href=user_href,
                    user_name=operation_context.user.name,
                    task_href=task_href,
                    org_href=operation_context.user.org_href,
                    error_message=f"{err}")
    finally:
        if operation_context.sysadmin_client:
            operation_context.end()
def ovdc_update(request_data, op_ctx: ctx.OperationContext):
    """Request handler for ovdc enable, disable operations.

    Required data: org_name, ovdc_name, k8s_provider
    Conditional data:
        if k8s_provider is 'ent-pks': pks_plan_name, pks_cluster_domain

    :return: Dictionary with org VDC update task href.
    """
    # TODO the data flow here should be better understood.
    # org_name and ovdc_name seem redundant if we already have ovdc_id

    data = req_utils.flatten_request_data(
        request_data, [RequestKey.INPUT_SPEC])

    required = [
        RequestKey.ORG_NAME,
        RequestKey.OVDC_NAME,
        RequestKey.K8S_PROVIDER,
        RequestKey.OVDC_ID
    ]
    validated_data = data
    req_utils.validate_payload(validated_data, required)

    k8s_provider = validated_data[RequestKey.K8S_PROVIDER]
    k8s_provider_info = {K8S_PROVIDER_KEY: k8s_provider}

    # Record the telemetry data
    cse_params = copy.deepcopy(validated_data)
    cse_params[PayloadKey.SOURCE_DESCRIPTION] = thread_local_data.get_thread_local_data(ThreadLocalData.USER_AGENT)  # noqa: E501
    cse_operation = CseOperation.OVDC_DISABLE if k8s_provider == K8sProvider.NONE else CseOperation.OVDC_ENABLE  # noqa: E501
    record_user_action_details(cse_operation=cse_operation, cse_params=cse_params)  # noqa: E501

    sysadmin_client_v33 = \
        op_ctx.get_sysadmin_client(api_version=DEFAULT_API_VERSION)
    try:
        if k8s_provider == K8sProvider.PKS:
            if not server_utils.is_pks_enabled():
                raise e.CseServerError('CSE server is not '
                                       'configured to work with PKS.')
            required = [
                RequestKey.PKS_PLAN_NAME,
                RequestKey.PKS_CLUSTER_DOMAIN
            ]
            req_utils.validate_payload(validated_data, required)

            # Check if target ovdc is not already enabled for other non PKS k8 providers # noqa: E501
            ovdc_metadata = ovdc_utils.get_ovdc_k8s_provider_metadata(
                sysadmin_client_v33,
                ovdc_id=validated_data[RequestKey.OVDC_ID])
            ovdc_k8_provider = ovdc_metadata.get(K8S_PROVIDER_KEY)
            if ovdc_k8_provider != K8sProvider.NONE and \
                    ovdc_k8_provider != k8s_provider:
                raise e.CseServerError("Ovdc already enabled for different K8 provider")  # noqa: E501

            k8s_provider_info = ovdc_utils.construct_k8s_metadata_from_pks_cache(  # noqa: E501
                sysadmin_client_v33,
                ovdc_id=validated_data[RequestKey.OVDC_ID],
                org_name=validated_data[RequestKey.ORG_NAME],
                pks_plans=validated_data[RequestKey.PKS_PLAN_NAME],
                pks_cluster_domain=validated_data[RequestKey.PKS_CLUSTER_DOMAIN],  # noqa: E501
                k8s_provider=k8s_provider)
            ovdc_utils.create_pks_compute_profile(validated_data,
                                                  op_ctx,
                                                  k8s_provider_info)

        task = ovdc_utils.update_ovdc_k8s_provider_metadata(
            sysadmin_client_v33,
            validated_data[RequestKey.OVDC_ID],
            k8s_provider_data=k8s_provider_info,
            k8s_provider=k8s_provider)

        # Telemetry - Record successful enabling/disabling of ovdc
        record_user_action(cse_operation, status=OperationStatus.SUCCESS)

        return {'task_href': task.get('href')}
    except Exception as err:
        logger.SERVER_LOGGER.error(f"Error while updating OVDC: {str(err)}")
        # Telemetry - Record failed enabling/disabling of ovdc
        record_user_action(cse_operation, status=OperationStatus.FAILED)
        raise err
def ovdc_list(request_data, op_ctx: ctx.OperationContext):
    """Request handler for ovdc list operation.

    :return: List of dictionaries with org VDC k8s provider metadata.
    :rtype: list
    """
    # NOTE: response sent out by this handler should not be paginated

    data = req_utils.flatten_request_data(
        request_data, [RequestKey.QUERY_PARAMS])

    defaults = {
        RequestKey.LIST_PKS_PLANS: False,
    }
    validated_data = {**defaults, **data}

    list_pks_plans = utils.str_to_bool(validated_data[RequestKey.LIST_PKS_PLANS])  # noqa: E501

    # Record telemetry data
    cse_params = copy.deepcopy(validated_data)
    cse_params[RequestKey.LIST_PKS_PLANS] = list_pks_plans
    cse_params[PayloadKey.SOURCE_DESCRIPTION] = thread_local_data.get_thread_local_data(ThreadLocalData.USER_AGENT)  # noqa: E501
    record_user_action_details(cse_operation=CseOperation.OVDC_LIST,
                               cse_params=cse_params)

    client_v33 = op_ctx.get_client(api_version=DEFAULT_API_VERSION)
    if list_pks_plans and not client_v33.is_sysadmin():
        raise e.UnauthorizedRequestError(
            'Operation denied. Enterprise PKS plans visible only '
            'to System Administrators.')

    ovdcs = []
    org_vdcs = vcd_utils.get_all_ovdcs(client_v33)
    sysadmin_client_v33 = \
        op_ctx.get_sysadmin_client(api_version=DEFAULT_API_VERSION)
    for ovdc in org_vdcs:
        ovdc_name = ovdc.get('name')
        org_name = ovdc.get('orgName')
        ovdc_id = vcd_utils.extract_id(ovdc.get('id'))
        k8s_metadata = ovdc_utils.get_ovdc_k8s_provider_metadata(
            sysadmin_client_v33,
            ovdc_id=ovdc_id,
            ovdc_name=ovdc_name,
            org_name=org_name)
        k8s_provider = k8s_metadata[K8S_PROVIDER_KEY]
        ovdc_dict = {
            OvdcInfoKey.OVDC_NAME: ovdc_name,
            OvdcInfoKey.ORG_NAME: org_name,
            OvdcInfoKey.K8S_PROVIDER: k8s_provider
        }
        if list_pks_plans:
            pks_plans = ''
            pks_server = ''
            if k8s_provider == K8sProvider.PKS:
                # vc name for vdc can only be found using typed query
                qfilter = f"name=={urllib.parse.quote(ovdc_name)};" \
                          f"orgName=={urllib.parse.quote(org_name)}"
                q = client_v33.get_typed_query(
                    vcd_client.ResourceType.ADMIN_ORG_VDC.value,
                    query_result_format=vcd_client.QueryResultFormat.RECORDS,  # noqa: E501
                    qfilter=qfilter)
                # should only ever be one element in the generator
                ovdc_records = list(q.execute())
                if len(ovdc_records) == 0:
                    raise vcd_e.EntityNotFoundException(
                        f"Org VDC {ovdc_name} not found in org {org_name}")
                ovdc_record = None
                for record in ovdc_records:
                    ovdc_record = pyvcd_utils.to_dict(
                        record, resource_type=vcd_client.ResourceType.ADMIN_ORG_VDC.value)  # noqa: E501
                    break

                vc_to_pks_plans_map = {}
                pks_contexts = pksbroker_manager.create_pks_context_for_all_accounts_in_org(op_ctx)  # noqa: E501

                for pks_context in pks_contexts:
                    if pks_context['vc'] in vc_to_pks_plans_map:
                        continue
                    pks_broker = pksbroker.PksBroker(pks_context, op_ctx)
                    plans = pks_broker.list_plans()
                    plan_names = [plan.get('name') for plan in plans]
                    vc_to_pks_plans_map[pks_context['vc']] = \
                        [plan_names, pks_context['host']]

                pks_plan_and_server_info = vc_to_pks_plans_map.get(
                    ovdc_record['vcName'], [])
                if len(pks_plan_and_server_info) > 0:
                    pks_plans = pks_plan_and_server_info[0]
                    pks_server = pks_plan_and_server_info[1]

            ovdc_dict[PKSOvdcInfoKey.PKS_API_SERVER] = pks_server
            ovdc_dict[PKSOvdcInfoKey.AVAILABLE_PKS_PLANS] = pks_plans
        ovdcs.append(ovdc_dict)
    return ovdcs