示例#1
0
    def create(self, project_id, auth_token, service_json):
        """create.

        :param project_id
        :param service_obj
        :raises LookupError, ValueError
        """
        try:
            flavor = self.flavor_controller.get(service_json.get('flavor_id'))
        # raise a lookup error if the flavor is not found
        except LookupError as e:
            raise e

        # add any default rules so its explicitly defined
        self._append_defaults(service_json)

        # convert to an object
        service_obj = service.Service.init_from_dict(service_json)
        service_id = service_obj.service_id

        # validate the service
        service_json = service_obj.to_dict()
        schema = service_schema.ServiceSchema.get_schema("service", "POST")
        validators.is_valid_service_configuration(service_json, schema)

        # deal with shared ssl domains
        for domain in service_obj.domains:
            if domain.protocol == 'https' and domain.certificate == 'shared':
                domain.domain = self._generate_shared_ssl_domain(
                    domain.domain
                )

        try:
            self.storage_controller.create(
                project_id,
                service_obj)
        # ValueError will be raised if the service has already existed
        except ValueError as e:
            raise e

        providers = [p.provider_id for p in flavor.providers]
        kwargs = {
            'providers_list_json': json.dumps(providers),
            'project_id': project_id,
            'auth_token': auth_token,
            'service_id': service_id,
            'time_seconds': self.determine_sleep_times()
        }

        self.distributed_task_controller.submit_task(
            create_service.create_service, **kwargs)

        return service_obj
