Exemple #1
0
    def get_metrics_by_domain(self, project_id, domain_name, **extras):

        storage_controller = self.storage_controller
        try:
            result = storage_controller.get_service_details_by_domain_name(
                domain_name=domain_name, project_id=project_id)
        except ValueError:
            msg = "Domain: {0} was not found for project_id: {1}".format(
                domain_name, project_id)
            LOG.warning(msg)
            raise errors.ServiceNotFound(msg)
        if not result:
            msg = "Domain: {0} was not found for project_id: {1}".format(
                domain_name, project_id)
            LOG.warning(msg)
            raise errors.ServiceNotFound(msg)

        if not result.provider_details:
            msg = "Provider Details were None " \
                  "for the service_id: {0} " \
                  "corresponding to project_id: {1}".format(result.service_id,
                                                            project_id)
            LOG.warning(msg)
            raise errors.ServiceProviderDetailsNotFound(msg)

        provider_details_dict = result.provider_details

        provider_for_domain = None

        for provider, provider_details in provider_details_dict.items():
            if provider_details.get_domain_access_url(domain=domain_name):
                provider_for_domain = provider

        if not provider_for_domain:
            msg = "Provider not found for Domain : {0}".format(domain_name)
            LOG.warning(msg)
            raise errors.ProviderNotFound(msg)

        provider_obj = self.providers[provider_for_domain.lower()].obj
        provider_service_controller = provider_obj.service_controller
        extras['metrics_controller'] = self.metrics_controller
        metrics = provider_service_controller.get_metrics_by_domain(
            project_id, domain_name, provider_obj.regions, **extras)

        metrics['provider'] = provider_for_domain.lower()
        metrics['flavor'] = result.flavor_id
        return metrics
Exemple #2
0
    def test_migrate_domain_service_not_found(self):
        payload = {
            "project_id": "12345",
            "service_id": "abcdef",
            "domain_name": "www.mywebsite.com",
            "new_cert": "scdn1.secure6.raxcdn.com.edgekey.net",
            "cert_status": "create_in_progress"
        }
        self.request.body = bytearray(json.dumps(payload), encoding='utf-8')

        self.manager.services_controller.migrate_domain.side_effect = (
            errors.ServiceNotFound("Mock -- Couldn't find service!")
        )

        self.assertRaises(exc.HTTPNotFound, self.controller.post, payload)
Exemple #3
0
    def migrate_domain(self,
                       project_id,
                       service_id,
                       domain_name,
                       new_cert,
                       cert_status='deployed'):
        dns_controller = self.dns_controller
        storage_controller = self.storage_controller

        try:
            # Update CNAME records and provider_details in cassandra
            provider_details = storage_controller.get_provider_details(
                project_id, service_id)
        except ValueError as e:
            # If service is not found
            LOG.warning('Migrating domain failed: Service {0} could not '
                        'be found.. Error message: {1}'.format(service_id, e))
            raise errors.ServiceNotFound(e)

        for provider in provider_details:
            for url in provider_details[provider].access_urls:
                if url.get('domain') == domain_name:
                    if 'operator_url' in url:
                        access_url = url['operator_url']
                        dns_controller.modify_cname(access_url, new_cert)
                        url['provider_url'] = new_cert
                        storage_controller.update_provider_details(
                            project_id, service_id, provider_details)
                        break
            else:
                links = {}
                link_key_tuple = (domain_name, 'san')
                links[link_key_tuple] = new_cert
                created_dns_link = dns_controller._create_cname_records(links)
                new_url = {
                    'domain':
                    domain_name,
                    'operator_url':
                    (created_dns_link[link_key_tuple]['operator_url']),
                    'provider_url':
                    new_cert
                }
                provider_details[provider].access_urls.append(new_url)
                provider_details[provider].domains_certificate_status.\
                    set_domain_certificate_status(domain_name, cert_status)
                storage_controller.update_provider_details(
                    project_id, service_id, provider_details)
