diff --git a/ironic_lib/common/config.py b/ironic_lib/common/config.py new file mode 100644 index 00000000..26cb1365 --- /dev/null +++ b/ironic_lib/common/config.py @@ -0,0 +1,22 @@ +# 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 oslo_config import types + + +class Octal(types.Integer): + + def __call__(self, value): + if isinstance(value, int): + return value + else: + return int(str(value), 8) diff --git a/ironic_lib/json_rpc/__init__.py b/ironic_lib/json_rpc/__init__.py index 390d5813..95e2934b 100644 --- a/ironic_lib/json_rpc/__init__.py +++ b/ironic_lib/json_rpc/__init__.py @@ -12,6 +12,7 @@ from oslo_config import cfg +from ironic_lib.common import config from ironic_lib.common.i18n import _ from ironic_lib import keystone @@ -54,6 +55,11 @@ opts = [ cfg.ListOpt('allowed_roles', default=['admin'], help=_("List of roles allowed to use JSON RPC")), + cfg.StrOpt('unix_socket', + help=_('Unix socket to listen on. Disables host_ip and port.')), + cfg.Opt('unix_socket_mode', type=config.Octal(), + help=_('File mode (an octal number) of the unix socket to ' + 'listen on. Ignored if unix_socket is not set.')), ] diff --git a/ironic_lib/json_rpc/server.py b/ironic_lib/json_rpc/server.py index 0212ab35..7d2cafe8 100644 --- a/ironic_lib/json_rpc/server.py +++ b/ironic_lib/json_rpc/server.py @@ -31,8 +31,6 @@ try: import oslo_messaging except ImportError: oslo_messaging = None -from oslo_service import service -from oslo_service import wsgi from oslo_utils import strutils import webob @@ -40,6 +38,7 @@ from ironic_lib import auth_basic from ironic_lib.common.i18n import _ from ironic_lib import exception from ironic_lib import json_rpc +from ironic_lib import wsgi CONF = cfg.CONF @@ -100,7 +99,7 @@ class EmptyContext: return self.__dict__.copy() -class WSGIService(service.Service): +class WSGIService(wsgi.WSGIService): """Provides ability to launch JSON RPC as a WSGI application.""" def __init__(self, manager, serializer, context_class=EmptyContext): @@ -130,10 +129,7 @@ class WSGIService(service.Service): cfg.CONF.json_rpc.http_basic_auth_user_file) else: app = self._application - self.server = wsgi.Server(CONF, 'ironic-json-rpc', app, - host=CONF.json_rpc.host_ip, - port=CONF.json_rpc.port, - use_ssl=CONF.json_rpc.use_ssl) + super().__init__('ironic-json-rpc', app, CONF.json_rpc) def _application(self, environment, start_response): """WSGI application for conductor JSON RPC.""" @@ -294,31 +290,3 @@ class WSGIService(service.Service): strutils.mask_dict_password(result) if isinstance(result, dict) else result) return result - - def start(self): - """Start serving this service using loaded configuration. - - :returns: None - """ - self.server.start() - - def stop(self): - """Stop serving this API. - - :returns: None - """ - self.server.stop() - - def wait(self): - """Wait for the service to stop serving this API. - - :returns: None - """ - self.server.wait() - - def reset(self): - """Reset server greenpool size to default. - - :returns: None - """ - self.server.reset() diff --git a/ironic_lib/wsgi.py b/ironic_lib/wsgi.py new file mode 100644 index 00000000..ca048d58 --- /dev/null +++ b/ironic_lib/wsgi.py @@ -0,0 +1,77 @@ +# 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 socket + +from oslo_config import cfg +from oslo_service import service +from oslo_service import wsgi + +from ironic_lib import utils + +CONF = cfg.CONF + + +class WSGIService(service.ServiceBase): + + def __init__(self, name, app, conf): + """Initialize, but do not start the WSGI server. + + :param name: The name of the WSGI server given to the loader. + :param app: WSGI application to run. + :param conf: Object to load configuration from. + :returns: None + """ + self.name = name + self._conf = conf + if conf.unix_socket: + utils.unlink_without_raise(conf.unix_socket) + self.server = wsgi.Server(CONF, name, app, + socket_family=socket.AF_UNIX, + socket_file=conf.unix_socket, + socket_mode=conf.unix_socket_mode, + use_ssl=conf.use_ssl) + else: + self.server = wsgi.Server(CONF, name, app, + host=conf.host_ip, + port=conf.port, + use_ssl=conf.use_ssl) + + def start(self): + """Start serving this service using loaded configuration. + + :returns: None + """ + self.server.start() + + def stop(self): + """Stop serving this API. + + :returns: None + """ + self.server.stop() + if self._conf.unix_socket: + utils.unlink_without_raise(self._conf.unix_socket) + + def wait(self): + """Wait for the service to stop serving this API. + + :returns: None + """ + self.server.wait() + + def reset(self): + """Reset server greenpool size to default. + + :returns: None + """ + self.server.reset()