Skip to content

Commit

Permalink
Initial import
Browse files Browse the repository at this point in the history
  • Loading branch information
gtema committed Jul 7, 2021
0 parents commit 0f43f97
Show file tree
Hide file tree
Showing 59 changed files with 5,427 additions and 0 deletions.
28 changes: 28 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
*.DS_Store
*.egg*
*.log
*.mo
*.pyc
*.swo
*.swp
*~
octavia_proxy-*/
.coverage
.idea
.stestr/
.testrepository
.tox
build
ChangeLog
dist
# Doc related
doc/build
# Development environment files
.project
.pydevproject
cover
# Files created by releasenotes build
releasenotes/build
.ropeproject
test.py
.vscode
3 changes: 3 additions & 0 deletions .stestr.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[DEFAULT]
test_path=${OS_TEST_PATH:-./octavia_proxy/tests/unit}
top_dir=./
16 changes: 16 additions & 0 deletions .zuul.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
- job:
name: otc-tox-py39-tips
parent: otc-tox-py39
description: |
Execute tests with latest dependencies
required-projects:
- opentelekomcloud/python-otcextensions:
override-checkout: elb

- project:
merge-mode: squash-merge
default-branch: main
check:
jobs:
- otc-tox-pep8
- otc-tox-py39-tips
39 changes: 39 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
=============
Octavia Proxy
=============

This project translates Octavia API requests into elbv2 and elbv3 of the Open
Telekom Cloud. It is required due to missing possibility to implement elbv3
support as a native Octavia driver (it doesn't offer admin type of access and
to have primary data source in Octavia).

Goals
-----

- provide customer facing load balancer APIs using Octavia API
- cover elbv3 and elbv2
- Admin APIs are not going to be implemented


Status
------

POC in development phase


Requirements
------------

- validatetoken (fork of keystonemiddleware.auth_token middleware to allow token validation in the frontend)
- python-otcextensions (elb branch)

Developer setup
---------------

- tox create venv for octavia-proxy
- source into it
- with the venv python go to otcextensions elb branch and do `python setup.py develop`
- add into the clouds.yaml `load_balancer_endpoint_override: http://127.0.0.1:9876/`. IMPORTANT (for now): do not use profile:otc
- get python-openstackclient with python-octaviaclient (otce overrides loadbalancer function now, therefore - upstream)
- `python octavia_proxy/cmd/api.py --config-file etc/octavia.conf`
- `openstack loadbalancer list`
128 changes: 128 additions & 0 deletions etc/octavia.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
[DEFAULT]
# Print debugging output (set logging level to DEBUG instead of default WARNING level).
# debug = False

# Plugin options are hot_plug_plugin (Hot-pluggable controller plugin)
# octavia_plugins = hot_plug_plugin

# Hostname to be used by the host machine for services running on it.
# The default value is the hostname of the host machine.
# host =

# AMQP Transport URL
# For Single Host, specify one full transport URL:
# transport_url = rabbit://<user>:<pass>@127.0.0.1:5672/<vhost>
# For HA, specify queue nodes in cluster, comma delimited:
# transport_url = rabbit://<user>:<pass>@server01,<user>:<pass>@server02/<vhost>
# transport_url =

# How long in seconds to wait for octavia worker to exit before killing them.
# graceful_shutdown_timeout = 60
#
[validatetoken]
auth_url=https://iam.eu-de.otc.t-systems.com
log_name='token_validate'

[api_settings]
# bind_host = 127.0.0.1
# bind_port = 9876

# How should authentication be handled (keystone, noauth)
# auth_strategy = keystone

# allow_pagination = True
# allow_sorting = True
# pagination_max_limit = 1000
# Base URI for the API for use in pagination links.
# This will be autodetected from the request if not overridden here.
# Example:
# api_base_uri = http://localhost:9876
# api_base_uri =

# Enable/disable ability for users to create TLS Terminated listeners
# allow_tls_terminated_listeners = True

# Enable/disable ability for users to create PING type Health Monitors
# allow_ping_health_monitors = True