Exemple #4
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
Exemple #5
0
    def migrate_domain(self,
                       project_id,
                       service_id,
                       domain_name,
                       new_cert,
                       cert_status='deployed'):
        dns_controller = self.dns_controller
        storage_controller = self.storage_controller

        try:
            # Update CNAME records and provider_details in cassandra
            provider_details = storage_controller.get_provider_details(
                project_id, service_id)
        except ValueError as e:
            # If service is not found
            LOG.warning('Migrating domain failed: Service {0} could not '
                        'be found. Error message: {1}'.format(service_id, e))
            raise errors.ServiceNotFound(e)

        for provider in provider_details:
            provider_details[provider].domains_certificate_status.\
                set_domain_certificate_status(domain_name, cert_status)

            # Currently there's only one flavor, and thus expect one result
            # from the query below. Once additional flavors are added, a
            # query for the service object rather than provider details only
            # should provide the flavor id to use in the query below
            cert_obj = self.ssl_certificate_storage.get_certs_by_domain(
                domain_name, project_id=project_id, cert_type='san')

            if cert_obj != []:
                # cert was found, update the cert status
                cert_details = cert_obj.cert_details
                cert_details[provider]['extra_info']['status'] = cert_status
                cert_details[provider] = json.dumps(cert_details[provider])

                storage_controller.update_cert_info(cert_obj.domain_name,
                                                    cert_obj.cert_type,
                                                    cert_obj.flavor_id,
                                                    cert_details)

            for url in provider_details[provider].access_urls:
                if url.get('domain') == domain_name:
                    if 'operator_url' in url:
                        access_url = url['operator_url']
                        dns_controller.modify_cname(access_url, new_cert)
                        url['provider_url'] = new_cert
                        break
            else:
                links = {}
                link_key_tuple = (domain_name, 'san')
                links[link_key_tuple] = new_cert
                created_dns_link = dns_controller._create_cname_records(links)
                new_url = {
                    'domain':
                    domain_name,
                    'operator_url':
                    (created_dns_link[link_key_tuple]['operator_url']),
                    'provider_url':
                    new_cert
                }
                provider_details[provider].access_urls.append(new_url)

            storage_controller.update_provider_details(project_id, service_id,
                                                       provider_details)
Exemple #6
0
    def update_access_url_service(self, project_id, service_id,
                                  access_url_changes):
        try:
            service_old = self.storage_controller.get_service(
                project_id, service_id)
        except ValueError as e:
            # If service is not found
            LOG.warning('Get service {0} failed. '
                        'Error message: {1}'.format(service_id, e))
            raise errors.ServiceNotFound(e)

        updated_details = False
        provider_details = service_old.provider_details
        domain_name = access_url_changes.get('domain_name')
        for provider in provider_details:
            for access_url in provider_details[provider].access_urls:
                if access_url.get('domain') == domain_name:
                    if ('operator_url' in access_url
                            and 'provider_url' in access_url):
                        new_access_url = access_url_changes['operator_url']
                        new_provider_url = access_url_changes['provider_url']
                        if access_url.get('shared_ssl_flag', False) is True:
                            raise errors.InvalidOperation(
                                'Changing access urls for shared ssl domains '
                                'is not supported.')
                        if not new_access_url.startswith(domain_name):
                            LOG.info('Invalid access_url/domain_name.')
                            raise errors.InvalidResourceName(
                                'Invalid access_url/domain_name.')
                        if new_access_url == access_url['operator_url']:
                            LOG.info(
                                "No changes made, both old and new access "
                                "urls are the same. "
                                "Domain '{0}'.".format(domain_name))
                            return False
                        if new_provider_url != access_url['provider_url']:
                            raise errors.InvalidOperation(
                                'Please use the migrate domain functionality '
                                'to migrate the domain to a new cert.')
                        certificate = ("shared" if access_url.get(
                            'shared_ssl_flag', False) is True else None)
                        self.dns_controller._create_preferred_cname_record(
                            domain_name, certificate, new_access_url,
                            new_provider_url)
                        self.dns_controller._delete_cname_record(
                            access_url['operator_url'],
                            access_url.get('shared_ssl_flag', False))
                        access_url['provider_url'] = new_provider_url
                        access_url['operator_url'] = new_access_url
                        updated_details = True
                        break

        if updated_details is True:
            self.storage_controller.update_provider_details(
                project_id, service_id, provider_details)
        else:
            err_msg = 'Domain {0} could not be found on service {1}.'.format(
                domain_name, service_id)
            LOG.error(err_msg)
            raise ValueError(err_msg)

        return updated_details