示例#2
0
    def update(self, project_id, service_id, auth_token, service_updates):
        """update.

        :param project_id
        :param service_id
        :param service_updates
        :raises LookupError, ValueError
        """
        # get the current service object
        try:
            service_old = self.storage_controller.get(project_id, service_id)
        except ValueError:
            raise errors.ServiceNotFound("Service not found")

        if service_old.operator_status == u'disabled':
            raise errors.ServiceStatusDisabled(
                u'Service {0} is disabled'.format(service_id))

        if service_old.status not in [u'deployed', u'failed']:
            raise errors.ServiceStatusNeitherDeployedNorFailed(
                u'Service {0} neither deployed nor failed'.format(service_id))

        # Fixing the operator_url domain for ssl
        # for schema validation
        existing_shared_domains = {}
        for domain in service_old.domains:
            if domain.protocol == 'https' and domain.certificate == 'shared':
                customer_domain = domain.domain.split('.')[0]
                existing_shared_domains[customer_domain] = domain.domain
                domain.domain = customer_domain

            # old domains need to bind as well
            elif domain.certificate == 'san':
                cert_for_domain = (self.storage_controller.get_certs_by_domain(
                    domain.domain,
                    project_id=project_id,
                    flavor_id=service_old.flavor_id,
                    cert_type=domain.certificate))
                if cert_for_domain == []:
                    cert_for_domain = None
                domain.cert_info = cert_for_domain

        service_old_json = json.loads(json.dumps(service_old.to_dict()))

        # remove fields that cannot be part of PATCH
        del service_old_json['service_id']
        del service_old_json['status']
        del service_old_json['operator_status']
        del service_old_json['provider_details']

        for domain in service_old_json['domains']:
            if 'cert_info' in domain:
                del domain['cert_info']

        service_new_json = jsonpatch.apply_patch(service_old_json,
                                                 service_updates)

        # add any default rules so its explicitly defined
        self._append_defaults(service_new_json, operation='update')

        # validate the updates
        schema = service_schema.ServiceSchema.get_schema("service", "POST")
        validators.is_valid_service_configuration(service_new_json, schema)

        try:
            self.flavor_controller.get(service_new_json['flavor_id'])
        # raise a lookup error if the flavor is not found
        except LookupError as e:
            raise e

        # must be valid, carry on
        service_new_json['service_id'] = service_old.service_id
        service_new = service.Service.init_from_dict(project_id,
                                                     service_new_json)

        store = str(uuid.uuid4()).replace('-', '_')
        service_new.provider_details = service_old.provider_details

        # fixing the old and new shared ssl domains in service_new
        for domain in service_new.domains:
            if domain.protocol == 'https':
                if domain.certificate == 'shared':
                    customer_domain = domain.domain.split('.')[0]
                    # if this domain is from service_old
                    if customer_domain in existing_shared_domains:
                        domain.domain = existing_shared_domains[
                            customer_domain]
                    else:
                        domain.domain = self._pick_shared_ssl_domain(
                            customer_domain, service_new.service_id, store)
                elif domain.certificate == 'san':
                    cert_for_domain = (
                        self.storage_controller.get_certs_by_domain(
                            domain.domain,
                            project_id=project_id,
                            flavor_id=service_new.flavor_id,
                            cert_type=domain.certificate))
                    if cert_for_domain == []:
                        cert_for_domain = None
                    domain.cert_info = cert_for_domain

                    # retrofit the access url info into
                    # certificate_info table
                    # Note(tonytan4ever): this is for backward
                    # compatibility
                    if domain.cert_info is None and \
                            service_new.provider_details is not None:
                        # Note(tonytan4ever): right now we assume
                        # only one provider per flavor, that's
                        # why we use values()[0]
                        access_url_for_domain = (
                            service_new.provider_details.values()
                            [0].get_domain_access_url(domain.domain))
                        if access_url_for_domain is not None:
                            providers = (self.flavor_controller.get(
                                service_new.flavor_id).providers)
                            san_cert_url = access_url_for_domain.get(
                                'provider_url')
                            # Note(tonytan4ever): stored san_cert_url
                            # for two times, that's intentional
                            # a little extra info does not hurt
                            new_cert_detail = {
                                providers[0].provider_id.title():
                                json.dumps(
                                    dict(cert_domain=san_cert_url,
                                         extra_info={
                                             'status':
                                             'deployed',
                                             'san cert':
                                             san_cert_url,
                                             'created_at':
                                             str(datetime.datetime.now())
                                         }))
                            }
                            new_cert_obj = ssl_certificate.SSLCertificate(
                                service_new.flavor_id, domain.domain, 'san',
                                project_id, new_cert_detail)
                            self.storage_controller.create_cert(
                                project_id, new_cert_obj)
                            # deserialize cert_details dict
                            new_cert_obj.cert_details[
                                providers[0].provider_id.title()] = json.loads(
                                    new_cert_obj.cert_details[
                                        providers[0].provider_id.title()])
                            domain.cert_info = new_cert_obj

        if hasattr(self, store):
            delattr(self, store)

        # check if the service domain names already exist
        # existing ones does not count!
        for d in service_new.domains:
            if self.storage_controller.domain_exists_elsewhere(
                    d.domain,
                    service_id) is True and \
                    d.domain not in existing_shared_domains.values():
                raise ValueError("Domain {0} has already been taken".format(
                    d.domain))

        # set status in provider details to u'update_in_progress'
        provider_details = service_old.provider_details
        for provider in provider_details:
            provider_details[provider].status = u'update_in_progress'
        service_new.provider_details = provider_details
        self.storage_controller.update(project_id, service_id, service_new)

        kwargs = {
            'project_id': project_id,
            'service_id': service_id,
            'auth_token': auth_token,
            'service_old': json.dumps(service_old.to_dict()),
            'service_obj': json.dumps(service_new.to_dict()),
            'time_seconds': self.determine_sleep_times(),
            'context_dict': context_utils.get_current().to_dict()
        }

        self.distributed_task_controller.submit_task(
            update_service.update_service, **kwargs)

        return