# Dictionary of enabled provider driver names and descriptions
# A comma separated list of dictionaries of the enabled provider driver names
# and descriptions.
enabled_provider_drivers = elbv3:The Open Telekom Cloud AZ aware LD driver.
#enabled_provider_drivers = elbv2:The Open Telekom Cloud Enhanced LB driver.,elbv3:The Open Telekom Cloud AZ aware LD driver.
#

# Default provider driver
default_provider_driver = elbv3

# The minimum health monitor delay interval for UDP-CONNECT Health Monitor type
# udp_connect_min_interval_health_monitor = 3

# Boolean to enable/disable oslo middleware /healthcheck in the Octavia API
# healthcheck_enabled = False

# Default cipher string for new TLS-terminated listeners
# Cipher strings are in OpenSSL format, see https://www.openssl.org/docs/man1.1.1/man1/ciphers.html
# This example is the "Broad Compatibility" cipher string from OWASP,
# see https://cheatsheetseries.owasp.org/cheatsheets/TLS_Cipher_String_Cheat_Sheet.html
# default_listener_ciphers = TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256

# Default cipher string for new TLS-enabled pools, in OpenSSL format.
# Cipher strings are in OpenSSL format, see https://www.openssl.org/docs/man1.1.1/man1/ciphers.html
# This example is the "Broad Compatibility" cipher string from OWASP,
# see https://cheatsheetseries.owasp.org/cheatsheets/TLS_Cipher_String_Cheat_Sheet.html
# default_pool_ciphers = TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256

# Colon-separated list of disallowed ciphers. Ciphers specified here will not be
# allowed on listeners, pools, or the default values for either.
# tls_cipher_prohibit_list =

# List of default TLS versions to be used on new TLS-terminated
# listeners. Available versions: SSLv3, TLSv1, TLSv1.1, TLSv1.2, TLSv1.3
# default_listener_tls_versions = TLSv1.2, TLSv1.3

# List of default TLS versions to be used on new TLS-enabled
# pools. Available versions: SSLv3, TLSv1, TLSv1.1, TLSv1.2, TLSv1.3
# default_pool_tls_versions = TLSv1.2, TLSv1.3

# Minimum TLS version to allow for listeners, pools, or the defaults for
# either. Available versions: SSLv3, TLSv1, TLSv1.1, TLSv1.2, TLSv1.3
# minimum_tls_version =

# List of default ALPN protocols to be used on new TLS-terminated
# listeners. Available protocols: http/1.0, http/1.1, h2
# default_listener_alpn_protocols = http/1.1, http/1.0

# List of default ALPN protocols to be used on new TLS-terminated
# pools. Available protocols: http/1.0, http/1.1, h2
# default_pool_alpn_protocols = http/1.1, http/1.0


[keystone_authtoken]
# This group of config options are imported from keystone middleware. Thus the
# option names should match the names declared in the middleware.
# The www_authenticate_uri is the public endpoint and is returned in headers on a 401
# www_authenticate_uri = https://localhost:5000/v3
# The auth_url is the admin endpoint actually used for validating tokens
# auth_url = https://localhost:5000/v3
# username = octavia
# password = password
# project_name = service

# Domain names must be set, these are *not* default but work for most clouds
# project_domain_name = Default
# user_domain_name = Default

# insecure = False
# cafile =

[oslo_messaging]
# Queue Consumer Thread Pool Size
# rpc_thread_pool_size = 2

# Topic (i.e. Queue) Name
# topic = octavia_prov

[oslo_middleware]
# HTTPProxyToWSGI middleware enabled
# enable_proxy_headers_parsing = False
23 changes: 23 additions & 0 deletions etc/policy.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# This policy.yaml will revert the Octavia API to follow the legacy
# admin-or-owner RBAC policies.
# It provides a similar policy to legacy OpenStack policies where any
# user or admin has access to load-balancer resources that they own.
# Users with the admin role has access to all load-balancer resources,
# whether they own them or not.

# Role Rules
#"context_is_admin": "role:admin or role:load-balancer_admin"
#"admin_or_owner": "is_admin:True or project_id:%(project_id)s"
"load-balancer:member_and_owner": "(role:te_admin and rule:load-balancer:owner)"
#"load-balancer:read": "(rule:load-balancer:observer_and_owner or rule:load-balancer:global_observer or rule:load-balancer:member_and_owner or rule:load-balancer:admin)",

