fix: update service when missing provider details

Updating a service that was missing provider details
failed to update the service status. This changeset ensures
that the service is updated properly.

Change-Id: Ifd668d6336dde0ed5528a2be63fafdd076ed7510
This commit is contained in:
Isaac Mungai 2016-03-28 09:01:40 -04:00
parent fce2fb8718
commit 28d241ceec
7 changed files with 176 additions and 16 deletions

View File

@ -174,7 +174,8 @@ class DefaultServicesController(base.ServicesController):
"""create.
:param project_id
:param service_obj
:param auth_token
:param service_json
:raises LookupError, ValueError
"""
try:
@ -236,12 +237,15 @@ class DefaultServicesController(base.ServicesController):
return service_obj
def update(self, project_id, service_id, auth_token, service_updates):
def update(self, project_id, service_id,
auth_token, service_updates, force_update=False):
"""update.
:param project_id
:param service_id
:param auth_token
:param service_updates
:param force_update
:raises LookupError, ValueError
"""
# get the current service object
@ -254,7 +258,10 @@ class DefaultServicesController(base.ServicesController):
raise errors.ServiceStatusDisabled(
u'Service {0} is disabled'.format(service_id))
if service_old.status not in [u'deployed', u'failed']:
if (
service_old.status not in [u'deployed', u'failed'] and
force_update is False
):
raise errors.ServiceStatusNeitherDeployedNorFailed(
u'Service {0} neither deployed nor failed'.format(service_id))
@ -434,11 +441,23 @@ class DefaultServicesController(base.ServicesController):
project_id=project_id,
project_limit=limit)
def set_service_provider_details(self, project_id, service_id, status):
def set_service_provider_details(self, project_id, service_id,
auth_token, status):
old_service = self.storage_controller.get(project_id, service_id)
if (
old_service.status == 'create_in_progress' and
old_service.provider_details == {}
):
self.update(
project_id, service_id, auth_token, [], force_update=True)
return 202
self.storage_controller.set_service_provider_details(
project_id,
service_id,
status)
status
)
return 201
def get_services_limit(self, project_id):
limit = self.storage_controller.get_service_limit(

View File

@ -191,7 +191,7 @@ class CassandraStorageDriver(base.Driver):
"""Health check for Cassandra."""
try:
self.session.execute(
self.database.execute(
"SELECT cluster_name, data_center FROM system.local;")
except Exception:
return False

View File

@ -390,10 +390,14 @@ class ServiceStatusController(base.Controller, hooks.HookController):
status = service_state_json['status']
services_controller = self._driver.manager.services_controller
status_code = None
try:
services_controller.set_service_provider_details(project_id,
service_id,
status)
status_code = services_controller.set_service_provider_details(
project_id,
service_id,
self.auth_token,
status
)
except Exception as e:
pecan.abort(404, detail=(
'Setting state of service {0} on tenant: {1} '
@ -403,7 +407,7 @@ class ServiceStatusController(base.Controller, hooks.HookController):
status,
str(e))))
return pecan.Response(None, 201)
return pecan.Response(None, status_code)
class AdminCertController(base.Controller, hooks.HookController):

View File

@ -580,7 +580,7 @@ def is_valid_service_status(request):
# supported statuses
VALID_STATUSES = [
u'deploy_in_progress',
u'create_in_progress',
u'deployed',
u'update_in_progress',
u'delete_in_progress',

View File

@ -53,9 +53,9 @@ class TestGetServiceStatus(base.FunctionalTest):
self.assertEqual(response.status_code, 400)
@ddt.data('deploy_in_progress', 'deployed', 'update_in_progress',
@ddt.data('create_in_progress', 'deployed', 'update_in_progress',
'delete_in_progress', 'failed')
def test_get_service_status_valid_queryparam(self, status):
def test_get_service_status_valid_query_param(self, status):
# valid status
with mock.patch.object(DefaultServicesController,
'get_services_by_status'):

View File

@ -30,7 +30,78 @@ class TestServicesState(base.FunctionalTest):
super(TestServicesState, self).setUp()
self.project_id = str(uuid.uuid4())
self.service_id = str(uuid.uuid4())
self.service_name = str(uuid.uuid1())
self.flavor_id = str(uuid.uuid1())
# create a mock flavor to be used by new service creations
flavor_json = {
"id": self.flavor_id,
"providers": [
{
"provider": "mock",
"links": [
{
"href": "http://mock.cdn",
"rel": "provider_url"
}
]
}
]
}
response = self.app.post('/v1.0/flavors',
params=json.dumps(flavor_json),
headers={
"Content-Type": "application/json",
"X-Project-ID": self.project_id})
self.assertEqual(201, response.status_code)
# create an initial service to be used by the tests
self.service_json = {
"name": self.service_name,
"domains": [
{"domain": "test.mocksite.com"},
{"domain": "blog.mocksite.com"}
],
"origins": [
{
"origin": "mocksite.com",
"port": 80,
"ssl": False
}
],
"flavor_id": self.flavor_id,
"caching": [
{
"name": "default",
"ttl": 3600
}
],
"restrictions": [
{
"name": "website only",
"type": "whitelist",
"rules": [
{
"name": "mocksite.com",
"referrer": "www.mocksite.com"
}
]
}
]
}
response = self.app.post('/v1.0/services',
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_id = (response.headers['Location']
[response.headers['Location'].rfind('/') + 1:])
self.req_body = {
'project_id': self.project_id,
'service_id': self.service_id,
@ -38,6 +109,13 @@ class TestServicesState(base.FunctionalTest):
@ddt.data(u'deployed', u'failed')
def test_services_state_valid_states(self, status):
response = self.app.get(
'/v1.0/services/{0}'.format(self.service_id),
headers={'X-Project-ID': self.project_id}
)
self.assertEqual(200, response.status_code)
self.req_body['status'] = status
response = self.app.post(
'/v1.0/admin/services/status',

View File

@ -20,6 +20,7 @@ import uuid
import ddt
import mock
from oslo_config import cfg
from oslo_context import context
import requests
import six
@ -103,8 +104,8 @@ class DefaultManagerServiceTests(base.TestCase):
@mock.patch('poppy.storage.base.driver.StorageDriverBase')
@mock.patch('poppy.distributed_task.base.driver.DistributedTaskDriverBase')
@mock.patch('poppy.metrics.base.driver.MetricsDriverBase')
def setUp(self, mock_distributed_task, mock_storage,
mock_dns, mock_notification, mock_bootstrap, mock_metrics):
def setUp(self, mock_metrics, mock_distributed_task, mock_storage,
mock_dns, mock_notification, mock_bootstrap):
# NOTE(TheSriram): the mock.patch decorator applies mocks
# in the reverse order of the arguments present
super(DefaultManagerServiceTests, self).setUp()
@ -216,6 +217,9 @@ class DefaultManagerServiceTests(base.TestCase):
self.service_obj = service.load_from_json(self.service_json)
self.mock_storage = mock_storage
self.mock_distributed_task = mock_distributed_task
@mock.patch('poppy.bootstrap.Bootstrap')
def mock_purge_service(self, mock_bootstrap, hard=False):
mock_bootstrap.return_value = self.bootstrap_obj
@ -1005,3 +1009,58 @@ class DefaultManagerServiceTests(base.TestCase):
memoized_controllers.task_controllers):
self.mock_purge_service(hard=True)
self.mock_purge_service(hard=False)
def test_set_service_provider_details_missing_provider_details(self):
context.RequestContext(overwrite=True)
mock_service_obj = mock.Mock()
mock_service_obj.to_dict.return_value = {
'name': 'name',
'flavor_id': 'flavor_id',
'service_id': 'service_id',
'status': 'status',
'operator_status': 'operator_status',
'provider_details': 'provider_details',
'domains': [
{'domain': 'www.test.com'}
],
'origins': [
{
"origin": "www.tester.com",
"port": 80,
"ssl": False,
"rules": [
{
"name": "default",
"request_url": "/*"
}
],
"hostheadertype": "domain"
}
]
}
type(mock_service_obj).service_id = mock.PropertyMock(
return_value='service_id'
)
type(mock_service_obj).status = mock.PropertyMock(
return_value="create_in_progress"
)
type(mock_service_obj).provider_details = mock.PropertyMock(
return_value=dict()
)
type(mock_service_obj).domains = mock.PropertyMock(
return_value=list()
)
self.mock_storage.services_controller.get.return_value = (
mock_service_obj
)
self.sc.set_service_provider_details(
"project_id", "service_id", "auth_token", "deployed"
)
self.assertTrue(self.mock_storage.services_controller.get.called)
self.assertTrue(self.mock_storage.services_controller.update.called)
self.assertTrue(
self.mock_distributed_task.services_controller.submit_task.called
)