示例#3
0
    def create(self, project_id, auth_token, service_json):
        """create.

        :param project_id
        :param service_obj
        :raises LookupError, ValueError
        """
        try:
            flavor = self.flavor_controller.get(service_json.get('flavor_id'))
        # raise a lookup error if the flavor is not found
        except LookupError as e:
            raise e

        # add any default rules so its explicitly defined
        self._append_defaults(service_json, operation='create')

        # convert to an object
        service_obj = service.Service.init_from_dict(project_id, service_json)
        service_id = service_obj.service_id

        # validate the service
        service_json = service_obj.to_dict()
        schema = service_schema.ServiceSchema.get_schema("service", "POST")
        validators.is_valid_service_configuration(service_json, schema)

        service_limit = self.storage_controller.get_service_limit(project_id)
        service_count = self.storage_controller.get_service_count(project_id)

        if service_count >= service_limit:
            raise errors.ServicesOverLimit('Maximum Services '
                                           'Limit of {0} '
                                           'reached!'.format(service_limit))

        if any([
                domain for domain in service_obj.domains
                if domain.certificate == "shared"
        ]):
            try:
                store = str(uuid.uuid4()).replace('-', '_')
                service_obj = self._shard_retry(project_id,
                                                service_obj,
                                                store=store)
            except errors.SharedShardsExhausted as e:
                raise e
            except ValueError as e:
                raise e

        try:
            self.storage_controller.create(project_id, service_obj)
        except ValueError as e:
            raise e

        providers = [p.provider_id for p in flavor.providers]
        kwargs = {
            'providers_list_json': json.dumps(providers),
            'project_id': project_id,
            'auth_token': auth_token,
            'service_id': service_id,
            'time_seconds': self.determine_sleep_times(),
            'context_dict': context_utils.get_current().to_dict()
        }

        self.distributed_task_controller.submit_task(
            create_service.create_service, **kwargs)

        return service_obj
