Support kubernetes python client 4.0.0
From 4.0.0, kubernetes-incubator/client-python uses multiprocessing libaray to send request to k8s cluster, which is not supported by eventlet. This patch introduced the following changes to fix the issue: - Use cotyledon for engine service rather than oslo.service - Update global requirments - Provide separate scripts for api and engine service References: [1] https://github.com/eventlet/eventlet/issues/147 [2] https://bugs.launchpad.net/taskflow/+bug/1225275 Change-Id: Ib99565e00eedc72c388e8ebec6b7f1453f77f30f
This commit is contained in:
parent
76f87d59ec
commit
aa765e2ae9
|
@ -80,7 +80,7 @@ function configure_qinling {
|
|||
|
||||
# Setup keystone_authtoken section
|
||||
configure_auth_token_middleware $QINLING_CONF_FILE qinling $QINLING_AUTH_CACHE_DIR
|
||||
iniset $QINLING_CONF_FILE keystone_authtoken auth_uri $KEYSTONE_AUTH_URI_V3
|
||||
iniset $QINLING_CONF_FILE keystone_authtoken www_authenticate_uri $KEYSTONE_AUTH_URI_V3
|
||||
|
||||
# Setup RabbitMQ credentials
|
||||
iniset_rpc_backend qinling $QINLING_CONF_FILE
|
||||
|
@ -99,8 +99,8 @@ function init_qinling {
|
|||
|
||||
|
||||
function start_qinling {
|
||||
run_process qinling-engine "$QINLING_BIN_DIR/qinling-server --server engine --config-file $QINLING_CONF_FILE"
|
||||
run_process qinling-api "$QINLING_BIN_DIR/qinling-server --server api --config-file $QINLING_CONF_FILE"
|
||||
run_process qinling-engine "$QINLING_BIN_DIR/qinling-engine --config-file $QINLING_CONF_FILE"
|
||||
run_process qinling-api "$QINLING_BIN_DIR/qinling-api --config-file $QINLING_CONF_FILE"
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -76,7 +76,6 @@ class FunctionsController(rest.RestController):
|
|||
def __init__(self, *args, **kwargs):
|
||||
self.storage_provider = storage_base.load_storage_provider(CONF)
|
||||
self.engine_client = rpc.get_engine_client()
|
||||
self.type = 'function'
|
||||
|
||||
super(FunctionsController, self).__init__(*args, **kwargs)
|
||||
|
||||
|
@ -92,7 +91,7 @@ class FunctionsController(rest.RestController):
|
|||
@rest_utils.wrap_pecan_controller_exception
|
||||
@pecan.expose()
|
||||
def get(self, id):
|
||||
LOG.info("Get resource.", resource={'type': self.type, 'id': id})
|
||||
LOG.info("Get function %s.", id)
|
||||
|
||||
download = strutils.bool_from_string(
|
||||
pecan.request.GET.get('download', False)
|
||||
|
@ -104,6 +103,7 @@ class FunctionsController(rest.RestController):
|
|||
pecan.override_template('json')
|
||||
return resources.Function.from_dict(func_db.to_dict()).to_dict()
|
||||
else:
|
||||
LOG.info("Downloading function %s", id)
|
||||
source = func_db.code['source']
|
||||
|
||||
if source == 'package':
|
||||
|
@ -126,11 +126,12 @@ class FunctionsController(rest.RestController):
|
|||
pecan.response.headers['Content-Disposition'] = (
|
||||
'attachment; filename="%s"' % os.path.basename(func_db.name)
|
||||
)
|
||||
LOG.info("Downloaded function %s", id)
|
||||
|
||||
@rest_utils.wrap_pecan_controller_exception
|
||||
@pecan.expose('json')
|
||||
def post(self, **kwargs):
|
||||
LOG.info("Creating %s, params: %s", self.type, kwargs)
|
||||
LOG.info("Creating function, params: %s", kwargs)
|
||||
|
||||
# When using image to create function, runtime_id is not a required
|
||||
# param.
|
||||
|
@ -221,7 +222,7 @@ class FunctionsController(rest.RestController):
|
|||
filters = rest_utils.get_filters(
|
||||
project_id=project_id,
|
||||
)
|
||||
LOG.info("Get all %ss. filters=%s", self.type, filters)
|
||||
LOG.info("Get all functions. filters=%s", filters)
|
||||
db_functions = db_api.get_functions(insecure=all_projects, **filters)
|
||||
functions = [resources.Function.from_dict(db_model.to_dict())
|
||||
for db_model in db_functions]
|
||||
|
@ -232,7 +233,7 @@ class FunctionsController(rest.RestController):
|
|||
@wsme_pecan.wsexpose(None, types.uuid, status_code=204)
|
||||
def delete(self, id):
|
||||
"""Delete the specified function."""
|
||||
LOG.info("Delete resource.", resource={'type': self.type, 'id': id})
|
||||
LOG.info("Delete function %s.", id)
|
||||
|
||||
with db_api.transaction():
|
||||
func_db = db_api.get_function(id)
|
||||
|
@ -280,9 +281,7 @@ class FunctionsController(rest.RestController):
|
|||
if kwargs.get(key) is not None:
|
||||
values.update({key: kwargs[key]})
|
||||
|
||||
LOG.info('Update resource, params: %s', values,
|
||||
resource={'type': self.type, 'id': id})
|
||||
|
||||
LOG.info('Update function %s, params: %s', id, values)
|
||||
ctx = context.get_ctx()
|
||||
|
||||
if set(values.keys()).issubset(set(['name', 'description'])):
|
||||
|
|
|
@ -14,25 +14,34 @@
|
|||
|
||||
from oslo_concurrency import processutils
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
from oslo_service import service
|
||||
from oslo_service import wsgi
|
||||
|
||||
from qinling.api import app
|
||||
|
||||
CONF = cfg.CONF
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class WSGIService(service.ServiceBase):
|
||||
"""Provides ability to launch Mistral API from wsgi app."""
|
||||
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
def __init__(self):
|
||||
self.app = app.setup_app()
|
||||
self.workers = (
|
||||
cfg.CONF.api.api_workers or processutils.get_worker_count()
|
||||
)
|
||||
|
||||
self.workers = CONF.api.api_workers
|
||||
if self.workers is not None and self.workers < 1:
|
||||
LOG.warning(
|
||||
"Value of config option api_workers must be integer "
|
||||
"greater than 1. Input value ignored."
|
||||
)
|
||||
self.workers = None
|
||||
self.workers = self.workers or processutils.get_worker_count()
|
||||
|
||||
self.server = wsgi.Server(
|
||||
cfg.CONF,
|
||||
name,
|
||||
"qinling_api",
|
||||
self.app,
|
||||
host=cfg.CONF.api.host,
|
||||
port=cfg.CONF.api.port,
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
# Copyright 2017 - Catalyst IT Limited
|
||||
#
|
||||
# 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.
|
||||
|
||||
import eventlet
|
||||
eventlet.monkey_patch()
|
||||
|
||||
import sys
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
from oslo_service import service
|
||||
|
||||
from qinling.api import service as api_service
|
||||
from qinling import config
|
||||
from qinling import rpc
|
||||
from qinling.utils import common
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
||||
def main():
|
||||
try:
|
||||
config.parse_args(args=common.get_properly_ordered_parameters())
|
||||
common.print_server_info("api")
|
||||
logging.setup(CONF, 'qinling')
|
||||
# Initialize RPC configuration.
|
||||
rpc.get_transport()
|
||||
|
||||
api_server = api_service.WSGIService()
|
||||
launcher = service.launch(CONF, api_server, workers=api_server.workers)
|
||||
launcher.wait()
|
||||
except RuntimeError as excp:
|
||||
sys.stderr.write("ERROR: %s\n" % excp)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -0,0 +1,49 @@
|
|||
# Copyright 2017 - Catalyst IT Limited
|
||||
#
|
||||
# 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.
|
||||
|
||||
import sys
|
||||
|
||||
import cotyledon
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
|
||||
from qinling import config
|
||||
from qinling.engine import service as eng_service
|
||||
from qinling import rpc
|
||||
from qinling.utils import common
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
||||
def main():
|
||||
try:
|
||||
config.parse_args(args=common.get_properly_ordered_parameters())
|
||||
common.print_server_info("engine")
|
||||
logging.setup(CONF, 'qinling')
|
||||
# Initialize RPC configuration.
|
||||
rpc.get_transport()
|
||||
|
||||
sm = cotyledon.ServiceManager()
|
||||
sm.add(
|
||||
eng_service.EngineService,
|
||||
workers=1,
|
||||
)
|
||||
sm.run()
|
||||
except RuntimeError as excp:
|
||||
sys.stderr.write("ERROR: %s\n" % excp)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -1,161 +0,0 @@
|
|||
# Copyright 2017 - Catalyst IT Limited
|
||||
#
|
||||
# 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.
|
||||
|
||||
import sys
|
||||
|
||||
import eventlet
|
||||
|
||||
eventlet.monkey_patch(
|
||||
os=True,
|
||||
select=True,
|
||||
socket=True,
|
||||
thread=False if '--use-debugger' in sys.argv else True,
|
||||
time=True)
|
||||
|
||||
import os
|
||||
|
||||
# If ../qinling/__init__.py exists, add ../ to Python search path, so that
|
||||
# it will override what happens to be installed in /usr/(local/)lib/python...
|
||||
POSSIBLE_TOPDIR = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]),
|
||||
os.pardir,
|
||||
os.pardir))
|
||||
if os.path.exists(os.path.join(POSSIBLE_TOPDIR, 'qinling', '__init__.py')):
|
||||
sys.path.insert(0, POSSIBLE_TOPDIR)
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
from oslo_service import service
|
||||
|
||||
from qinling.api import service as api_service
|
||||
from qinling import config
|
||||
from qinling.engine import service as eng_service
|
||||
from qinling import rpc
|
||||
from qinling import version
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
||||
def launch_api():
|
||||
try:
|
||||
server = api_service.WSGIService('qinling_api')
|
||||
launcher = service.launch(CONF, server, workers=server.workers)
|
||||
return launcher
|
||||
except Exception as e:
|
||||
sys.stderr.write("ERROR: %s\n" % e)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def launch_engine():
|
||||
try:
|
||||
server = eng_service.EngineService()
|
||||
launcher = service.launch(CONF, server)
|
||||
return launcher
|
||||
except Exception as e:
|
||||
sys.stderr.write("ERROR: %s\n" % e)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def launch_any(options):
|
||||
launchers = [LAUNCH_OPTIONS[option]() for option in options]
|
||||
for l in launchers:
|
||||
l.wait()
|
||||
|
||||
|
||||
LAUNCH_OPTIONS = {
|
||||
'api': launch_api,
|
||||
'engine': launch_engine
|
||||
}
|
||||
|
||||
QINLING_TITLE = r"""
|
||||
/^L_ ,."\
|
||||
/~\ __ /~ \ ./ \
|
||||
/ _\ _/ \ /T~\|~\_\ / \_ /~| _^
|
||||
/ \ /W \ / V^\/X /~ T . \/ \ ,v-./
|
||||
,'`-. /~ ^ H , . \/ ; . \ `. \-' /
|
||||
M ~ | . ; / , _ : . ~\_,-'
|
||||
/ ~ . \ / : ' \ ,/`
|
||||
I o. ^ oP '98b - _ 9.` `\9b.
|
||||
8oO888. oO888P d888b9bo. .8o 888o. 8bo. o 988o.
|
||||
88888888888888888888888888bo.98888888bo. 98888bo. .d888P
|
||||
88888888888888888888888888888888888888888888888888888888888
|
||||
_ __ _
|
||||
___ _ (_) ___ / / (_) ___ ___ _
|
||||
/ _ `/ / / / _ \ / / / / / _ \ / _ `/
|
||||
\_, / /_/ /_//_//_/ /_/ /_//_/ \_, /
|
||||
/_/ /___/
|
||||
|
||||
Function as a Service in OpenStack, version: %s
|
||||
""" % version.version_string()
|
||||
|
||||
|
||||
def print_server_info():
|
||||
print(QINLING_TITLE)
|
||||
|
||||
comp_str = ("[%s]" % ','.join(LAUNCH_OPTIONS)
|
||||
if cfg.CONF.server == ['all'] else cfg.CONF.server)
|
||||
|
||||
print('Launching server components %s...' % comp_str)
|
||||
|
||||
|
||||
def get_properly_ordered_parameters():
|
||||
"""Orders launch parameters in the right order.
|
||||
|
||||
In oslo it's important the order of the launch parameters.
|
||||
if --config-file came after the command line parameters the command
|
||||
line parameters are ignored.
|
||||
So to make user command line parameters are never ignored this method
|
||||
moves --config-file to be always first.
|
||||
"""
|
||||
args = sys.argv[1:]
|
||||
|
||||
for arg in sys.argv[1:]:
|
||||
if arg == '--config-file' or arg.startswith('--config-file='):
|
||||
if "=" in arg:
|
||||
conf_file_value = arg.split("=", 1)[1]
|
||||
else:
|
||||
conf_file_value = args[args.index(arg) + 1]
|
||||
args.remove(conf_file_value)
|
||||
args.remove(arg)
|
||||
args.insert(0, "--config-file")
|
||||
args.insert(1, conf_file_value)
|
||||
|
||||
return args
|
||||
|
||||
|
||||
def main():
|
||||
try:
|
||||
config.parse_args(get_properly_ordered_parameters())
|
||||
print_server_info()
|
||||
|
||||
logging.setup(CONF, 'Qinling')
|
||||
|
||||
# Initialize RPC configuration.
|
||||
rpc.get_transport()
|
||||
|
||||
if cfg.CONF.server == ['all']:
|
||||
launch_any(LAUNCH_OPTIONS.keys())
|
||||
else:
|
||||
if set(cfg.CONF.server) - set(LAUNCH_OPTIONS.keys()):
|
||||
raise Exception('Valid options are all or any combination of '
|
||||
', '.join(LAUNCH_OPTIONS.keys()))
|
||||
|
||||
launch_any(set(cfg.CONF.server))
|
||||
|
||||
except RuntimeError as excp:
|
||||
sys.stderr.write("ERROR: %s\n" % excp)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
|
@ -38,6 +38,7 @@ api_opts = [
|
|||
),
|
||||
cfg.IntOpt(
|
||||
'api_workers',
|
||||
default=1,
|
||||
help='Number of workers for Qinling API service '
|
||||
'default is equal to the number of CPUs available if that can '
|
||||
'be determined, else a default worker count of 1 is returned.'
|
||||
|
@ -134,7 +135,7 @@ kubernetes_opts = [
|
|||
),
|
||||
cfg.StrOpt(
|
||||
'kube_host',
|
||||
default='127.0.0.1:8001',
|
||||
default='http://127.0.0.1:8001',
|
||||
help='Kubernetes server address, e.g. you can start a proxy to the '
|
||||
'Kubernetes API server by using "kubectl proxy" command.'
|
||||
),
|
||||
|
@ -194,6 +195,7 @@ def parse_args(args=None, usage=None, default_config_files=None):
|
|||
'keystoneclient=INFO',
|
||||
'requests.packages.urllib3.connectionpool=CRITICAL',
|
||||
'urllib3.connectionpool=CRITICAL',
|
||||
'cotyledon=INFO'
|
||||
]
|
||||
default_log_levels = log.get_default_log_levels()
|
||||
default_log_levels.extend(_DEFAULT_LOG_LEVELS)
|
||||
|
|
|
@ -12,11 +12,11 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import cotyledon
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
import oslo_messaging as messaging
|
||||
from oslo_messaging.rpc import dispatcher
|
||||
from oslo_service import service
|
||||
|
||||
from qinling.db import api as db_api
|
||||
from qinling.engine import default_engine as engine
|
||||
|
@ -28,12 +28,12 @@ LOG = logging.getLogger(__name__)
|
|||
CONF = cfg.CONF
|
||||
|
||||
|
||||
class EngineService(service.Service):
|
||||
def __init__(self):
|
||||
super(EngineService, self).__init__()
|
||||
class EngineService(cotyledon.Service):
|
||||
def __init__(self, worker_id):
|
||||
super(EngineService, self).__init__(worker_id)
|
||||
self.server = None
|
||||
|
||||
def start(self):
|
||||
def run(self):
|
||||
orchestrator = orchestra_base.load_orchestrator(CONF)
|
||||
db_api.setup_db()
|
||||
|
||||
|
@ -47,11 +47,10 @@ class EngineService(service.Service):
|
|||
transport,
|
||||
target,
|
||||
[endpoint],
|
||||
executor='eventlet',
|
||||
executor='threading',
|
||||
access_policy=access_policy,
|
||||
serializer=rpc.ContextSerializer(
|
||||
messaging.serializer.JsonPayloadSerializer()
|
||||
)
|
||||
messaging.serializer.JsonPayloadSerializer())
|
||||
)
|
||||
|
||||
LOG.info('Starting function mapping periodic task...')
|
||||
|
@ -60,25 +59,10 @@ class EngineService(service.Service):
|
|||
LOG.info('Starting engine...')
|
||||
self.server.start()
|
||||
|
||||
super(EngineService, self).start()
|
||||
|
||||
def stop(self, graceful=False):
|
||||
def terminate(self):
|
||||
periodics.stop()
|
||||
|
||||
if self.server:
|
||||
LOG.info('Stopping engine...')
|
||||
self.server.stop()
|
||||
if graceful:
|
||||
LOG.info(
|
||||
'Consumer successfully stopped. Waiting for final '
|
||||
'messages to be processed...'
|
||||
)
|
||||
self.server.wait()
|
||||
|
||||
super(EngineService, self).stop(graceful=graceful)
|
||||
|
||||
def reset(self):
|
||||
if self.server:
|
||||
self.server.reset()
|
||||
|
||||
super(EngineService, self).reset()
|
||||
self.server.wait()
|
||||
|
|
|
@ -82,7 +82,7 @@ def get_request_data(conf, function_id, execution_id, input, entry, trust_id):
|
|||
data.update(
|
||||
{
|
||||
'token': ctx.auth_token,
|
||||
'auth_url': conf.keystone_authtoken.auth_uri,
|
||||
'auth_url': conf.keystone_authtoken.www_authenticate_uri,
|
||||
'username': conf.keystone_authtoken.username,
|
||||
'password': conf.keystone_authtoken.password,
|
||||
'trust_id': trust_id
|
||||
|
|
|
@ -18,7 +18,6 @@ import os
|
|||
import time
|
||||
|
||||
import jinja2
|
||||
from kubernetes import client
|
||||
from oslo_log import log as logging
|
||||
import requests
|
||||
import tenacity
|
||||
|
@ -27,6 +26,7 @@ import yaml
|
|||
from qinling.engine import utils
|
||||
from qinling import exceptions as exc
|
||||
from qinling.orchestrator import base
|
||||
from qinling.orchestrator.kubernetes import utils as k8s_util
|
||||
from qinling.utils import common
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
@ -38,9 +38,9 @@ class KubernetesManager(base.OrchestratorBase):
|
|||
def __init__(self, conf):
|
||||
self.conf = conf
|
||||
|
||||
client.Configuration().host = self.conf.kubernetes.kube_host
|
||||
self.v1 = client.CoreV1Api()
|
||||
self.v1extention = client.ExtensionsV1beta1Api()
|
||||
clients = k8s_util.get_k8s_clients(self.conf)
|
||||
self.v1 = clients['v1']
|
||||
self.v1extention = clients['v1extention']
|
||||
|
||||
# Create namespace if not exists
|
||||
self._ensure_namespace()
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
# Copyright 2018 Catalyst IT Limited
|
||||
#
|
||||
# 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.
|
||||
|
||||
from kubernetes.client import api_client
|
||||
from kubernetes.client.apis import core_v1_api
|
||||
from kubernetes.client.apis import extensions_v1beta1_api
|
||||
from kubernetes.client import configuration as k8s_config
|
||||
|
||||
|
||||
def get_k8s_clients(conf):
|
||||
config = k8s_config.Configuration()
|
||||
config.host = conf.kubernetes.kube_host
|
||||
config.verify_ssl = False
|
||||
client = api_client.ApiClient(configuration=config)
|
||||
v1 = core_v1_api.CoreV1Api(client)
|
||||
v1extention = extensions_v1beta1_api.ExtensionsV1beta1Api(client)
|
||||
|
||||
clients = {
|
||||
'v1': v1,
|
||||
'v1extention': v1extention
|
||||
}
|
||||
|
||||
return clients
|
|
@ -39,7 +39,7 @@ class FileSystemStorage(base.PackageStorage):
|
|||
:param function: Function ID.
|
||||
:param data: Package data.
|
||||
"""
|
||||
LOG.info(
|
||||
LOG.debug(
|
||||
'Store package, function: %s, project: %s', function, project_id
|
||||
)
|
||||
|
||||
|
@ -64,7 +64,7 @@ class FileSystemStorage(base.PackageStorage):
|
|||
:param function: Function ID.
|
||||
:return: File descriptor that needs to close outside.
|
||||
"""
|
||||
LOG.info(
|
||||
LOG.debug(
|
||||
'Get package data, function: %s, project: %s', function, project_id
|
||||
)
|
||||
|
||||
|
@ -80,11 +80,12 @@ class FileSystemStorage(base.PackageStorage):
|
|||
)
|
||||
|
||||
f = open(func_zip, 'rb')
|
||||
LOG.debug('Found package data')
|
||||
|
||||
return f
|
||||
|
||||
def delete(self, project_id, function):
|
||||
LOG.info(
|
||||
LOG.debug(
|
||||
'Delete package data, function: %s, project: %s', function,
|
||||
project_id
|
||||
)
|
||||
|
|
|
@ -12,11 +12,65 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
import functools
|
||||
import sys
|
||||
import warnings
|
||||
|
||||
from oslo_utils import uuidutils
|
||||
import six
|
||||
|
||||
from qinling import version
|
||||
|
||||
|
||||
def print_server_info(service):
|
||||
QINLING_TITLE = r"""
|
||||
/^L_ ,."\
|
||||
/~\ __ /~ \ ./ \
|
||||
/ _\ _/ \ /T~\|~\_\ / \_ /~| _^
|
||||
/ \ /W \ / V^\/X /~ T . \/ \ ,v-./
|
||||
,'`-. /~ ^ H , . \/ ; . \ `. \-' /
|
||||
M ~ | . ; / , _ : . ~\_,-'
|
||||
/ ~ . \ / : ' \ ,/`
|
||||
I o. ^ oP '98b - _ 9.` `\9b.
|
||||
8oO888. oO888P d888b9bo. .8o 888o. 8bo. o 988o.
|
||||
88888888888888888888888888bo.98888888bo. 98888bo. .d888P
|
||||
88888888888888888888888888888888888888888888888888888888888
|
||||
_ __ _
|
||||
___ _ (_) ___ / / (_) ___ ___ _
|
||||
/ _ `/ / / / _ \ / / / / / _ \ / _ `/
|
||||
\_, / /_/ /_//_//_/ /_/ /_//_/ \_, /
|
||||
/_/ /___/
|
||||
|
||||
Function as a Service in OpenStack, version: %s
|
||||
""" % version.version_string()
|
||||
|
||||
print(QINLING_TITLE)
|
||||
print('Launching server components %s...' % service)
|
||||
|
||||
|
||||
def get_properly_ordered_parameters():
|
||||
"""Orders launch parameters in the right order.
|
||||
|
||||
In oslo it's important the order of the launch parameters.
|
||||
if --config-file came after the command line parameters the command
|
||||
line parameters are ignored.
|
||||
So to make user command line parameters are never ignored this method
|
||||
moves --config-file to be always first.
|
||||
"""
|
||||
args = sys.argv[1:]
|
||||
|
||||
for arg in sys.argv[1:]:
|
||||
if arg == '--config-file' or arg.startswith('--config-file='):
|
||||
if "=" in arg:
|
||||
conf_file_value = arg.split("=", 1)[1]
|
||||
else:
|
||||
conf_file_value = args[args.index(arg) + 1]
|
||||
args.remove(conf_file_value)
|
||||
args.remove(arg)
|
||||
args.insert(0, "--config-file")
|
||||
args.insert(1, conf_file_value)
|
||||
|
||||
return args
|
||||
|
||||
|
||||
def convert_dict_to_string(d):
|
||||
temp_list = ['%s=%s' % (k, v) for k, v in d.items()]
|
||||
|
|
|
@ -30,7 +30,7 @@ def _get_user_keystone_session():
|
|||
ctx = context.get_ctx()
|
||||
|
||||
auth = v3.Token(
|
||||
auth_url=CONF.keystone_authtoken.auth_uri,
|
||||
auth_url=CONF.keystone_authtoken.www_authenticate_uri,
|
||||
token=ctx.auth_token,
|
||||
)
|
||||
|
||||
|
@ -49,7 +49,7 @@ def get_swiftclient():
|
|||
@common.disable_ssl_warnings
|
||||
def get_user_client():
|
||||
ctx = context.get_ctx()
|
||||
auth_url = CONF.keystone_authtoken.auth_uri
|
||||
auth_url = CONF.keystone_authtoken.www_authenticate_uri
|
||||
client = ks_client.Client(
|
||||
user_id=ctx.user,
|
||||
token=ctx.auth_token,
|
||||
|
@ -67,7 +67,7 @@ def get_service_client():
|
|||
username=CONF.keystone_authtoken.username,
|
||||
password=CONF.keystone_authtoken.password,
|
||||
project_name=CONF.keystone_authtoken.project_name,
|
||||
auth_url=CONF.keystone_authtoken.auth_uri,
|
||||
auth_url=CONF.keystone_authtoken.www_authenticate_uri,
|
||||
user_domain_name=CONF.keystone_authtoken.user_domain_name,
|
||||
project_domain_name=CONF.keystone_authtoken.project_domain_name
|
||||
)
|
||||
|
@ -80,7 +80,7 @@ def get_trust_client(trust_id):
|
|||
client = ks_client.Client(
|
||||
username=CONF.keystone_authtoken.username,
|
||||
password=CONF.keystone_authtoken.password,
|
||||
auth_url=CONF.keystone_authtoken.auth_uri,
|
||||
auth_url=CONF.keystone_authtoken.www_authenticate_uri,
|
||||
trust_id=trust_id
|
||||
)
|
||||
|
||||
|
|
|
@ -41,6 +41,6 @@ QinlingGroup = [
|
|||
'publicURL', 'adminURL', 'internalURL'],
|
||||
help="The endpoint type to use for the qinling service."),
|
||||
cfg.StrOpt('kube_host',
|
||||
default='127.0.0.1:8001',
|
||||
default='http://127.0.0.1:8001',
|
||||
help="The Kubernetes service address."),
|
||||
]
|
||||
|
|
|
@ -13,12 +13,13 @@
|
|||
# limitations under the License.
|
||||
import os
|
||||
|
||||
from kubernetes import client as k8s_client
|
||||
from tempest import config
|
||||
from tempest.lib.common.utils import data_utils
|
||||
from tempest import test
|
||||
import tenacity
|
||||
|
||||
from qinling_tempest_plugin.tests import utils
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
|
||||
|
@ -41,9 +42,9 @@ class BaseQinlingTest(test.BaseTestCase):
|
|||
cls.admin_client = cls.os_admin.qinling.QinlingClient()
|
||||
|
||||
# Initilize k8s client
|
||||
k8s_client.Configuration().host = CONF.qinling.kube_host
|
||||
cls.k8s_v1 = k8s_client.CoreV1Api()
|
||||
cls.k8s_v1extention = k8s_client.ExtensionsV1beta1Api()
|
||||
clients = utils.get_k8s_clients(CONF)
|
||||
cls.k8s_v1 = clients['v1']
|
||||
cls.k8s_v1extention = clients['v1extention']
|
||||
cls.namespace = 'qinling'
|
||||
|
||||
@tenacity.retry(
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
# Copyright 2018 Catalyst IT Limited
|
||||
#
|
||||
# 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.
|
||||
|
||||
from kubernetes.client import api_client
|
||||
from kubernetes.client.apis import core_v1_api
|
||||
from kubernetes.client.apis import extensions_v1beta1_api
|
||||
from kubernetes.client import configuration as k8s_config
|
||||
|
||||
|
||||
def get_k8s_clients(conf):
|
||||
config = k8s_config.Configuration()
|
||||
config.host = conf.qinling.kube_host
|
||||
config.verify_ssl = False
|
||||
client = api_client.ApiClient(configuration=config)
|
||||
v1 = core_v1_api.CoreV1Api(client)
|
||||
v1extention = extensions_v1beta1_api.ExtensionsV1beta1Api(client)
|
||||
|
||||
clients = {
|
||||
'v1': v1,
|
||||
'v1extention': v1extention
|
||||
}
|
||||
|
||||
return clients
|
|
@ -4,30 +4,30 @@
|
|||
|
||||
pbr!=2.1.0,>=2.0.0 # Apache-2.0
|
||||
Babel!=2.4.0,>=2.3.4 # BSD
|
||||
eventlet!=0.18.3,!=0.20.1,<0.21.0,>=0.18.2 # MIT
|
||||
keystoneauth1>=2.21.0 # Apache-2.0
|
||||
keystonemiddleware>=4.12.0 # Apache-2.0
|
||||
oslo.concurrency>=3.8.0 # Apache-2.0
|
||||
oslo.config!=4.3.0,!=4.4.0,>=4.0.0 # Apache-2.0
|
||||
oslo.db>=4.23.0 # Apache-2.0
|
||||
oslo.messaging!=5.25.0,>=5.24.2 # Apache-2.0
|
||||
oslo.policy>=1.23.0 # Apache-2.0
|
||||
oslo.utils>=3.20.0 # Apache-2.0
|
||||
oslo.log>=3.22.0 # Apache-2.0
|
||||
oslo.serialization>=1.10.0 # Apache-2.0
|
||||
oslo.service>=1.10.0 # Apache-2.0
|
||||
keystoneauth1>=3.3.0 # Apache-2.0
|
||||
keystonemiddleware>=4.17.0 # Apache-2.0
|
||||
oslo.concurrency>=3.20.0 # Apache-2.0
|
||||
oslo.config>=5.1.0 # Apache-2.0
|
||||
oslo.db>=4.27.0 # Apache-2.0
|
||||
oslo.messaging>=5.29.0 # Apache-2.0
|
||||
oslo.policy>=1.30.0 # Apache-2.0
|
||||
oslo.utils>=3.33.0 # Apache-2.0
|
||||
oslo.log>=3.30.0 # Apache-2.0
|
||||
oslo.serialization!=2.19.1,>=2.18.0 # Apache-2.0
|
||||
oslo.service!=1.28.1,>=1.24.0 # Apache-2.0
|
||||
pecan!=1.0.2,!=1.0.3,!=1.0.4,!=1.2,>=1.0.0 # BSD
|
||||
setuptools!=24.0.0,!=34.0.0,!=34.0.1,!=34.0.2,!=34.0.3,!=34.1.0,!=34.1.1,!=34.2.0,!=34.3.0,!=34.3.1,!=34.3.2,>=16.0 # PSF/ZPL
|
||||
six>=1.9.0 # MIT
|
||||
setuptools!=24.0.0,!=34.0.0,!=34.0.1,!=34.0.2,!=34.0.3,!=34.1.0,!=34.1.1,!=34.2.0,!=34.3.0,!=34.3.1,!=34.3.2,!=36.2.0,>=16.0 # PSF/ZPL
|
||||
six>=1.10.0 # MIT
|
||||
SQLAlchemy!=1.1.5,!=1.1.6,!=1.1.7,!=1.1.8,>=1.0.10 # MIT
|
||||
sqlalchemy-migrate>=0.11.0 # Apache-2.0
|
||||
stevedore>=1.20.0 # Apache-2.0
|
||||
WSME>=0.8 # MIT
|
||||
kubernetes>=1.0.0b1 # Apache-2.0
|
||||
PyYAML>=3.10.0 # MIT
|
||||
WSME>=0.8.0 # MIT
|
||||
kubernetes>=4.0.0 # Apache-2.0
|
||||
PyYAML>=3.10 # MIT
|
||||
python-swiftclient>=3.2.0 # Apache-2.0
|
||||
croniter>=0.3.4 # MIT License
|
||||
python-dateutil>=2.4.2 # BSD
|
||||
tenacity>=3.2.1 # Apache-2.0
|
||||
PyMySQL>=0.7.6 # MIT License
|
||||
etcd3gw>=0.2.0 # Apache-2.0
|
||||
python-dateutil>=2.4.2 # BSD
|
||||
tenacity>=3.2.1 # Apache-2.0
|
||||
PyMySQL>=0.7.6 # MIT License
|
||||
etcd3gw>=0.2.0 # Apache-2.0
|
||||
cotyledon>=1.3.0 # Apache-2.0
|
||||
|
|
|
@ -25,7 +25,8 @@ packages =
|
|||
|
||||
[entry_points]
|
||||
console_scripts =
|
||||
qinling-server = qinling.cmd.launch:main
|
||||
qinling-api = qinling.cmd.api:main
|
||||
qinling-engine = qinling.cmd.engine:main
|
||||
qinling-db-manage = qinling.db.sqlalchemy.migration.cli:main
|
||||
|
||||
qinling.storage.provider:
|
||||
|
|
2
setup.py
2
setup.py
|
@ -25,5 +25,5 @@ except ImportError:
|
|||
pass
|
||||
|
||||
setuptools.setup(
|
||||
setup_requires=['pbr>=2.0.0'],
|
||||
setup_requires=['pbr'],
|
||||
pbr=True)
|
||||
|
|
|
@ -8,11 +8,10 @@ sphinx>=1.6.2 # BSD
|
|||
oslotest>=1.10.0 # Apache-2.0
|
||||
testrepository>=0.0.18 # Apache-2.0/BSD
|
||||
testscenarios>=0.4 # Apache-2.0/BSD
|
||||
testtools>=1.4.0 # MIT
|
||||
tempest>=16.1.0 # Apache-2.0
|
||||
futurist>=1.2.0 # Apache-2.0
|
||||
testtools>=2.2.0 # MIT
|
||||
tempest>=17.1.0 # Apache-2.0
|
||||
futurist>=1.2.0 # Apache-2.0
|
||||
openstackdocstheme>=1.17.0 # Apache-2.0
|
||||
reno>=2.5.0 # Apache-2.0
|
||||
|
||||
openstackdocstheme>=1.16.0 # Apache-2.0
|
||||
|
||||
# releasenotes
|
||||
reno!=2.3.1,>=1.8.0 # Apache-2.0
|
||||
kubernetes>=4.0.0 # Apache-2.0
|
||||
|
|
Loading…
Reference in New Issue