Proton Version Management
This patch impletements the Proton Version Management specifications located here: https://review.openstack.org/#/c/456772/ Change-Id: I7581b55dbaac170439ac9274454a5e2c553fa7ca
This commit is contained in:
parent
b82abe1579
commit
618e637f8a
|
@ -19,24 +19,50 @@ import wsmeext.pecan as wsme_pecan
|
|||
|
||||
from gluon.api.baseObject import APIBase
|
||||
from gluon.api import link
|
||||
from gluon.api import types
|
||||
from gluon.particleGenerator import generator as particle_generator
|
||||
from oslo_config import cfg
|
||||
|
||||
|
||||
class ProtonRoot(APIBase):
|
||||
"""The representation of the version 1 of the API."""
|
||||
class Proton(APIBase):
|
||||
|
||||
id = wtypes.text
|
||||
"""The ID of the version, also acts as the release number"""
|
||||
proton_service = wtypes.text
|
||||
"""The name of Proton service"""
|
||||
|
||||
status = types.create_enum_type('CURRENT', 'STABLE', 'DEPRECATED')
|
||||
"""Status of the API, which can be CURRENT, STABLE or DEPRECATED"""
|
||||
|
||||
links = [link.Link]
|
||||
"""A Link that point to the root of proton"""
|
||||
|
||||
@staticmethod
|
||||
def convert(service, status='CURRENT'):
|
||||
proton = Proton()
|
||||
proton.status = status
|
||||
proton.proton_service = service
|
||||
proton.links = [link.Link.make_link('self',
|
||||
pecan.request.host_url,
|
||||
'proton',
|
||||
service,
|
||||
bookmark=True)]
|
||||
return proton
|
||||
|
||||
|
||||
class ProtonRoot(APIBase):
|
||||
|
||||
protons = [Proton]
|
||||
"""List of protons in their current version"""
|
||||
|
||||
@staticmethod
|
||||
def convert():
|
||||
service_list = particle_generator.get_service_list()
|
||||
protons = list()
|
||||
for service in service_list:
|
||||
proton = Proton.convert(service)
|
||||
protons.append(proton)
|
||||
|
||||
root = ProtonRoot()
|
||||
root.id = "proton"
|
||||
root.links = [link.Link.make_link('self', pecan.request.host_url,
|
||||
'proton', '', bookmark=True), ]
|
||||
root.protons = protons
|
||||
return root
|
||||
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import pecan
|
||||
from pecan import rest
|
||||
import six
|
||||
from wsme import types as wtypes
|
||||
|
@ -21,9 +22,11 @@ from gluon.api.baseObject import APIBase
|
|||
from gluon.api.baseObject import APIBaseObject
|
||||
from gluon.api.baseObject import RootObjectController
|
||||
from gluon.api.baseObject import SubObjectController
|
||||
from gluon.api import link
|
||||
from gluon.api import types
|
||||
from gluon.particleGenerator.DataBaseModelGenerator \
|
||||
import DataBaseModelProcessor
|
||||
from gluon.particleGenerator.generator import load_model_for_service
|
||||
|
||||
|
||||
class MyData(object):
|
||||
|
@ -34,26 +37,117 @@ ApiGenData = MyData()
|
|||
ApiGenData.svc_controllers = {}
|
||||
|
||||
|
||||
class ServiceRoot(APIBase):
|
||||
"""The root service URL"""
|
||||
id = wtypes.text
|
||||
class ProtonVersion(APIBase):
|
||||
"""The root of proton service URL"""
|
||||
|
||||
proton_service = wtypes.text
|
||||
"""Name of proton service"""
|
||||
|
||||
version_id = wtypes.text
|
||||
"""Version id of proton service, e.g. v1.0, v2.0, ..."""
|
||||
|
||||
status = types.create_enum_type('CURRENT', 'STABLE', 'DEPRECATED')
|
||||
"""Status of the API, which can be CURRENT, STABLE or DEPRECATED"""
|
||||
|
||||
links = [link.Link]
|
||||
"""A Link that point to a specific version of the API"""
|
||||
|
||||
@staticmethod
|
||||
def convert(api_name):
|
||||
def convert(service, version_id, status='CURRENT'):
|
||||
version = ProtonVersion()
|
||||
version.proton_service = service
|
||||
version.version_id = version_id
|
||||
version.status = status
|
||||
resource_args = service + '/' + version_id
|
||||
version.links = [link.Link.make_link('self',
|
||||
pecan.request.host_url,
|
||||
'proton',
|
||||
resource_args,
|
||||
bookmark=True)]
|
||||
return version
|
||||
|
||||
|
||||
class Resource(ProtonVersion):
|
||||
"""Resource under a specific version of proton service"""
|
||||
|
||||
resource_name = wtypes.text
|
||||
"""The resource name"""
|
||||
|
||||
@staticmethod
|
||||
def convert(service, version_id, resource_name, status='CURRENT'):
|
||||
resource = Resource()
|
||||
resource.proton_service = service
|
||||
resource.version_id = version_id
|
||||
resource.status = status
|
||||
resource.resource_name = resource_name
|
||||
resource_args = service + '/' + version_id + '/' + resource_name
|
||||
resource.links = [link.Link.make_link('self',
|
||||
pecan.request.host_url,
|
||||
'proton',
|
||||
resource_args,
|
||||
bookmark=True)]
|
||||
return resource
|
||||
|
||||
|
||||
class ServiceRoot(APIBase):
|
||||
"""The root service URL of a proton"""
|
||||
|
||||
default_version = ProtonVersion
|
||||
"""Default version of a service"""
|
||||
|
||||
versions = [ProtonVersion]
|
||||
"""Supported versions of a service"""
|
||||
|
||||
# TODO(JinLi) need to handle multiple versions of a proton service.
|
||||
# for now we only have one version, so we put it in
|
||||
# both default_version and versions.
|
||||
@staticmethod
|
||||
def convert(service, version_id):
|
||||
version = ProtonVersion.convert(service, version_id)
|
||||
root = ServiceRoot()
|
||||
root.id = api_name
|
||||
root.default_version = version
|
||||
root.versions = [version]
|
||||
return root
|
||||
|
||||
|
||||
class ServiceVersionRoot(APIBase):
|
||||
"""The root service URL of a specific version of a proton"""
|
||||
|
||||
resources = [Resource]
|
||||
"""Resources available for a specific version of a proton service"""
|
||||
|
||||
@staticmethod
|
||||
def convert(service_name, version_id):
|
||||
model = load_model_for_service(service_name)
|
||||
root = ServiceVersionRoot()
|
||||
root.resources = list()
|
||||
for table_name, table_data in model['api_objects'].items():
|
||||
resource_name = table_data['api']['plural_name']
|
||||
resource = Resource.convert(service_name,
|
||||
version_id,
|
||||
resource_name)
|
||||
root.resources.append(resource)
|
||||
return root
|
||||
|
||||
|
||||
class ServiceController(rest.RestController):
|
||||
"""Version 1 API controller root."""
|
||||
|
||||
def __init__(self, api_name):
|
||||
def __init__(self, api_name, version_id):
|
||||
self.api_name = api_name
|
||||
self.version_id = version_id
|
||||
|
||||
@wsme_pecan.wsexpose(ServiceRoot)
|
||||
def get(self):
|
||||
return ServiceRoot.convert(self.api_name)
|
||||
return ServiceRoot.convert(self.api_name, self.version_id)
|
||||
|
||||
|
||||
class ServiceVersionController(ServiceController):
|
||||
"""Version 1 API controller root."""
|
||||
|
||||
@wsme_pecan.wsexpose(ServiceVersionRoot)
|
||||
def get(self):
|
||||
return ServiceVersionRoot.convert(self.api_name, self.version_id)
|
||||
|
||||
|
||||
class APIGenerator(object):
|
||||
|
@ -65,11 +159,16 @@ class APIGenerator(object):
|
|||
def add_model(self, model):
|
||||
self.data = model
|
||||
|
||||
def create_controller(self, service_name, root):
|
||||
controller = ServiceController(service_name)
|
||||
def create_controller(self, service_name, version_id, root):
|
||||
controller = ServiceController(service_name, version_id)
|
||||
setattr(root, service_name, controller)
|
||||
return controller
|
||||
|
||||
def create_version_controller(self, service_name, version_id, root):
|
||||
controller = ServiceVersionController(service_name, version_id)
|
||||
setattr(root, version_id, controller)
|
||||
return controller
|
||||
|
||||
def create_api(self, root, service_name, db_models):
|
||||
self.db_models = db_models
|
||||
self.service_name = service_name
|
||||
|
|
|
@ -160,9 +160,10 @@ def make_url(host, port, *args):
|
|||
return url
|
||||
|
||||
|
||||
def make_list_func(api_model, tablename):
|
||||
def make_list_func(api_model, version, tablename):
|
||||
def list_func(**kwargs):
|
||||
url = make_url(kwargs["host"], kwargs["port"], api_model, tablename)
|
||||
url = make_url(kwargs["host"], kwargs["port"], api_model,
|
||||
version, tablename)
|
||||
result = json_get(url)
|
||||
print(json.dumps(result, indent=4))
|
||||
return result
|
||||
|
@ -170,10 +171,10 @@ def make_list_func(api_model, tablename):
|
|||
return list_func
|
||||
|
||||
|
||||
def make_show_func(api_model, tablename, primary_key):
|
||||
def make_show_func(api_model, version, tablename, primary_key):
|
||||
def show_func(**kwargs):
|
||||
url = make_url(kwargs["host"], kwargs["port"], api_model, tablename,
|
||||
kwargs[primary_key])
|
||||
url = make_url(kwargs["host"], kwargs["port"], api_model,
|
||||
version, tablename, kwargs[primary_key])
|
||||
result = json_get(url)
|
||||
print(json.dumps(result, indent=4))
|
||||
return result
|
||||
|
@ -181,9 +182,10 @@ def make_show_func(api_model, tablename, primary_key):
|
|||
return show_func
|
||||
|
||||
|
||||
def make_create_func(api_model, tablename):
|
||||
def make_create_func(api_model, version, tablename):
|
||||
def create_func(**kwargs):
|
||||
url = make_url(kwargs["host"], kwargs["port"], api_model, tablename)
|
||||
url = make_url(kwargs["host"], kwargs["port"], api_model,
|
||||
version, tablename)
|
||||
del kwargs["host"]
|
||||
del kwargs["port"]
|
||||
data = {}
|
||||
|
@ -196,10 +198,10 @@ def make_create_func(api_model, tablename):
|
|||
return create_func
|
||||
|
||||
|
||||
def make_update_func(api_model, tablename, primary_key):
|
||||
def make_update_func(api_model, version, tablename, primary_key):
|
||||
def update_func(**kwargs):
|
||||
url = make_url(kwargs["host"], kwargs["port"], api_model, tablename,
|
||||
kwargs[primary_key])
|
||||
url = make_url(kwargs["host"], kwargs["port"], api_model,
|
||||
version, tablename, kwargs[primary_key])
|
||||
del kwargs["host"]
|
||||
del kwargs["port"]
|
||||
del kwargs[primary_key]
|
||||
|
@ -213,15 +215,21 @@ def make_update_func(api_model, tablename, primary_key):
|
|||
return update_func
|
||||
|
||||
|
||||
def make_delete_func(api_model, tablename, primary_key):
|
||||
def make_delete_func(api_model, version, tablename, primary_key):
|
||||
def delete_func(**kwargs):
|
||||
url = make_url(kwargs["host"], kwargs["port"], api_model, tablename,
|
||||
kwargs[primary_key])
|
||||
url = make_url(kwargs["host"], kwargs["port"], api_model,
|
||||
version, tablename, kwargs[primary_key])
|
||||
do_delete(url)
|
||||
|
||||
return delete_func
|
||||
|
||||
|
||||
def get_version(model):
|
||||
version = str(model['info']['version'])
|
||||
version = 'v' + version
|
||||
return version
|
||||
|
||||
|
||||
def get_primary_key(table_data):
|
||||
primary = []
|
||||
for k, v in table_data['attributes'].items():
|
||||
|
@ -261,6 +269,7 @@ def proc_model(cli, package_name="unknown",
|
|||
portdefault=0):
|
||||
# print("loading model")
|
||||
model = load_model(package_name, model_dir, api_model)
|
||||
version = get_version(model)
|
||||
for table_name, table_data in model['api_objects'].items():
|
||||
get_primary_key(table_data)
|
||||
for table_name, table_data in model['api_objects'].items():
|
||||
|
@ -300,7 +309,7 @@ def proc_model(cli, package_name="unknown",
|
|||
#
|
||||
hosthelp = "Host of endpoint (%s) " % hostenv
|
||||
porthelp = "Port of endpoint (%s) " % portenv
|
||||
list = make_list_func(api_model, attrs['__tablename__'])
|
||||
list = make_list_func(api_model, version, attrs['__tablename__'])
|
||||
list.func_name = "%s-list" % (attrs['__objname__'])
|
||||
list = click.option("--host", envvar=hostenv,
|
||||
default=hostdefault, help=hosthelp)(list)
|
||||
|
@ -308,7 +317,7 @@ def proc_model(cli, package_name="unknown",
|
|||
default=portdefault, help=porthelp)(list)
|
||||
cli.command()(list)
|
||||
|
||||
show = make_show_func(api_model, attrs['__tablename__'],
|
||||
show = make_show_func(api_model, version, attrs['__tablename__'],
|
||||
attrs['_primary_key'])
|
||||
show.func_name = "%s-show" % (attrs['__objname__'])
|
||||
show = click.option("--host", envvar=hostenv,
|
||||
|
@ -318,7 +327,8 @@ def proc_model(cli, package_name="unknown",
|
|||
show = click.argument(attrs['_primary_key'])(show)
|
||||
cli.command()(show)
|
||||
|
||||
create = make_create_func(api_model, attrs['__tablename__'])
|
||||
create = make_create_func(api_model, version,
|
||||
attrs['__tablename__'])
|
||||
create.func_name = "%s-create" % (attrs['__objname__'])
|
||||
create = click.option("--host", envvar=hostenv,
|
||||
default=hostdefault, help=hosthelp)(create)
|
||||
|
@ -336,7 +346,8 @@ def proc_model(cli, package_name="unknown",
|
|||
create = click.option(option_name, **kwargs)(create)
|
||||
cli.command()(create)
|
||||
|
||||
update = make_update_func(api_model, attrs['__tablename__'],
|
||||
update = make_update_func(api_model, version,
|
||||
attrs['__tablename__'],
|
||||
attrs['_primary_key'])
|
||||
update.func_name = "%s-update" % (attrs['__objname__'])
|
||||
update = click.option("--host", envvar=hostenv,
|
||||
|
@ -355,7 +366,8 @@ def proc_model(cli, package_name="unknown",
|
|||
update = click.argument(attrs['_primary_key'])(update)
|
||||
cli.command()(update)
|
||||
|
||||
del_func = make_delete_func(api_model, attrs['__tablename__'],
|
||||
del_func = make_delete_func(api_model, version,
|
||||
attrs['__tablename__'],
|
||||
attrs['_primary_key'])
|
||||
del_func.func_name = "%s-delete" % (attrs['__objname__'])
|
||||
del_func = click.option("--host", envvar=hostenv,
|
||||
|
|
|
@ -367,11 +367,16 @@ def build_sql_models(service_list):
|
|||
def build_api(root, service_list):
|
||||
from gluon.particleGenerator.ApiGenerator import APIGenerator
|
||||
for service in service_list:
|
||||
load_model_for_service(service)
|
||||
model = load_model_for_service(service)
|
||||
version_id = str(model['info']['version'])
|
||||
version_id = 'v' + version_id
|
||||
api_gen = APIGenerator()
|
||||
service_root = api_gen.create_controller(service, root)
|
||||
service_root = api_gen.create_controller(service, version_id, root)
|
||||
service_version_root = \
|
||||
api_gen.create_version_controller(service, version_id,
|
||||
service_root)
|
||||
api_gen.add_model(load_model_for_service(service))
|
||||
api_gen.create_api(service_root, service,
|
||||
api_gen.create_api(service_version_root, service,
|
||||
GenData.DBGeneratorInstance.get_db_models(service))
|
||||
|
||||
|
||||
|
|
|
@ -212,9 +212,10 @@ class CliTestCase(partgen_base.ParticleGeneratorTestCase):
|
|||
def test_make_list_func(self, mock_json_get):
|
||||
kwargs = {"host": "gluonURL.net", "port": 8080}
|
||||
api_model = "apimodel"
|
||||
version = "v1"
|
||||
tablename = "tablename"
|
||||
mock_json_get.return_value = {"result": "successful"}
|
||||
list_func = cli.make_list_func(api_model, tablename)
|
||||
list_func = cli.make_list_func(api_model, version, tablename)
|
||||
observed = list_func(**kwargs)
|
||||
# self.assertIsNone(observed)
|
||||
expected = {"result": "successful"}
|
||||
|
@ -227,10 +228,12 @@ class CliTestCase(partgen_base.ParticleGeneratorTestCase):
|
|||
def test_make_show_func(self, mock_json_get):
|
||||
kwargs = {"host": "gluonURL.net", "port": 8080, "id": 1}
|
||||
api_model = "apimodel"
|
||||
version = "v1"
|
||||
tablename = "tablename"
|
||||
primary_key = "id"
|
||||
mock_json_get.return_value = {"result": "successful"}
|
||||
show_func = cli.make_show_func(api_model, tablename, primary_key)
|
||||
show_func = cli.make_show_func(api_model, version,
|
||||
tablename, primary_key)
|
||||
observed = show_func(**kwargs)
|
||||
# self.assertIsNone(observed)
|
||||
expected = {"result": "successful"}
|
||||
|
@ -245,9 +248,10 @@ class CliTestCase(partgen_base.ParticleGeneratorTestCase):
|
|||
kwargs = {"host": "gluonURL.net", "port": 8080, "id": 1,
|
||||
"firstname": "Jane", "lastName": "Doe"}
|
||||
api_model = "apiModel"
|
||||
version = "v1"
|
||||
tablename = "user"
|
||||
mock_do_post.return_value = '{"result": "successful"}'
|
||||
create_func = cli.make_create_func(api_model, tablename)
|
||||
create_func = cli.make_create_func(api_model, version, tablename)
|
||||
observed = create_func(**kwargs)
|
||||
self.assertIsNone(observed)
|
||||
|
||||
|
@ -261,9 +265,11 @@ class CliTestCase(partgen_base.ParticleGeneratorTestCase):
|
|||
"firstname": "Jane", "lastName": "Doe"}
|
||||
api_model = "apiModel"
|
||||
tablename = "user"
|
||||
version = "v1"
|
||||
primary_key = "id"
|
||||
mock_do_put.return_value = '{"result": "successful"}'
|
||||
update_func = cli.make_update_func(api_model, tablename, primary_key)
|
||||
update_func = cli.make_update_func(api_model, version,
|
||||
tablename, primary_key)
|
||||
observed = update_func(**kwargs)
|
||||
self.assertIsNone(observed)
|
||||
|
||||
|
@ -275,10 +281,12 @@ class CliTestCase(partgen_base.ParticleGeneratorTestCase):
|
|||
def test_make_delete_func(self, mock_do_delete):
|
||||
kwargs = {"host": "gluonURL.net", "port": 8080, "id": 1}
|
||||
api_model = "apiModel"
|
||||
version = "v1"
|
||||
tablename = "user"
|
||||
primary_key = "id"
|
||||
mock_do_delete.return_value = '{"result": "successful"}'
|
||||
delete_func = cli.make_delete_func(api_model, tablename, primary_key)
|
||||
delete_func = cli.make_delete_func(api_model, version,
|
||||
tablename, primary_key)
|
||||
observed = delete_func(**kwargs)
|
||||
self.assertIsNone(observed)
|
||||
|
||||
|
|
|
@ -74,6 +74,7 @@ class GeneratorTestCase(partgen_base.ParticleGeneratorTestCase):
|
|||
"""
|
||||
@mock.patch('gluon.particleGenerator.generator.load_model')
|
||||
@mock.patch.object(APIGenerator, 'create_controller')
|
||||
@mock.patch.object(APIGenerator, 'create_version_controller')
|
||||
@mock.patch.object(APIGenerator, 'add_model')
|
||||
@mock.patch.object(APIGenerator, 'create_api')
|
||||
@mock.patch('gluon.particleGenerator.generator.GenData.DBGeneratorInstance'
|
||||
|
@ -82,24 +83,28 @@ class GeneratorTestCase(partgen_base.ParticleGeneratorTestCase):
|
|||
mock_DBGeneratorInstance,
|
||||
mock_create_api,
|
||||
mock_add_model,
|
||||
mock_create_version_controller,
|
||||
mock_create_controller,
|
||||
mock_load_model):
|
||||
root = object()
|
||||
service_list = ['test']
|
||||
mock_service = {'foo': 'bar'}
|
||||
mock_service = {'foo': 'bar', 'info': {'version': '1.0'}}
|
||||
mock_load_model.return_value = mock_service
|
||||
db_models = mock.Mock()
|
||||
mock_DBGeneratorInstance.get_db_models.return_value = db_models
|
||||
service_root = mock.Mock()
|
||||
version_root = mock.Mock()
|
||||
mock_create_controller.return_value = service_root
|
||||
|
||||
mock_create_version_controller.return_value = version_root
|
||||
generator.build_api(root, service_list)
|
||||
|
||||
mock_load_model.assert_called_with('gluon', 'models', 'test')
|
||||
mock_create_controller.assert_called_with('test', root)
|
||||
mock_create_controller.assert_called_with('test', 'v1.0', root)
|
||||
mock_create_version_controller.assert_called_with('test', 'v1.0',
|
||||
service_root)
|
||||
mock_add_model.assert_called_with(mock_service)
|
||||
mock_DBGeneratorInstance.get_db_models.assert_called_with('test')
|
||||
mock_create_api.assert_called_with(service_root,
|
||||
mock_create_api.assert_called_with(version_root,
|
||||
'test',
|
||||
db_models)
|
||||
"""
|
||||
|
|
Loading…
Reference in New Issue