From bfe024288360ab8304ba374d174595fbaa839d9c Mon Sep 17 00:00:00 2001 From: Pino de Candia Date: Mon, 12 Mar 2018 20:30:39 +0000 Subject: [PATCH] Add API versioning. This also fixes the openstack CLI warning: "Failed to contact the endpoint at <...> for discovery. Fallback to using that endpoint as the base url." Change-Id: I411b7a795ac01e050cf8162e48d1fdbdc870c8f9 Signed-off-by: Pino de Candia --- devstack/plugin.sh | 3 ++- tatu/api/app.py | 65 +++++++++++++++++++++++++++++++++++----------- tatu/config.py | 3 +++ 3 files changed, 55 insertions(+), 16 deletions(-) diff --git a/devstack/plugin.sh b/devstack/plugin.sh index e1c78e3..c5d4bc3 100644 --- a/devstack/plugin.sh +++ b/devstack/plugin.sh @@ -54,6 +54,7 @@ function configure_tatu { iniset $TATU_CONF tatu sqlalchemy_engine `database_connection_url tatu` iniset $TATU_CONF tatu api_endpoint_for_vms $TATU_API_FOR_VMS iniset $TATU_CONF tatu pam_sudo True + iniset $TATU_CONF tatu api_base_uri $TATU_SERVICE_PROTOCOL://$TATU_SERVICE_HOST:$TATU_SERVICE_PORT/ # Need Keystone and Nova notifications iniset $KEYSTONE_CONF oslo_messaging_notifications topics notifications,tatu_notifications @@ -65,7 +66,7 @@ function configure_tatu { $TATU_DIR/scripts/cloud-config-to-vendor-data $TATU_DIR/files/user-cloud-config > $NOVA_CONF_DIR/tatu_static_vd.json iniset $NOVA_CONF api vendordata_providers StaticJSON,DynamicJSON iniset $NOVA_CONF api vendordata_jsonfile_path $NOVA_CONF_DIR/tatu_static_vd.json - iniset $NOVA_CONF api vendordata_dynamic_targets tatu@$TATU_SERVICE_PROTOCOL://$TATU_SERVICE_HOST:$TATU_SERVICE_PORT/novavendordata + iniset $NOVA_CONF api vendordata_dynamic_targets tatu@$TATU_SERVICE_PROTOCOL://$TATU_SERVICE_HOST:$TATU_SERVICE_PORT/v1/novavendordata iniset $NOVA_CONF api vendordata_dynamic_connect_timeout 5 iniset $NOVA_CONF api vendordata_dynamic_read_timeout 30 iniset $NOVA_CONF vendordata_dynamic_auth auth_url $KEYSTONE_SERVICE_URI diff --git a/tatu/api/app.py b/tatu/api/app.py index fb2fdd0..fedc731 100644 --- a/tatu/api/app.py +++ b/tatu/api/app.py @@ -14,30 +14,64 @@ import falcon import json from oslo_log import log as logging from tatu.api import models +from tatu.config import CONF from tatu.db.persistence import SQLAlchemySessionManager LOG = logging.getLogger(__name__) -class RootPage(object): +_versions = [] +_base = CONF.tatu.api_base_uri.rstrip('/') + +def _version(version, status, base_uri): + _versions.append({ + 'id': '%s' % version, + 'status': status, + 'links': [{ + 'href': base_uri + '/' + version, + 'rel': 'self' + }] + }) + +_version('v1', 'CURRENT', _base) + +class Versions(object): + def on_get(self, req, resp): - resp.body = json.dumps({}) + body = { + 'versions': { + 'values': _versions + }, + } + resp.body = json.dumps(body) resp.status = falcon.HTTP_OK +class Version1(object): + + def on_get(self, req, resp): + body = { + 'version': _versions[0], + } + resp.body = json.dumps(body) + resp.status = falcon.HTTP_OK + + def create_app(sa): LOG.info("Creating falcon API instance for authenticated API calls.") api = falcon.API(middleware=[models.Logger(), sa]) - api.add_route('/authorities', models.Authorities()) - api.add_route('/authorities/{auth_id}', models.Authority()) - api.add_route('/usercerts', models.UserCerts()) - api.add_route('/usercerts/{serial}', models.UserCert()) - api.add_route('/hosts', models.Hosts()) - api.add_route('/hosts/{host_id}', models.Host()) - api.add_route('/hostcerts', models.HostCerts()) - api.add_route('/hostcerts/{host_id}/{fingerprint}', models.HostCert()) - api.add_route('/hosttokens', models.Tokens()) - api.add_route('/novavendordata', models.NovaVendorData()) - api.add_route('/revokeduserkeys/{auth_id}', models.RevokedUserKeys()) - api.add_route('/pats', models.PATs()) + api.add_route('/v1/authorities', models.Authorities()) + api.add_route('/v1/authorities/{auth_id}', models.Authority()) + api.add_route('/v1/usercerts', models.UserCerts()) + api.add_route('/v1/usercerts/{serial}', models.UserCert()) + api.add_route('/v1/hosts', models.Hosts()) + api.add_route('/v1/hosts/{host_id}', models.Host()) + api.add_route('/v1/hostcerts', models.HostCerts()) + api.add_route('/v1/hostcerts/{host_id}/{fingerprint}', models.HostCert()) + api.add_route('/v1/hosttokens', models.Tokens()) + api.add_route('/v1/novavendordata', models.NovaVendorData()) + api.add_route('/v1/revokeduserkeys/{auth_id}', models.RevokedUserKeys()) + api.add_route('/v1/pats', models.PATs()) + api.add_route('/v1', Version1()) + api.add_route('/', Versions()) return api def create_noauth_app(sa): @@ -45,7 +79,8 @@ def create_noauth_app(sa): api = falcon.API(middleware=[models.Logger(), sa]) api.add_route('/hostcerts', models.HostCerts()) api.add_route('/revokeduserkeys/{auth_id}', models.RevokedUserKeys()) - api.add_route('/', RootPage()) + api.add_route('/v1', Version1()) + api.add_route('/', Versions()) return api def auth_factory(global_config, **settings): diff --git a/tatu/config.py b/tatu/config.py index a642a2b..6a4f108 100644 --- a/tatu/config.py +++ b/tatu/config.py @@ -62,6 +62,9 @@ opts = [ cfg.StrOpt('api_endpoint_for_vms', default='http://169.254.169.254', help='Where a VM accesses the API for SSH certs and revoked keys'), + cfg.StrOpt('api_base_uri', + default='http://169.254.169.254', + help='Base URI for version discovery.'), ] CONF = cfg.ConfigOpts()