Adds Rackspace DNS Driver
Change-Id: Id49e24364ab0aa39245fc287960451e4233569bc
This commit is contained in:
parent
5b4361bc0b
commit
b893de24de
|
@ -71,13 +71,16 @@ replication_strategy = class:SimpleStrategy, replication_factor:1
|
|||
[drivers:storage:mockdb]
|
||||
database = poppy
|
||||
|
||||
|
||||
[drivers:dns:rackspace]
|
||||
project_id = "<operator_project_id>"
|
||||
api_key = "<operator_api_key>"
|
||||
use_shards = True
|
||||
num_shards = 500
|
||||
shard_prefix = "cdn_"
|
||||
num_shards = 499
|
||||
shard_prefix = "cdn"
|
||||
url = "poppycdn.net"
|
||||
# You email associated with DNS, for notifications
|
||||
email = "your@email.com"
|
||||
|
||||
[drivers:provider:fastly]
|
||||
apikey = "MYAPIKEY"
|
||||
|
|
|
@ -18,4 +18,4 @@ from poppy.dns.base import services
|
|||
|
||||
|
||||
Driver = driver.DNSDriverBase
|
||||
ServiceBase = services.ServicesControllerBase
|
||||
ServicesBase = services.ServicesControllerBase
|
||||
|
|
|
@ -43,14 +43,29 @@ class DNSDriverBase(object):
|
|||
|
||||
:raises NotImplementedError
|
||||
"""
|
||||
|
||||
raise NotImplementedError
|
||||
|
||||
@abc.abstractproperty
|
||||
def dns_name(self):
|
||||
"""Name of this provider.
|
||||
|
||||
:raises NotImplementedError
|
||||
"""
|
||||
|
||||
raise NotImplementedError
|
||||
|
||||
@property
|
||||
def client(self):
|
||||
"""Client for this provider.
|
||||
|
||||
:raises NotImplementedError
|
||||
"""
|
||||
|
||||
raise NotImplementedError
|
||||
|
||||
@abc.abstractproperty
|
||||
def service_controller(self):
|
||||
def services_controller(self):
|
||||
"""Returns the driver's hostname controller.
|
||||
|
||||
:raises NotImplementedError
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
# Copyright (c) 2014 Rackspace, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import traceback
|
||||
|
||||
|
||||
class Responder(object):
|
||||
"""Responder Class."""
|
||||
|
||||
def __init__(self, dns_name):
|
||||
self.dns = dns_name
|
||||
|
||||
def failed(self, msg):
|
||||
"""failed.
|
||||
|
||||
:param msg
|
||||
:returns {error, error details}
|
||||
"""
|
||||
|
||||
return {
|
||||
'error': msg,
|
||||
'error_detail': traceback.format_exc()
|
||||
}
|
||||
|
||||
def created(self, dns_details):
|
||||
"""created.
|
||||
|
||||
:param dns_details
|
||||
:returns dns_details
|
||||
"""
|
||||
|
||||
return dns_details
|
||||
|
||||
def updated(self, dns_details):
|
||||
"""updated.
|
||||
|
||||
:param dns_details
|
||||
:returns dns_details
|
||||
"""
|
||||
|
||||
return dns_details
|
||||
|
||||
def deleted(self, dns_details):
|
||||
"""deleted.
|
||||
|
||||
:param dns_details
|
||||
:returns dns_details
|
||||
"""
|
||||
|
||||
return dns_details
|
|
@ -18,6 +18,7 @@ import abc
|
|||
import six
|
||||
|
||||
from poppy.dns.base import controller
|
||||
from poppy.dns.base import responder
|
||||
|
||||
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
|
@ -27,3 +28,34 @@ class ServicesControllerBase(controller.DNSControllerBase):
|
|||
|
||||
def __init__(self, driver):
|
||||
super(ServicesControllerBase, self).__init__(driver)
|
||||
|
||||
self.responder = responder.Responder(driver.dns_name)
|
||||
|
||||
def update(self, service_old, service_updates, responders):
|
||||
"""update.
|
||||
|
||||
:param service_old: previous service state
|
||||
:param service_updates: updates to service state
|
||||
:param responders: responders from providers
|
||||
:raises NotImplementedError
|
||||
"""
|
||||
|
||||
raise NotImplementedError
|
||||
|
||||
def delete(self, provider_details):
|
||||
"""delete.
|
||||
|
||||
:param provider_details
|
||||
:raises NotImplementedError
|
||||
"""
|
||||
|
||||
raise NotImplementedError
|
||||
|
||||
def create(self, responders):
|
||||
"""create.
|
||||
|
||||
:param responders
|
||||
:raises NotImplementedError
|
||||
"""
|
||||
|
||||
raise NotImplementedError
|
||||
|
|
|
@ -24,4 +24,4 @@ Field Mappings:
|
|||
|
||||
from poppy.dns.default import services
|
||||
|
||||
ServiceController = services.ServiceController
|
||||
ServicesController = services.ServicesController
|
||||
|
|
|
@ -23,17 +23,42 @@ LOG = logging.getLogger(__name__)
|
|||
|
||||
|
||||
class DNSProvider(base.Driver):
|
||||
"""Default DNS Provider."""
|
||||
|
||||
def __init__(self, conf):
|
||||
super(DNSProvider, self).__init__(conf)
|
||||
|
||||
def is_alive(self):
|
||||
return False
|
||||
"""is_alive.
|
||||
|
||||
:return boolean
|
||||
"""
|
||||
|
||||
return True
|
||||
|
||||
@property
|
||||
def dns_name(self):
|
||||
return "Default"
|
||||
"""DNS provider name.
|
||||
|
||||
:return 'Default'
|
||||
"""
|
||||
|
||||
return 'Default'
|
||||
|
||||
@property
|
||||
def service_controller(self):
|
||||
return controllers.ServiceController(self)
|
||||
def client(self):
|
||||
"""Client to this provider.
|
||||
|
||||
:return None
|
||||
"""
|
||||
|
||||
return None
|
||||
|
||||
@property
|
||||
def services_controller(self):
|
||||
"""Hook for service controller.
|
||||
|
||||
:return service_controller
|
||||
"""
|
||||
|
||||
return controllers.ServicesController(self)
|
||||
|
|
|
@ -16,9 +16,64 @@
|
|||
from poppy.dns import base
|
||||
|
||||
|
||||
class ServiceController(base.ServiceBase):
|
||||
class ServicesController(base.ServicesBase):
|
||||
|
||||
def __init__(self, driver):
|
||||
super(ServiceController, self).__init__(driver)
|
||||
super(ServicesController, self).__init__(driver)
|
||||
|
||||
self.driver = driver
|
||||
|
||||
def update(self, service_old, service_updates, responders):
|
||||
"""Default DNS update.
|
||||
|
||||
:param service_old: previous service state
|
||||
:param service_updates: updates to service state
|
||||
:param responders: responders from providers
|
||||
"""
|
||||
|
||||
dns_details = {}
|
||||
for responder in responders:
|
||||
for provider_name in responder:
|
||||
if 'error' in responder[provider_name]:
|
||||
continue
|
||||
access_urls = []
|
||||
for link in responder[provider_name]['links']:
|
||||
access_url = {
|
||||
'domain': link['domain'],
|
||||
'provider_url': link['href'],
|
||||
'operator_url': link['href']}
|
||||
access_urls.append(access_url)
|
||||
dns_details[provider_name] = {'access_urls': access_urls}
|
||||
return self.responder.created(dns_details)
|
||||
|
||||
def delete(self, provider_details):
|
||||
"""Default DNS delete.
|
||||
|
||||
:param provider_details
|
||||
"""
|
||||
|
||||
dns_details = {}
|
||||
for provider_name in provider_details:
|
||||
dns_details[provider_name] = self.responder.deleted({})
|
||||
return dns_details
|
||||
|
||||
def create(self, responders):
|
||||
"""Default DNS create.
|
||||
|
||||
:param responders: responders from providers
|
||||
"""
|
||||
|
||||
dns_details = {}
|
||||
for responder in responders:
|
||||
for provider_name in responder:
|
||||
if 'error' in responder[provider_name]:
|
||||
continue
|
||||
access_urls = []
|
||||
for link in responder[provider_name]['links']:
|
||||
access_url = {
|
||||
'domain': link['domain'],
|
||||
'provider_url': link['href'],
|
||||
'operator_url': link['href']}
|
||||
access_urls.append(access_url)
|
||||
dns_details[provider_name] = {'access_urls': access_urls}
|
||||
return self.responder.created(dns_details)
|
||||
|
|
|
@ -24,4 +24,4 @@ Field Mappings:
|
|||
|
||||
from poppy.dns.designate import services
|
||||
|
||||
ServiceController = services.ServiceController
|
||||
ServicesController = services.ServicesController
|
||||
|
|
|
@ -16,9 +16,9 @@
|
|||
from poppy.dns import base
|
||||
|
||||
|
||||
class ServiceController(base.ServiceBase):
|
||||
class ServicesController(base.ServicesBase):
|
||||
|
||||
def __init__(self, driver):
|
||||
super(ServiceController, self).__init__(driver)
|
||||
super(ServicesController, self).__init__(driver)
|
||||
|
||||
self.driver = driver
|
||||
|
|
|
@ -24,4 +24,4 @@ Field Mappings:
|
|||
|
||||
from poppy.dns.rackspace import services
|
||||
|
||||
ServiceController = services.ServiceController
|
||||
ServicesController = services.ServicesController
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
"""DNS Provider implementation."""
|
||||
|
||||
from oslo.config import cfg
|
||||
import pyrax
|
||||
|
||||
from poppy.dns import base
|
||||
from poppy.dns.rackspace import controllers
|
||||
|
@ -34,6 +35,8 @@ RACKSPACE_OPTIONS = [
|
|||
help='The shard prefix to use'),
|
||||
cfg.StrOpt('url', default='',
|
||||
help='The url for customers to CNAME to'),
|
||||
cfg.StrOpt('email', help='The email to be provided to Rackspace DNS for'
|
||||
'creating subdomains'),
|
||||
]
|
||||
|
||||
RACKSPACE_GROUP = 'drivers:dns:rackspace'
|
||||
|
@ -42,17 +45,51 @@ LOG = logging.getLogger(__name__)
|
|||
|
||||
|
||||
class DNSProvider(base.Driver):
|
||||
"""Rackspace DNS Provider."""
|
||||
|
||||
def __init__(self, conf):
|
||||
super(DNSProvider, self).__init__(conf)
|
||||
|
||||
self._conf.register_opts(RACKSPACE_OPTIONS, group=RACKSPACE_GROUP)
|
||||
self.rackdns_conf = self._conf[RACKSPACE_GROUP]
|
||||
pyrax.set_setting("identity_type", "rackspace")
|
||||
pyrax.set_credentials(self.rackdns_conf.project_id,
|
||||
self.rackdns_conf.api_key)
|
||||
self.rackdns_client = pyrax.cloud_dns
|
||||
|
||||
def is_alive(self):
|
||||
"""is_alive.
|
||||
|
||||
:return boolean
|
||||
"""
|
||||
|
||||
# TODO(obulpathi): Implement health check
|
||||
# and add DNS to health endpoint
|
||||
return True
|
||||
|
||||
@property
|
||||
def dns_name(self):
|
||||
return "Rackspace Cloud DNS"
|
||||
"""DNS provider name.
|
||||
|
||||
:return 'Rackspace Cloud DNS'
|
||||
"""
|
||||
|
||||
return 'Rackspace Cloud DNS'
|
||||
|
||||
@property
|
||||
def service_controller(self):
|
||||
return controllers.ServiceController(self)
|
||||
def client(self):
|
||||
"""Client to this provider.
|
||||
|
||||
:return client
|
||||
"""
|
||||
|
||||
return self.rackdns_client
|
||||
|
||||
@property
|
||||
def services_controller(self):
|
||||
"""Hook for service controller.
|
||||
|
||||
:return service_controller
|
||||
"""
|
||||
|
||||
return controllers.ServicesController(self)
|
||||
|
|
|
@ -13,12 +13,334 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import random
|
||||
import sets
|
||||
|
||||
import pyrax.exceptions as exc
|
||||
|
||||
from poppy.dns import base
|
||||
from poppy.openstack.common import log
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
class ServiceController(base.ServiceBase):
|
||||
class ServicesController(base.ServicesBase):
|
||||
|
||||
def __init__(self, driver):
|
||||
super(ServiceController, self).__init__(driver)
|
||||
super(ServicesController, self).__init__(driver)
|
||||
|
||||
self.driver = driver
|
||||
self.client = driver.client
|
||||
|
||||
def _get_subdomain(self, subdomain_name):
|
||||
"""Returns a subdomain, if it does not exist, create it
|
||||
|
||||
:param subdomain_name
|
||||
:return subdomain
|
||||
"""
|
||||
|
||||
try:
|
||||
subdomain = self.client.find(name=subdomain_name)
|
||||
except exc.NotFound:
|
||||
subdomain = self.client.create(
|
||||
name=subdomain_name,
|
||||
emailAddress=self._driver.rackdns_conf.email,
|
||||
ttl=900)
|
||||
return subdomain
|
||||
|
||||
def _create_cname_records(self, links):
|
||||
"""Creates a subdomain
|
||||
|
||||
:param links: Access URLS from providers
|
||||
:return dns_links: Map from provider access URL to DNS access URL
|
||||
"""
|
||||
|
||||
cdn_domain_name = self._driver.rackdns_conf.url
|
||||
shard_prefix = self._driver.rackdns_conf.shard_prefix
|
||||
num_shards = self._driver.rackdns_conf.num_shards
|
||||
|
||||
# randomly select a shard
|
||||
shard_id = random.randint(0, num_shards - 1)
|
||||
subdomain_name = '{0}{1}.{2}'.format(shard_prefix, shard_id,
|
||||
cdn_domain_name)
|
||||
subdomain = self._get_subdomain(subdomain_name)
|
||||
# create CNAME record for adding
|
||||
cname_records = []
|
||||
dns_links = {}
|
||||
for link in links:
|
||||
name = '{0}.{1}'.format(link, subdomain_name)
|
||||
cname_record = {'type': 'CNAME',
|
||||
'name': name,
|
||||
'data': links[link],
|
||||
'ttl': 300}
|
||||
dns_links[links[link]] = name
|
||||
cname_records.append(cname_record)
|
||||
# add the cname records
|
||||
subdomain.add_records(cname_records)
|
||||
return dns_links
|
||||
|
||||
def _delete_cname_record(self, access_url):
|
||||
"""Delete a CNAME record
|
||||
|
||||
:param access_url: DNS Access URL
|
||||
:return error_msg: returns error message, if any
|
||||
"""
|
||||
|
||||
# extract shard name
|
||||
shard_name = access_url.split('.')[-3]
|
||||
subdomain_name = '.'.join([shard_name, self._driver.rackdns_conf.url])
|
||||
# get subdomain
|
||||
subdomain = self.client.find(name=subdomain_name)
|
||||
# search and find the CNAME record
|
||||
name = access_url
|
||||
record_type = 'CNAME'
|
||||
records = self.client.search_records(subdomain, record_type, name)
|
||||
# delete the record
|
||||
# we should get one record,
|
||||
# or none if it has been deleted already
|
||||
if not records:
|
||||
LOG.info('DNS record already deleted: {0}'.format(access_url))
|
||||
elif len(records) == 1:
|
||||
LOG.info('Deleting DNS records for : {0}'.format(access_url))
|
||||
records[0].delete()
|
||||
elif len(records) > 1:
|
||||
error_msg = 'Multiple DNS records found: {0}'.format(access_url)
|
||||
return error_msg
|
||||
return
|
||||
|
||||
def create(self, responders):
|
||||
"""Create CNAME record for a service.
|
||||
|
||||
:param responders: responders from providers
|
||||
:return dns_links: Map from provider urls to DNS urls
|
||||
"""
|
||||
# gather the provider urls and cname them
|
||||
links = {}
|
||||
for responder in responders:
|
||||
for provider_name in responder:
|
||||
if 'error' in responder[provider_name]:
|
||||
continue
|
||||
for link in responder[provider_name]['links']:
|
||||
if link['rel'] == 'access_url':
|
||||
links[link['domain']] = link['href']
|
||||
|
||||
# create CNAME records
|
||||
try:
|
||||
dns_links = self._create_cname_records(links)
|
||||
except Exception as e:
|
||||
error_msg = 'Rackspace DNS Exception: {0}'.format(e)
|
||||
LOG.error(error_msg)
|
||||
return self.responder.failed(error_msg)
|
||||
|
||||
# gather the CNAMED links
|
||||
dns_details = {}
|
||||
for responder in responders:
|
||||
for provider_name in responder:
|
||||
if 'error' in responder[provider_name]:
|
||||
continue
|
||||
access_urls = []
|
||||
for link in responder[provider_name]['links']:
|
||||
if link['rel'] == 'access_url':
|
||||
access_url = {
|
||||
'domain': link['domain'],
|
||||
'provider_url': link['href'],
|
||||
'operator_url': dns_links[link['href']]}
|
||||
access_urls.append(access_url)
|
||||
dns_details[provider_name] = {'access_urls': access_urls}
|
||||
return self.responder.created(dns_details)
|
||||
|
||||
def delete(self, provider_details):
|
||||
"""Delete CNAME records for a service.
|
||||
|
||||
:param provider_details
|
||||
:return dns_details: Map from provider_name to delete errors
|
||||
"""
|
||||
|
||||
dns_details = {}
|
||||
for provider_name in provider_details:
|
||||
error_msg = ''
|
||||
access_urls = provider_details[provider_name].access_urls
|
||||
for access_url in access_urls:
|
||||
try:
|
||||
msg = self._delete_cname_record(access_url['operator_url'])
|
||||
if msg:
|
||||
error_msg = error_msg + msg
|
||||
except exc.NotFound as e:
|
||||
LOG.error('Can not access the subdomain. Please make sure'
|
||||
' it exists and you have permissions to CDN '
|
||||
'subdomain {0}'.format(e))
|
||||
error_msg = (error_msg + 'Can not access subdomain . '
|
||||
'Exception: {0}'.format(e))
|
||||
except Exception as e:
|
||||
LOG.error('Exception: {0}'.format(e))
|
||||
error_msg = error_msg + 'Exception: {0}'.format(e)
|
||||
# format the error or success message for this provider
|
||||
if error_msg:
|
||||
dns_details[provider_name] = self.responder.failed(error_msg)
|
||||
else:
|
||||
dns_details[provider_name] = self.responder.deleted({})
|
||||
return dns_details
|
||||
|
||||
def _update_added_domains(self, responders, added_domains):
|
||||
"""Update added domains."""
|
||||
|
||||
# if no domains are added, return
|
||||
dns_details = {}
|
||||
if not added_domains:
|
||||
for responder in responders:
|
||||
for provider_name in responder:
|
||||
dns_details[provider_name] = {'access_urls': {}}
|
||||
return dns_details
|
||||
|
||||
# gather the provider links for the added domains
|
||||
links = {}
|
||||
for responder in responders:
|
||||
for provider_name in responder:
|
||||
if 'error' in responder[provider_name]:
|
||||
continue
|
||||
for link in responder[provider_name]['links']:
|
||||
domain_added = (link['rel'] == 'access_url' and
|
||||
link['domain'] in added_domains)
|
||||
if domain_added:
|
||||
links[link['domain']] = link['href']
|
||||
|
||||
# create CNAME records for added domains
|
||||
try:
|
||||
dns_links = self._create_cname_records(links)
|
||||
except Exception as e:
|
||||
error_msg = 'Rackspace DNS Exception: {0}'.format(e)
|
||||
LOG.error(error_msg)
|
||||
return self.responder.failed(error_msg)
|
||||
|
||||
# gather the CNAMED links for added domains
|
||||
for responder in responders:
|
||||
for provider_name in responder:
|
||||
if 'error' in responder[provider_name]:
|
||||
continue
|
||||
access_urls = {}
|
||||
for link in responder[provider_name]['links']:
|
||||
if link['domain'] in added_domains:
|
||||
access_urls[link['href']] = dns_links[link['href']]
|
||||
dns_details[provider_name] = {'access_urls': access_urls}
|
||||
return dns_details
|
||||
|
||||
def _update_removed_domains(self, provider_details, removed_domains):
|
||||
"""Update removed domains."""
|
||||
|
||||
# if no domains are removed, return
|
||||
dns_details = {}
|
||||
if not removed_domains:
|
||||
for provider_name in provider_details:
|
||||
dns_details[provider_name] = {'access_urls': {}}
|
||||
return dns_details
|
||||
|
||||
# delete the records for deleted domains
|
||||
for provider_name in provider_details:
|
||||
error_msg = ''
|
||||
provider_detail = provider_details[provider_name]
|
||||
for access_url in provider_detail.access_urls:
|
||||
if access_url['domain'] not in removed_domains:
|
||||
continue
|
||||
try:
|
||||
msg = self._delete_cname_record(access_url['operator_url'])
|
||||
if msg:
|
||||
error_msg = error_msg + msg
|
||||
except exc.NotFound as e:
|
||||
LOG.error('Can not access the subdomain. Please make sure'
|
||||
' it exists and you have permissions to CDN '
|
||||
'subdomain {0}'.format(e))
|
||||
error_msg = (error_msg + 'Can not access subdomain. '
|
||||
'Exception: {0}'.format(e))
|
||||
except Exception as e:
|
||||
LOG.error('Exception: {0}'.format(e))
|
||||
error_msg = error_msg + 'Exception: {0}'.format(e)
|
||||
# format the error or success message for this provider
|
||||
if error_msg:
|
||||
dns_details[provider_name] = self.responder.failed(error_msg)
|
||||
else:
|
||||
dns_details[provider_name] = self.responder.deleted({})
|
||||
return dns_details
|
||||
|
||||
def update(self, service_old, service_updates, responders):
|
||||
"""Update CNAME records for a service.
|
||||
|
||||
:param service_old: previous service state
|
||||
:param service_updates: updates to service state
|
||||
:param responders: responders from providers
|
||||
|
||||
:return dns_details: Map from provider_name to update errors
|
||||
"""
|
||||
|
||||
# get old domains
|
||||
old_domains = sets.Set()
|
||||
old_access_urls_map = {}
|
||||
provider_details = service_old.provider_details
|
||||
for provider_name in provider_details:
|
||||
provider_detail = provider_details[provider_name]
|
||||
access_urls = provider_detail.access_urls
|
||||
old_access_urls_map[provider_name] = {'access_urls': access_urls}
|
||||
for access_url in access_urls:
|
||||
old_domains.add(access_url['domain'])
|
||||
|
||||
# get new_domains
|
||||
new_domains = sets.Set()
|
||||
for responder in responders:
|
||||
for provider_name in responder:
|
||||
links = responder[provider_name]['links']
|
||||
for link in links:
|
||||
new_domains.add(link['domain'])
|
||||
|
||||
# if domains have not been updated, return
|
||||
if not service_updates.domains:
|
||||
return old_access_urls_map
|
||||
|
||||
# if the old set of domains is the same as new set of domains, return
|
||||
if old_domains == new_domains:
|
||||
return old_access_urls_map
|
||||
|
||||
# get the list of added, removed and common domains
|
||||
added_domains = new_domains.difference(old_domains)
|
||||
removed_domains = old_domains.difference(new_domains)
|
||||
common_domains = new_domains.intersection(old_domains)
|
||||
|
||||
# add new domains
|
||||
dns_links = self._update_added_domains(responders, added_domains)
|
||||
|
||||
# remove CNAME records for deleted domains
|
||||
provider_details = service_old.provider_details
|
||||
self._update_removed_domains(provider_details, removed_domains)
|
||||
|
||||
# gather the CNAMED links and remove stale links
|
||||
dns_details = {}
|
||||
for responder in responders:
|
||||
for provider_name in responder:
|
||||
if 'error' in responder[provider_name]:
|
||||
continue
|
||||
provider_detail = service_old.provider_details[provider_name]
|
||||
old_access_urls = provider_detail.access_urls
|
||||
operator_urls = dns_links[provider_name]['access_urls']
|
||||
access_urls = []
|
||||
for link in responder[provider_name]['links']:
|
||||
if link['domain'] in removed_domains:
|
||||
continue
|
||||
elif link['domain'] in added_domains:
|
||||
operator_url = operator_urls[link['href']]
|
||||
access_url = {
|
||||
'domain': link['domain'],
|
||||
'provider_url': link['href'],
|
||||
'operator_url': operator_url}
|
||||
access_urls.append(access_url)
|
||||
elif link['domain'] in common_domains:
|
||||
# iterate through old access urls and get access url
|
||||
operator_url = None
|
||||
for old_access_url in old_access_urls:
|
||||
if old_access_url['domain'] == link['domain']:
|
||||
operator_url = old_access_url['operator_url']
|
||||
break
|
||||
access_url = {
|
||||
'domain': link['domain'],
|
||||
'provider_url': link['href'],
|
||||
'operator_url': operator_url}
|
||||
access_urls.append(access_url)
|
||||
dns_details[provider_name] = {'access_urls': access_urls}
|
||||
|
||||
return self.responder.updated(dns_details)
|
||||
|
|
|
@ -29,29 +29,34 @@ def service_create_worker(providers_list, service_controller,
|
|||
service_obj)
|
||||
responders.append(responder)
|
||||
|
||||
# create dns mapping
|
||||
dns = service_controller.dns_controller
|
||||
dns_responder = dns.create(responders)
|
||||
|
||||
provider_details_dict = {}
|
||||
for responder in responders:
|
||||
for provider_name in responder:
|
||||
if 'error' not in responder[provider_name]:
|
||||
if 'error' in responder[provider_name]:
|
||||
error_info = responder[provider_name]['error_detail']
|
||||
provider_details_dict[provider_name] = (
|
||||
provider_details.ProviderDetail(error_info=error_info))
|
||||
provider_details_dict[provider_name].status = 'failed'
|
||||
elif 'error' in dns_responder[provider_name]:
|
||||
error_info = dns_responder[provider_name]['error_detail']
|
||||
provider_details_dict[provider_name] = (
|
||||
provider_details.ProviderDetail(error_info=error_info))
|
||||
provider_details_dict[provider_name].status = 'failed'
|
||||
else:
|
||||
access_urls = dns_responder[provider_name]['access_urls']
|
||||
provider_details_dict[provider_name] = (
|
||||
provider_details.ProviderDetail(
|
||||
provider_service_id=responder[provider_name]['id'],
|
||||
access_urls=[link['href'] for link in
|
||||
responder[provider_name]['links']])
|
||||
)
|
||||
access_urls=access_urls))
|
||||
if 'status' in responder[provider_name]:
|
||||
provider_details_dict[provider_name].status = (
|
||||
responder[provider_name]['status'])
|
||||
else:
|
||||
provider_details_dict[provider_name].status = (
|
||||
'deployed')
|
||||
else:
|
||||
provider_details_dict[provider_name] = (
|
||||
provider_details.ProviderDetail(
|
||||
error_info=responder[provider_name]['error_detail']
|
||||
)
|
||||
)
|
||||
provider_details_dict[provider_name].status = 'failed'
|
||||
provider_details_dict[provider_name].status = 'deployed'
|
||||
|
||||
service_controller.storage_controller.update_provider_details(
|
||||
project_id,
|
||||
|
|
|
@ -31,6 +31,9 @@ def service_delete_worker(provider_details, service_controller,
|
|||
responders.append(responder)
|
||||
LOG.info('Deleting service from %s complete...' % provider)
|
||||
|
||||
# delete associated cname records from DNS
|
||||
dns_responder = service_controller.dns_controller.delete(provider_details)
|
||||
|
||||
for responder in responders:
|
||||
# this is the item of responder, if there's "error"
|
||||
# key in it, it means the deletion for this provider failed.
|
||||
|
@ -43,13 +46,19 @@ def service_delete_worker(provider_details, service_controller,
|
|||
(provider_name, service_name))
|
||||
# stores the error info for debugging purposes.
|
||||
provider_details[provider_name].error_info = (
|
||||
responder[provider_name].get('error_info')
|
||||
)
|
||||
responder[provider_name].get('error_info'))
|
||||
elif 'error' in dns_responder[provider_name]:
|
||||
LOG.info('Delete service from DNS failed')
|
||||
LOG.info('Updating provider detail status of %s for %s'.foramt(
|
||||
(provider_name, service_name)))
|
||||
# stores the error info for debugging purposes.
|
||||
provider_details[provider_name].error_info = (
|
||||
dns_responder[provider_name].get('error_info'))
|
||||
else:
|
||||
# delete service successful, remove this provider detail record
|
||||
del provider_details[provider_name]
|
||||
|
||||
service_controller.storage_controller._driver.connect()
|
||||
service_controller.storage_controller._driver.connect()
|
||||
if provider_details == {}:
|
||||
# Only if all provider successfully deleted we can delete
|
||||
# the poppy service.
|
||||
|
@ -65,4 +74,4 @@ def service_delete_worker(provider_details, service_controller,
|
|||
service_controller.storage_controller.update_provider_details(
|
||||
project_id,
|
||||
service_name,
|
||||
provider_details)
|
||||
provider_details)
|
||||
|
|
|
@ -32,17 +32,20 @@ def update_worker(service_controller, project_id, service_name,
|
|||
responders.append(responder)
|
||||
LOG.info(u'Updating service from {0} complete'.format(provider))
|
||||
|
||||
# create dns mapping
|
||||
dns = service_controller.dns_controller
|
||||
dns_responder = dns.update(service_old, service_updates, responders)
|
||||
|
||||
# gather links and status for service from providers
|
||||
provider_details_dict = {}
|
||||
for responder in responders:
|
||||
for provider_name in responder:
|
||||
if 'error' not in responder[provider_name]:
|
||||
access_urls = dns_responder[provider_name]['access_urls']
|
||||
provider_details_dict[provider_name] = (
|
||||
provider_details.ProviderDetail(
|
||||
provider_service_id=responder[provider_name]['id'],
|
||||
access_urls=[link['href'] for link in
|
||||
responder[provider_name]['links']])
|
||||
)
|
||||
access_urls=access_urls))
|
||||
if 'status' in responder[provider_name]:
|
||||
provider_details_dict[provider_name].status = (
|
||||
responder[provider_name]['status'])
|
||||
|
|
|
@ -32,6 +32,7 @@ class DefaultServicesController(base.ServicesController):
|
|||
|
||||
self.storage_controller = self._driver.storage.services_controller
|
||||
self.flavor_controller = self._driver.storage.flavors_controller
|
||||
self.dns_controller = self._driver.dns.services_controller
|
||||
|
||||
def _get_provider_details(self, project_id, service_name):
|
||||
try:
|
||||
|
@ -86,6 +87,7 @@ class DefaultServicesController(base.ServicesController):
|
|||
raise e
|
||||
|
||||
self.storage_controller._driver.close_connection()
|
||||
|
||||
p = multiprocessing.Process(
|
||||
name='Process: create poppy service %s for'
|
||||
' project id: %s' %
|
||||
|
@ -141,6 +143,7 @@ class DefaultServicesController(base.ServicesController):
|
|||
provider_details)
|
||||
|
||||
self.storage_controller._driver.close_connection()
|
||||
|
||||
p = multiprocessing.Process(
|
||||
name=('Process: update poppy service {0} for project id: {1}'
|
||||
.format(service_name, project_id)),
|
||||
|
@ -172,6 +175,7 @@ class DefaultServicesController(base.ServicesController):
|
|||
provider_details)
|
||||
|
||||
self.storage_controller._driver.close_connection()
|
||||
|
||||
p = multiprocessing.Process(
|
||||
name='Process: delete poppy service %s for'
|
||||
' project id: %s' %
|
||||
|
@ -184,6 +188,7 @@ class DefaultServicesController(base.ServicesController):
|
|||
project_id,
|
||||
service_name))
|
||||
p.start()
|
||||
|
||||
return
|
||||
|
||||
def purge(self, project_id, service_name, purge_url=None):
|
||||
|
|
|
@ -26,7 +26,7 @@ class ProviderDetail(object):
|
|||
|
||||
"""ProviderDetail object for each provider."""
|
||||
|
||||
def __init__(self, provider_service_id=None, access_urls=[],
|
||||
def __init__(self, provider_service_id=None, access_urls={},
|
||||
status=u"deploy_in_progress", name=None, error_info=None):
|
||||
self._provider_service_id = provider_service_id
|
||||
self._id = provider_service_id
|
||||
|
@ -44,14 +44,14 @@ class ProviderDetail(object):
|
|||
def provider_service_id(self, value):
|
||||
self._provider_service_id = value
|
||||
|
||||
@property
|
||||
def access_urls(self):
|
||||
return self._access_urls
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def access_urls(self):
|
||||
return self._access_urls
|
||||
|
||||
@access_urls.setter
|
||||
def access_urls(self, value):
|
||||
self._access_urls = value
|
||||
|
|
|
@ -98,7 +98,8 @@ class ServiceController(base.ServiceBase):
|
|||
LOG.info('Creating policy %s on domain %s complete' %
|
||||
(dp, ','.join(classified_domain)))
|
||||
links.append({'href': self.driver.akamai_access_url_link,
|
||||
"rel": 'access_url'
|
||||
'rel': 'access_url',
|
||||
'domain': service_obj.name
|
||||
})
|
||||
except Exception:
|
||||
return self.responder.failed("failed to create service")
|
||||
|
@ -279,7 +280,8 @@ class ServiceController(base.ServiceBase):
|
|||
LOG.info('Creating/Updateing policy %s on domain %s '
|
||||
'complete' % (dp, ','.join(classified_domain)))
|
||||
links.append({'href': self.driver.akamai_access_url_link,
|
||||
'rel': 'access_url'
|
||||
'rel': 'access_url',
|
||||
'domain': service_obj.name
|
||||
})
|
||||
except Exception:
|
||||
return self.responder.failed("failed to update service")
|
||||
|
@ -348,7 +350,9 @@ class ServiceController(base.ServiceBase):
|
|||
return self.responder.failed("failed to update service")
|
||||
ids = policies
|
||||
links.append({'href': self.driver.akamai_access_url_link,
|
||||
'rel': 'access_url'})
|
||||
'rel': 'access_url',
|
||||
'domain': service_obj.name
|
||||
})
|
||||
return self.responder.updated(json.dumps(ids), links)
|
||||
|
||||
def delete(self, provider_service_id):
|
||||
|
|
|
@ -50,7 +50,8 @@ class ServiceController(base.ServiceBase):
|
|||
service_version.number)
|
||||
links = [{"href": '.'.join([domain_check.domain.name,
|
||||
"global.prod.fastly.net"]),
|
||||
"rel": 'access_url'}
|
||||
"rel": 'access_url',
|
||||
"domain": domain_check.domain.name}
|
||||
for domain_check in domain_checks]
|
||||
|
||||
for origin in service_obj.origins:
|
||||
|
|
|
@ -37,6 +37,7 @@ class ServiceController(base.ServiceBase):
|
|||
service_id = uuid.uuid1()
|
||||
return self.responder.created(str(service_id), [{
|
||||
"href": "www.mysite.com",
|
||||
"domain": "www.mydomain.com",
|
||||
'rel': "access_url"}])
|
||||
|
||||
def delete(self, provider_service_id):
|
||||
|
|
|
@ -293,7 +293,7 @@ class ServicesController(base.ServicesController):
|
|||
provider_detail_dict = json.loads(
|
||||
provider_details_result[provider_name])
|
||||
provider_service_id = provider_detail_dict.get('id', None)
|
||||
access_urls = provider_detail_dict.get("access_urls", None)
|
||||
access_urls = provider_detail_dict.get("access_urls", [])
|
||||
status = provider_detail_dict.get("status", u'creating')
|
||||
error_info = provider_detail_dict.get("error_info", None)
|
||||
provider_detail_obj = provider_details.ProviderDetail(
|
||||
|
|
|
@ -37,16 +37,17 @@ class ServicesController(base.ServicesController):
|
|||
provider_details = {
|
||||
'MaxCDN': json.dumps(
|
||||
{'id': 11942,
|
||||
'access_urls': ['mypullzone.netdata.com']}),
|
||||
'access_urls': [{'operator_url': 'mypullzone.netdata.com'}]}),
|
||||
'Mock': json.dumps(
|
||||
{'id': 73242,
|
||||
'access_urls': ['mycdn.mock.com']}),
|
||||
'access_urls': [{'operator_url': 'mycdn.mock.com'}]}),
|
||||
'CloudFront': json.dumps(
|
||||
{'id': '5ABC892',
|
||||
'access_urls': ['cf123.cloudcf.com']}),
|
||||
'access_urls': [{'operator_url': 'cf123.cloudcf.com'}]}),
|
||||
'Fastly': json.dumps(
|
||||
{'id': 3488,
|
||||
'access_urls': ['mockcf123.fastly.prod.com']})}
|
||||
'access_urls':
|
||||
[{'operator_url': 'mockcf123.fastly.prod.com'}]})}
|
||||
|
||||
services = [{'name': 'mockdb1_service_name',
|
||||
'domains': [json.dumps({'domain': 'www.mywebsite.com'})],
|
||||
|
@ -88,16 +89,17 @@ class ServicesController(base.ServicesController):
|
|||
provider_details = {
|
||||
'MaxCDN': json.dumps(
|
||||
{'id': 11942,
|
||||
'access_urls': ['mypullzone.netdata.com']}),
|
||||
'access_urls': [{'operator_url': 'mypullzone.netdata.com'}]}),
|
||||
'Mock': json.dumps(
|
||||
{'id': 73242,
|
||||
'access_urls': ['mycdn.mock.com']}),
|
||||
'access_urls': [{'operator_url': 'mycdn.mock.com'}]}),
|
||||
'CloudFront': json.dumps(
|
||||
{'id': '5ABC892',
|
||||
'access_urls': ['cf123.cloudcf.com']}),
|
||||
'access_urls': [{'operator_url': 'cf123.cloudcf.com'}]}),
|
||||
'Fastly': json.dumps(
|
||||
{'id': 3488,
|
||||
'access_urls': ['mockcf123.fastly.prod.com']})}
|
||||
'access_urls':
|
||||
[{'operator_url': 'mockcf123.fastly.prod.com'}]})}
|
||||
|
||||
service_dict = {'name': service_name,
|
||||
'domains': [domain_json],
|
||||
|
|
|
@ -49,10 +49,10 @@ class Model(collections.OrderedDict):
|
|||
request.host_url,
|
||||
self['name']))),
|
||||
'self')]
|
||||
|
||||
for provider_name in service_obj.provider_details:
|
||||
for access_url in (
|
||||
service_obj.provider_details[provider_name].access_urls):
|
||||
provider_detail = service_obj.provider_details[provider_name]
|
||||
access_urls = provider_detail.access_urls
|
||||
for access_url in access_urls:
|
||||
self["links"].append(link.Model(
|
||||
access_url,
|
||||
access_url['operator_url'],
|
||||
'access_url'))
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
pyrax
|
|
@ -1,8 +1,9 @@
|
|||
[drivers]
|
||||
providers = mock,cloudfront,fastly
|
||||
providers = mock,maxcdn,cloudfront,fastly
|
||||
transport = pecan
|
||||
manager = default
|
||||
storage = mockdb
|
||||
dns = default
|
||||
|
||||
[drivers:storage:cassandra]
|
||||
cluster = "192.168.59.103"
|
||||
|
|
Loading…
Reference in New Issue