Browse Source
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: Ib99565e00eedc72c388e8ebec6b7f1453f77f30fchanges/28/530428/7
21 changed files with 306 additions and 251 deletions
@ -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()) |
@ -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 |
@ -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 |
Loading…
Reference in new issue