def _get_instance(srv_inst):
    # get the latest info
    mani_id = srv_inst.context['manifest_id']
    mani = STORE.get_manifest(manifest_id=mani_id)
    if len(mani) < 1:
        return 'no manifest found.', 404
    # Get the latest info of the instance
    # could also use STORE.get_service_instance(srv_inst) but will not have all details
    inst_info = RM.info(instance_id=srv_inst.context['id'], manifest_type=mani[0].manifest_type)

    if inst_info['srv_inst.state.state'] == 'failed':
        # try epm.delete(instance_id=instance_id)?
        return 'There has been a failure in creating the service instance.', 500

    srv_inst.state.state = inst_info['srv_inst.state.state']
    srv_inst.state.description = inst_info['srv_inst.state.description']

    # don't need you any more, buh-bye!
    del inst_info['srv_inst.state.state']
    del inst_info['srv_inst.state.description']

    # merge the two context dicts
    srv_inst.context = {**srv_inst.context, **inst_info}

    # update the service instance record - there should be an asynch method doing the update - event based
    STORE.add_service_instance(srv_inst)

    return srv_inst
예제 #2
0
def store_manifest(manifest_id, manifest):
    """
    takes deployment description of a software service and associates with a service and plan
    takes deployment description of a software service and associates with a service and plan that is already
    registered in the service catalog.
    :param manifest_id: The manifest_id of a manifest to be associated with a plan of a servicetype.
    :type manifest_id: str
    :param manifest: the manifest to store
    :type manifest: dict | bytes

    :rtype: ServiceResponse
    """
    ok, message, code = _version_ok()
    if not ok:
        return message, code
    else:
        if connexion.request.is_json:
            manifest = Manifest.from_dict(connexion.request.get_json())
        else:
            return "Supplied body content is not or is mal-formed JSON", 400
        if manifest.manifest_content.find(
                '</br>') > 0:  # TODO(dizz) remove this check in R4
            return "Manifest content contains '</br>'. Please remove these and replace with '\n'", 400
        manifest.id = manifest_id

        result, code = STORE.add_manifest(manifest)

        if code == 200:
            return Empty(), code
        else:
            return result, code
    def test_create_service_instance(self):
        """
        Test case for create_service_instance

        Provisions a service instance
        """
        self._assert200(self.response)
        self.assertEquals(len(STORE.get_service_instance()), 1)
예제 #4
0
def list_manifests():
    """
    returns a list of manifests registered at with the ESM
    hi!

    :rtype: List[Manifest]
    """
    manifests = STORE.get_manifest()
    return manifests, 200
def delete_service_type(service_id):  # noqa: E501
    """Deletes a registered service type

    Deletes a service that is already registered with the service manager.
    It does not delete the manifest or plan associated with the service type.  # noqa: E501

    :param service_id: service ID to be deleted
    :type service_id: str

    :rtype: Empty
    """
    srv = STORE.get_service(service_id)
    # expectation: if not found, srv is None
    if srv:
        STORE.delete_service(service_id)
        return Empty()
    else:
        return "Service type not found", 404
예제 #6
0
    def health_check():
        db_engines_ok = STORE.is_ok()  # calls specific DB check
        resource_engine_ok = RM.is_ok()  # calls specific RM check
        this_ok = (1 + 1 == 2)  # basic local check
        # maintenance = False

        if this_ok and db_engines_ok and resource_engine_ok:
            return {'status', 'up'}
        # elif not maintenance:
        #     return {'status', 'out_of_service'}
        else:
            return {'status', 'down'}
예제 #7
0
def register_service(service):
    """
    Registers the service with the catalog.
    \&quot;Service providers need a means to register their service with a service broker. This provides this
    functionality. Also using PUT a service provider can update their registration. Note that this requires the
    complete content and will REPLACE the existing service information registered with the broker.\&quot;
    :param service: the service description to register
    :type service: dict | bytes

    :rtype: Empty
    """
    ok, message, code = _version_ok()
    if not ok:
        return message, code
    else:
        if connexion.request.is_json:
            service = ServiceType.from_dict(connexion.request.get_json())
        else:
            return "Supplied body content is not or is mal-formed JSON", 400
        STORE.add_service(service=service)
        return Empty()
