Switch service urls to use UUID instead of service name
This change makes services retrievable via serviceid instead of by servicename. This results in a more secure approach to getting services, reducing the attack surface. It also brings resources in line with other openstack services where resources are referenced with a uuid. Closes-Bug: 1404998 Change-Id: If9c7201e6d01a61aa7b8a3a1446e222d1f3f6c44
This commit is contained in:
parent
68561541c8
commit
6f90e793da
|
@ -24,5 +24,4 @@ sed -i -e "s/AKAM_SECURE_URL_LINK/$AKAM_SECURE_URL_LINK/" $CON
|
|||
sed -i -e "s/AKAM_HTTP_POLICY/$AKAM_HTTP_POLICY/" $CONFIG
|
||||
sed -i -e "s/AKAM_HTTPS_POLICY/$AKAM_HTTPS_POLICY/" $CONFIG
|
||||
|
||||
|
||||
/usr/local/bin/uwsgi --ini /root/uwsgi.ini
|
||||
|
|
|
@ -13,3 +13,4 @@ no-orphans = true
|
|||
vacuum = true
|
||||
module = poppy.transport.app:app
|
||||
py-auto-reload = 1
|
||||
virtualenv = /usr/
|
|
@ -3,7 +3,7 @@
|
|||
##
|
||||
##
|
||||
|
||||
FROM ubuntu
|
||||
FROM ubuntu:14.04
|
||||
MAINTAINER Tony Tan, tonytan198211@gmail.com
|
||||
|
||||
# Add PPA for the necessary JDK
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Dockerfile for Repose (www.openrepose.org)
|
||||
|
||||
FROM ubuntu
|
||||
FROM ubuntu:14.04
|
||||
|
||||
MAINTAINER Felix Sargent (felix.sargent@rackspace.com)
|
||||
|
||||
|
|
|
@ -42,11 +42,11 @@ class ServicesControllerBase(controller.ManagerControllerBase):
|
|||
raise NotImplementedError
|
||||
|
||||
@abc.abstractmethod
|
||||
def get(self, project_id, service_name):
|
||||
def get(self, project_id, service_id):
|
||||
"""GET
|
||||
|
||||
:param project_id
|
||||
:param service_name
|
||||
:param service_id
|
||||
:raises: NotImplementedError
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
@ -62,27 +62,27 @@ class ServicesControllerBase(controller.ManagerControllerBase):
|
|||
raise NotImplementedError
|
||||
|
||||
@abc.abstractmethod
|
||||
def update(self, project_id, service_name, service_obj):
|
||||
def update(self, project_id, service_id, service_obj):
|
||||
"""POST
|
||||
|
||||
:param project_id
|
||||
:param service_name
|
||||
:param service_id
|
||||
:param service_obj
|
||||
:raises: NotImplementedError
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abc.abstractmethod
|
||||
def delete(self, project_id, service_name):
|
||||
def delete(self, project_id, service_id):
|
||||
"""DELETE
|
||||
|
||||
:param project_id
|
||||
:param service_name
|
||||
:param service_id
|
||||
:raises: NotImplementedError
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abc.abstractmethod
|
||||
def purge(self, project_id, service_name, purge_url=None):
|
||||
def purge(self, project_id, service_id, purge_url=None):
|
||||
'''If purge_url is none, all content of this service will be purge.'''
|
||||
raise NotImplementedError
|
||||
|
|
|
@ -32,7 +32,7 @@ conf(project='poppy', prog='poppy', args=[])
|
|||
|
||||
|
||||
def service_create_worker(providers_list_json,
|
||||
project_id, service_name, service_obj_json):
|
||||
project_id, service_id, service_obj_json):
|
||||
LOG.logger.setLevel(logging.INFO)
|
||||
bootstrap_obj = bootstrap.Bootstrap(conf)
|
||||
service_controller = bootstrap_obj.manager.services_controller
|
||||
|
@ -90,7 +90,7 @@ def service_create_worker(providers_list_json,
|
|||
|
||||
service_controller.storage_controller.update_provider_details(
|
||||
project_id,
|
||||
service_name,
|
||||
service_id,
|
||||
provider_details_dict)
|
||||
|
||||
service_controller.storage_controller._driver.close_connection()
|
||||
|
@ -106,14 +106,14 @@ if __name__ == '__main__':
|
|||
|
||||
parser.add_argument('providers_list_json', action="store")
|
||||
parser.add_argument('project_id', action="store")
|
||||
parser.add_argument('service_name', action="store")
|
||||
parser.add_argument('service_id', action="store")
|
||||
parser.add_argument('service_obj_json', action="store")
|
||||
|
||||
result = parser.parse_args()
|
||||
providers_list_json = result.providers_list_json
|
||||
project_id = result.project_id
|
||||
service_name = result.service_name
|
||||
service_id = result.service_id
|
||||
service_obj_json = result.service_obj_json
|
||||
LOG.logger.setLevel(logging.INFO)
|
||||
service_create_worker(providers_list_json, project_id,
|
||||
service_name, service_obj_json)
|
||||
service_id, service_obj_json)
|
||||
|
|
|
@ -32,7 +32,7 @@ conf(project='poppy', prog='poppy', args=[])
|
|||
|
||||
|
||||
def service_delete_worker(provider_details,
|
||||
project_id, service_name):
|
||||
project_id, service_id):
|
||||
LOG.logger.setLevel(logging.INFO)
|
||||
bootstrap_obj = bootstrap.Bootstrap(conf)
|
||||
service_controller = bootstrap_obj.manager.services_controller
|
||||
|
@ -60,14 +60,14 @@ def service_delete_worker(provider_details,
|
|||
if 'error' in responder[provider_name]:
|
||||
LOG.info('Delete service from %s failed' % provider_name)
|
||||
LOG.info('Updating provider detail status of %s for %s' %
|
||||
(provider_name, service_name))
|
||||
(provider_name, service_id))
|
||||
# stores the error info for debugging purposes.
|
||||
provider_details[provider_name].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'.format(
|
||||
(provider_name, service_name)))
|
||||
(provider_name, service_id)))
|
||||
# stores the error info for debugging purposes.
|
||||
provider_details[provider_name].error_info = (
|
||||
dns_responder[provider_name].get('error_info'))
|
||||
|
@ -82,19 +82,19 @@ def service_delete_worker(provider_details,
|
|||
# action, maybe for debug and/or support.
|
||||
LOG.info('Delete failed for one or more providers'
|
||||
'Updating poppy service provider details for %s' %
|
||||
service_name)
|
||||
service_id)
|
||||
service_controller.storage_controller.update_provider_details(
|
||||
project_id,
|
||||
service_name,
|
||||
service_id,
|
||||
provider_details)
|
||||
|
||||
# always delete from Poppy. Provider Details will contain
|
||||
# any provider issues that may have occurred.
|
||||
LOG.info('Deleting poppy service %s from all providers successful'
|
||||
% service_name)
|
||||
service_controller.storage_controller.delete(project_id, service_name)
|
||||
% service_id)
|
||||
service_controller.storage_controller.delete(project_id, service_id)
|
||||
service_controller.storage_controller._driver.close_connection()
|
||||
LOG.info('Deleting poppy service %s succeeded' % service_name)
|
||||
LOG.info('Deleting poppy service %s succeeded' % service_id)
|
||||
LOG.info('Delete service worker process %s complete...' %
|
||||
str(os.getpid()))
|
||||
|
||||
|
@ -107,10 +107,10 @@ if __name__ == '__main__':
|
|||
|
||||
parser.add_argument('provider_details', action="store")
|
||||
parser.add_argument('project_id', action="store")
|
||||
parser.add_argument('service_name', action="store")
|
||||
parser.add_argument('service_id', action="store")
|
||||
|
||||
result = parser.parse_args()
|
||||
provider_details = result.provider_details
|
||||
project_id = result.project_id
|
||||
service_name = result.service_name
|
||||
service_delete_worker(provider_details, project_id, service_name)
|
||||
service_id = result.service_id
|
||||
service_delete_worker(provider_details, project_id, service_id)
|
||||
|
|
|
@ -32,7 +32,7 @@ conf(project='poppy', prog='poppy', args=[])
|
|||
|
||||
|
||||
def service_purge_worker(provider_details,
|
||||
project_id, service_name, purge_url):
|
||||
project_id, service_id, purge_url):
|
||||
LOG.logger.setLevel(logging.INFO)
|
||||
bootstrap_obj = bootstrap.Bootstrap(conf)
|
||||
service_controller = bootstrap_obj.manager.services_controller
|
||||
|
@ -72,7 +72,7 @@ def service_purge_worker(provider_details,
|
|||
if 'error' in responder[provider_name]:
|
||||
LOG.info('Purging content from %s failed' % provider_name)
|
||||
LOG.info('Updating provider detail status of %s for %s' %
|
||||
(provider_name, service_name))
|
||||
(provider_name, service_id))
|
||||
# stores the error info for debugging purposes.
|
||||
changed_provider_details_dict[provider_name] = (
|
||||
provider_details[provider_name]
|
||||
|
@ -88,7 +88,7 @@ def service_purge_worker(provider_details,
|
|||
provider_details.update(changed_provider_details_dict)
|
||||
service_controller.storage_controller.update_provider_details(
|
||||
project_id,
|
||||
service_name,
|
||||
service_id,
|
||||
provider_details)
|
||||
|
||||
service_controller.storage_controller._driver.close_connection()
|
||||
|
@ -104,12 +104,12 @@ if __name__ == '__main__':
|
|||
|
||||
parser.add_argument('provider_details', action="store")
|
||||
parser.add_argument('project_id', action="store")
|
||||
parser.add_argument('service_name', action="store")
|
||||
parser.add_argument('service_id', action="store")
|
||||
parser.add_argument('purge_url', action="store")
|
||||
|
||||
result = parser.parse_args()
|
||||
provider_details = result.provider_details
|
||||
project_id = result.project_id
|
||||
service_name = result.service_name
|
||||
service_id = result.service_id
|
||||
purge_url = result.purge_url
|
||||
service_purge_worker(provider_details, project_id, service_name, purge_url)
|
||||
service_purge_worker(provider_details, project_id, service_id, purge_url)
|
||||
|
|
|
@ -30,7 +30,7 @@ conf = cfg.CONF
|
|||
conf(project='poppy', prog='poppy', args=[])
|
||||
|
||||
|
||||
def update_worker(project_id, service_name,
|
||||
def update_worker(project_id, service_id,
|
||||
service_old, service_updates, service_obj):
|
||||
LOG.logger.setLevel(logging.INFO)
|
||||
bootstrap_obj = bootstrap.Bootstrap(conf)
|
||||
|
@ -88,12 +88,12 @@ def update_worker(project_id, service_name,
|
|||
'deployed')
|
||||
|
||||
# update the service object
|
||||
service_controller.storage_controller.update(project_id, service_name,
|
||||
service_controller.storage_controller.update(project_id, service_id,
|
||||
service_obj)
|
||||
# update the provider details
|
||||
service_controller.storage_controller.update_provider_details(
|
||||
project_id,
|
||||
service_name,
|
||||
service_id,
|
||||
provider_details_dict)
|
||||
|
||||
service_controller.storage_controller._driver.close_connection()
|
||||
|
@ -108,16 +108,16 @@ if __name__ == '__main__':
|
|||
' script arg parser')
|
||||
|
||||
parser.add_argument('project_id', action="store")
|
||||
parser.add_argument('service_name', action="store")
|
||||
parser.add_argument('service_id', action="store")
|
||||
parser.add_argument('service_old', action="store")
|
||||
parser.add_argument('service_updates', action="store")
|
||||
parser.add_argument('service_obj', action="store")
|
||||
|
||||
result = parser.parse_args()
|
||||
project_id = result.project_id
|
||||
service_name = result.service_name
|
||||
service_id = result.service_id
|
||||
service_old = result.service_old
|
||||
service_updates = result.service_updates
|
||||
service_obj = result.service_obj
|
||||
update_worker(project_id, service_name, service_old, service_updates,
|
||||
update_worker(project_id, service_id, service_old, service_updates,
|
||||
service_obj)
|
||||
|
|
|
@ -32,6 +32,7 @@ LOG = log.getLogger(__name__)
|
|||
|
||||
|
||||
class DefaultServicesController(base.ServicesController):
|
||||
|
||||
"""Default Services Controller."""
|
||||
|
||||
def __init__(self, manager):
|
||||
|
@ -41,14 +42,14 @@ class DefaultServicesController(base.ServicesController):
|
|||
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):
|
||||
def _get_provider_details(self, project_id, service_id):
|
||||
try:
|
||||
provider_details = self.storage_controller.get_provider_details(
|
||||
project_id,
|
||||
service_name)
|
||||
service_id)
|
||||
except Exception:
|
||||
raise LookupError(u'Service {0} does not exist'.format(
|
||||
service_name))
|
||||
service_id))
|
||||
return provider_details
|
||||
|
||||
def list(self, project_id, marker=None, limit=None):
|
||||
|
@ -61,14 +62,14 @@ class DefaultServicesController(base.ServicesController):
|
|||
"""
|
||||
return self.storage_controller.list(project_id, marker, limit)
|
||||
|
||||
def get(self, project_id, service_name):
|
||||
def get(self, project_id, service_id):
|
||||
"""get.
|
||||
|
||||
:param project_id
|
||||
:param service_name
|
||||
:param service_id
|
||||
:return controller
|
||||
"""
|
||||
return self.storage_controller.get(project_id, service_name)
|
||||
return self.storage_controller.get(project_id, service_id)
|
||||
|
||||
def create(self, project_id, service_obj):
|
||||
"""create.
|
||||
|
@ -83,7 +84,7 @@ class DefaultServicesController(base.ServicesController):
|
|||
except LookupError as e:
|
||||
raise e
|
||||
providers = [p.provider_id for p in flavor.providers]
|
||||
service_name = service_obj.name
|
||||
service_id = service_obj.service_id
|
||||
|
||||
try:
|
||||
self.storage_controller.create(
|
||||
|
@ -107,7 +108,7 @@ class DefaultServicesController(base.ServicesController):
|
|||
proxy_path,
|
||||
script_path,
|
||||
json.dumps(providers),
|
||||
project_id, service_name,
|
||||
project_id, service_id,
|
||||
json.dumps(service_obj.to_dict())]
|
||||
LOG.info('Starting create service subprocess: %s' % cmd_list)
|
||||
p = subprocess.Popen(cmd_list, env=os.environ.copy())
|
||||
|
@ -115,18 +116,18 @@ class DefaultServicesController(base.ServicesController):
|
|||
|
||||
return
|
||||
|
||||
def update(self, project_id, service_name, service_updates):
|
||||
def update(self, project_id, service_id, service_updates):
|
||||
"""update.
|
||||
|
||||
:param project_id
|
||||
:param service_name
|
||||
:param service_id
|
||||
:param service_updates
|
||||
"""
|
||||
# get the current service object
|
||||
service_old = self.storage_controller.get(project_id, service_name)
|
||||
service_old = self.storage_controller.get(project_id, service_id)
|
||||
if service_old.status != u'deployed':
|
||||
raise errors.ServiceStatusNotDeployed(
|
||||
u'Service {0} not deployed'.format(service_name))
|
||||
u'Service {0} not deployed'.format(service_id))
|
||||
|
||||
service_obj = copy.deepcopy(service_old)
|
||||
|
||||
|
@ -145,14 +146,14 @@ class DefaultServicesController(base.ServicesController):
|
|||
raise Exception(u'Currently this operation is not supported')
|
||||
|
||||
# get provider details for this service
|
||||
provider_details = self._get_provider_details(project_id, service_name)
|
||||
provider_details = self._get_provider_details(project_id, service_id)
|
||||
|
||||
# set status in provider details to u'update_in_progress'
|
||||
for provider in provider_details:
|
||||
provider_details[provider].status = u'update_in_progress'
|
||||
self.storage_controller.update_provider_details(
|
||||
project_id,
|
||||
service_name,
|
||||
service_id,
|
||||
provider_details)
|
||||
|
||||
proxy_path = os.path.join(os.path.dirname(os.path.abspath(__file__)),
|
||||
|
@ -168,7 +169,7 @@ class DefaultServicesController(base.ServicesController):
|
|||
cmd_list = [executable,
|
||||
proxy_path,
|
||||
script_path,
|
||||
project_id, service_name,
|
||||
project_id, service_id,
|
||||
json.dumps(service_old.to_dict()),
|
||||
json.dumps(service_updates.to_dict()),
|
||||
json.dumps(service_obj.to_dict())]
|
||||
|
@ -178,14 +179,14 @@ class DefaultServicesController(base.ServicesController):
|
|||
|
||||
return
|
||||
|
||||
def delete(self, project_id, service_name):
|
||||
def delete(self, project_id, service_id):
|
||||
"""delete.
|
||||
|
||||
:param project_id
|
||||
:param service_name
|
||||
:param service_id
|
||||
:raises LookupError
|
||||
"""
|
||||
provider_details = self._get_provider_details(project_id, service_name)
|
||||
provider_details = self._get_provider_details(project_id, service_id)
|
||||
|
||||
# change each provider detail's status to delete_in_progress
|
||||
# TODO(tonytan4ever): what if this provider is in 'failed' status?
|
||||
|
@ -195,7 +196,7 @@ class DefaultServicesController(base.ServicesController):
|
|||
|
||||
self.storage_controller.update_provider_details(
|
||||
project_id,
|
||||
service_name,
|
||||
service_id,
|
||||
provider_details)
|
||||
|
||||
proxy_path = os.path.join(os.path.dirname(os.path.abspath(__file__)),
|
||||
|
@ -213,16 +214,16 @@ class DefaultServicesController(base.ServicesController):
|
|||
script_path,
|
||||
json.dumps(dict([(k, v.to_dict())
|
||||
for k, v in provider_details.items()])),
|
||||
project_id, service_name]
|
||||
project_id, service_id]
|
||||
LOG.info('Starting delete service subprocess: %s' % cmd_list)
|
||||
p = subprocess.Popen(cmd_list, env=os.environ.copy())
|
||||
p.communicate()
|
||||
|
||||
return
|
||||
|
||||
def purge(self, project_id, service_name, purge_url=None):
|
||||
def purge(self, project_id, service_id, purge_url=None):
|
||||
'''If purge_url is none, all content of this service will be purge.'''
|
||||
provider_details = self._get_provider_details(project_id, service_name)
|
||||
provider_details = self._get_provider_details(project_id, service_id)
|
||||
|
||||
# possible validation of purge url here...
|
||||
proxy_path = os.path.join(os.path.dirname(os.path.abspath(__file__)),
|
||||
|
@ -240,7 +241,7 @@ class DefaultServicesController(base.ServicesController):
|
|||
script_path,
|
||||
json.dumps(dict([(k, v.to_dict())
|
||||
for k, v in provider_details.items()])),
|
||||
project_id, service_name,
|
||||
project_id, service_id,
|
||||
str(purge_url)]
|
||||
|
||||
LOG.info('Starting purge service subprocess: %s' % cmd_list)
|
||||
|
|
|
@ -60,6 +60,22 @@ class CachingRule(common.DictSerializableModel):
|
|||
"""
|
||||
self._rules = value
|
||||
|
||||
@classmethod
|
||||
def init_from_dict(cls, dict_obj):
|
||||
"""Construct a model instance from a dictionary.
|
||||
|
||||
This serves as a 2nd constructor
|
||||
|
||||
:param dict_obj: dictionary object
|
||||
:returns o
|
||||
"""
|
||||
o = cls(
|
||||
dict_obj.get("name", "unnamed"),
|
||||
dict_obj.get("ttl", 0),
|
||||
dict_obj.get("rules", [])
|
||||
)
|
||||
return o
|
||||
|
||||
def to_dict(self):
|
||||
result = common.DictSerializableModel.to_dict(self)
|
||||
# need to deserialize the nested rules object
|
||||
|
|
|
@ -17,6 +17,7 @@ from poppy.model import common
|
|||
|
||||
|
||||
class Restriction(common.DictSerializableModel):
|
||||
|
||||
"""Restriction."""
|
||||
|
||||
def __init__(self, name, rules=[]):
|
||||
|
@ -43,6 +44,21 @@ class Restriction(common.DictSerializableModel):
|
|||
def rules(self, value):
|
||||
self._rules = value
|
||||
|
||||
@classmethod
|
||||
def init_from_dict(cls, dict_obj):
|
||||
"""Construct a model instance from a dictionary.
|
||||
|
||||
This serves as a 2nd constructor
|
||||
|
||||
:param dict_obj: dictionary object
|
||||
:returns o
|
||||
"""
|
||||
o = cls(
|
||||
dict_obj.get("name", "unnamed"),
|
||||
dict_obj.get("rules", [])
|
||||
)
|
||||
return o
|
||||
|
||||
def to_dict(self):
|
||||
result = common.DictSerializableModel.to_dict(self)
|
||||
# need to deserialize the nested rules object
|
||||
|
|
|
@ -12,10 +12,13 @@
|
|||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
import uuid
|
||||
|
||||
from poppy.model import common
|
||||
from poppy.model.helpers import cachingrule
|
||||
from poppy.model.helpers import domain
|
||||
from poppy.model.helpers import origin
|
||||
from poppy.model.helpers import restriction
|
||||
|
||||
|
||||
VALID_STATUSES = [u'create_in_progress', u'deployed', u'update_in_progress',
|
||||
|
@ -27,12 +30,14 @@ class Service(common.DictSerializableModel):
|
|||
"""Service Class."""
|
||||
|
||||
def __init__(self,
|
||||
service_id,
|
||||
name,
|
||||
domains,
|
||||
origins,
|
||||
flavor_id,
|
||||
caching=[],
|
||||
restrictions=[]):
|
||||
self._service_id = str(service_id)
|
||||
self._name = name
|
||||
self._domains = domains
|
||||
self._origins = origins
|
||||
|
@ -42,6 +47,15 @@ class Service(common.DictSerializableModel):
|
|||
self._status = 'create_in_progress'
|
||||
self._provider_details = {}
|
||||
|
||||
@property
|
||||
def service_id(self):
|
||||
"""Get service id."""
|
||||
return self._service_id
|
||||
|
||||
@service_id.setter
|
||||
def service_id(self, value):
|
||||
self._service_id = value
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Get or set name."""
|
||||
|
@ -159,13 +173,23 @@ class Service(common.DictSerializableModel):
|
|||
When converting a model into a request model,
|
||||
use to_dict.
|
||||
"""
|
||||
o = cls('unnamed', [], [], 'unnamed')
|
||||
o = cls(service_id=uuid.uuid4(), name='unnamed',
|
||||
domains=[], origins=[], flavor_id='unnamed')
|
||||
domains = input_dict.get('domains', [])
|
||||
input_dict['domains'] = [domain.Domain.init_from_dict(d)
|
||||
for d in domains]
|
||||
origins = input_dict.get('origins', [])
|
||||
input_dict['origins'] = [origin.Origin.init_from_dict(og)
|
||||
for og in origins]
|
||||
|
||||
caching_rules = input_dict.get('caching', [])
|
||||
input_dict['caching'] = [cachingrule.CachingRule.init_from_dict(cr)
|
||||
for cr in caching_rules]
|
||||
|
||||
restrictions = input_dict.get('restrictions', [])
|
||||
input_dict['restrictions'] = [restriction.Restriction.init_from_dict(r)
|
||||
for r in restrictions]
|
||||
|
||||
o.from_dict(input_dict)
|
||||
return o
|
||||
|
||||
|
|
|
@ -39,33 +39,33 @@ class ServicesControllerBase(controller.StorageControllerBase):
|
|||
raise NotImplementedError
|
||||
|
||||
@abc.abstractmethod
|
||||
def create(self, project_id, service_name, service_json):
|
||||
def create(self, project_id, service_id, service_json):
|
||||
"""create
|
||||
|
||||
:param project_id
|
||||
:param service_name
|
||||
:param service_id
|
||||
:param service_json
|
||||
:raise NotImplementedError
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abc.abstractmethod
|
||||
def update(self, project_id, service_name, service_json):
|
||||
def update(self, project_id, service_id, service_json):
|
||||
"""update
|
||||
|
||||
:param project_id
|
||||
:param service_name
|
||||
:param service_id
|
||||
:param service_json
|
||||
:raise NotImplementedError
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abc.abstractmethod
|
||||
def delete(self, project_id, service_name):
|
||||
def delete(self, project_id, service_id):
|
||||
"""delete
|
||||
|
||||
:param project_id
|
||||
:param service_name
|
||||
:param service_id
|
||||
:raise NotImplementedError
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
@ -79,11 +79,11 @@ class ServicesControllerBase(controller.StorageControllerBase):
|
|||
raise NotImplementedError
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_provider_details(self, project_id, service_name):
|
||||
def get_provider_details(self, project_id, service_id):
|
||||
"""get_provider_details
|
||||
|
||||
:param project_id
|
||||
:param service_name
|
||||
:param service_id
|
||||
:raise NotImplementedError
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
|
|
@ -3,6 +3,7 @@ USE poppy;
|
|||
|
||||
CREATE TABLE services (
|
||||
project_id VARCHAR,
|
||||
service_id UUID,
|
||||
service_name VARCHAR,
|
||||
flavor_id VARCHAR,
|
||||
domains LIST<TEXT>,
|
||||
|
@ -10,11 +11,19 @@ CREATE TABLE services (
|
|||
caching_rules LIST<TEXT>,
|
||||
restrictions LIST<TEXT>,
|
||||
provider_details MAP<TEXT, TEXT>,
|
||||
PRIMARY KEY (project_id, service_name)
|
||||
PRIMARY KEY (project_id, service_id)
|
||||
);
|
||||
|
||||
CREATE TABLE domain_names (
|
||||
project_id VARCHAR,
|
||||
service_id UUID,
|
||||
domain_name VARCHAR,
|
||||
PRIMARY KEY (domain_name)
|
||||
);
|
||||
|
||||
CREATE TABLE archives (
|
||||
project_id VARCHAR,
|
||||
service_id UUID,
|
||||
service_name VARCHAR,
|
||||
flavor_id VARCHAR,
|
||||
domains LIST<TEXT>,
|
||||
|
@ -23,7 +32,7 @@ CREATE TABLE archives (
|
|||
restrictions LIST<TEXT>,
|
||||
provider_details MAP<TEXT, TEXT>,
|
||||
archived_time timestamp,
|
||||
PRIMARY KEY (project_id, service_name, archived_time)
|
||||
PRIMARY KEY (project_id, service_id, archived_time)
|
||||
);
|
||||
|
||||
CREATE TABLE flavors (
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
schema_statements = [
|
||||
'''CREATE TABLE services (
|
||||
project_id VARCHAR,
|
||||
service_id UUID,
|
||||
service_name VARCHAR,
|
||||
flavor_id VARCHAR,
|
||||
domains LIST<TEXT>,
|
||||
|
@ -24,7 +25,7 @@ schema_statements = [
|
|||
caching_rules LIST<TEXT>,
|
||||
restrictions LIST<TEXT>,
|
||||
provider_details MAP<TEXT, TEXT>,
|
||||
PRIMARY KEY (project_id, service_name)
|
||||
PRIMARY KEY (project_id, service_id)
|
||||
);
|
||||
''',
|
||||
'''CREATE TABLE flavors (
|
||||
|
@ -33,8 +34,16 @@ schema_statements = [
|
|||
PRIMARY KEY (flavor_id)
|
||||
);
|
||||
''',
|
||||
'''CREATE TABLE domain_names (
|
||||
project_id VARCHAR,
|
||||
service_id UUID,
|
||||
domain_name VARCHAR,
|
||||
PRIMARY KEY (domain_name)
|
||||
);
|
||||
''',
|
||||
'''CREATE TABLE archives (
|
||||
project_id VARCHAR,
|
||||
service_id UUID,
|
||||
service_name VARCHAR,
|
||||
flavor_id VARCHAR,
|
||||
domains LIST<TEXT>,
|
||||
|
@ -43,7 +52,7 @@ schema_statements = [
|
|||
restrictions LIST<TEXT>,
|
||||
provider_details MAP<TEXT, TEXT>,
|
||||
archived_time timestamp,
|
||||
PRIMARY KEY (project_id, service_name, archived_time)
|
||||
PRIMARY KEY (project_id, service_id, archived_time)
|
||||
);
|
||||
'''
|
||||
]
|
||||
|
|
|
@ -15,11 +15,14 @@
|
|||
|
||||
import datetime
|
||||
import json
|
||||
import uuid
|
||||
try:
|
||||
import ordereddict as collections
|
||||
except ImportError: # pragma: no cover
|
||||
import collections # pragma: no cover
|
||||
|
||||
from cassandra import query
|
||||
|
||||
from poppy.model.helpers import cachingrule
|
||||
from poppy.model.helpers import domain
|
||||
from poppy.model.helpers import origin
|
||||
|
@ -27,11 +30,15 @@ from poppy.model.helpers import provider_details
|
|||
from poppy.model.helpers import restriction
|
||||
from poppy.model.helpers import rule
|
||||
from poppy.model import service
|
||||
from poppy.openstack.common import log as logging
|
||||
from poppy.storage import base
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
CQL_GET_ALL_SERVICES = '''
|
||||
SELECT project_id,
|
||||
service_id,
|
||||
service_name,
|
||||
domains,
|
||||
flavor_id,
|
||||
|
@ -44,6 +51,7 @@ CQL_GET_ALL_SERVICES = '''
|
|||
|
||||
CQL_LIST_SERVICES = '''
|
||||
SELECT project_id,
|
||||
service_id,
|
||||
service_name,
|
||||
domains,
|
||||
flavor_id,
|
||||
|
@ -53,13 +61,14 @@ CQL_LIST_SERVICES = '''
|
|||
provider_details
|
||||
FROM services
|
||||
WHERE project_id = %(project_id)s
|
||||
AND service_name > %(service_name)s
|
||||
ORDER BY service_name
|
||||
AND service_id > %(marker)s
|
||||
ORDER BY service_id
|
||||
LIMIT %(limit)s
|
||||
'''
|
||||
|
||||
CQL_GET_SERVICE = '''
|
||||
SELECT project_id,
|
||||
service_id,
|
||||
service_name,
|
||||
flavor_id,
|
||||
domains,
|
||||
|
@ -68,12 +77,30 @@ CQL_GET_SERVICE = '''
|
|||
restrictions,
|
||||
provider_details
|
||||
FROM services
|
||||
WHERE project_id = %(project_id)s AND service_name = %(service_name)s
|
||||
WHERE project_id = %(project_id)s AND service_id = %(service_id)s
|
||||
'''
|
||||
|
||||
CQL_VERIFY_DOMAIN = '''
|
||||
SELECT project_id,
|
||||
service_id,
|
||||
domain_name
|
||||
FROM domain_names
|
||||
WHERE domain_name = %(domain_name)s
|
||||
'''
|
||||
|
||||
CQL_CLAIM_DOMAIN = '''
|
||||
INSERT INTO domain_names (domain_name,
|
||||
project_id,
|
||||
service_id)
|
||||
VALUES (%(domain_name)s,
|
||||
%(project_id)s,
|
||||
%(service_id)s)
|
||||
'''
|
||||
|
||||
CQL_ARCHIVE_SERVICE = '''
|
||||
BEGIN BATCH
|
||||
INSERT INTO archives (project_id,
|
||||
service_id,
|
||||
service_name,
|
||||
flavor_id,
|
||||
domains,
|
||||
|
@ -84,6 +111,7 @@ CQL_ARCHIVE_SERVICE = '''
|
|||
archived_time
|
||||
)
|
||||
VALUES (%(project_id)s,
|
||||
%(service_id)s,
|
||||
%(service_name)s,
|
||||
%(flavor_id)s,
|
||||
%(domains)s,
|
||||
|
@ -94,17 +122,26 @@ CQL_ARCHIVE_SERVICE = '''
|
|||
%(archived_time)s)
|
||||
|
||||
DELETE FROM services
|
||||
WHERE project_id = %(project_id)s AND service_name = %(service_name)s;
|
||||
WHERE project_id = %(project_id)s AND service_id = %(service_id)s;
|
||||
|
||||
DELETE FROM domain_names
|
||||
WHERE domain_name IN %(domain_list)s
|
||||
APPLY BATCH;
|
||||
'''
|
||||
|
||||
CQL_DELETE_SERVICE = '''
|
||||
DELETE FROM services
|
||||
WHERE project_id = %(project_id)s AND service_name = %(service_name)s
|
||||
BEGIN BATCH
|
||||
DELETE FROM services
|
||||
WHERE project_id = %(project_id)s AND service_id = %(service_id)s
|
||||
|
||||
DELETE FROM domain_names
|
||||
WHERE domain_name IN %(domain_list)s
|
||||
APPLY BATCH
|
||||
'''
|
||||
|
||||
CQL_CREATE_SERVICE = '''
|
||||
INSERT INTO services (project_id,
|
||||
service_id,
|
||||
service_name,
|
||||
flavor_id,
|
||||
domains,
|
||||
|
@ -114,6 +151,7 @@ CQL_CREATE_SERVICE = '''
|
|||
provider_details
|
||||
)
|
||||
VALUES (%(project_id)s,
|
||||
%(service_id)s,
|
||||
%(service_name)s,
|
||||
%(flavor_id)s,
|
||||
%(domains)s,
|
||||
|
@ -128,37 +166,37 @@ CQL_UPDATE_SERVICE = CQL_CREATE_SERVICE
|
|||
CQL_UPDATE_DOMAINS = '''
|
||||
UPDATE services
|
||||
SET domains = %(domains)s
|
||||
WHERE project_id = %(project_id)s AND service_name = %(service_name)s
|
||||
WHERE project_id = %(project_id)s AND service_id = %(service_id)s
|
||||
'''
|
||||
|
||||
CQL_UPDATE_ORIGINS = '''
|
||||
UPDATE services
|
||||
SET origins = %(origins)s
|
||||
WHERE project_id = %(project_id)s AND service_name = %(service_name)s
|
||||
WHERE project_id = %(project_id)s AND service_id = %(service_id)s
|
||||
'''
|
||||
|
||||
CQL_UPDATE_CACHING_RULES = '''
|
||||
UPDATE services
|
||||
SET caching_rules = %(caching_rules)s
|
||||
WHERE project_id = %(project_id)s AND service_name = %(service_name)s
|
||||
WHERE project_id = %(project_id)s AND service_id = %(service_id)s
|
||||
'''
|
||||
|
||||
CQL_UPDATE_RESTRICTIONS = '''
|
||||
UPDATE services
|
||||
SET restrictions = %(restrictions)s
|
||||
WHERE project_id = %(project_id)s AND service_name = %(service_name)s
|
||||
WHERE project_id = %(project_id)s AND service_id = %(service_id)s
|
||||
'''
|
||||
|
||||
CQL_GET_PROVIDER_DETAILS = '''
|
||||
SELECT provider_details
|
||||
FROM services
|
||||
WHERE project_id = %(project_id)s AND service_name = %(service_name)s
|
||||
WHERE project_id = %(project_id)s AND service_id = %(service_id)s
|
||||
'''
|
||||
|
||||
CQL_UPDATE_PROVIDER_DETAILS = '''
|
||||
UPDATE services
|
||||
set provider_details = %(provider_details)s
|
||||
WHERE project_id = %(project_id)s AND service_name = %(service_name)s
|
||||
WHERE project_id = %(project_id)s AND service_id = %(service_id)s
|
||||
'''
|
||||
|
||||
|
||||
|
@ -184,9 +222,12 @@ class ServicesController(base.ServicesController):
|
|||
:returns services
|
||||
"""
|
||||
# list services
|
||||
if marker is None:
|
||||
marker = '00000000-00000000-00000000-00000000'
|
||||
|
||||
args = {
|
||||
'project_id': project_id,
|
||||
'service_name': marker,
|
||||
'marker': uuid.UUID(str(marker)),
|
||||
'limit': limit
|
||||
}
|
||||
|
||||
|
@ -195,7 +236,7 @@ class ServicesController(base.ServicesController):
|
|||
|
||||
return services
|
||||
|
||||
def get(self, project_id, service_name):
|
||||
def get(self, project_id, service_id):
|
||||
"""get.
|
||||
|
||||
:param project_id
|
||||
|
@ -207,13 +248,13 @@ class ServicesController(base.ServicesController):
|
|||
# get the requested service from storage
|
||||
args = {
|
||||
'project_id': project_id,
|
||||
'service_name': service_name
|
||||
'service_id': uuid.UUID(str(service_id))
|
||||
}
|
||||
results = self.session.execute(CQL_GET_SERVICE, args)
|
||||
|
||||
if len(results) != 1:
|
||||
raise ValueError('No service or multiple service found: %s'
|
||||
% service_name)
|
||||
raise ValueError('No service found: %s'
|
||||
% service_id)
|
||||
|
||||
# at this point, it is certain that there's exactly 1 result in
|
||||
# results.
|
||||
|
@ -221,6 +262,39 @@ class ServicesController(base.ServicesController):
|
|||
|
||||
return self.format_result(result)
|
||||
|
||||
def _exists_elsewhere(self, domain_name, service_id):
|
||||
"""_exists_elsewhere
|
||||
|
||||
Check if a service with this domain name has already been created.
|
||||
|
||||
:param domain_name
|
||||
:param service_id
|
||||
|
||||
:raises ValueError
|
||||
:returns Boolean if the service exists with another user.
|
||||
"""
|
||||
try:
|
||||
LOG.info("Check if service '{0}' exists".format(domain_name))
|
||||
args = {
|
||||
'domain_name': domain_name.lower()
|
||||
}
|
||||
results = self.session.execute(CQL_VERIFY_DOMAIN, args)
|
||||
|
||||
if results:
|
||||
for r in results:
|
||||
if r.get('service_id') != str(service_id):
|
||||
LOG.info(
|
||||
"Domain '{0}' has already been taken."
|
||||
.format(domain_name))
|
||||
return True
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
except ValueError:
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
|
||||
def create(self, project_id, service_obj):
|
||||
"""create.
|
||||
|
||||
|
@ -229,18 +303,18 @@ class ServicesController(base.ServicesController):
|
|||
|
||||
:raises ValueError
|
||||
"""
|
||||
|
||||
# check if the service domain names already exist
|
||||
for d in service_obj.domains:
|
||||
if self._exists_elsewhere(
|
||||
d.domain,
|
||||
service_obj.service_id) is True:
|
||||
raise ValueError(
|
||||
"Domain %s has already been taken" % d.domain)
|
||||
|
||||
# create the service in storage
|
||||
service_id = service_obj.service_id
|
||||
service_name = service_obj.name
|
||||
|
||||
# check if the serivce already exist.
|
||||
# Note: If it does, no LookupError will be raised
|
||||
try:
|
||||
self.get(project_id, service_name)
|
||||
except ValueError: # this value error means this service doesn't exist
|
||||
pass
|
||||
else:
|
||||
raise ValueError("Service %s already exists..." % service_name)
|
||||
|
||||
domains = [json.dumps(d.to_dict())
|
||||
for d in service_obj.domains]
|
||||
origins = [json.dumps(o.to_dict())
|
||||
|
@ -250,9 +324,10 @@ class ServicesController(base.ServicesController):
|
|||
restrictions = [json.dumps(r.to_dict())
|
||||
for r in service_obj.restrictions]
|
||||
|
||||
# creates a new service
|
||||
args = {
|
||||
# create a new service
|
||||
service_args = {
|
||||
'project_id': project_id,
|
||||
'service_id': uuid.UUID(service_id),
|
||||
'service_name': service_name,
|
||||
'flavor_id': service_obj.flavor_id,
|
||||
'domains': domains,
|
||||
|
@ -262,10 +337,32 @@ class ServicesController(base.ServicesController):
|
|||
'provider_details': {}
|
||||
}
|
||||
|
||||
self.session.execute(CQL_CREATE_SERVICE, args)
|
||||
LOG.debug("Creating New Service - {0} ({1})".format(service_id,
|
||||
service_name))
|
||||
batch = query.BatchStatement()
|
||||
batch.add(query.SimpleStatement(CQL_CREATE_SERVICE), service_args)
|
||||
|
||||
def update(self, project_id, service_name, service_obj):
|
||||
for d in service_obj.domains:
|
||||
domain_args = {
|
||||
'domain_name': d.domain,
|
||||
'project_id': project_id,
|
||||
'service_id': uuid.UUID(service_id),
|
||||
}
|
||||
batch.add(query.SimpleStatement(CQL_CLAIM_DOMAIN), domain_args)
|
||||
|
||||
self.session.execute(batch)
|
||||
|
||||
def update(self, project_id, service_id, service_obj):
|
||||
|
||||
# check if the service domain names already exist
|
||||
for d in service_obj.domains:
|
||||
if self._exists_elsewhere(
|
||||
d.domain,
|
||||
service_id) is True:
|
||||
raise ValueError(
|
||||
"Domain %s has already been taken" % d)
|
||||
|
||||
service_name = service_obj.name
|
||||
domains = [json.dumps(d.to_dict())
|
||||
for d in service_obj.domains]
|
||||
origins = [json.dumps(o.to_dict())
|
||||
|
@ -275,9 +372,10 @@ class ServicesController(base.ServicesController):
|
|||
restrictions = [json.dumps(r.to_dict())
|
||||
for r in service_obj.restrictions]
|
||||
|
||||
# updates an existing new service
|
||||
# updates an existing service
|
||||
args = {
|
||||
'project_id': project_id,
|
||||
'service_id': uuid.UUID(str(service_id)),
|
||||
'service_name': service_name,
|
||||
'flavor_id': service_obj.flavor_id,
|
||||
'domains': domains,
|
||||
|
@ -289,7 +387,7 @@ class ServicesController(base.ServicesController):
|
|||
|
||||
self.session.execute(CQL_UPDATE_SERVICE, args)
|
||||
|
||||
def delete(self, project_id, service_name):
|
||||
def delete(self, project_id, service_id):
|
||||
"""delete.
|
||||
|
||||
Archive local configuration storage
|
||||
|
@ -297,17 +395,21 @@ class ServicesController(base.ServicesController):
|
|||
# delete local configuration from storage
|
||||
args = {
|
||||
'project_id': project_id,
|
||||
'service_name': service_name
|
||||
'service_id': uuid.UUID(str(service_id)),
|
||||
}
|
||||
|
||||
if self._driver.archive_on_delete:
|
||||
# get the existing service
|
||||
results = self.session.execute(CQL_GET_SERVICE, args)
|
||||
result = results[0]
|
||||
# get the existing service
|
||||
results = self.session.execute(CQL_GET_SERVICE, args)
|
||||
result = results[0]
|
||||
|
||||
if (result):
|
||||
if (result):
|
||||
domains_list = [d.get('domain')
|
||||
for d in result.get('domains')]
|
||||
|
||||
if self._driver.archive_on_delete:
|
||||
archive_args = {
|
||||
'project_id': result.get('project_id'),
|
||||
'service_id': result.get('service_id'),
|
||||
'service_name': result.get('service_name'),
|
||||
'flavor_id': result.get('flavor_id'),
|
||||
'domains': result.get('domains'),
|
||||
|
@ -315,25 +417,31 @@ class ServicesController(base.ServicesController):
|
|||
'caching_rules': result.get('caching_rules'),
|
||||
'restrictions': result.get('restrictions'),
|
||||
'provider_details': result.get('provider_details'),
|
||||
'archived_time': datetime.datetime.utcnow()
|
||||
'archived_time': datetime.datetime.utcnow(),
|
||||
'domains_list': domains_list
|
||||
}
|
||||
|
||||
# archive and delete the service
|
||||
self.session.execute(CQL_ARCHIVE_SERVICE, archive_args)
|
||||
else:
|
||||
self.session.execute(CQL_DELETE_SERVICE, args)
|
||||
else:
|
||||
delete_args = {
|
||||
'project_id': result.get('project_id'),
|
||||
'service_id': result.get('service_id'),
|
||||
'domains_list': domains_list
|
||||
}
|
||||
self.session.execute(CQL_DELETE_SERVICE, delete_args)
|
||||
|
||||
def get_provider_details(self, project_id, service_name):
|
||||
def get_provider_details(self, project_id, service_id):
|
||||
"""get_provider_details.
|
||||
|
||||
:param project_id
|
||||
:param service_name
|
||||
:param service_id
|
||||
:returns results Provider details
|
||||
"""
|
||||
|
||||
args = {
|
||||
'project_id': project_id,
|
||||
'service_name': service_name
|
||||
'service_id': uuid.UUID(str(service_id))
|
||||
}
|
||||
# TODO(tonytan4ever): Not sure this returns a list or a single
|
||||
# dictionary.
|
||||
|
@ -361,12 +469,12 @@ class ServicesController(base.ServicesController):
|
|||
results[provider_name] = provider_detail_obj
|
||||
return results
|
||||
|
||||
def update_provider_details(self, project_id, service_name,
|
||||
def update_provider_details(self, project_id, service_id,
|
||||
provider_details):
|
||||
"""update_provider_details.
|
||||
|
||||
:param project_id
|
||||
:param service_name
|
||||
:param service_id
|
||||
:param provider_details
|
||||
"""
|
||||
provider_detail_dict = {}
|
||||
|
@ -388,7 +496,7 @@ class ServicesController(base.ServicesController):
|
|||
the_provider_detail_dict)
|
||||
args = {
|
||||
'project_id': project_id,
|
||||
'service_name': service_name,
|
||||
'service_id': uuid.UUID(str(service_id)),
|
||||
'provider_details': provider_detail_dict
|
||||
}
|
||||
# TODO(tonytan4ever): Not sure this returns a list or a single
|
||||
|
@ -405,6 +513,7 @@ class ServicesController(base.ServicesController):
|
|||
:param result
|
||||
:returns formatted result
|
||||
"""
|
||||
service_id = result.get('service_id')
|
||||
name = result.get('service_name')
|
||||
|
||||
flavor_id = result.get('flavor_id')
|
||||
|
@ -446,7 +555,7 @@ class ServicesController(base.ServicesController):
|
|||
for caching_rule in caching_rules]
|
||||
|
||||
# create the service object
|
||||
s = service.Service(name, domains, origins, flavor_id,
|
||||
s = service.Service(service_id, name, domains, origins, flavor_id,
|
||||
caching=caching_rules,
|
||||
restrictions=restrictions)
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
# limitations under the License.
|
||||
|
||||
import json
|
||||
import uuid
|
||||
|
||||
from poppy.model.helpers import domain
|
||||
from poppy.model.helpers import origin
|
||||
|
@ -27,7 +28,7 @@ class ServicesController(base.ServicesController):
|
|||
def __init__(self, driver):
|
||||
super(ServicesController, self).__init__(driver)
|
||||
|
||||
self.created_service_names = []
|
||||
self.created_service_ids = []
|
||||
|
||||
@property
|
||||
def session(self):
|
||||
|
@ -50,8 +51,9 @@ class ServicesController(base.ServicesController):
|
|||
[{'operator_url': 'mockcf123.fastly.prod.com'}]})}
|
||||
|
||||
services = []
|
||||
for i in self.created_service_names:
|
||||
services = [{'name': i,
|
||||
for i in self.created_service_ids:
|
||||
services = [{'service_id': i,
|
||||
'name': uuid.uuid4(),
|
||||
'domains': [json.dumps(
|
||||
{'domain': 'www.mywebsite.com'})
|
||||
],
|
||||
|
@ -84,10 +86,10 @@ class ServicesController(base.ServicesController):
|
|||
|
||||
return services_result
|
||||
|
||||
def get(self, project_id, service_name):
|
||||
def get(self, project_id, service_id):
|
||||
# get the requested service from storage
|
||||
if service_name not in self.created_service_names:
|
||||
raise ValueError("service: % does not exist")
|
||||
if service_id not in self.created_service_ids:
|
||||
raise ValueError("service {0} does not exist".format(service_id))
|
||||
else:
|
||||
origin_json = json.dumps({'origin': 'mywebsite.com',
|
||||
'port': 80,
|
||||
|
@ -111,7 +113,8 @@ class ServicesController(base.ServicesController):
|
|||
'access_urls':
|
||||
[{'operator_url': 'mockcf123.fastly.prod.com'}]})}
|
||||
|
||||
service_dict = {'name': service_name,
|
||||
service_dict = {'service_id': service_id,
|
||||
'name': uuid.uuid4(),
|
||||
'domains': [domain_json],
|
||||
'origins': [origin_json],
|
||||
'flavor_id': 'standard',
|
||||
|
@ -136,42 +139,44 @@ class ServicesController(base.ServicesController):
|
|||
return service_result
|
||||
|
||||
def create(self, project_id, service_obj):
|
||||
if service_obj.name in self.created_service_names:
|
||||
raise ValueError("Service %s already exists." % service_obj.name)
|
||||
else:
|
||||
# TODO(amitgandhinz): append the entire service
|
||||
# instead of just the name
|
||||
self.created_service_names.append(service_obj.name)
|
||||
if service_obj.service_id in self.created_service_ids:
|
||||
raise ValueError("Service %s already exists." %
|
||||
service_obj.service_id)
|
||||
|
||||
def update(self, project_id, service_name, service_json):
|
||||
# TODO(amitgandhinz): append the entire service
|
||||
# instead of just the name
|
||||
self.created_service_ids.append(service_obj.service_id)
|
||||
|
||||
def update(self, project_id, service_id, service_json):
|
||||
# update configuration in storage
|
||||
return ''
|
||||
|
||||
def delete(self, project_id, service_name):
|
||||
if (service_name in self.created_service_names):
|
||||
self.created_service_names.remove(service_name)
|
||||
def delete(self, project_id, service_id):
|
||||
if (service_id in self.created_service_ids):
|
||||
self.created_service_ids.remove(service_id)
|
||||
|
||||
def get_provider_details(self, project_id, service_name):
|
||||
if service_name == 'non_exist_service_name':
|
||||
raise LookupError('Service non_exist_service_name does not exist')
|
||||
return {
|
||||
'MaxCDN': provider_details.ProviderDetail(
|
||||
provider_service_id=11942,
|
||||
name='my_service_name',
|
||||
access_urls=['my_service_name'
|
||||
'.mycompanyalias.netdna-cdn.com']),
|
||||
'Fastly': provider_details.ProviderDetail(
|
||||
provider_service_id=3488,
|
||||
name="my_service_name",
|
||||
access_urls=['my_service_name'
|
||||
'.global.prod.fastly.net']),
|
||||
'CloudFront': provider_details.ProviderDetail(
|
||||
provider_service_id=5892,
|
||||
access_urls=['my_service_name'
|
||||
'.gibberish.amzcf.com']),
|
||||
'Mock': provider_details.ProviderDetail(
|
||||
provider_service_id="73242",
|
||||
access_urls=['my_service_name.mock.com'])}
|
||||
def get_provider_details(self, project_id, service_id):
|
||||
if service_id not in self.created_service_ids:
|
||||
raise ValueError("service: % does not exist")
|
||||
else:
|
||||
return {
|
||||
'MaxCDN': provider_details.ProviderDetail(
|
||||
provider_service_id=11942,
|
||||
name='my_service_name',
|
||||
access_urls=['my_service_name'
|
||||
'.mycompanyalias.netdna-cdn.com']),
|
||||
'Fastly': provider_details.ProviderDetail(
|
||||
provider_service_id=3488,
|
||||
name="my_service_name",
|
||||
access_urls=['my_service_name'
|
||||
'.global.prod.fastly.net']),
|
||||
'CloudFront': provider_details.ProviderDetail(
|
||||
provider_service_id=5892,
|
||||
access_urls=['my_service_name'
|
||||
'.gibberish.amzcf.com']),
|
||||
'Mock': provider_details.ProviderDetail(
|
||||
provider_service_id="73242",
|
||||
access_urls=['my_service_name.mock.com'])}
|
||||
|
||||
def update_provider_details(self, project_id, service_name,
|
||||
provider_details):
|
||||
|
@ -179,6 +184,7 @@ class ServicesController(base.ServicesController):
|
|||
|
||||
@staticmethod
|
||||
def format_result(result):
|
||||
service_id = result.get('service_id')
|
||||
name = result.get('service_name')
|
||||
origins = [json.loads(o) for o in result.get('origins', [])]
|
||||
domains = [json.loads(d) for d in result.get('domains', [])]
|
||||
|
@ -188,7 +194,7 @@ class ServicesController(base.ServicesController):
|
|||
for o in origins]
|
||||
domains = [domain.Domain(d['domain']) for d in domains]
|
||||
flavor_id = result.get('flavor_id')
|
||||
s = service.Service(name, domains, origins, flavor_id)
|
||||
s = service.Service(service_id, name, domains, origins, flavor_id)
|
||||
provider_detail_results = result.get('provider_details') or {}
|
||||
provider_details_dict = {}
|
||||
for provider_name in provider_detail_results:
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
# limitations under the License.
|
||||
|
||||
import json
|
||||
import uuid
|
||||
|
||||
from oslo.config import cfg
|
||||
import pecan
|
||||
|
@ -45,7 +46,12 @@ class ServiceAssetsController(base.Controller, hooks.HookController):
|
|||
__hooks__ = [poppy_hooks.Context(), poppy_hooks.Error()]
|
||||
|
||||
@pecan.expose()
|
||||
def delete(self, service_name):
|
||||
@decorators.validate(
|
||||
service_id=rule.Rule(
|
||||
helpers.is_valid_service_id(),
|
||||
helpers.abort_with_message)
|
||||
)
|
||||
def delete(self, service_id):
|
||||
purge_url = pecan.request.GET.get('url', None)
|
||||
purge_all = pecan.request.GET.get('all', False)
|
||||
purge_all = (
|
||||
|
@ -58,7 +64,7 @@ class ServiceAssetsController(base.Controller, hooks.HookController):
|
|||
'and a url at the same time')
|
||||
services_controller = self._driver.manager.services_controller
|
||||
try:
|
||||
services_controller.purge(self.project_id, service_name,
|
||||
services_controller.purge(self.project_id, service_id,
|
||||
purge_url)
|
||||
except LookupError as e:
|
||||
pecan.abort(404, detail=str(e))
|
||||
|
@ -85,7 +91,7 @@ class ServicesController(base.Controller, hooks.HookController):
|
|||
|
||||
@pecan.expose('json')
|
||||
def get_all(self):
|
||||
marker = pecan.request.GET.get('marker', '')
|
||||
marker = pecan.request.GET.get('marker', None)
|
||||
limit = pecan.request.GET.get('limit', 10)
|
||||
try:
|
||||
limit = int(limit)
|
||||
|
@ -100,6 +106,12 @@ class ServicesController(base.Controller, hooks.HookController):
|
|||
u' or equal to {0}'.format(self.max_services_per_page))
|
||||
pecan.abort(400, detail=error)
|
||||
|
||||
try:
|
||||
if marker:
|
||||
marker = str(uuid.UUID(marker))
|
||||
except ValueError:
|
||||
pecan.abort(400, detail="Marker must be a valid UUID")
|
||||
|
||||
services_controller = self._driver.manager.services_controller
|
||||
service_resultset = services_controller.list(
|
||||
self.project_id, marker, limit)
|
||||
|
@ -112,7 +124,9 @@ class ServicesController(base.Controller, hooks.HookController):
|
|||
if len(results) > 0:
|
||||
links.append(
|
||||
link.Model(u'{0}/services?marker={1}&limit={2}'.format(
|
||||
self.base_url, results[-1]['name'], limit),
|
||||
self.base_url,
|
||||
results[-1]['id'],
|
||||
limit),
|
||||
'next'))
|
||||
|
||||
return {
|
||||
|
@ -121,14 +135,19 @@ class ServicesController(base.Controller, hooks.HookController):
|
|||
}
|
||||
|
||||
@pecan.expose('json')
|
||||
def get_one(self, service_name):
|
||||
@decorators.validate(
|
||||
service_id=rule.Rule(
|
||||
helpers.is_valid_service_id(),
|
||||
helpers.abort_with_message)
|
||||
)
|
||||
def get_one(self, service_id):
|
||||
services_controller = self._driver.manager.services_controller
|
||||
try:
|
||||
service_obj = services_controller.get(
|
||||
self.project_id, service_name)
|
||||
self.project_id, service_id)
|
||||
except ValueError:
|
||||
pecan.abort(404, detail='service %s is not found' %
|
||||
service_name)
|
||||
pecan.abort(404, detail='service %s could not be found' %
|
||||
service_id)
|
||||
# convert a service model into a response service model
|
||||
return resp_service_model.Model(service_obj, self)
|
||||
|
||||
|
@ -143,7 +162,7 @@ class ServicesController(base.Controller, hooks.HookController):
|
|||
services_controller = self._driver.manager.services_controller
|
||||
service_json_dict = json.loads(pecan.request.body.decode('utf-8'))
|
||||
service_obj = req_service_model.load_from_json(service_json_dict)
|
||||
service_name = service_json_dict.get("name", None)
|
||||
service_id = service_obj.service_id
|
||||
try:
|
||||
services_controller.create(self.project_id, service_obj)
|
||||
except LookupError as e: # error handler for no flavor
|
||||
|
@ -153,15 +172,20 @@ class ServicesController(base.Controller, hooks.HookController):
|
|||
service_url = str(
|
||||
uri.encode(u'{0}/v1.0/services/{1}'.format(
|
||||
pecan.request.host_url,
|
||||
service_name)))
|
||||
service_id)))
|
||||
|
||||
return pecan.Response(None, 202, headers={"Location": service_url})
|
||||
|
||||
@pecan.expose('json')
|
||||
def delete(self, service_name):
|
||||
@decorators.validate(
|
||||
service_id=rule.Rule(
|
||||
helpers.is_valid_service_id(),
|
||||
helpers.abort_with_message)
|
||||
)
|
||||
def delete(self, service_id):
|
||||
services_controller = self._driver.manager.services_controller
|
||||
try:
|
||||
services_controller.delete(self.project_id, service_name)
|
||||
services_controller.delete(self.project_id, service_id)
|
||||
except LookupError as e:
|
||||
pecan.abort(404, detail=str(e))
|
||||
|
||||
|
@ -169,15 +193,15 @@ class ServicesController(base.Controller, hooks.HookController):
|
|||
|
||||
@pecan.expose('json')
|
||||
@decorators.validate(
|
||||
service_name=rule.Rule(
|
||||
helpers.is_valid_service_name(),
|
||||
service_id=rule.Rule(
|
||||
helpers.is_valid_service_id(),
|
||||
helpers.abort_with_message),
|
||||
request=rule.Rule(
|
||||
helpers.json_matches_schema(
|
||||
service.ServiceSchema.get_schema("service", "PATCH")),
|
||||
helpers.abort_with_message,
|
||||
stoplight_helpers.pecan_getter))
|
||||
def patch_one(self, service_name):
|
||||
def patch_one(self, service_id):
|
||||
service_json_dict = json.loads(pecan.request.body.decode('utf-8'))
|
||||
|
||||
# TODO(obulpathi): remove these restrictions, once cachingrule and
|
||||
|
@ -196,7 +220,9 @@ class ServicesController(base.Controller, hooks.HookController):
|
|||
|
||||
try:
|
||||
services_controller.update(
|
||||
self.project_id, service_name, service_updates)
|
||||
self.project_id, service_id, service_updates)
|
||||
except ValueError as e:
|
||||
pecan.abort(404, detail='service could not be found')
|
||||
except errors.ServiceStatusNotDeployed as e:
|
||||
pecan.abort(400, detail=str(e))
|
||||
except Exception as e:
|
||||
|
@ -205,6 +231,6 @@ class ServicesController(base.Controller, hooks.HookController):
|
|||
service_url = str(
|
||||
uri.encode(u'{0}/v1.0/services/{1}'.format(
|
||||
pecan.request.host_url,
|
||||
service_name)))
|
||||
service_id)))
|
||||
|
||||
return pecan.Response(None, 202, headers={"Location": service_url})
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
import uuid
|
||||
|
||||
from poppy.model import service
|
||||
from poppy.transport.pecan.models.request import cachingrule
|
||||
|
@ -22,21 +23,32 @@ from poppy.transport.pecan.models.request import restriction
|
|||
|
||||
|
||||
def load_from_json(json_data):
|
||||
service_id = uuid.uuid4()
|
||||
|
||||
name = json_data.get("name")
|
||||
origins = json_data.get("origins", [])
|
||||
domains = json_data.get("domains", [])
|
||||
flavor_id = json_data.get("flavor_id")
|
||||
restrictions = json_data.get("restrictions", [])
|
||||
pd = json_data.get("provider_details", {})
|
||||
|
||||
# load caching rules json string from input
|
||||
caching = json_data.get("caching", [])
|
||||
origins = [origin.load_from_json(o) for o in origins]
|
||||
domains = [domain.load_from_json(d) for d in domains]
|
||||
restrictions = [restriction.load_from_json(r) for r in restrictions]
|
||||
# convert caching rule jsong string list into object list
|
||||
|
||||
# convert caching rule json string list into object list
|
||||
caching = [cachingrule.load_from_json(c) for c in caching]
|
||||
r = service.Service(name, domains, origins, flavor_id, caching,
|
||||
|
||||
r = service.Service(service_id,
|
||||
name,
|
||||
domains,
|
||||
origins,
|
||||
flavor_id,
|
||||
caching,
|
||||
restrictions)
|
||||
|
||||
r.provider_details = dict([(k, provider_details.load_from_json(v))
|
||||
for k, v in pd.items()])
|
||||
return r
|
||||
|
|
|
@ -33,6 +33,7 @@ class Model(collections.OrderedDict):
|
|||
def __init__(self, service_obj, controller):
|
||||
super(Model, self).__init__()
|
||||
self["name"] = service_obj.name
|
||||
self["id"] = str(service_obj.service_id)
|
||||
self["domains"] = [domain.Model(d) for d in service_obj.domains]
|
||||
self["origins"] = [origin.Model(o) for o in service_obj.origins]
|
||||
self["restrictions"] = [restriction.Model(r) for r in
|
||||
|
@ -44,14 +45,12 @@ class Model(collections.OrderedDict):
|
|||
|
||||
self["errors"] = []
|
||||
|
||||
# TODO(tonytan4ever) : add access_url links.
|
||||
# This has things to do with provider_detail change. (CDN-172)
|
||||
self["links"] = [
|
||||
link.Model(
|
||||
str(
|
||||
uri.encode(u'{0}/services/{1}'.format(
|
||||
controller.base_url,
|
||||
self['name']))),
|
||||
service_obj.service_id))),
|
||||
'self'),
|
||||
link.Model(
|
||||
str(
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
import collections
|
||||
import functools
|
||||
import json
|
||||
import uuid
|
||||
|
||||
try:
|
||||
import falcon
|
||||
|
@ -195,8 +196,11 @@ def json_matches_schema(input_schema):
|
|||
|
||||
|
||||
@decorators.validation_function
|
||||
def is_valid_service_name(service_name):
|
||||
pass
|
||||
def is_valid_service_id(service_id):
|
||||
try:
|
||||
uuid.UUID(service_id)
|
||||
except ValueError:
|
||||
raise exceptions.ValidationFailed('Invalid service id')
|
||||
|
||||
|
||||
@decorators.validation_function
|
||||
|
|
|
@ -1 +1 @@
|
|||
pecan==0.8.1
|
||||
pecan>=0.8.1
|
|
@ -88,11 +88,21 @@ class TestFlavorActions(base.TestBase):
|
|||
super(TestFlavorActions, self).setUp()
|
||||
if self.test_config.generate_flavors:
|
||||
self.flavor_id = str(uuid.uuid1())
|
||||
self.provider_list = [
|
||||
{
|
||||
"provider": "fastly",
|
||||
"links": [
|
||||
{
|
||||
"href": "www.fastly.com",
|
||||
"rel": "provider_url"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
self.client.create_flavor(
|
||||
flavor_id=self.flavor_id,
|
||||
provider_list=[{"provider": "fastly",
|
||||
"links": [{"href": "www.fastly.com",
|
||||
"rel": "provider_url"}]}])
|
||||
provider_list=self.provider_list)
|
||||
else:
|
||||
self.flavor_id = self.test_config.default_flavor
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"all_fields": {
|
||||
"name": "my_service_name",
|
||||
"domain_list": [{"domain": "mywebsite.com"},
|
||||
{"domain": "blog.mywebsite.com"}],
|
||||
"domain_list": [{"domain": "mywebsite.com", "protocol": "http"},
|
||||
{"domain": "blog.mywebsite.com", "protocol": "http"}],
|
||||
"origin_list": [{"origin": "mywebsite1.com",
|
||||
"port": 443,
|
||||
"ssl": false}],
|
||||
|
@ -14,8 +14,8 @@
|
|||
},
|
||||
"caching_empty": {
|
||||
"name": "caching_empty",
|
||||
"domain_list": [{"domain": "mywebsite.com"},
|
||||
{"domain": "blog.mywebsite.com"}],
|
||||
"domain_list": [{"domain": "mywebsite.com", "protocol": "http"},
|
||||
{"domain": "blog.mywebsite.com", "protocol": "http"}],
|
||||
"origin_list": [{"origin": "mywebsite1.com",
|
||||
"port": 443,
|
||||
"ssl": false}],
|
||||
|
@ -23,8 +23,8 @@
|
|||
},
|
||||
"non_ASCII": {
|
||||
"name": "איבערזעצן",
|
||||
"domain_list": [{"domain": "сайт.com"},
|
||||
{"domain": "ਦੀ ਵੈੱਬਸਾਈਟ.com"}],
|
||||
"domain_list": [{"domain": "сайт.com", "protocol": "http"},
|
||||
{"domain": "ਦੀ ਵੈੱਬਸਾਈਟ.com", "protocol": "http"}],
|
||||
"origin_list": [{"origin": "www.இணையதளத்தில்.com",
|
||||
"port": 443,
|
||||
"ssl": false}],
|
||||
|
|
|
@ -16,6 +16,10 @@
|
|||
# limitations under the License.
|
||||
|
||||
import time
|
||||
try:
|
||||
import urllib.parse as urlparse
|
||||
except ImportError:
|
||||
import urlparse
|
||||
import uuid
|
||||
|
||||
import ddt
|
||||
|
@ -33,6 +37,7 @@ class TestCreateService(providers.TestProviderBase):
|
|||
|
||||
def setUp(self):
|
||||
super(TestCreateService, self).setUp()
|
||||
self.service_url = ''
|
||||
self.service_name = str(uuid.uuid1())
|
||||
self.flavor_id = self.test_config.default_flavor
|
||||
|
||||
|
@ -61,8 +66,9 @@ class TestCreateService(providers.TestProviderBase):
|
|||
flavor_id=flavor_id)
|
||||
self.assertEqual(resp.status_code, 202)
|
||||
self.assertEqual(resp.text, '')
|
||||
self.service_url = resp.headers['location']
|
||||
|
||||
resp = self.client.get_service(service_name=self.service_name)
|
||||
resp = self.client.get_service(location=self.service_url)
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
|
||||
body = resp.json()
|
||||
|
@ -124,10 +130,14 @@ class TestCreateService(providers.TestProviderBase):
|
|||
origin_list=origin_list,
|
||||
caching_list=caching_list,
|
||||
flavor_id=flavor_id)
|
||||
if 'location' in resp.headers:
|
||||
self.service_url = resp.headers['location']
|
||||
|
||||
self.assertEqual(resp.status_code, 400)
|
||||
|
||||
def tearDown(self):
|
||||
self.client.delete_service(service_name=self.service_name)
|
||||
if self.service_url != '':
|
||||
self.client.delete_service(location=self.service_url)
|
||||
|
||||
if self.test_config.generate_flavors:
|
||||
self.client.delete_flavor(flavor_id=self.flavor_id)
|
||||
|
@ -153,12 +163,14 @@ class TestListServices(base.TestBase):
|
|||
"rules": [{"name": "index",
|
||||
"request_url": "/index.htm"}]}]
|
||||
|
||||
self.client.create_service(service_name=service_name,
|
||||
domain_list=self.domain_list,
|
||||
origin_list=self.origin_list,
|
||||
caching_list=self.caching_list,
|
||||
flavor_id=self.flavor_id)
|
||||
return service_name
|
||||
resp = self.client.create_service(service_name=service_name,
|
||||
domain_list=self.domain_list,
|
||||
origin_list=self.origin_list,
|
||||
caching_list=self.caching_list,
|
||||
flavor_id=self.flavor_id)
|
||||
|
||||
self.service_url = resp.headers["location"]
|
||||
return self.service_url
|
||||
|
||||
def setUp(self):
|
||||
super(TestListServices, self).setUp()
|
||||
|
@ -222,9 +234,15 @@ class TestListServices(base.TestBase):
|
|||
|
||||
@attrib.attr('smoke')
|
||||
@ddt.data(-1, -10000000000, 0, 10000000, 'invalid', '学校', '')
|
||||
def test_list_services_various_markers(self, marker):
|
||||
def test_list_services_various_invalid_markers(self, marker):
|
||||
url_param = {'marker': marker}
|
||||
resp = self.client.list_services(param=url_param)
|
||||
self.assertEqual(resp.status_code, 400)
|
||||
|
||||
@attrib.attr('smoke')
|
||||
def test_list_services_markers(self):
|
||||
url_param = {'marker': str(uuid.uuid4())}
|
||||
resp = self.client.list_services(param=url_param)
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
|
||||
@attrib.attr('smoke')
|
||||
|
@ -235,7 +253,7 @@ class TestListServices(base.TestBase):
|
|||
|
||||
def tearDown(self):
|
||||
for service in self.service_list:
|
||||
self.client.delete_service(service_name=service)
|
||||
self.client.delete_service(location=service)
|
||||
|
||||
if self.test_config.generate_flavors:
|
||||
self.client.delete_flavor(flavor_id=self.flavor_id)
|
||||
|
@ -262,7 +280,7 @@ class TestServiceActions(base.TestBase):
|
|||
|
||||
domain = str(uuid.uuid1()) + u'.com'
|
||||
self.domain_list = [
|
||||
{"domain": domain}
|
||||
{"domain": domain, "protocol": "http"}
|
||||
]
|
||||
|
||||
origin = str(uuid.uuid1()) + u'.com'
|
||||
|
@ -302,25 +320,28 @@ class TestServiceActions(base.TestBase):
|
|||
}
|
||||
]
|
||||
|
||||
self.client.create_service(service_name=self.service_name,
|
||||
domain_list=self.domain_list,
|
||||
origin_list=self.origin_list,
|
||||
caching_list=self.caching_list,
|
||||
restrictions_list=self.restrictions_list,
|
||||
flavor_id=self.flavor_id)
|
||||
resp = self.client.create_service(
|
||||
service_name=self.service_name,
|
||||
domain_list=self.domain_list,
|
||||
origin_list=self.origin_list,
|
||||
caching_list=self.caching_list,
|
||||
restrictions_list=self.restrictions_list,
|
||||
flavor_id=self.flavor_id)
|
||||
|
||||
self.service_url = resp.headers["location"]
|
||||
|
||||
def test_delete_service(self):
|
||||
resp = self.client.delete_service(service_name=self.service_name)
|
||||
resp = self.client.delete_service(location=self.service_url)
|
||||
self.assertEqual(resp.status_code, 202)
|
||||
|
||||
# As is, the servvice is still available in the DB till deleted from
|
||||
# As is, the service is still available in the DB till deleted from
|
||||
# the provider. The test should be able to handle this with
|
||||
# exponential sleep or whatever(!).
|
||||
status_code = 0
|
||||
count = 0
|
||||
while (count < 5):
|
||||
service_deleted = self.client.get_service(
|
||||
service_name=self.service_name)
|
||||
location=self.service_url)
|
||||
status_code = service_deleted.status_code
|
||||
if status_code == 200:
|
||||
time.sleep(1)
|
||||
|
@ -332,7 +353,12 @@ class TestServiceActions(base.TestBase):
|
|||
self.assertEqual(404, status_code)
|
||||
|
||||
def test_delete_non_existing_service(self):
|
||||
resp = self.client.delete_service(service_name='this_cant_be_true')
|
||||
parsed_url = urlparse.urlparse(self.service_url)
|
||||
url = "{0}://{1}{2}{3}".format(parsed_url.scheme,
|
||||
parsed_url.netloc,
|
||||
'/v1.0/services/',
|
||||
uuid.uuid4())
|
||||
resp = self.client.delete_service(location=url)
|
||||
self.assertEqual(resp.status_code, 404)
|
||||
|
||||
def test_delete_failed_service(self):
|
||||
|
@ -343,17 +369,20 @@ class TestServiceActions(base.TestBase):
|
|||
|
||||
@ddt.file_data('data_get_service_by_name.json')
|
||||
def test_get_service_by_name(self, value):
|
||||
self.client.create_service(service_name=value,
|
||||
domain_list=self.domain_list,
|
||||
origin_list=self.origin_list,
|
||||
caching_list=self.caching_list,
|
||||
flavor_id=self.flavor_id)
|
||||
resp = self.client.create_service(service_name=value,
|
||||
domain_list=self.domain_list,
|
||||
origin_list=self.origin_list,
|
||||
caching_list=self.caching_list,
|
||||
flavor_id=self.flavor_id)
|
||||
|
||||
resp = self.client.get_service(service_name=value)
|
||||
self.assertEqual(resp.status_code, 202)
|
||||
url = resp.headers["location"]
|
||||
|
||||
resp = self.client.get_service(location=url)
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
|
||||
def test_get_service(self):
|
||||
resp = self.client.get_service(service_name=self.service_name)
|
||||
resp = self.client.get_service(location=self.service_url)
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
|
||||
body = resp.json()
|
||||
|
@ -370,7 +399,12 @@ class TestServiceActions(base.TestBase):
|
|||
self.assertEqual(body['flavor_id'], self.flavor_id)
|
||||
|
||||
def test_get_non_existing_service(self):
|
||||
resp = self.client.get_service(service_name='this_cant_be_true')
|
||||
parsed_url = urlparse.urlparse(self.service_url)
|
||||
url = "{0}://{1}{2}{3}".format(parsed_url.scheme,
|
||||
parsed_url.netloc,
|
||||
'/v1.0/services/',
|
||||
uuid.uuid4())
|
||||
resp = self.client.get_service(location=url)
|
||||
self.assertEqual(resp.status_code, 404)
|
||||
|
||||
def test_get_failed_service(self):
|
||||
|
@ -380,7 +414,7 @@ class TestServiceActions(base.TestBase):
|
|||
pass
|
||||
|
||||
def tearDown(self):
|
||||
self.client.delete_service(service_name=self.service_name)
|
||||
self.client.delete_service(location=self.service_url)
|
||||
if self.test_config.generate_flavors:
|
||||
self.client.delete_flavor(flavor_id=self.flavor_id)
|
||||
super(TestServiceActions, self).tearDown()
|
||||
|
@ -416,13 +450,16 @@ class TestServicePatch(base.TestBase):
|
|||
"rules": [{"name": "index",
|
||||
"request_url": "/index.htm"}]}]
|
||||
|
||||
self.client.create_service(service_name=self.service_name,
|
||||
domain_list=self.domain_list,
|
||||
origin_list=self.origin_list,
|
||||
caching_list=self.caching_list,
|
||||
flavor_id=self.flavor_id)
|
||||
resp = self.client.create_service(service_name=self.service_name,
|
||||
domain_list=self.domain_list,
|
||||
origin_list=self.origin_list,
|
||||
caching_list=self.caching_list,
|
||||
flavor_id=self.flavor_id)
|
||||
|
||||
self.service_url = resp.headers["location"]
|
||||
|
||||
self.client.wait_for_service_status(
|
||||
service_name=self.service_name,
|
||||
location=self.service_url,
|
||||
status='deployed',
|
||||
retry_interval=self.test_config.status_check_retry_interval,
|
||||
retry_timeout=self.test_config.status_check_retry_timeout)
|
||||
|
@ -431,22 +468,20 @@ class TestServicePatch(base.TestBase):
|
|||
def test_patch_service(self, test_data):
|
||||
'''Implemented - PATCH Origins & Domains.'''
|
||||
|
||||
resp = self.client.patch_service(service_name=self.service_name,
|
||||
resp = self.client.patch_service(location=self.service_url,
|
||||
request_body=test_data)
|
||||
|
||||
self.assertEqual(resp.status_code, 202)
|
||||
|
||||
location = resp.headers['location']
|
||||
resp = self.client.get_service(location=location)
|
||||
resp = self.client.get_service(location=self.service_url)
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
|
||||
self.client.wait_for_service_status(
|
||||
service_name=self.service_name,
|
||||
location=self.service_url,
|
||||
status='deployed',
|
||||
retry_interval=self.test_config.status_check_retry_interval,
|
||||
retry_timeout=self.test_config.status_check_retry_timeout)
|
||||
|
||||
resp = self.client.get_service(service_name=self.service_name)
|
||||
resp = self.client.get_service(location=self.service_url)
|
||||
body = resp.json()
|
||||
|
||||
if 'domain_list' in test_data:
|
||||
|
@ -467,11 +502,11 @@ class TestServicePatch(base.TestBase):
|
|||
@ddt.file_data('data_patch_service_negative.json')
|
||||
def test_patch_service_HTTP_400(self, test_data):
|
||||
|
||||
resp = self.client.patch_service(service_name=self.service_name,
|
||||
resp = self.client.patch_service(location=self.service_url,
|
||||
request_body=test_data)
|
||||
self.assertEqual(resp.status_code, 400)
|
||||
|
||||
resp = self.client.get_service(service_name=self.service_name)
|
||||
resp = self.client.get_service(location=self.service_url)
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
|
||||
body = resp.json()
|
||||
|
@ -489,7 +524,7 @@ class TestServicePatch(base.TestBase):
|
|||
# self.assertEqual(sorted(self.caching_list), sorted(body['caching']))
|
||||
|
||||
def tearDown(self):
|
||||
self.client.delete_service(service_name=self.service_name)
|
||||
self.client.delete_service(location=self.service_url)
|
||||
if self.test_config.generate_flavors:
|
||||
self.client.delete_flavor(flavor_id=self.flavor_id)
|
||||
super(TestServicePatch, self).tearDown()
|
||||
|
|
|
@ -97,7 +97,7 @@ class PoppyClient(client.AutoMarshallingHTTPClient):
|
|||
return self.request('POST', url, request_entity=request_object,
|
||||
requestslib_kwargs=requestslib_kwargs)
|
||||
|
||||
def patch_service(self, service_name=None, request_body=None,
|
||||
def patch_service(self, location, request_body=None,
|
||||
requestslib_kwargs=None):
|
||||
"""Updates Service
|
||||
|
||||
|
@ -105,25 +105,19 @@ class PoppyClient(client.AutoMarshallingHTTPClient):
|
|||
PATCH
|
||||
services/{service_name}
|
||||
"""
|
||||
url = '{0}/services/{1}'.format(self.url, service_name)
|
||||
request_object = requests.PatchService(request_body=request_body)
|
||||
return self.request('PATCH', url, request_entity=request_object,
|
||||
return self.request('PATCH', location, request_entity=request_object,
|
||||
requestslib_kwargs=requestslib_kwargs)
|
||||
|
||||
def get_service(self, location=None, service_name=None):
|
||||
def get_service(self, location=None):
|
||||
"""Get Service
|
||||
|
||||
:return: Response Object containing response code 200 and body with
|
||||
details of service
|
||||
GET
|
||||
services/{service_name}
|
||||
services/{service_id}
|
||||
"""
|
||||
|
||||
if location:
|
||||
url = location
|
||||
else:
|
||||
url = '{0}/services/{1}'.format(self.url, service_name)
|
||||
return self.request('GET', url)
|
||||
return self.request('GET', location)
|
||||
|
||||
def list_services(self, param=None):
|
||||
"""Get a list of Services
|
||||
|
@ -137,16 +131,15 @@ class PoppyClient(client.AutoMarshallingHTTPClient):
|
|||
url = '{0}/services'.format(self.url)
|
||||
return self.request('GET', url, params=param)
|
||||
|
||||
def delete_service(self, service_name):
|
||||
def delete_service(self, location):
|
||||
"""Delete Service
|
||||
|
||||
:return: Response Object containing response code 204
|
||||
DELETE
|
||||
services/{service_name}
|
||||
services/{service_id}
|
||||
"""
|
||||
|
||||
url = '{0}/services/{1}'.format(self.url, service_name)
|
||||
return self.request('DELETE', url)
|
||||
return self.request('DELETE', location)
|
||||
|
||||
def check_health(self):
|
||||
"""Check Health of the application
|
||||
|
@ -217,7 +210,7 @@ class PoppyClient(client.AutoMarshallingHTTPClient):
|
|||
|
||||
return self.request('DELETE', url)
|
||||
|
||||
def wait_for_service_status(self, service_name, status, retry_interval=2,
|
||||
def wait_for_service_status(self, location, status, retry_interval=2,
|
||||
retry_timeout=30):
|
||||
"""Waits for a service to reach a given status."""
|
||||
current_status = ''
|
||||
|
@ -225,7 +218,7 @@ class PoppyClient(client.AutoMarshallingHTTPClient):
|
|||
stop_time = start_time + retry_timeout
|
||||
while current_status != status:
|
||||
time.sleep(retry_interval)
|
||||
service = self.get_service(service_name=service_name)
|
||||
service = self.get_service(location=location)
|
||||
body = service.json()
|
||||
current_status = body['status']
|
||||
if (current_status == status):
|
||||
|
|
|
@ -50,14 +50,23 @@ links = {'type': 'object',
|
|||
'flavor']}}
|
||||
}
|
||||
|
||||
error_message = {'type': 'object',
|
||||
'properties': {
|
||||
'message': {'type': 'string'}},
|
||||
'required': ['message'],
|
||||
'additionalProperties': False}
|
||||
|
||||
restrictions = {'type': 'array'}
|
||||
flavor_id = {'type': 'string', 'pattern': '([a-zA-Z0-9_\-]{1,256})'}
|
||||
service_name = {'type': 'string', 'pattern': '([a-zA-Z0-9_\-\.]{1,256})'}
|
||||
uuid4 = '^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$' # noqa
|
||||
service_id = {'type': 'string', 'pattern': uuid4}
|
||||
|
||||
# Response Schema Definition for Get Service API
|
||||
get_service = {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'id': service_id,
|
||||
'name': service_name,
|
||||
'domains': {'type': 'array',
|
||||
'items': domain,
|
||||
|
@ -80,7 +89,9 @@ get_service = {
|
|||
'enum': ['create_in_progress', 'creating',
|
||||
'delete_in_progress', 'deployed', 'failed']},
|
||||
'restrictions': restrictions,
|
||||
'flavor_id': flavor_id
|
||||
'flavor_id': flavor_id,
|
||||
'errors': {'type': 'array',
|
||||
'items': error_message}
|
||||
},
|
||||
'required': ['domains', 'origins', 'links', 'flavor_id', 'status',
|
||||
'errors'],
|
||||
|
@ -94,7 +105,7 @@ list_services_link = {
|
|||
'pattern':
|
||||
'(https?)(:/{1,3})([a-z0-9\.\-:]{1,400})'
|
||||
'(/v1\.0/([a-z0-9]{1,400})/services'
|
||||
'\?marker=)([a-zA-Z0-9_\-\.]{1,256})'
|
||||
'\?marker=)(' + uuid4 + ')'
|
||||
'(&limit=)([1-9]|1[0-9])'}},
|
||||
'required': ['rel', 'href'],
|
||||
'additionalProperties': False}
|
||||
|
|
|
@ -14,6 +14,10 @@
|
|||
# limitations under the License.
|
||||
|
||||
import json
|
||||
try:
|
||||
import urllib.parse as urlparse
|
||||
except ImportError:
|
||||
import urlparse
|
||||
import uuid
|
||||
|
||||
import ddt
|
||||
|
@ -65,8 +69,8 @@ class ServiceControllerTest(base.FunctionalTest):
|
|||
self.assertEqual(201, response.status_code)
|
||||
|
||||
# create an initial service to be used by the tests
|
||||
service_json = {
|
||||
"name": "mysite.com",
|
||||
self.service_json = {
|
||||
"name": self.service_name,
|
||||
"domains": [
|
||||
{"domain": "test.mocksite.com"},
|
||||
{"domain": "blog.mocksite.com"}
|
||||
|
@ -98,13 +102,15 @@ class ServiceControllerTest(base.FunctionalTest):
|
|||
]
|
||||
}
|
||||
|
||||
service_json['name'] = self.service_name
|
||||
response = self.app.post('/v1.0/services',
|
||||
params=json.dumps(service_json),
|
||||
params=json.dumps(self.service_json),
|
||||
headers={
|
||||
'Content-Type': 'application/json',
|
||||
'X-Project-ID': self.project_id})
|
||||
self.assertEqual(202, response.status_code)
|
||||
self.assertTrue('Location' in response.headers)
|
||||
|
||||
self.service_url = urlparse.urlparse(response.headers["Location"]).path
|
||||
|
||||
def tearDown(self):
|
||||
super(ServiceControllerTest, self).tearDown()
|
||||
|
@ -118,10 +124,8 @@ class ServiceControllerTest(base.FunctionalTest):
|
|||
# self.assertEqual(200, response.status_code)
|
||||
|
||||
def test_get_all(self):
|
||||
response = self.app.get('/v1.0/services', params={
|
||||
"marker": 2,
|
||||
"limit": 3
|
||||
}, headers={'X-Project-ID': self.project_id})
|
||||
response = self.app.get('/v1.0/services',
|
||||
headers={'X-Project-ID': self.project_id})
|
||||
|
||||
self.assertEqual(200, response.status_code)
|
||||
|
||||
|
@ -134,8 +138,8 @@ class ServiceControllerTest(base.FunctionalTest):
|
|||
self.limits_conf = self.conf[LIMITS_GROUP]
|
||||
self.max_services_per_page = self.limits_conf.max_services_per_page
|
||||
|
||||
response = self.app.get('/v1.0/0001/services', params={
|
||||
"marker": 'service_name',
|
||||
response = self.app.get('/v1.0/services', params={
|
||||
"marker": uuid.uuid4(),
|
||||
"limit": self.max_services_per_page + 1
|
||||
}, expect_errors=True)
|
||||
|
||||
|
@ -143,7 +147,7 @@ class ServiceControllerTest(base.FunctionalTest):
|
|||
|
||||
def test_get_one(self):
|
||||
response = self.app.get(
|
||||
'/v1.0/services/' + self.service_name,
|
||||
self.service_url,
|
||||
headers={'X-Project-ID': self.project_id})
|
||||
|
||||
self.assertEqual(200, response.status_code)
|
||||
|
@ -153,7 +157,7 @@ class ServiceControllerTest(base.FunctionalTest):
|
|||
self.assertTrue("origins" in response_dict)
|
||||
|
||||
def test_get_one_not_exist(self):
|
||||
response = self.app.get('/v1.0/services/non_exist_service_name',
|
||||
response = self.app.get('/v1.0/services/' + str(uuid.uuid4()),
|
||||
headers={
|
||||
'Content-Type': 'application/json',
|
||||
'X-Project-ID': self.project_id},
|
||||
|
@ -212,11 +216,11 @@ class ServiceControllerTest(base.FunctionalTest):
|
|||
'X-Project-ID': self.project_id
|
||||
},
|
||||
expect_errors=True)
|
||||
self.assertEqual(400, response.status_code)
|
||||
self.assertEqual(202, response.status_code)
|
||||
|
||||
def test_update_with_bad_input(self):
|
||||
# update with erroneous data
|
||||
response = self.app.patch('/v1.0/services/' + self.service_name,
|
||||
response = self.app.patch(self.service_url,
|
||||
params=json.dumps({
|
||||
"origins": [
|
||||
{
|
||||
|
@ -236,12 +240,12 @@ class ServiceControllerTest(base.FunctionalTest):
|
|||
|
||||
def test_update_with_good_input(self):
|
||||
response = self.app.get(
|
||||
'/v1.0/services/' + self.service_name,
|
||||
self.service_url,
|
||||
headers={'X-Project-ID': self.project_id})
|
||||
self.assertEqual(200, response.status_code)
|
||||
|
||||
# update with good data
|
||||
response = self.app.patch('/v1.0/services/' + self.service_name,
|
||||
response = self.app.patch(self.service_url,
|
||||
params=json.dumps({
|
||||
"origins": [
|
||||
{
|
||||
|
@ -259,20 +263,22 @@ class ServiceControllerTest(base.FunctionalTest):
|
|||
|
||||
def test_patch_non_exist(self):
|
||||
# This is for coverage 100%
|
||||
response = self.app.patch("/v1.0",
|
||||
headers={
|
||||
'Content-Type': 'application/json',
|
||||
'X-Project-ID': self.project_id
|
||||
},
|
||||
expect_errors=True)
|
||||
self.assertEqual(404, response.status_code)
|
||||
|
||||
response = self.app.patch("/v1.0/",
|
||||
headers={
|
||||
'Content-Type': 'application/json',
|
||||
'X-Project-ID': self.project_id
|
||||
},
|
||||
expect_errors=True)
|
||||
response = self.app.patch(
|
||||
"/v1.0/services/{0}".format(str(uuid.uuid4())),
|
||||
headers={
|
||||
'Content-Type': 'application/json',
|
||||
'X-Project-ID': self.project_id
|
||||
},
|
||||
params=json.dumps({
|
||||
"origins": [
|
||||
{
|
||||
"origin": "44.33.22.11",
|
||||
"port": 80,
|
||||
"ssl": False
|
||||
}
|
||||
]
|
||||
}),
|
||||
expect_errors=True)
|
||||
self.assertEqual(404, response.status_code)
|
||||
|
||||
class FakeController(c_base.Controller):
|
||||
|
@ -287,7 +293,7 @@ class ServiceControllerTest(base.FunctionalTest):
|
|||
|
||||
def test_delete(self):
|
||||
response = self.app.delete(
|
||||
'/v1.0/services/%s' % self.service_name,
|
||||
self.service_url,
|
||||
headers={
|
||||
'Content-Type': 'application/json',
|
||||
'X-Project-ID': self.project_id
|
||||
|
@ -298,7 +304,7 @@ class ServiceControllerTest(base.FunctionalTest):
|
|||
# TODO(amitgandhinz): commented out as thread model
|
||||
# is not allowing thread to process with test
|
||||
|
||||
# # check if it actually gets deleted
|
||||
# check if it actually gets deleted
|
||||
# status_code = 0
|
||||
# count = 0
|
||||
# while (count < 5):
|
||||
|
@ -322,18 +328,19 @@ class ServiceControllerTest(base.FunctionalTest):
|
|||
# self.assertEqual(404, status_code)
|
||||
|
||||
def test_delete_non_exist(self):
|
||||
response = self.app.delete('/v1.0/services/non_exist_service_name',
|
||||
headers={
|
||||
'Content-Type': 'application/json',
|
||||
'X-Project-ID': self.project_id
|
||||
},
|
||||
expect_errors=True)
|
||||
response = self.app.delete(
|
||||
"/v1.0/services/{0}".format(str(uuid.uuid4())),
|
||||
headers={
|
||||
'Content-Type': 'application/json',
|
||||
'X-Project-ID': self.project_id
|
||||
},
|
||||
expect_errors=True)
|
||||
self.assertEqual(404, response.status_code)
|
||||
|
||||
def test_purge_non_exist(self):
|
||||
# This is for coverage 100%
|
||||
response = self.app.delete(
|
||||
"/v1.0/services/non_exist_service_name/assets?all=true",
|
||||
"/v1.0/services/{0}/assets?all=true".format(str(uuid.uuid4())),
|
||||
headers={
|
||||
"Content-Type": "application/json",
|
||||
'X-Project-ID': self.project_id
|
||||
|
@ -343,7 +350,7 @@ class ServiceControllerTest(base.FunctionalTest):
|
|||
|
||||
def test_purge_error_parms(self):
|
||||
response = self.app.delete(
|
||||
'/v1.0/services/fake_service_name_4/assets',
|
||||
self.service_url + '/assets',
|
||||
headers={
|
||||
"Content-Type": "application/json",
|
||||
'X-Project-ID': self.project_id
|
||||
|
@ -353,7 +360,7 @@ class ServiceControllerTest(base.FunctionalTest):
|
|||
self.assertEqual(400, response.status_code)
|
||||
|
||||
response = self.app.delete(
|
||||
'/v1.0/services/fake_service_name_4/assets?all=true&url=/abc',
|
||||
self.service_url + '/assets?all=true&url=/abc',
|
||||
headers={
|
||||
"Content-Type": "application/json",
|
||||
'X-Project-ID': self.project_id
|
||||
|
@ -364,7 +371,7 @@ class ServiceControllerTest(base.FunctionalTest):
|
|||
|
||||
def test_purge_all(self):
|
||||
response = self.app.delete(
|
||||
'/v1.0/services/fake_service_name_4/assets?all=true',
|
||||
self.service_url + '/assets?all=true',
|
||||
headers={
|
||||
"Content-Type": "application/json",
|
||||
'X-Project-ID': self.project_id
|
||||
|
@ -375,7 +382,7 @@ class ServiceControllerTest(base.FunctionalTest):
|
|||
|
||||
def test_purge_single_url(self):
|
||||
response = self.app.delete(
|
||||
'/v1.0/services/fake_service_name_4/assets?url=/abc',
|
||||
self.service_url + '/assets?url=/abc',
|
||||
headers={
|
||||
"Content-Type": "application/json",
|
||||
'X-Project-ID': self.project_id
|
||||
|
|
|
@ -30,8 +30,9 @@ class ErrorHookTest(base.FunctionalTest):
|
|||
self.headers['X-Project-Id'] = '000001'
|
||||
# use try except to actually catch the response body in
|
||||
# exception part
|
||||
service_id = str(uuid.uuid4())
|
||||
response = self.app.get(
|
||||
'/v1.0/services/non_exist_service_name',
|
||||
'/v1.0/services/' + service_id,
|
||||
headers=self.headers,
|
||||
status=404)
|
||||
|
||||
|
@ -39,5 +40,5 @@ class ErrorHookTest(base.FunctionalTest):
|
|||
self.assertEqual('application/json', response.content_type)
|
||||
response_json = json.loads(response.body.decode('utf-8'))
|
||||
self.assertTrue('message' in response_json)
|
||||
self.assertEqual('service non_exist_service_name is not found',
|
||||
self.assertEqual('service {0} could not be found'.format(service_id),
|
||||
response_json['message'])
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import uuid
|
||||
|
||||
import ddt
|
||||
import mock
|
||||
from oslo.config import cfg
|
||||
|
@ -58,8 +60,11 @@ class TestServicesCreate(base.TestCase):
|
|||
if six.PY2:
|
||||
responders = [{
|
||||
'Fastly':
|
||||
{'error_detail': 'Error in create',
|
||||
'error': 'failed to create service'}}]
|
||||
{
|
||||
'error_detail': 'Error in create',
|
||||
'error': 'failed to create service'
|
||||
}
|
||||
}]
|
||||
self.controller.create(responders)
|
||||
|
||||
def test_create(self):
|
||||
|
@ -78,7 +83,7 @@ class TestServicesCreate(base.TestCase):
|
|||
'rel': 'access_url'
|
||||
}
|
||||
]}
|
||||
}]
|
||||
}]
|
||||
self.controller.create(responders)
|
||||
|
||||
|
||||
|
@ -115,7 +120,8 @@ class TestServicesUpdate(base.TestCase):
|
|||
'Fastly': fastly_provider_details_old
|
||||
}
|
||||
|
||||
self.service_old = service.Service(name='myservice',
|
||||
self.service_old = service.Service(service_id=uuid.uuid4(),
|
||||
name='myservice',
|
||||
domains=self.domains_old,
|
||||
origins=self.origins_old,
|
||||
flavor_id='standard')
|
||||
|
@ -133,7 +139,8 @@ class TestServicesUpdate(base.TestCase):
|
|||
domains_new = [domain.Domain('www.domain1.com'),
|
||||
domain.Domain('www.domain2.com'),
|
||||
domain.Domain('www.domain3.com')]
|
||||
service_updates = service.Service(name='myservice',
|
||||
service_updates = service.Service(service_id=uuid.uuid4(),
|
||||
name='myservice',
|
||||
domains=domains_new,
|
||||
origins=[],
|
||||
flavor_id='standard')
|
||||
|
@ -142,8 +149,8 @@ class TestServicesUpdate(base.TestCase):
|
|||
'Fastly': {
|
||||
'id': u'4PRhL3lHlZhrXr1mJUt24M',
|
||||
'error': 'Create service failed'
|
||||
}
|
||||
}]
|
||||
}
|
||||
}]
|
||||
|
||||
self.controller.update(self.service_old,
|
||||
service_updates,
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
# limitations under the License.
|
||||
|
||||
import json
|
||||
import uuid
|
||||
|
||||
import ddt
|
||||
import mock
|
||||
|
@ -41,7 +42,7 @@ class DefaultManagerServiceTests(base.TestCase):
|
|||
# create mocked config and driver
|
||||
conf = cfg.ConfigOpts()
|
||||
|
||||
# mock a steveodore provider extension
|
||||
# mock a stevedore provider extension
|
||||
def get_provider_by_name(name):
|
||||
name_p_name_mapping = {
|
||||
'maxcdn': 'MaxCDN',
|
||||
|
@ -61,10 +62,11 @@ class DefaultManagerServiceTests(base.TestCase):
|
|||
# stubbed driver
|
||||
self.sc = services.DefaultServicesController(manager_driver)
|
||||
|
||||
self.project_id = 'mock_id'
|
||||
self.service_name = 'mock_service'
|
||||
self.project_id = str(uuid.uuid4())
|
||||
self.service_name = str(uuid.uuid4())
|
||||
self.service_id = str(uuid.uuid4())
|
||||
self.service_json = {
|
||||
"name": "mock_service",
|
||||
"name": self.service_name,
|
||||
"domains": [
|
||||
{"domain": "www.mywebsite.com"},
|
||||
{"domain": "blog.mywebsite.com"},
|
||||
|
@ -240,7 +242,7 @@ class DefaultManagerServiceTests(base.TestCase):
|
|||
res = create_service_worker.service_create_worker(
|
||||
json.dumps(providers_list),
|
||||
self.project_id,
|
||||
self.service_name,
|
||||
self.service_id,
|
||||
json.dumps(service_obj.to_dict()))
|
||||
self.assertTrue(res is None)
|
||||
|
||||
|
@ -273,7 +275,7 @@ class DefaultManagerServiceTests(base.TestCase):
|
|||
service_obj.status = u'deployed'
|
||||
self.sc.storage_controller.get.return_value = service_obj
|
||||
service_update_obj = service.load_from_json(update_json)
|
||||
self.sc.update(self.project_id, self.service_name, service_update_obj)
|
||||
self.sc.update(self.project_id, self.service_id, service_update_obj)
|
||||
|
||||
# ensure the manager calls the storage driver with the appropriate data
|
||||
self.sc.storage_controller.update.assert_called_once()
|
||||
|
@ -301,14 +303,14 @@ class DefaultManagerServiceTests(base.TestCase):
|
|||
self.provider_details
|
||||
)
|
||||
|
||||
self.sc.delete(self.project_id, self.service_name)
|
||||
self.sc.delete(self.project_id, self.service_id)
|
||||
|
||||
# ensure the manager calls the storage driver with the appropriate data
|
||||
# break into 2 lines.
|
||||
sc = self.sc.storage_controller
|
||||
sc.get_provider_details.assert_called_once_with(
|
||||
self.project_id,
|
||||
self.service_name)
|
||||
self.service_id)
|
||||
|
||||
@ddt.file_data('data_provider_details.json')
|
||||
def test_detele_service_worker_success(self, provider_details_json):
|
||||
|
@ -376,10 +378,10 @@ class DefaultManagerServiceTests(base.TestCase):
|
|||
for k, v in
|
||||
self.provider_details.items()])),
|
||||
self.project_id,
|
||||
self.service_name)
|
||||
self.service_id)
|
||||
|
||||
@ddt.file_data('data_provider_details.json')
|
||||
def test_detele_service_worker_with_error(self, provider_details_json):
|
||||
def test_delete_service_worker_with_error(self, provider_details_json):
|
||||
self.provider_details = {}
|
||||
for provider_name in provider_details_json:
|
||||
provider_detail_dict = json.loads(
|
||||
|
@ -441,7 +443,7 @@ class DefaultManagerServiceTests(base.TestCase):
|
|||
for k, v in
|
||||
self.provider_details.items()])),
|
||||
self.project_id,
|
||||
self.service_name)
|
||||
self.service_id)
|
||||
|
||||
@ddt.file_data('data_provider_details.json')
|
||||
def test_purge(self, provider_details_json):
|
||||
|
@ -463,13 +465,13 @@ class DefaultManagerServiceTests(base.TestCase):
|
|||
self.provider_details
|
||||
)
|
||||
|
||||
self.sc.purge(self.project_id, self.service_name, None)
|
||||
self.sc.purge(self.project_id, self.service_id, None)
|
||||
|
||||
# ensure the manager calls the storage driver with the appropriate data
|
||||
sc = self.sc.storage_controller
|
||||
sc.get_provider_details.assert_called_once_with(
|
||||
self.project_id,
|
||||
self.service_name,
|
||||
self.service_id,
|
||||
)
|
||||
|
||||
@ddt.file_data('data_provider_details.json')
|
||||
|
@ -508,9 +510,11 @@ class DefaultManagerServiceTests(base.TestCase):
|
|||
provider_name='MaxCDN',
|
||||
service_controller=mock.Mock(
|
||||
purge=mock.Mock(return_value={
|
||||
'MaxCDN': {'id':
|
||||
'08d2e326-377e-11e4-b531-3c15c2b8d2d6'
|
||||
}})
|
||||
'MaxCDN': {
|
||||
'id':
|
||||
'08d2e326-377e-11e4-b531-3c15c2b8d2d6'
|
||||
}
|
||||
})
|
||||
)
|
||||
))
|
||||
else:
|
||||
|
@ -533,7 +537,7 @@ class DefaultManagerServiceTests(base.TestCase):
|
|||
for k, v in
|
||||
self.provider_details.items()])),
|
||||
self.project_id,
|
||||
self.service_name,
|
||||
self.service_id,
|
||||
str(None))
|
||||
|
||||
@ddt.file_data('data_provider_details.json')
|
||||
|
@ -587,5 +591,5 @@ class DefaultManagerServiceTests(base.TestCase):
|
|||
for k, v in
|
||||
self.provider_details.items()])),
|
||||
self.project_id,
|
||||
self.service_name,
|
||||
self.service_id,
|
||||
str(None))
|
||||
|
|
|
@ -32,6 +32,7 @@ class TestServiceModel(base.TestCase):
|
|||
def setUp(self):
|
||||
super(TestServiceModel, self).setUp()
|
||||
|
||||
self.service_id = str(uuid.uuid4())
|
||||
self.service_name = uuid.uuid1()
|
||||
self.flavor_id = "strawberry"
|
||||
|
||||
|
@ -59,10 +60,14 @@ class TestServiceModel(base.TestCase):
|
|||
|
||||
def test_create(self):
|
||||
myservice = service.Service(
|
||||
self.service_id,
|
||||
self.service_name, self.mydomains, self.myorigins, self.flavor_id,
|
||||
self.mycaching, self.myrestrictions)
|
||||
|
||||
# test all properties
|
||||
# id
|
||||
self.assertEqual(myservice.service_id, self.service_id)
|
||||
|
||||
# name
|
||||
self.assertEqual(myservice.name, self.service_name)
|
||||
changed_service_name = 'ChangedServiceName'
|
||||
|
@ -104,23 +109,40 @@ class TestServiceModel(base.TestCase):
|
|||
def test_init_from_dict_method(self):
|
||||
# this should generate a service copy from my service
|
||||
myservice = service.Service(
|
||||
self.service_id,
|
||||
self.service_name, self.mydomains, self.myorigins, self.flavor_id,
|
||||
self.mycaching, self.myrestrictions)
|
||||
cloned_service = service.Service.init_from_dict(myservice.to_dict())
|
||||
|
||||
self.assertEqual(cloned_service.service_id, myservice.service_id)
|
||||
self.assertEqual(cloned_service.name, myservice.name)
|
||||
self.assertEqual(cloned_service.flavor_id, myservice.flavor_id)
|
||||
|
||||
self.assertEqual([domain.to_dict() for domain
|
||||
in cloned_service.domains],
|
||||
[domain.to_dict() for domain
|
||||
in myservice.domains])
|
||||
|
||||
self.assertEqual([origin.to_dict() for origin
|
||||
in cloned_service.origins],
|
||||
[origin.to_dict() for origin
|
||||
in myservice.origins])
|
||||
self.assertEqual(cloned_service.flavor_id, myservice.flavor_id)
|
||||
|
||||
# (amitgandhinz) need to add caching and restrictions
|
||||
# self.assertEqual([caching.to_dict() for caching
|
||||
# in cloned_service.caching],
|
||||
# [caching.to_dict() for caching
|
||||
# in myservice.caching])
|
||||
|
||||
# self.assertEqual([restrictions.to_dict() for restrictions
|
||||
# in cloned_service.restrictions],
|
||||
# [restrictions.to_dict() for restrictions
|
||||
# in myservice.restrictions])
|
||||
|
||||
@ddt.data(u'', u'apple')
|
||||
def test_set_invalid_status(self, status):
|
||||
myservice = service.Service(
|
||||
self.service_id,
|
||||
self.service_name,
|
||||
self.mydomains,
|
||||
self.myorigins,
|
||||
|
@ -131,6 +153,7 @@ class TestServiceModel(base.TestCase):
|
|||
@ddt.data(u'create_in_progress', u'deployed', u'delete_in_progress')
|
||||
def test_set_valid_status(self, status):
|
||||
myservice = service.Service(
|
||||
self.service_id,
|
||||
self.service_name,
|
||||
self.mydomains,
|
||||
self.myorigins,
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
{
|
||||
"using_all_fields": [
|
||||
{
|
||||
"service_name" : "mocksite",
|
||||
"service_id": "00000000-0000-0000-0000-000000000000",
|
||||
"service_name": "mocksite",
|
||||
"domains": [
|
||||
"{\"domain\": \"www.mocksite.com\"}",
|
||||
"{\"domain\": \"blog.mocksite.com\"}"
|
||||
|
|
|
@ -181,12 +181,14 @@ class CassandraStorageDriverTests(base.TestCase):
|
|||
|
||||
def test_is_alive_no_connection(self):
|
||||
"""No connection test for checking the health of Cassandra."""
|
||||
self.skipTest('Too slow, need to mock exception')
|
||||
|
||||
self.cassandra_driver.session = None
|
||||
self.assertFalse(self.cassandra_driver.is_alive())
|
||||
|
||||
def test_is_alive_with_exception(self):
|
||||
"""Broken connection test for checking the health of Cassandra."""
|
||||
self.skipTest('Too slow, need to mock exception')
|
||||
|
||||
self.cassandra_driver.session = None
|
||||
self.cassandra_driver.connect = mock.Mock()
|
||||
|
@ -198,6 +200,7 @@ class CassandraStorageDriverTests(base.TestCase):
|
|||
|
||||
def test_is_alive(self):
|
||||
"""Happy path test for checking the health of Cassandra."""
|
||||
self.skipTest('Too slow, need to mock exception')
|
||||
|
||||
self.cassandra_driver.session = None
|
||||
self.cassandra_driver.connect = mock.Mock()
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
# limitations under the License.
|
||||
|
||||
import json
|
||||
import uuid
|
||||
try:
|
||||
import ordereddict as collections
|
||||
except ImportError: # pragma: no cover
|
||||
|
@ -39,6 +40,7 @@ class CassandraStorageServiceTests(base.TestCase):
|
|||
|
||||
# mock arguments to use
|
||||
self.project_id = '123456'
|
||||
self.service_id = uuid.uuid4()
|
||||
self.service_name = 'mocksite'
|
||||
|
||||
# create mocked config and driver
|
||||
|
@ -61,13 +63,14 @@ class CassandraStorageServiceTests(base.TestCase):
|
|||
def test_get_service(self, value, mock_session, mock_execute):
|
||||
|
||||
# mock the response from cassandra
|
||||
value[0]['service_id'] = self.service_id
|
||||
mock_execute.execute.return_value = value
|
||||
|
||||
actual_response = self.sc.get(self.project_id, self.service_name)
|
||||
actual_response = self.sc.get(self.project_id, self.service_id)
|
||||
|
||||
# TODO(amitgandhinz): assert the response
|
||||
# matches the expectation (using jsonschema)
|
||||
self.assertEqual(actual_response.name, self.service_name)
|
||||
self.assertEqual(str(actual_response.service_id), str(self.service_id))
|
||||
|
||||
@mock.patch.object(services.ServicesController, 'session')
|
||||
@mock.patch.object(cassandra.cluster.Session, 'execute')
|
||||
|
@ -77,12 +80,16 @@ class CassandraStorageServiceTests(base.TestCase):
|
|||
mock_execute.execute.return_value = []
|
||||
|
||||
self.assertRaises(ValueError, self.sc.get,
|
||||
self.project_id, self.service_name)
|
||||
self.project_id, self.service_id)
|
||||
|
||||
@ddt.file_data('../data/data_create_service.json')
|
||||
@mock.patch.object(services.ServicesController,
|
||||
'_exists_elsewhere',
|
||||
return_value=False)
|
||||
@mock.patch.object(services.ServicesController, 'session')
|
||||
@mock.patch.object(cassandra.cluster.Session, 'execute')
|
||||
def test_create_service(self, value, mock_session, mock_execute):
|
||||
def test_create_service(self, value,
|
||||
mock_check, mock_session, mock_execute):
|
||||
service_obj = req_service.load_from_json(value)
|
||||
responses = self.sc.create(self.project_id, service_obj)
|
||||
|
||||
|
@ -93,10 +100,13 @@ class CassandraStorageServiceTests(base.TestCase):
|
|||
# TODO(amitgandhinz): need to validate the create to cassandra worked.
|
||||
|
||||
@ddt.file_data('../data/data_create_service.json')
|
||||
@mock.patch.object(services.ServicesController,
|
||||
'_exists_elsewhere',
|
||||
return_value=True)
|
||||
@mock.patch.object(services.ServicesController, 'session')
|
||||
@mock.patch.object(cassandra.cluster.Session, 'execute')
|
||||
def test_create_service_exist(self, value, mock_session, mock_execute):
|
||||
value.update({'name': self.service_name})
|
||||
def test_create_service_exist(self, value,
|
||||
mock_check, mock_session, mock_execute):
|
||||
service_obj = req_service.load_from_json(value)
|
||||
self.sc.get = mock.Mock(return_value=service_obj)
|
||||
|
||||
|
@ -122,26 +132,49 @@ class CassandraStorageServiceTests(base.TestCase):
|
|||
@mock.patch.object(cassandra.cluster.Session, 'execute')
|
||||
def test_delete_service(self, mock_session, mock_execute):
|
||||
# mock the response from cassandra
|
||||
actual_response = self.sc.delete(self.project_id, self.service_name)
|
||||
actual_response = self.sc.delete(self.project_id, self.service_id)
|
||||
|
||||
# Expect the response to be None as there are no providers passed
|
||||
# into the driver to respond to this call
|
||||
self.assertEqual(actual_response, None)
|
||||
|
||||
@ddt.file_data('../data/data_update_service.json')
|
||||
@mock.patch.object(services.ServicesController,
|
||||
'_exists_elsewhere',
|
||||
return_value=False)
|
||||
@mock.patch.object(services.ServicesController, 'session')
|
||||
@mock.patch.object(cassandra.cluster.Session, 'execute')
|
||||
def test_update_service(self, service_json, mock_session, mock_execute):
|
||||
# mock the response from cassandra
|
||||
def test_update_service(self, service_json,
|
||||
mock_check, mock_session, mock_execute):
|
||||
mock_check.return_value = False
|
||||
service_obj = req_service.load_from_json(service_json)
|
||||
actual_response = self.sc.update(self.project_id,
|
||||
self.service_name,
|
||||
self.service_id,
|
||||
service_obj)
|
||||
|
||||
# Expect the response to be None as there are no providers passed
|
||||
# into the driver to respond to this call
|
||||
self.assertEqual(actual_response, None)
|
||||
|
||||
@ddt.file_data('../data/data_update_service.json')
|
||||
@mock.patch.object(services.ServicesController,
|
||||
'_exists_elsewhere',
|
||||
return_value=True)
|
||||
@mock.patch.object(services.ServicesController, 'session')
|
||||
@mock.patch.object(cassandra.cluster.Session, 'execute')
|
||||
def test_update_service_duplicate_domain(self, service_json,
|
||||
mock_check, mock_session,
|
||||
mock_execute):
|
||||
# mock the response from cassandra
|
||||
service_obj = req_service.load_from_json(service_json)
|
||||
|
||||
# Expect the response to be a ValueError Exception
|
||||
self.assertRaises(ValueError,
|
||||
self.sc.update,
|
||||
self.project_id,
|
||||
self.service_id,
|
||||
service_obj)
|
||||
|
||||
@ddt.file_data('data_provider_details.json')
|
||||
@mock.patch.object(services.ServicesController, 'session')
|
||||
@mock.patch.object(cassandra.cluster.Session, 'execute')
|
||||
|
@ -151,7 +184,7 @@ class CassandraStorageServiceTests(base.TestCase):
|
|||
mock_execute.execute.return_value = [{'provider_details':
|
||||
provider_details_json}]
|
||||
actual_response = self.sc.get_provider_details(self.project_id,
|
||||
self.service_name)
|
||||
self.service_id)
|
||||
self.assertTrue("MaxCDN" in actual_response)
|
||||
self.assertTrue("Mock" in actual_response)
|
||||
self.assertTrue("CloudFront" in actual_response)
|
||||
|
@ -175,7 +208,7 @@ class CassandraStorageServiceTests(base.TestCase):
|
|||
|
||||
self.sc.update_provider_details(
|
||||
self.project_id,
|
||||
self.service_name,
|
||||
self.service_id,
|
||||
provider_details_dict)
|
||||
|
||||
# this is for update_provider_details unittest code coverage
|
||||
|
@ -198,7 +231,7 @@ class CassandraStorageServiceTests(base.TestCase):
|
|||
the_provider_detail_dict)
|
||||
args = {
|
||||
'project_id': self.project_id,
|
||||
'service_name': self.service_name,
|
||||
'service_id': self.service_id,
|
||||
'provider_details': arg_provider_details_dict
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
{
|
||||
"using_all_fields": {
|
||||
"service_id": "00000000-0000-0000-0000-000000000000",
|
||||
"name": "mocksite.com",
|
||||
"domains": [
|
||||
{"domain": "test.mocksite.com" },
|
||||
|
|
Loading…
Reference in New Issue