示例#4
0
    def update(self, project_id, service_id,
               auth_token, service_updates, force_update=False):
        """update.

        :param project_id
        :param service_id
        :param auth_token
        :param service_updates
        :param force_update
        :raises LookupError, ValueError
        """
        # get the current service object
        try:
            service_old = self.storage_controller.get(project_id, service_id)
        except ValueError:
            raise errors.ServiceNotFound("Service not found")

        if service_old.operator_status == u'disabled':
            raise errors.ServiceStatusDisabled(
                u'Service {0} is disabled'.format(service_id))

        if (
            service_old.status not in [u'deployed', u'failed'] and
            force_update is False
        ):
            raise errors.ServiceStatusNeitherDeployedNorFailed(
                u'Service {0} neither deployed nor failed'.format(service_id))

        # Fixing the operator_url domain for ssl
        # for schema validation
        existing_shared_domains = {}
        for domain in service_old.domains:
            if domain.protocol == 'https' and domain.certificate == 'shared':
                customer_domain = domain.domain.split('.')[0]
                existing_shared_domains[customer_domain] = domain.domain
                domain.domain = customer_domain

            # old domains need to bind as well
            elif domain.certificate == 'san':
                cert_for_domain = (
                    self.storage_controller.get_certs_by_domain(
                        domain.domain,
                        project_id=project_id,
                        flavor_id=service_old.flavor_id,
                        cert_type=domain.certificate))
                if cert_for_domain == []:
                    cert_for_domain = None
                domain.cert_info = cert_for_domain

        service_old_json = json.loads(json.dumps(service_old.to_dict()))

        # remove fields that cannot be part of PATCH
        del service_old_json['service_id']
        del service_old_json['status']
        del service_old_json['operator_status']
        del service_old_json['provider_details']

        for domain in service_old_json['domains']:
            if 'cert_info' in domain:
                del domain['cert_info']

        service_new_json = jsonpatch.apply_patch(
            service_old_json, service_updates)

        # add any default rules so its explicitly defined
        self._append_defaults(service_new_json, operation='update')

        # validate the updates
        schema = service_schema.ServiceSchema.get_schema("service", "POST")
        validators.is_valid_service_configuration(service_new_json, schema)

        try:
            self.flavor_controller.get(service_new_json['flavor_id'])
        # raise a lookup error if the flavor is not found
        except LookupError as e:
            raise e

        # must be valid, carry on
        service_new_json['service_id'] = service_old.service_id
        service_new = service.Service.init_from_dict(project_id,
                                                     service_new_json)

        store = str(uuid.uuid4()).replace('-', '_')
        service_new.provider_details = service_old.provider_details

        # fixing the old and new shared ssl domains in service_new
        for domain in service_new.domains:
            if domain.protocol == 'https':
                if domain.certificate == 'shared':
                    customer_domain = domain.domain.split('.')[0]
                    # if this domain is from service_old
                    if customer_domain in existing_shared_domains:
                        domain.domain = existing_shared_domains[
                            customer_domain
                        ]
                    else:
                        domain.domain = self._pick_shared_ssl_domain(
                            customer_domain,
                            service_new.service_id,
                            store)
                elif domain.certificate == 'san':
                    cert_for_domain = (
                        self.storage_controller.get_certs_by_domain(
                            domain.domain,
                            project_id=project_id,
                            flavor_id=service_new.flavor_id,
                            cert_type=domain.certificate))
                    if cert_for_domain == []:
                        cert_for_domain = None
                    domain.cert_info = cert_for_domain

                    # retrofit the access url info into
                    # certificate_info table
                    # Note(tonytan4ever): this is for backward
                    # compatibility
                    if domain.cert_info is None and \
                            service_new.provider_details is not None:
                        # Note(tonytan4ever): right now we assume
                        # only one provider per flavor, that's
                        # why we use values()[0]
                        access_url_for_domain = (
                            service_new.provider_details.values()[0].
                            get_domain_access_url(domain.domain))
                        if access_url_for_domain is not None:
                            providers = (
                                self.flavor_controller.get(
                                    service_new.flavor_id).providers
                            )
                            san_cert_url = access_url_for_domain.get(
                                'provider_url')
                            # Note(tonytan4ever): stored san_cert_url
                            # for two times, that's intentional
                            # a little extra info does not hurt
                            new_cert_detail = {
                                providers[0].provider_id.title():
                                json.dumps(dict(
                                    cert_domain=san_cert_url,
                                    extra_info={
                                        'status': 'deployed',
                                        'san cert': san_cert_url,
                                        'created_at': str(
                                            datetime.datetime.now())
                                    }
                                ))
                            }
                            new_cert_obj = ssl_certificate.SSLCertificate(
                                service_new.flavor_id,
                                domain.domain,
                                'san',
                                project_id,
                                new_cert_detail
                            )
                            self.storage_controller.create_cert(
                                project_id,
                                new_cert_obj
                            )
                            # deserialize cert_details dict
                            new_cert_obj.cert_details[
                                providers[0].provider_id.title()] = json.loads(
                                new_cert_obj.cert_details[
                                    providers[0].provider_id.title()]
                            )
                            domain.cert_info = new_cert_obj

        if hasattr(self, store):
            delattr(self, store)

        # check if the service domain names already exist
        # existing ones does not count!
        for d in service_new.domains:
            if self.storage_controller.domain_exists_elsewhere(
                    d.domain,
                    service_id) is True and \
                    d.domain not in existing_shared_domains.values():
                raise ValueError(
                    "Domain {0} has already been taken".format(d.domain))

        # set status in provider details to u'update_in_progress'
        provider_details = service_old.provider_details
        for provider in provider_details:
            provider_details[provider].status = u'update_in_progress'
        service_new.provider_details = provider_details
        self.storage_controller.update(project_id, service_id, service_new)

        kwargs = {
            'project_id': project_id,
            'service_id': service_id,
            'auth_token': auth_token,
            'service_old': json.dumps(service_old.to_dict()),
            'service_obj': json.dumps(service_new.to_dict()),
            'time_seconds': self.determine_sleep_times(),
            'context_dict': context_utils.get_current().to_dict()
        }

        self.distributed_task_controller.submit_task(
            update_service.update_service, **kwargs)

        return