def deprovision_service_instance(instance_id, service_id, plan_id, accept_incomplete=None):
    """
    Deprovisions a service instance.
    &#39;When a broker receives a deprovision request from a client, it should delete any resources it
    created during the provision. Usually this means that all resources are immediately reclaimed for
    future provisions.&#39;
    :param instance_id: &#39;The instance_id of a service instance is provided by the client. This ID will be used
    for future requests (bind and deprovision), so the broker must use it to correlate the resource it creates.&#39;
    :type instance_id: str
    :param service_id: service ID to be deprovisioned
    :type service_id: str
    :param plan_id: plan ID of the service to be deprovisioned
    :type plan_id: str
    :param accept_incomplete: Indicates that the client is supporting asynchronous operations
    :type accept_incomplete: bool

    :rtype: UpdateOperationResponse
    """
    ok, message, code = _version_ok()
    if not ok:
        return message, code
    else:
        # XXX if there's bindings remove first?
        # XXX what about undo?
        # check that the instance exists first
        instance = STORE.get_service_instance(instance_id=instance_id)
        if len(instance) == 1:
            mani_id = instance[0].context['manifest_id']
            mani = STORE.get_manifest(manifest_id=mani_id)
            if len(mani) < 1:
                return 'no service manifest found.', 404

            RM.delete(instance_id=instance_id, manifest_type=mani[0].manifest_type)
            STORE.delete_service_instance(instance_id)
            # we don't delete the last_operation explicitly as its embedded in the service_instance document
            # STORE.delete_last_operation(instance_id)

            return Empty(), 200
        else:
            return Empty(), 404
예제 #9
0
def get_manifest(manifest_id):
    """
    returns a specific of manifest registered at with the ESM
    hi!
    :param manifest_id: The manifest_id of a manifest to be associated with a plan of a servicetype.
    :type manifest_id: str

    :rtype: Manifest
    """

    manifest = STORE.get_manifest(manifest_id)

    if len(manifest) > 0:
        return manifest, 200
    else:
        return 'Manifest {id} could not be found'.format(id=manifest_id), 404
def all_instance_info():
    """
    Returns information about the service instance.
    Returns all service instances that are accessible to the end-user on this service manager.

    :rtype: List[ServiceInstance]
    """
    ok, message, code = _version_ok()
    if not ok:
        return message, code
    else:
        instances = STORE.get_service_instance()
        insts = list()
        for inst in instances:
            insts.append(_get_instance(inst))

        return insts, 200
예제 #11
0
def catalog():
    """
    Gets services registered within the broker
    \&quot;The first endpoint that a broker must implement is the service catalog. The client will initially fetch
    this endpoint from all brokers and make adjustments to the user-facing service catalog stored in the a
    client database. \\n\&quot;

    :rtype: Catalog
    """
    # get all services from the service collection

    ok, message, code = _version_ok()

    if not ok:
        return message, code
    else:
        services = STORE.get_service()
        return Catalog(services=services), 200
