Added credentials manager and updated omni drivers.

This change:
1. Adds credmanager service which handles credentials for AWS drivers.
2. Adds support for managing multiple AWS accounts through use of credmanager. Each account is mapped to a single project in keystone.
3. Adds support for multiple AZs by running one nova-compute and cinder-volume process per AZ.
4. Improves support for AWS networking in neutron.
5. Also, made few stability fixes in GCP and Azure drivers.

Change-Id: I0f87005a924423397db659ab754caaa6cde90274
This commit is contained in:
Harsha Dhake
2019-02-21 02:30:24 -05:00
parent 14f465f99d
commit 3fc8b3f97d
126 changed files with 8679 additions and 1274 deletions

View File

View File

@@ -0,0 +1,219 @@
# Copyright 2017 Platform9 Systems.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""Utility methods for working with WSGI servers."""
import webob.dec
import webob.exc
from credsmgr.api.controllers import api_version_request
from credsmgr import exception
SUPPORTED_CONTENT_TYPES = ('application/json')
SUPPORTED_ACCEPT_TYPES = ('application/json')
class Request(webob.Request):
def __init__(self, *args, **kwargs):
super(Request, self).__init__(*args, **kwargs)
self.support_api_request_version = False
if not hasattr(self, 'api_version_request'):
self.api_version_request = api_version_request.APIVersionRequest()
def set_api_version_request(self, url):
"""Set API version request based on the request header information.
"""
if 'v1' in url:
self.api_version_request = 'v1'
def get_content_type(self):
"""Determine content type of the request body.
Does not do any body introspection, only checks header
"""
if "Content-Type" not in self.headers:
return None
allowed_types = SUPPORTED_CONTENT_TYPES
content_type = self.content_type
if content_type not in allowed_types:
raise exception.InvalidContentType(content_type=content_type)
return content_type
def best_match_content_type(self):
"""Determine the requested response content-type."""
if 'credsmgr.best_content_type' not in self.environ:
# Calculate the best MIME type
content_type = None
# Check URL path suffix
parts = self.path.rsplit('.', 1)
if len(parts) > 1:
possible_type = 'application/' + parts[1]
if possible_type in SUPPORTED_CONTENT_TYPES:
content_type = possible_type
if not content_type:
# FIXME: Implement Accept best match algorithm when needed
# content_type = self.accept.best_match(
# SUPPORTED_CONTENT_TYPES)
content_type = 'application/json'
self.environ['credsmgr.best_content_type'] = content_type
return self.environ['credsmgr.best_content_type']
def best_match_language(self):
"""Determines best available locale from the Accept-Language header.
:returns: the best language match or None if the 'Accept-Language'
header was not available in the request.
"""
# if not self.accept_language:
# return None
# FIXME: TO be fixed when language support is added
return None
class Application(object):
"""Base WSGI application wrapper. Subclasses need to implement __call__."""
@classmethod
def factory(cls, global_config, **local_config):
"""Used for paste app factories in paste.deploy config files.
Any local configuration (that is, values under the [app:APPNAME]
section of the paste config) will be passed into the `__init__` method
as kwargs.
A hypothetical configuration would look like:
[app:wadl]
latest_version = 1.3
paste.app_factory = credsmgr.api.fancy_api:Wadl.factory
which would result in a call to the `Wadl` class as
import credsmgr.api.fancy_api
fancy_api.Wadl(latest_version='1.3')
You could of course re-implement the `factory` method in subclasses,
but using the kwarg passing it shouldn't be necessary.
"""
return cls(**local_config)
def __call__(self, environ, start_response):
r"""Subclasses will probably want to implement __call__ like this:
@webob.dec.wsgify(RequestClass=Request)
def __call__(self, req):
# Any of the following objects work as responses:
# Option 1: simple string
res = 'message\n'
# Option 2: a nicely formatted HTTP exception page
res = exc.HTTPForbidden(explanation='Nice try')
# Option 3: a webob Response object (in case you need to play with
# headers, or you want to be treated like an iterable)
res = Response();
res.app_iter = open('somefile')
# Option 4: any wsgi app to be run next
res = self.application
# Option 5: you can get a Response object for a wsgi app, too, to
# play with headers etc
res = req.get_response(self.application)
# You can then just return your response...
return res
# ... or set req.response and return None.
req.response = res
See the end of http://pythonpaste.org/webob/modules/dec.html
for more info.
"""
raise NotImplementedError('You must implement __call__')
class Middleware(Application):
"""Base WSGI middleware.
These classes require an application to be
initialized that will be called next. By default the middleware will
simply call its wrapped app, or you can override __call__ to customize its
behavior.
"""
@classmethod
def factory(cls, global_config, **local_config):
"""Used for paste app factories in paste.deploy config files.
Any local configuration (that is, values under the [filter:APPNAME]
section of the paste config) will be passed into the `__init__` method
as kwargs.
A hypothetical configuration would look like:
[filter:analytics]
redis_host = 127.0.0.1
paste.filter_factory = credsmgr.api.analytics:Analytics.factory
which would result in a call to the `Analytics` class as
import credsmgr.api.analytics
analytics.Analytics(app_from_paste, redis_host='127.0.0.1')
You could of course re-implement the `factory` method in subclasses,
but using the kwarg passing it shouldn't be necessary.
"""
def _factory(app):
return cls(app, **local_config)
return _factory
def __init__(self, application):
self.application = application
def process_request(self, req):
"""Called on each request.
If this returns None, the next application down the stack will be
executed. If it returns a response then that response will be returned
and execution will stop here.
"""
return None
def process_response(self, response):
"""Do whatever you'd like to the response."""
return response
@webob.dec.wsgify(RequestClass=Request)
def __call__(self, req):
response = self.process_request(req)
if response:
return response
response = req.get_response(self.application)
return self.process_response(response)