# Rules
#"load-balancer:read": "rule:admin_or_owner"
#"load-balancer:read-global": "is_admin:True"
#"load-balancer:write": "rule:admin_or_owner"
#"load-balancer:read-quota": "rule:admin_or_owner"
#"load-balancer:read-quota-global": "is_admin:True"
#"load-balancer:write-quota": "is_admin:True"

#"os_load-balancer_api:provider:get_all": "rule:load-balancer:read"
#"os_load-balancer_api:loadbalancer:get_all": "rule:admin_or_owner"
Empty file added octavia_proxy/__init__.py
Empty file.
Empty file added octavia_proxy/api/__init__.py
Empty file.
78 changes: 78 additions & 0 deletions octavia_proxy/api/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import sys

from oslo_config import cfg
from oslo_log import log as logging
from oslo_middleware import cors
from oslo_middleware import http_proxy_to_wsgi
from oslo_middleware import request_id
from pecan import configuration as pecan_configuration
from pecan import make_app as pecan_make_app

# TODO(gtema) this should actually become configurable whether we want
# validatetoken or keystonemiddleware
import validatetoken.middleware.validatetoken as validatetoken_middleware

from octavia_proxy.api import config as app_config
from octavia_proxy.api.drivers import driver_factory
from octavia_proxy.common import service as octavia_service


LOG = logging.getLogger(__name__)
CONF = cfg.CONF


def get_pecan_config():
"""Returns the pecan config."""
filename = app_config.__file__.replace('.pyc', '.py')
return pecan_configuration.conf_from_file(filename)


def _init_drivers():
"""Initialize provider drivers."""
for provider in CONF.api_settings.enabled_provider_drivers:
driver_factory.get_driver(provider)


def setup_app(pecan_config=None, debug=False, argv=None):
"""Creates and returns a pecan wsgi app."""
if argv is None:
argv = sys.argv
octavia_service.prepare_service(argv)
cfg.CONF.log_opt_values(LOG, logging.DEBUG)

_init_drivers()

if not pecan_config:
pecan_config = get_pecan_config()
pecan_configuration.set_config(dict(pecan_config), overwrite=True)

return pecan_make_app(
pecan_config.app.root,
wrap_app=_wrap_app,
debug=debug,
hooks=pecan_config.app.hooks,
wsme=pecan_config.wsme
)


def _wrap_app(app):
"""Wraps wsgi app with additional middlewares."""
app = request_id.RequestId(app)

app = validatetoken_middleware.ValidateToken(app, cfg.CONF.validatetoken)

app = http_proxy_to_wsgi.HTTPProxyToWSGI(app)

# This should be the last middleware in the list (which results in
# it being the first in the middleware chain). This is to ensure
# that any errors thrown by other middleware, such as an auth
# middleware - are annotated with CORS headers, and thus accessible
# by the browser.
app = cors.CORS(app, cfg.CONF)
cors.set_defaults(
allow_headers=['X-Auth-Token', 'X-Openstack-Request-Id'],
allow_methods=['GET', 'PUT', 'POST', 'DELETE'],
expose_headers=['X-Auth-Token', 'X-Openstack-Request-Id']
)

return app
Empty file.
34 changes: 34 additions & 0 deletions octavia_proxy/api/common/hooks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
from pecan import hooks

from oslo_log import log as logging
from oslo_config import cfg

from octavia.common import constants

from octavia_proxy.api.common import pagination
from octavia_proxy.common import context

CONF = cfg.CONF

LOG = logging.getLogger(__name__)


class ContextHook(hooks.PecanHook):
"""Configures a request context and attaches it to the request."""

def on_route(self, state):
context_obj = context.Context.from_environ(state.request.environ)
token_info = state.request.environ['keystone.token_info']
context_obj.set_token_info(token_info)
state.request.context['octavia_context'] = context_obj


class QueryParametersHook(hooks.PecanHook):

def before(self, state):
if state.request.method != 'GET':
return

state.request.context[
constants.PAGINATION_HELPER] = pagination.PaginationHelper(
state.request.params.mixed())
Loading

0 comments on commit 0f43f97

Please sign in to comment.