示例#5
0
    def create(self, project_id, auth_token, service_json):
        """create.

        :param project_id
        :param auth_token
        :param service_json
        :raises LookupError, ValueError
        """
        try:
            flavor = self.flavor_controller.get(service_json.get('flavor_id'))
        # raise a lookup error if the flavor is not found
        except LookupError as e:
            raise e

        # add any default rules so its explicitly defined
        self._append_defaults(service_json, operation='create')

        # convert to an object
        service_obj = service.Service.init_from_dict(project_id, service_json)
        service_id = service_obj.service_id

        # validate the service
        service_json = service_obj.to_dict()
        schema = service_schema.ServiceSchema.get_schema("service", "POST")
        validators.is_valid_service_configuration(service_json, schema)

        service_limit = self.storage_controller.get_service_limit(project_id)
        service_count = self.storage_controller.get_service_count(project_id)

        if service_count >= service_limit:
            raise errors.ServicesOverLimit('Maximum Services '
                                           'Limit of {0} '
                                           'reached!'.format(service_limit))

        if any([domain for domain in service_obj.domains
                if domain.certificate == "shared"]):
            try:
                store = str(uuid.uuid4()).replace('-', '_')
                service_obj = self._shard_retry(project_id,
                                                service_obj,
                                                store=store)
            except errors.SharedShardsExhausted as e:
                raise e
            except ValueError as e:
                raise e

        try:
            self.storage_controller.create(project_id,
                                           service_obj)
        except ValueError as e:
            raise e

        providers = [p.provider_id for p in flavor.providers]
        kwargs = {
            'providers_list_json': json.dumps(providers),
            'project_id': project_id,
            'auth_token': auth_token,
            'service_id': service_id,
            'time_seconds': self.determine_sleep_times(),
            'context_dict': context_utils.get_current().to_dict()
        }

        self.distributed_task_controller.submit_task(
            create_service.create_service, **kwargs)

        return service_obj
示例#6
0
    def update(self, project_id, service_id, auth_token, service_updates):
        """update.

        :param project_id
        :param service_id
        :param service_updates
        :raises LookupError, ValueError
        """
        # get the current service object
        try:
            service_old = self.storage_controller.get(project_id, service_id)
        except ValueError:
            raise errors.ServiceNotFound("Service not found")

        if service_old.status not in [u'deployed', u'failed']:
            raise errors.ServiceStatusNeitherDeployedNorFailed(
                u'Service {0} neither deployed nor failed'.format(service_id))

        # Fixing the operator_url domain for ssl
        # for schema validation
        existing_shared_domains = {}
        for domain in service_old.domains:
            if domain.protocol == 'https' and domain.certificate == 'shared':
                customer_domain = domain.domain.split('.')[0]
                existing_shared_domains[customer_domain] = domain.domain
                domain.domain = customer_domain

        service_old_json = json.loads(json.dumps(service_old.to_dict()))

        # remove fields that cannot be part of PATCH
        del service_old_json['service_id']
        del service_old_json['status']
        del service_old_json['provider_details']

        service_new_json = jsonpatch.apply_patch(
            service_old_json, service_updates)

        # add any default rules so its explicitly defined
        self._append_defaults(service_new_json)

        # validate the updates
        schema = service_schema.ServiceSchema.get_schema("service", "POST")
        validators.is_valid_service_configuration(service_new_json, schema)

        try:
            self.flavor_controller.get(service_new_json['flavor_id'])
        # raise a lookup error if the flavor is not found
        except LookupError as e:
            raise e

        # must be valid, carry on
        service_new_json['service_id'] = service_old.service_id
        service_new = service.Service.init_from_dict(service_new_json)

        # check if the service domain names already exist
        for d in service_new.domains:
            if self.storage_controller.domain_exists_elsewhere(
                    d.domain,
                    service_id) is True:
                raise ValueError(
                    "Domain {0} has already been taken".format(d.domain))

        # fixing the old and new shared ssl domains in service_new
        for domain in service_new.domains:
            if domain.protocol == 'https' and domain.certificate == 'shared':
                customer_domain = domain.domain.split('.')[0]
                # if this domain is from service_old
                if customer_domain in existing_shared_domains:
                    domain.domain = existing_shared_domains[customer_domain]
                else:
                    domain.domain = self._generate_shared_ssl_domain(
                        domain.domain
                    )

        # set status in provider details to u'update_in_progress'
        provider_details = service_old.provider_details
        for provider in provider_details:
            provider_details[provider].status = u'update_in_progress'
        self.storage_controller.update(project_id, service_id, service_old)

        kwargs = {
            'project_id': project_id,
            'service_id': service_id,
            'auth_token': auth_token,
            'service_old': json.dumps(service_old.to_dict()),
            'service_obj': json.dumps(service_new.to_dict()),
            'time_seconds': self.determine_sleep_times()
        }

        self.distributed_task_controller.submit_task(
            update_service.update_service, **kwargs)

        return
