diff --git a/etc/gceapi/gceapi.conf.sample b/etc/gceapi/gceapi.conf.sample index 3aa6937..125acaa 100644 --- a/etc/gceapi/gceapi.conf.sample +++ b/etc/gceapi/gceapi.conf.sample @@ -59,20 +59,6 @@ #gce_listen_port=8787 -# -# Options defined in gceapi.api -# - -# Name of network API. neutron(quantum) or nova (string value) -#network_api=neutron - -# Keystone URL (string value) -#keystone_gce_url=http://127.0.0.1:5000/v2.0 - -# name of public network (string value) -#public_network=public - - # # Options defined in gceapi.wsgi # @@ -102,6 +88,26 @@ #tcp_keepidle=600 +# +# Options defined in gceapi.api +# + +# Name of network API. neutron(quantum) or nova (string value) +#network_api=neutron + +# Keystone URL (string value) +#keystone_gce_url=http://127.0.0.1:5000/v2.0 + +# name of public network (string value) +#public_network=public + +# Place of protocol files (string value) +#protocol_dir= + +# Region of this service +#region=RegionOne + + # # Options defined in gceapi.openstack.common.db.sqlalchemy.session # @@ -181,7 +187,6 @@ # configuration to any other existing logging options. Please # see the Python logging module documentation for details on # logging configuration files. (string value) -# Deprecated group/name - [DEFAULT]/log_config #log_config_append= # DEPRECATED. A logging.Formatter log message format string @@ -197,12 +202,10 @@ # (Optional) Name of log file to output to. If no default is # set, logging will go to stdout. (string value) -# Deprecated group/name - [DEFAULT]/logfile #log_file= # (Optional) The base directory used for relative --log-file # paths (string value) -# Deprecated group/name - [DEFAULT]/logdir #log_dir= # Use syslog for logging. Existing syslog format is DEPRECATED @@ -227,7 +230,6 @@ # # The backend to use for db (string value) -# Deprecated group/name - [DEFAULT]/db_backend #backend=sqlalchemy @@ -237,9 +239,6 @@ # The SQLAlchemy connection string used to connect to the # database (string value) -# Deprecated group/name - [DEFAULT]/sql_connection -# Deprecated group/name - [DATABASE]/sql_connection -# Deprecated group/name - [sql]/connection #connection=sqlite:////gceapi/openstack/common/db/$sqlite_db # The SQLAlchemy connection string used to connect to the @@ -248,53 +247,38 @@ # Timeout before idle sql connections are reaped (integer # value) -# Deprecated group/name - [DEFAULT]/sql_idle_timeout -# Deprecated group/name - [DATABASE]/sql_idle_timeout -# Deprecated group/name - [sql]/idle_timeout #idle_timeout=3600 # Minimum number of SQL connections to keep open in a pool # (integer value) -# Deprecated group/name - [DEFAULT]/sql_min_pool_size -# Deprecated group/name - [DATABASE]/sql_min_pool_size #min_pool_size=1 # Maximum number of SQL connections to keep open in a pool # (integer value) -# Deprecated group/name - [DEFAULT]/sql_max_pool_size -# Deprecated group/name - [DATABASE]/sql_max_pool_size #max_pool_size= # Maximum db connection retries during startup. (setting -1 # implies an infinite retry count) (integer value) -# Deprecated group/name - [DEFAULT]/sql_max_retries -# Deprecated group/name - [DATABASE]/sql_max_retries #max_retries=10 # Interval between retries of opening a sql connection # (integer value) -# Deprecated group/name - [DEFAULT]/sql_retry_interval -# Deprecated group/name - [DATABASE]/reconnect_interval #retry_interval=10 # If set, use this value for max_overflow with sqlalchemy # (integer value) -# Deprecated group/name - [DEFAULT]/sql_max_overflow -# Deprecated group/name - [DATABASE]/sqlalchemy_max_overflow #max_overflow= # Verbosity of SQL debugging information. 0=None, # 100=Everything (integer value) -# Deprecated group/name - [DEFAULT]/sql_connection_debug #connection_debug=0 # Add python stack traces to SQL as comment strings (boolean # value) -# Deprecated group/name - [DEFAULT]/sql_connection_trace #connection_trace=false # If set, use this value for pool_timeout with sqlalchemy # (integer value) -# Deprecated group/name - [DATABASE]/sqlalchemy_pool_timeout #pool_timeout= + diff --git a/gceapi/api/__init__.py b/gceapi/api/__init__.py index 29808b9..9c74fed 100644 --- a/gceapi/api/__init__.py +++ b/gceapi/api/__init__.py @@ -49,9 +49,9 @@ gce_opts = [ cfg.StrOpt('protocol_dir', default=None, help='Place of protocol files'), - cfg.StrOpt('region_list', + cfg.StrOpt('region', default='RegionOne', - help='list of regions separated by commas'), + help='Region of this service'), ] CONF = cfg.CONF diff --git a/gceapi/api/clients.py b/gceapi/api/clients.py index f0e153b..8262e44 100644 --- a/gceapi/api/clients.py +++ b/gceapi/api/clients.py @@ -58,7 +58,7 @@ def nova(context, service_type='compute'): client = novaclient.Client(1.1, **args) - management_url = _url_for(context, service_type=service_type) + management_url = get_endpoint(context, service_type) client.client.auth_token = context.auth_token client.client.management_url = management_url @@ -73,7 +73,7 @@ def neutron(context): 'auth_url': CONF.keystone_gce_url, 'service_type': 'network', 'token': context.auth_token, - 'endpoint_url': _url_for(context, service_type='network'), + 'endpoint_url': get_endpoint(context, 'network'), } return neutronclient.Client(**args) @@ -90,7 +90,7 @@ def glance(context): } return glanceclient.Client( - "1", endpoint=_url_for(context, service_type='image'), **args) + "1", endpoint=get_endpoint(context, 'image'), **args) def cinder(context): @@ -105,7 +105,7 @@ def cinder(context): } _cinder = cinderclient.Client('1', **args) - management_url = _url_for(context, service_type='volume') + management_url = get_endpoint(context, 'volume') _cinder.client.auth_token = context.auth_token _cinder.client.management_url = management_url @@ -121,21 +121,25 @@ def keystone(context): return _keystone -def _url_for(context, **kwargs): +def get_endpoint_from_catalog(service_catalog, service_type): + for service in service_catalog: + if service["type"] != service_type: + continue + for endpoint in service["endpoints"]: + if endpoint["region"] != CONF["region"]: + continue + return endpoint.get("publicURL") + + return None + + return None + + +def get_endpoint(context, service_type): service_catalog = context.service_catalog if not service_catalog: catalog = keystone(context).service_catalog.catalog service_catalog = catalog["serviceCatalog"] context.service_catalog = service_catalog - service_type = kwargs["service_type"] - for service in service_catalog: - if service["type"] != service_type: - continue - for endpoint in service["endpoints"]: - if "publicURL" in endpoint: - return endpoint["publicURL"] - else: - return None - - return None + return get_endpoint_from_catalog(service_catalog, service_type) diff --git a/gceapi/api/common.py b/gceapi/api/common.py index 0d7a858..faf28af 100644 --- a/gceapi/api/common.py +++ b/gceapi/api/common.py @@ -18,6 +18,9 @@ import os.path import re from webob import exc +from oslo.config import cfg + +from gceapi.api import clients from gceapi.api import operation_api from gceapi.api import operation_util from gceapi.api import scopes @@ -28,6 +31,7 @@ from gceapi.openstack.common import log as logging from gceapi.openstack.common import timeutils LOG = logging.getLogger(__name__) +FLAGS = cfg.CONF class Controller(object): @@ -263,8 +267,16 @@ class Controller(object): 'zones/zone_id' prefix for zone(similar for regions) resources. """ + context = self._get_context(request) + public_url = clients.get_endpoint(context, "gceapi") + if public_url: + public_url = public_url.rstrip("/") + "/"\ + + request.script_name.lstrip("/") + else: + public_url = request.application_url + result = os.path.join( - request.application_url, self._get_context(request).project_name) + public_url, context.project_name) if controller: if scope: result = os.path.join(result, scope.get_path()) diff --git a/gceapi/api/discovery.py b/gceapi/api/discovery.py index 4129fcb..33d4b2e 100644 --- a/gceapi/api/discovery.py +++ b/gceapi/api/discovery.py @@ -17,8 +17,10 @@ import os import threading import webob +from keystoneclient.v2_0 import client as keystone_client from oslo.config import cfg +from gceapi.api import clients from gceapi.openstack.common import log as logging from gceapi import wsgi_ext as openstack_wsgi @@ -34,17 +36,28 @@ class Controller(object): def discovery(self, req, version): """Returns appropriate json by its version.""" - key = version + req.host_url + key = version if key in self._files: return self._files[key] + tenant = FLAGS.keystone_authtoken["admin_tenant_name"] + user = FLAGS.keystone_authtoken["admin_user"] + password = FLAGS.keystone_authtoken["admin_password"] + keystone = keystone_client.Client(username=user, password=password, + tenant_name=tenant, auth_url=FLAGS.keystone_gce_url) + catalog = keystone.service_catalog.catalog["serviceCatalog"] + public_url = clients.get_endpoint_from_catalog(catalog, "gceapi") + if not public_url: + public_url = req.host_url + public_url = public_url.rstrip("/") + self._lock.acquire() try: if key in self._files: return self._files[key] jfile = self._load_file(version) - jfile = jfile.replace("{HOST_URL}", req.host_url) + jfile = jfile.replace("{HOST_URL}", public_url) self._files[key] = jfile return jfile finally: diff --git a/gceapi/api/oauth.py b/gceapi/api/oauth.py index 7ca1efb..bf27e33 100644 --- a/gceapi/api/oauth.py +++ b/gceapi/api/oauth.py @@ -32,7 +32,7 @@ LOG = logging.getLogger(__name__) INTERNAL_GCUTIL_PROJECTS = ["debian-cloud", "centos-cloud", "suse-cloud", - "rhel-cloud", "google"] + "rhel-cloud", "windows-cloud", "google"] class OAuthFault(openstack_wsgi.Fault): diff --git a/gceapi/api/region_api.py b/gceapi/api/region_api.py index 0d43c0c..c8a7443 100644 --- a/gceapi/api/region_api.py +++ b/gceapi/api/region_api.py @@ -24,7 +24,8 @@ CONF = cfg.CONF class API(base_api.API): """GCE Regions API - Stubbed now for support only one predefined region nova + Stubbed now for support only one predefined region from config + #TODO(apavlov): need to implement discovering or regions from keystone """ KIND = "region" @@ -32,8 +33,7 @@ class API(base_api.API): def __init__(self, *args, **kwargs): super(API, self).__init__(*args, **kwargs) - regions = CONF.get("region_list").split(",") - self._REGIONS = [r.strip() for r in regions] + self._REGIONS = [CONF.get("region").strip()] def _get_type(self): return self.KIND diff --git a/install.sh b/install.sh index fda74f3..aa3724f 100755 --- a/install.sh +++ b/install.sh @@ -8,6 +8,9 @@ CONNECTION="mysql://root:password@127.0.0.1/gceapi?charset=utf8" LOG_DIR=/var/log/gceapi CONF_DIR=/etc/gceapi SIGNING_DIR=/var/cache/gceapi +#this default values are for devstack. change it for real cloud (NETWORK_API=nova for example) +NETWORK_API=quantum +REGION=RegionOne #Check for environment if [[ -z "$OS_AUTH_URL" || -z "$OS_USERNAME" || -z "$OS_PASSWORD" || -z "$OS_TENANT_NAME" ]]; then @@ -200,7 +203,7 @@ APIPASTE_FILE=$CONF_DIR/api-paste.ini echo Creating configs sudo mkdir -p /etc/gceapi > /dev/null if [ ! -s $CONF_FILE ]; then - sudo cp etc/gceapi/gceapi.conf $CONF_FILE + sudo cp etc/gceapi/gceapi.conf.sample $CONF_FILE fi if [ ! -s $APIPASTE_FILE ]; then sudo cp etc/gceapi/api-paste.ini $APIPASTE_FILE @@ -213,12 +216,15 @@ AUTH_PORT=`keystone catalog|grep -A 9 identity|grep adminURL|awk '{print $4}'` AUTH_PORT=${AUTH_PORT##*:} AUTH_PORT=${AUTH_PORT%%/*} AUTH_PROTO=${OS_AUTH_URL%%:*} +PUBLIC_URL=${OS_AUTH_URL%:*}:8787/ #update default config with some values iniset $CONF_FILE DEFAULT api_paste_config $APIPASTE_FILE iniset $CONF_FILE DEFAULT logging_context_format_string "%(asctime)s.%(msecs)03d %(levelname)s %(name)s [%(request_id)s %(user_name)s %(project_name)s] %(instance)s%(message)s" iniset $CONF_FILE DEFAULT verbose True iniset $CONF_FILE DEFAULT keystone_gce_url "$OS_AUTH_URL" +iniset $CONF_FILE DEFAULT network_api "$NETWORK_API" +iniset $CONF_FILE DEFAULT region "$REGION" iniset $CONF_FILE database connection "$CONNECTION" iniset $CONF_FILE keystone_authtoken signing_dir $SIGNING_DIR