Exemple #7
0
    def migrate_domain(self,
                       project_id,
                       service_id,
                       domain_name,
                       new_cert,
                       cert_status='deployed'):
        """Migrate domain.

        Domain migration includes
         - Set cert_status to all the provider's domain_certification
         - Update the all the certificates with cert_status
         - Update the access_url of all the providers with new_cert

        As of now, below are the supported statuses.
         - create_in_progress
         - deployed
         - failed
         - cancelled

        :param unicode project_id: The project id
        :param unicode service_id: The service id
        :param unicode domain_name: The domain name
        :param unicode new_cert: The new certificate
        :param unicode cert_status: (Default 'deployed')Certificate status

        :raises ServiceNotFound: if the service not found
        """
        dns_controller = self.dns_controller
        storage_controller = self.storage_controller

        try:
            # Update CNAME records and provider_details in cassandra
            provider_details = storage_controller.get_provider_details(
                project_id, service_id)
        except ValueError as e:
            # If service is not found
            LOG.warning('Migrating domain failed: Service {0} could not '
                        'be found. Error message: {1}'.format(service_id, e))
            raise errors.ServiceNotFound(e)

        for provider in provider_details:
            provider_details[provider].domains_certificate_status.\
                set_domain_certificate_status(domain_name, cert_status)

            # Currently there's only one flavor, and thus expect one result
            # from the query below. Once additional flavors are added, a
            # query for the service object rather than provider details only
            # should provide the flavor id to use in the query below
            try:
                cert_obj = self.ssl_certificate_storage.get_certs_by_domain(
                    domain_name, project_id=project_id, cert_type='san')

                # cert was found, update the cert status
                cert_details = cert_obj.cert_details
                cert_details[provider]['extra_info']['status'] = cert_status
                cert_details[provider] = json.dumps(cert_details[provider])

                self.ssl_certificate_storage.update_certificate(
                    cert_obj.domain_name, cert_obj.cert_type,
                    cert_obj.flavor_id, cert_details)
            except ValueError:
                LOG.info("No matching certificate found for the "
                         "combination of {0} and {1} and {2} "
                         "".format(domain_name, project_id, 'san'))

            for url in provider_details[provider].access_urls:
                if url.get('domain') == domain_name:
                    if 'operator_url' in url:
                        access_url = url['operator_url']
                        dns_controller.modify_cname(access_url, new_cert)
                        url['provider_url'] = new_cert
                        break
            else:
                links = {}
                link_key_tuple = (domain_name, 'san', None)
                links[link_key_tuple] = new_cert
                created_dns_link = dns_controller._create_cname_records(links)
                new_url = {
                    'domain':
                    domain_name,
                    'operator_url':
                    (created_dns_link[link_key_tuple]['operator_url']),
                    'provider_url':
                    new_cert
                }
                provider_details[provider].access_urls.append(new_url)

            storage_controller.update_provider_details(project_id, service_id,
                                                       provider_details)
Exemple #8
0
    def get_metrics_by_domain(self, project_id, domain_name, **extras):
        """Gets metrics information for a domain.

        The below keys are expected in ``extras`` along with their values.
         - metricType
         - startTime
         - endTime
         - metrics_controller

        Example return:
            ``{'provider': '', 'flavor':'', 'domain':'', 'metricType': {}}``

        :param unicode project_id: The project id
        :param unicode domain_name: The domain name
        :param dict extras: Additional arguments to supply

        :return: A dictionary containing domain name and its metrics
        :rtype: dict

        :raises ServiceNotFound: if domain not present under project id
        :raises ServiceProviderDetailsNotFound: if no provider details
          exists for the service id and project id combo
        :raises ProviderDetailsIncomplete: if provider is not found
          for the domain
        """

        storage_controller = self.storage_controller
        try:
            result = storage_controller.get_service_details_by_domain_name(
                domain_name=domain_name, project_id=project_id)
        except ValueError as ve:
            msg = ("Error retrieving details for domain {0} "
                   "project_id {1} : {2}".format(domain_name, project_id, ve))
            LOG.error(msg)
            raise errors.ServiceNotFound(msg)
        if not result:
            msg = "Domain: {0} was not found for project_id: {1}".format(
                domain_name, project_id)
            LOG.warning(msg)
            raise errors.ServiceNotFound(msg)

        if not result.provider_details:
            msg = "Provider Details were None " \
                  "for the service_id: {0} " \
                  "corresponding to project_id: {1}".format(result.service_id,
                                                            project_id)
            LOG.warning(msg)
            raise errors.ServiceProviderDetailsNotFound(msg)

        provider_details_dict = result.provider_details

        provider_for_domain = None

        for provider, provider_details in provider_details_dict.items():
            if provider_details.get_domain_access_url(domain=domain_name):
                provider_for_domain = provider

        if not provider_for_domain:
            msg = "Provider not found for Domain {0}".format(domain_name)
            LOG.error(msg)
            raise errors.ProviderDetailsIncomplete(msg)

        provider_obj = self.providers[provider_for_domain.lower()].obj
        provider_service_controller = provider_obj.service_controller
        extras['metrics_controller'] = self.metrics_controller
        metrics = provider_service_controller.get_metrics_by_domain(
            project_id, domain_name, provider_obj.regions, **extras)

        metrics['provider'] = provider_for_domain.lower()
        metrics['flavor'] = result.flavor_id
        return metrics