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:
parent
fce2fb8718
commit
28d241ceec
|
@ -174,7 +174,8 @@ class DefaultServicesController(base.ServicesController):
|
||||||
"""create.
|
"""create.
|
||||||
|
|
||||||
:param project_id
|
:param project_id
|
||||||
:param service_obj
|
:param auth_token
|
||||||
|
:param service_json
|
||||||
:raises LookupError, ValueError
|
:raises LookupError, ValueError
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
|
@ -236,12 +237,15 @@ class DefaultServicesController(base.ServicesController):
|
||||||
|
|
||||||
return service_obj
|
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.
|
"""update.
|
||||||
|
|
||||||
:param project_id
|
:param project_id
|
||||||
:param service_id
|
:param service_id
|
||||||
|
:param auth_token
|
||||||
:param service_updates
|
:param service_updates
|
||||||
|
:param force_update
|
||||||
:raises LookupError, ValueError
|
:raises LookupError, ValueError
|
||||||
"""
|
"""
|
||||||
# get the current service object
|
# get the current service object
|
||||||
|
@ -254,7 +258,10 @@ class DefaultServicesController(base.ServicesController):
|
||||||
raise errors.ServiceStatusDisabled(
|
raise errors.ServiceStatusDisabled(
|
||||||
u'Service {0} is disabled'.format(service_id))
|
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(
|
raise errors.ServiceStatusNeitherDeployedNorFailed(
|
||||||
u'Service {0} neither deployed nor failed'.format(service_id))
|
u'Service {0} neither deployed nor failed'.format(service_id))
|
||||||
|
|
||||||
|
@ -434,11 +441,23 @@ class DefaultServicesController(base.ServicesController):
|
||||||
project_id=project_id,
|
project_id=project_id,
|
||||||
project_limit=limit)
|
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(
|
self.storage_controller.set_service_provider_details(
|
||||||
project_id,
|
project_id,
|
||||||
service_id,
|
service_id,
|
||||||
status)
|
status
|
||||||
|
)
|
||||||
|
return 201
|
||||||
|
|
||||||
def get_services_limit(self, project_id):
|
def get_services_limit(self, project_id):
|
||||||
limit = self.storage_controller.get_service_limit(
|
limit = self.storage_controller.get_service_limit(
|
||||||
|
|
|
@ -191,7 +191,7 @@ class CassandraStorageDriver(base.Driver):
|
||||||
"""Health check for Cassandra."""
|
"""Health check for Cassandra."""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.session.execute(
|
self.database.execute(
|
||||||
"SELECT cluster_name, data_center FROM system.local;")
|
"SELECT cluster_name, data_center FROM system.local;")
|
||||||
except Exception:
|
except Exception:
|
||||||
return False
|
return False
|
||||||
|
|
|
@ -390,10 +390,14 @@ class ServiceStatusController(base.Controller, hooks.HookController):
|
||||||
status = service_state_json['status']
|
status = service_state_json['status']
|
||||||
services_controller = self._driver.manager.services_controller
|
services_controller = self._driver.manager.services_controller
|
||||||
|
|
||||||
|
status_code = None
|
||||||
try:
|
try:
|
||||||
services_controller.set_service_provider_details(project_id,
|
status_code = services_controller.set_service_provider_details(
|
||||||
service_id,
|
project_id,
|
||||||
status)
|
service_id,
|
||||||
|
self.auth_token,
|
||||||
|
status
|
||||||
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
pecan.abort(404, detail=(
|
pecan.abort(404, detail=(
|
||||||
'Setting state of service {0} on tenant: {1} '
|
'Setting state of service {0} on tenant: {1} '
|
||||||
|
@ -403,7 +407,7 @@ class ServiceStatusController(base.Controller, hooks.HookController):
|
||||||
status,
|
status,
|
||||||
str(e))))
|
str(e))))
|
||||||
|
|
||||||
return pecan.Response(None, 201)
|
return pecan.Response(None, status_code)
|
||||||
|
|
||||||
|
|
||||||
class AdminCertController(base.Controller, hooks.HookController):
|
class AdminCertController(base.Controller, hooks.HookController):
|
||||||
|
|
|
@ -580,7 +580,7 @@ def is_valid_service_status(request):
|
||||||
# supported statuses
|
# supported statuses
|
||||||
|
|
||||||
VALID_STATUSES = [
|
VALID_STATUSES = [
|
||||||
u'deploy_in_progress',
|
u'create_in_progress',
|
||||||
u'deployed',
|
u'deployed',
|
||||||
u'update_in_progress',
|
u'update_in_progress',
|
||||||
u'delete_in_progress',
|
u'delete_in_progress',
|
||||||
|
|
|
@ -53,9 +53,9 @@ class TestGetServiceStatus(base.FunctionalTest):
|
||||||
|
|
||||||
self.assertEqual(response.status_code, 400)
|
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')
|
'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
|
# valid status
|
||||||
with mock.patch.object(DefaultServicesController,
|
with mock.patch.object(DefaultServicesController,
|
||||||
'get_services_by_status'):
|
'get_services_by_status'):
|
||||||
|
|
|
@ -30,7 +30,78 @@ class TestServicesState(base.FunctionalTest):
|
||||||
super(TestServicesState, self).setUp()
|
super(TestServicesState, self).setUp()
|
||||||
|
|
||||||
self.project_id = str(uuid.uuid4())
|
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 = {
|
self.req_body = {
|
||||||
'project_id': self.project_id,
|
'project_id': self.project_id,
|
||||||
'service_id': self.service_id,
|
'service_id': self.service_id,
|
||||||
|
@ -38,6 +109,13 @@ class TestServicesState(base.FunctionalTest):
|
||||||
|
|
||||||
@ddt.data(u'deployed', u'failed')
|
@ddt.data(u'deployed', u'failed')
|
||||||
def test_services_state_valid_states(self, status):
|
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
|
self.req_body['status'] = status
|
||||||
response = self.app.post(
|
response = self.app.post(
|
||||||
'/v1.0/admin/services/status',
|
'/v1.0/admin/services/status',
|
||||||
|
|
|
@ -20,6 +20,7 @@ import uuid
|
||||||
import ddt
|
import ddt
|
||||||
import mock
|
import mock
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
|
from oslo_context import context
|
||||||
import requests
|
import requests
|
||||||
import six
|
import six
|
||||||
|
|
||||||
|
@ -103,8 +104,8 @@ class DefaultManagerServiceTests(base.TestCase):
|
||||||
@mock.patch('poppy.storage.base.driver.StorageDriverBase')
|
@mock.patch('poppy.storage.base.driver.StorageDriverBase')
|
||||||
@mock.patch('poppy.distributed_task.base.driver.DistributedTaskDriverBase')
|
@mock.patch('poppy.distributed_task.base.driver.DistributedTaskDriverBase')
|
||||||
@mock.patch('poppy.metrics.base.driver.MetricsDriverBase')
|
@mock.patch('poppy.metrics.base.driver.MetricsDriverBase')
|
||||||
def setUp(self, mock_distributed_task, mock_storage,
|
def setUp(self, mock_metrics, mock_distributed_task, mock_storage,
|
||||||
mock_dns, mock_notification, mock_bootstrap, mock_metrics):
|
mock_dns, mock_notification, mock_bootstrap):
|
||||||
# NOTE(TheSriram): the mock.patch decorator applies mocks
|
# NOTE(TheSriram): the mock.patch decorator applies mocks
|
||||||
# in the reverse order of the arguments present
|
# in the reverse order of the arguments present
|
||||||
super(DefaultManagerServiceTests, self).setUp()
|
super(DefaultManagerServiceTests, self).setUp()
|
||||||
|
@ -216,6 +217,9 @@ class DefaultManagerServiceTests(base.TestCase):
|
||||||
|
|
||||||
self.service_obj = service.load_from_json(self.service_json)
|
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')
|
@mock.patch('poppy.bootstrap.Bootstrap')
|
||||||
def mock_purge_service(self, mock_bootstrap, hard=False):
|
def mock_purge_service(self, mock_bootstrap, hard=False):
|
||||||
mock_bootstrap.return_value = self.bootstrap_obj
|
mock_bootstrap.return_value = self.bootstrap_obj
|
||||||
|
@ -1005,3 +1009,58 @@ class DefaultManagerServiceTests(base.TestCase):
|
||||||
memoized_controllers.task_controllers):
|
memoized_controllers.task_controllers):
|
||||||
self.mock_purge_service(hard=True)
|
self.mock_purge_service(hard=True)
|
||||||
self.mock_purge_service(hard=False)
|
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
|
||||||
|
)
|
||||||
|
|
Loading…
Reference in New Issue