def last_binding_operation(self, instance_id: str, binding_id: str, operation_data: Optional[str], **kwargs) -> LastOperation: instance = self.service_instances.get(instance_id, {}) if instance.get('state') == self.BINDING: instance['state'] = self.BOUND return LastOperation(OperationState.SUCCEEDED) elif instance.get('state') == self.UNBINDING: instance['state'] = self.CREATED return LastOperation(OperationState.SUCCEEDED)
def last_operation(self, instance_id: str, operation_data: Optional[str], **kwargs) -> LastOperation: """ Further readings `CF Broker API#LastOperation <https://docs.cloudfoundry.org/services/api.html#polling>`_ :param instance_id: Instance id provided by the platform :param operation_data: Operation data received from async operation :param kwargs: May contain additional information, improves compatibility with upstream versions :rtype: LastOperation """ instance = ServiceInstance.query.get(instance_id) if not instance: raise errors.ErrInstanceDoesNotExist if not operation_data: raise errors.ErrBadRequest(msg="Missing operation ID") operation = instance.operations.filter_by( id=int(operation_data)).first() if not operation: raise errors.ErrBadRequest( msg= f"Invalid operation id {operation_data} for service {instance_id}" ) return LastOperation( state=Operation.States(operation.state), description=operation.step_description, )
def catalog(self) -> Service: # We should add the ability to inject the service plans # this is where cluster admins can create the various t-shirt # sizes to support for MongoDB print("loaded service providers\n".join("{}\t{}".format(k, v) for k, v in self.service_providers.items())) plans = [] tags = ['MongoDB', 'Database' ] for provider_name in self.service_providers.keys(): print("loading plans for provider: %s" % provider_name) provider = self.service_providers[provider_name] provider_plans = provider.plans() for plan in provider_plans: self.service_plans[plan.id]= { 'provider_name' : provider_name, 'plans' : provider_plans } plans.extend( provider_plans ) tags.extend( provider.tags() ) # Omitting this, needs nested v2.DashboardClient type # dashboard_client='http://mongodb-open-service-broker:8080', catalog = Service( id='mongodb-open-service-broker', name='mongodb-open-service-broker-service', description='This service creates and provides your applications access to MongoDB services.', bindable=True, plans=plans, tags=list(set(tags)), plan_updateable=False, ) self.__last_op = LastOperation("catalog", catalog ) self.__catalog = catalog return catalog
def test_routes_last_operation(self): instance_id = str(uuid4()) operation_str = str(uuid4()) self.b1.last_operation.return_value = LastOperation(state=OperationState.IN_PROGRESS) _ = self.router.last_operation(instance_id, 's1 ' + operation_str) self.b1.last_operation.assert_called_with(instance_id, operation_str)
def last_operation(self, instance_id: str, operation_data: str) -> LastOperation: logger.info("last_opertation") if not instance_id in self.provisioned_services: raise errors.ErrInstanceDoesNotExist() spec = self.provisioned_services[instance_id]["spec"] op = self.provisioned_services[instance_id]["last_op"] lo = LastOperation(op, spec) return lo
def test_last_operation_called_just_with_required_fields(self): self.broker.last_binding_operation.return_value = LastOperation(OperationState.IN_PROGRESS, 'Running...') self.client.get( '/v2/service_instances/here-instance_id/service_bindings/binding_id/last_operation', headers={ 'X-Broker-Api-Version': '2.13', 'Authorization': self.auth_header }) self.broker.last_binding_operation.assert_called_once_with('here-instance_id', 'binding_id', None)
def provision(self, instance_id: str, service_details: ProvisionDetails, async_allowed: bool) -> ProvisionedServiceSpec: logger.info("provision") provider_name = self.service_plans[service_details.plan_id]['provider_name'] provider = self.service_providers[provider_name] logger.info("provider_name=%s, provider=%s" % ( provider_name, provider) ) self.provisioned_services[instance_id]={ "provider" : provider, "plan_id" : service_details.plan_id, "spec" : None, "last_op" : LastOperation("provision","Started") } logger.info("request to provision plan_id=%s" % service_details.plan_id) spec = provider.provision(instance_id, service_details, async_allowed) self.provisioned_services[instance_id]={ "provider" : provider, "plan_id" : service_details.plan_id, "spec" : spec, "last_op" : LastOperation("provision",spec) } return spec
def last_operation(self, instance_id: str, operation_data: Optional[str], **kwargs) -> LastOperation: instance = self.service_instances.get(instance_id) if instance is None: raise errors.ErrInstanceDoesNotExist() if instance.get('state') == self.CREATING: instance['state'] = self.CREATED return LastOperation(OperationState.SUCCEEDED) elif instance.get('state') == self.DELETING: del self.service_instances[instance_id] raise errors.ErrInstanceDoesNotExist()
def test_returns_400_on_invalid_request(self): self.broker.last_operation.return_value = LastOperation( OperationState.IN_PROGRESS, "Running...") query = "service_id=123&plan_id=456&operation=somethingwrong" response = self.client.get( "/v2/service_instances/here-instance_id/last_operation?%s" % query, headers={ 'X-Broker-Api-Version': '2.13', 'Authorization': self.auth_header }) self.assertEqual(response.status_code, http.HTTPStatus.BAD_REQUEST)
def test_last_operation_called_with_operation_data(self): self.broker.last_binding_operation.return_value = LastOperation(OperationState.IN_PROGRESS, 'Running...') query = 'service_id=&plan_id=456&operation=service-guid-here%20operation-data' self.client.get( '/v2/service_instances/here-instance_id/service_bindings/binding_id/last_operation?%s' % query, headers={ 'X-Broker-Api-Version': '2.13', 'Authorization': self.auth_header }) self.broker.last_binding_operation.assert_called_once_with('here-instance_id', 'binding_id', 'service-guid-here operation-data')
def test_last_operation_called_with_the_right_values(self): self.broker.last_operation.return_value = LastOperation( OperationState.IN_PROGRESS, "Running...") query = "service_id=&plan_id=456&operation=service-guid-here%20operation-data" self.client.get( "/v2/service_instances/here-instance_id/last_operation?%s" % query, headers={ 'X-Broker-Api-Version': '2.13', 'Authorization': self.auth_header }) self.broker.last_operation.assert_called_once_with( "here-instance_id", "service-guid-here operation-data")
def test_last_operation_called_just_with_required_fields(self): self.broker.last_operation.return_value = LastOperation( OperationState.IN_PROGRESS, "Running...") query = "operation=service-guid-here" self.client.get( "/v2/service_instances/here-instance_id/last_operation?%s" % query, headers={ 'X-Broker-Api-Version': '2.13', 'Authorization': self.auth_header }) self.broker.last_operation.assert_called_once_with( "here-instance_id", None)
def test_returns_200_with_given_state(self): self.broker.last_binding_operation.return_value = LastOperation(OperationState.IN_PROGRESS, 'Running...') query = 'service_id=123&plan_id=456&operation=service-guid-here%20operation-data' response = self.client.get( '/v2/service_instances/here-instance_id/service_bindings/binding_id/last_operation?%s' % query, headers={ 'X-Broker-Api-Version': '2.13', 'Authorization': self.auth_header }) self.assertEqual(response.status_code, http.HTTPStatus.OK) self.assertEqual(response.json, dict( state=OperationState.IN_PROGRESS.value, description='Running...' ))
def catalog(self) -> Service: self.logger.debug("loaded service providers\n".join( "{}\t{}".format(k, v) for k, v in self.service_providers.items())) plans = [] tags = ['MongoDB', 'Database'] for provider_name in self.service_providers.keys(): self.logger.debug("loading plans for provider: %s" % provider_name) provider = self.service_providers[provider_name] self.logger.debug(f'{provider}') provider_plans = provider.plans() for plan in provider_plans: self.logger.debug(f'plan={plan}') self.service_plans[plan.id] = { 'provider_name': provider_name, 'plans': provider_plans } plans.extend(provider_plans) tags.extend(provider.tags()) # Omitting this, needs nested v2.DashboardClient type # dashboard_client='http://mongodb-open-service-broker:8080', catalog = Service( id='mongodb-open-service-broker', name='mongodb-open-service-broker-service', description= 'The MongoDB Enterprise Open Service Broker. https://mongodb.com/osb', bindable=True, plans=plans, tags=list(set(tags)), plan_updateable=False, ) self.__last_op = LastOperation("catalog", catalog) self.__catalog = catalog return catalog