示例#7
0
    def create_service(self, project_id, auth_token, service_json):
        """Create a new service.

        :param unicode project_id: The project id
        :param unicode auth_token: Token for authorization
        :param dict service_json: The service details to create

        :return: The new service object created
        :rtype: poppy.model.service.Service

        :raises LookupError: if the flavor does not exists
        :raises ValueError: if shard domain retry operation has problem
        """
        try:
            flavor = self.flavor_controller.get(service_json.get('flavor_id'))
        # raise a lookup error if the flavor is not found
        except LookupError as e:
            raise e

        # add any default rules so its explicitly defined
        self._append_defaults(service_json, operation='create')

        # convert to an object
        service_obj = service.Service.init_from_dict(project_id, service_json)
        service_id = service_obj.service_id

        # validate the service
        service_json = service_obj.to_dict()
        schema = service_schema.ServiceSchema.get_schema("service", "POST")
        validators.is_valid_service_configuration(service_json, schema)

        service_limit = self.storage_controller.get_service_limit(project_id)
        service_count = self.storage_controller.get_service_count(project_id)

        services_delete_in_progress = self.storage_controller.\
            get_services_by_status('delete_in_progress')

        services_delete_count = len(services_delete_in_progress)

        # Check that the number of deleted services is less
        # than the total number of existing services for the project.
        # Adjust the service count removing delete_in_progress
        # services.
        service_count -= (services_delete_count
                          if 0 < services_delete_count < service_count else 0)
        # service_count should always be a >= 0.

        if service_count >= service_limit:
            raise errors.ServicesOverLimit('Maximum Services '
                                           'Limit of {0} '
                                           'reached!'.format(service_limit))

        if any([
                domain for domain in service_obj.domains
                if domain.certificate == "shared"
        ]):
            try:
                store = str(uuid.uuid4()).replace('-', '_')
                service_obj = self._shard_retry(project_id,
                                                service_obj,
                                                store=store)
            except errors.SharedShardsExhausted as e:
                raise e
            except ValueError as e:
                raise e

        try:
            self.storage_controller.create_service(project_id, service_obj)
        except ValueError as e:
            raise e

        providers = [p.provider_id for p in flavor.providers]
        kwargs = {
            'providers_list_json': json.dumps(providers),
            'project_id': project_id,
            'auth_token': auth_token,
            'service_id': service_id,
            'time_seconds': self.determine_sleep_times(),
            'context_dict': context_utils.get_current().to_dict()
        }

        self.distributed_task_controller.submit_task(
            create_service.create_service, **kwargs)

        return service_obj