def ovdc_compute_policy_update(request_data, tenant_auth_token): """Request handler for ovdc compute-policy update operation. Required data: ovdc_id, compute_policy_action, compute_policy_names :return: Dictionary with task href. """ required = [ RequestKey.OVDC_ID, RequestKey.COMPUTE_POLICY_ACTION, RequestKey.COMPUTE_POLICY_NAME ] req_utils.validate_payload(request_data, required) defaults = { RequestKey.REMOVE_COMPUTE_POLICY_FROM_VMS: False, } validated_data = {**defaults, **request_data} req_utils.validate_payload(request_data, required) action = validated_data[RequestKey.COMPUTE_POLICY_ACTION] cp_name = validated_data[RequestKey.COMPUTE_POLICY_NAME] ovdc_id = validated_data[RequestKey.OVDC_ID] remove_compute_policy_from_vms = validated_data[ RequestKey.REMOVE_COMPUTE_POLICY_FROM_VMS] # noqa: E501 client, _ = vcd_utils.connect_vcd_user_via_token(tenant_auth_token) cpm = ComputePolicyManager(client) cp_href = None cp_id = None if cp_name == SYSTEM_DEFAULT_COMPUTE_POLICY_NAME: for _cp in cpm.list_compute_policies_on_vdc(ovdc_id): if _cp['name'] == cp_name: cp_href = _cp['href'] cp_id = _cp['id'] else: try: _cp = cpm.get_policy(cp_name) cp_href = _cp['href'] cp_id = _cp['id'] except EntityNotFoundException: pass if cp_href is None: raise BadRequestError(f"Compute policy '{cp_name}' not found.") if action == ComputePolicyAction.ADD: cpm.add_compute_policy_to_vdc(ovdc_id, cp_href) return f"Added compute policy '{cp_name}' ({cp_id}) to ovdc " \ f"({ovdc_id})" if action == ComputePolicyAction.REMOVE: return cpm.remove_compute_policy_from_vdc( ovdc_id, cp_href, remove_compute_policy_from_vms=remove_compute_policy_from_vms) raise BadRequestError("Unsupported compute policy action")
def update_status(self, tenant_auth_token, is_jwt_token, request_data): tenant_client = connect_vcd_user_via_token( tenant_auth_token=tenant_auth_token, is_jwt_token=is_jwt_token) if not tenant_client.is_sysadmin(): raise UnauthorizedRequestError( error_message='Unauthorized to update CSE') action = request_data.get(RequestKey.SERVER_ACTION) if self._state == ServerState.RUNNING: if action == ServerAction.ENABLE: raise BadRequestError( error_message='CSE is already enabled and running.') elif action == ServerAction.DISABLE: self._state = ServerState.DISABLED message = 'CSE has been disabled.' elif action == ServerAction.STOP: raise BadRequestError( error_message='Cannot stop CSE while it is enabled. ' 'Disable the service first') elif self._state == ServerState.DISABLED: if action == ServerAction.ENABLE: self._state = ServerState.RUNNING message = 'CSE has been enabled and is running.' elif action == ServerAction.DISABLE: raise BadRequestError( error_message='CSE is already disabled.') elif action == 'stop': message = 'CSE graceful shutdown started.' n = self.active_requests_count() if n > 0: message += f" CSE will finish processing {n} requests." self._state = ServerState.STOPPING elif self._state == ServerState.STOPPING: if action == ServerAction.ENABLE: raise BadRequestError( error_message='Cannot enable CSE while it is being' 'stopped.') elif action == ServerAction.DISABLE: raise BadRequestError( error_message='Cannot disable CSE while it is being' ' stopped.') elif action == ServerAction.STOP: message = 'CSE graceful shutdown is in progress.' return message
def process_request(body): from container_service_extension.service import Service LOGGER.debug(f"body: {json.dumps(body)}") url = body['requestUri'] # url_data = _parse_request_url(method=body['method'], url=body['requestUri']) # noqa: E501 url_data = _get_url_data(body['method'], url) operation = url_data[_OPERATION_KEY] # check if server is disabled if operation not in (CseOperation.SYSTEM_INFO, CseOperation.SYSTEM_UPDATE)\ and not Service().is_running(): raise BadRequestError(error_message='CSE service is disabled. Contact' ' the System Administrator.') # create request data dict from request body data request_data = {} if len(body['body']) > 0: raw_body = base64.b64decode(body['body']).decode( sys.getfilesystemencoding()) # noqa: E501 request_data = json.loads(raw_body) LOGGER.debug(f"request body: {request_data}") # update request data dict with query params data if body['queryString']: query_params = dict(parse_qsl(body['queryString'])) request_data.update(query_params) LOGGER.debug(f"query parameters: {query_params}") # update request spec with operation specific data in the url request_data.update(url_data) # remove None values from request payload data = {k: v for k, v in request_data.items() if v is not None} # extract out the authorization token tenant_auth_token = body['headers'].get('x-vcloud-authorization') is_jwt_token = False auth_header = body['headers'].get('Authorization') if auth_header: tokens = auth_header.split(" ") if len(tokens) == 2 and tokens[0].lower() == 'bearer': tenant_auth_token = tokens[1] is_jwt_token = True # process the request body_content = \ OPERATION_TO_HANDLER[operation](data, tenant_auth_token, is_jwt_token) if not (isinstance(body_content, (list, dict))): body_content = {RESPONSE_MESSAGE_KEY: str(body_content)} reply = { 'status_code': operation.ideal_response_code, 'body': body_content } LOGGER.debug(f"reply: {str(reply)}") return reply
def cluster_upgrade(request_data, tenant_auth_token, is_jwt_token): """Request handler for cluster upgrade operation. data validation handled in broker :return: Dict """ _, broker = broker_manager.get_cluster_info(request_data, tenant_auth_token, is_jwt_token) if isinstance(broker, vcdbroker.VcdBroker): return broker.upgrade_cluster(request_data) raise BadRequestError( error_message="'cluster upgrade' operation is not supported by non " "native clusters.")
def cluster_upgrade_plan(request_data, tenant_auth_token, is_jwt_token): """Request handler for cluster upgrade-plan operation. data validation handled in broker :return: List[Tuple(str, str)] """ _, broker = broker_manager.get_cluster_info(request_data, tenant_auth_token, is_jwt_token) if isinstance(broker, vcdbroker.VcdBroker): return broker.get_cluster_upgrade_plan(request_data) raise BadRequestError( error_message="'cluster upgrade-plan' operation is not supported by " "non native clusters.")
def node_delete(request_data, tenant_auth_token, is_jwt_token): """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 brokers) :return: Dict """ _, broker = broker_manager.get_cluster_info(request_data, tenant_auth_token, is_jwt_token) if isinstance(broker, vcdbroker.VcdBroker): return broker.delete_nodes(request_data) raise BadRequestError( error_message="'node delete' operation is not supported by non native " "clusters.")
def validate_payload(payload, required_keys): """Validate a given payload is good for a particular request. Raise appropriate error if keys are missing or if the corresponding value in the payload is None. Otherwise return True. :param dict payload: :param list required_keys: :return: True, if payload is valid :rtype: bool """ valid = True minor_error_code = None required = set(required_keys) if not required.issubset(payload.keys()): missing_keys = list(required.difference(payload.keys())) error_message = \ f"Missing required keys in request payload: {missing_keys}" valid = False key = RequestKey(missing_keys[0]) if key in MISSING_KEY_TO_MINOR_ERROR_CODE_MAPPING: minor_error_code = MISSING_KEY_TO_MINOR_ERROR_CODE_MAPPING[key] else: keys_with_none_value = [ k for k, v in payload.items() if k in required and v is None ] # noqa: E501 if len(keys_with_none_value) > 0: error_message = f"Following keys in request payloads have None as value: {keys_with_none_value}" # noqa: E501 valid = False key = RequestKey(keys_with_none_value[0]) if key in INVALID_VALUE_TO_MINOR_ERROR_CODE_MAPPING: minor_error_code = INVALID_VALUE_TO_MINOR_ERROR_CODE_MAPPING[ key] # noqa: E501 if not valid: raise BadRequestError(error_message, minor_error_code) return valid
def validate_request_payload(input_spec: dict, reference_spec: dict, exclude_fields=[]): """Validate the desired spec with the current spec. :param dict input_spec: input spec :param dict reference_spec: reference spec to validate the desired spec :param list exclude_fields: exclude the list of given flattened-keys from validation # noqa: E501 :return: true on successful validation :rtype: bool :raises: BadRequestError on encountering invalid payload value """ input_dict = utils.flatten_dictionary(input_spec) reference_dict = utils.flatten_dictionary(reference_spec) exclude_key_set = set(exclude_fields) key_set_for_validation = set(input_dict.keys()) - exclude_key_set keys_with_invalid_value = [key for key in key_set_for_validation if input_dict.get(key) != reference_dict.get(key)] # noqa: E501 if len(keys_with_invalid_value) > 0: error_msg = f"Invalid input values found in {sorted(keys_with_invalid_value)}" # noqa: E501 raise BadRequestError(error_msg) return True
def node_create(request_data, tenant_auth_token, is_jwt_token): """Request handler for node create operation. Required data: cluster_name, network_name Optional data and default values: org_name=None, ovdc_name=None, num_nodes=1, num_cpu=None, mb_memory=None, storage_profile_name=None, template_name=default, template_revision=default, ssh_key=None, rollback=True, enable_nfs=False, (data validation handled in brokers) :return: Dict """ # Currently node create is a vCD only operation. # Different from resize because this can create nfs nodes _, broker = broker_manager.get_cluster_info(request_data, tenant_auth_token, is_jwt_token) if isinstance(broker, vcdbroker.VcdBroker): return broker.create_nodes(request_data) raise BadRequestError( error_message="'node create' operation is not supported by non native " "clusters.")