def instance_info(instance_id):
    """
    Returns information about the service instance.
    Returns information about the service instance. This is a simple read operation against the broker database and
    is provided as a developer/consumer convienence.
    :param instance_id: &#39;The instance_id of a service instance is provided by the client. This ID will be used
    for future requests (bind and deprovision), so the broker must use it to correlate the resource it creates.&#39;
    :type instance_id: str

    :rtype: ServiceInstance
    """
    ok, message, code = _version_ok()
    if not ok:
        return message, code
    else:
        # service instance should already be recorded
        srv_inst = STORE.get_service_instance(instance_id)
        if len(srv_inst) < 1:
            return 'no service instance found.', 404
        srv_inst = srv_inst[0]

        srv_inst = _get_instance(srv_inst)

        return srv_inst, 200
    def setUp(self):
        super().setUp()
        sql_host = os.environ.get('ESM_SQL_HOST',
                                  os.environ.get('ET_EDM_MYSQL_HOST', ''))
        if sql_host:
            STORE.set_up()

        self.store = STORE
        if len(self.store.get_service_instance()) > 0:
            raise Exception(
                'This shouldnt happen - the store should be empty on each run!'
            )

        self.instance_id = 'this_is_a_test_instance'
        self.binding_id = 'this_is_a_test_instance_binding'

        self.test_plan = Plan(id='testplan',
                              name='testing plan',
                              description='plan for testing',
                              metadata=None,
                              free=True,
                              bindable=False)

        self.test_service = ServiceType(id='test-svc',
                                        name='test_svc',
                                        description='this is a test service',
                                        bindable=True,
                                        tags=['test', 'tester'],
                                        metadata=None,
                                        requires=[],
                                        plan_updateable=False,
                                        plans=[self.test_plan],
                                        dashboard_client=None)

        self.store.add_service(self.test_service)
        print('Service registration content of:\n {content}'.format(
            content=json.dumps(self.test_service)))

        path = os.path.dirname(
            os.path.abspath(inspect.getfile(inspect.currentframe())))
        with open(path + MANIFEST, "r") as mani_file:
            mani = mani_file.read()

        with open(path + '/manifests/test_endpoints.json', 'r') as ep_file:
            ep = ep_file.read()

        if os.getenv('DOCKER_TESTS', 'NO') == 'YES':
            m_type = 'docker-compose'
        else:
            m_type = 'dummy'

        self.test_manifest = Manifest(id='test-mani',
                                      plan_id=self.test_plan.id,
                                      service_id=self.test_service.id,
                                      manifest_type=m_type,
                                      manifest_content=mani,
                                      endpoints=json.loads(ep))
        self.store.add_manifest(self.test_manifest)
        print('Manifest registration content of:\n {content}'.format(
            content=json.dumps(self.test_manifest)))

        self.response = self._send_service_request()
        self._assert200(self.response)
def create_service_instance(instance_id, service, accept_incomplete=None):
    """
    Provisions a service instance
    When the broker receives a provision request from a client, it should synchronously take whatever action is
    necessary to create a new service resource for the developer. The result of provisioning varies by service
    type, although there are a few common actions that work for many services. Supports asynchronous operations.&#39;
    :param instance_id: &#39;The instance_id of a service instance is provided by the client. This ID will be used for
    future requests (bind and deprovision), so the broker must use it to correlate the resource it creates.&#39;
    :type instance_id: str
    :param service: Service information.
    :type service: dict | bytes
    :param accept_incomplete: Indicates that the client is supporting asynchronous operations
    :type accept_incomplete: bool

    :rtype: ServiceResponse
    """
    ok, message, code = _version_ok()
    if not ok:
        return message, code
    else:
        if len(STORE.get_service_instance(instance_id=instance_id)) == 1:
            return 'Service instance with id {id} already exists'.format(id=instance_id), 409

        if connexion.request.is_json:
            service = ServiceRequest.from_dict(connexion.request.get_json())
        else:
            return "Supplied body content is not or is mal-formed JSON", 400

        # look up manifest based on plan id
        # based on the manifest type, select the driver
        # send the manifest for creation to the target system
        # store the ID along with refs to service, plan and manifest

        # get the manifest for the service/plan
        svc_type = STORE.get_service(service.service_id)[0]
        if svc_type is None:
            return 'Unrecognised service requested to be instantiated', 404

        plans = svc_type.plans
        plan = [p for p in plans if p.id == service.plan_id]
        if len(plan) <= 0:
            return 'Plan {p_id} found.'.format(p_id=service.plan_id), 404

        mani = STORE.get_manifest(plan_id=plan[0].id)
        if len(mani) <= 0:
            return 'no manifest for service {plan} found.'.format(plan=service.plan_id), 404
        mani = mani[0]

        if accept_incomplete:  # given docker-compose runs in detached mode this is not needed - only timing can verify
            # XXX put this in a thread to allow for asynch processing?
            RM.create(instance_id=instance_id, content=mani.manifest_content,
                      c_type=mani.manifest_type, parameters=service.parameters)
        else:
            RM.create(instance_id=instance_id, content=mani.manifest_content,
                      c_type=mani.manifest_type, parameters=service.parameters)

        last_op = LastOperation(  # stored within the service instance doc
            state='creating',
            description='service instance is being created'
        )

        # store the instance Id with manifest id
        srv_inst = ServiceInstance(
            service_type=svc_type,
            state=last_op,
            context={
                'id': instance_id,
                'manifest_id': mani.id,
            }
        )

        STORE.add_service_instance(srv_inst)

        if accept_incomplete:
            STORE.add_last_operation(instance_id=instance_id, last_operation=last_op)

        return 'created', 200