Merge "Implement client and server framework of FlexVolume driver"
This commit is contained in:
commit
720ab1c1dd
|
@ -12,6 +12,20 @@
|
||||||
|
|
||||||
"""Start server of FlexVolume driver"""
|
"""Start server of FlexVolume driver"""
|
||||||
|
|
||||||
|
from oslo_log import log as logging
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from fuxi_kubernetes.common import config
|
||||||
|
from fuxi_kubernetes.common import constants
|
||||||
|
from fuxi_kubernetes.flex_volume_drivers.server import controller
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
raise NotImplemented()
|
config.init(sys.argv[1:])
|
||||||
|
logging.setup(config.CONF, 'fuxi-kubernetes')
|
||||||
|
|
||||||
|
controller.init_volume_drivers()
|
||||||
|
controller.start(
|
||||||
|
constants.LOCAL_HOST,
|
||||||
|
config.CONF[config.flexvolume_driver_group.name].driver_server_port,
|
||||||
|
debug=config.CONF.debug, threaded=True)
|
||||||
|
|
|
@ -11,8 +11,11 @@
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
|
from oslo_log import log as logging
|
||||||
|
|
||||||
|
from fuxi_kubernetes.common import constants
|
||||||
from fuxi_kubernetes.i18n import _
|
from fuxi_kubernetes.i18n import _
|
||||||
|
from fuxi_kubernetes.version import version_info
|
||||||
|
|
||||||
|
|
||||||
flexvolume_driver_group = cfg.OptGroup(
|
flexvolume_driver_group = cfg.OptGroup(
|
||||||
|
@ -27,8 +30,18 @@ flexvolume_driver_opts = [
|
||||||
cfg.IntOpt('driver_server_port',
|
cfg.IntOpt('driver_server_port',
|
||||||
default=7878,
|
default=7878,
|
||||||
help=_('Port for the server of FlexVolume driver.')),
|
help=_('Port for the server of FlexVolume driver.')),
|
||||||
|
cfg.StrOpt('host_platform',
|
||||||
|
default='baremetal',
|
||||||
|
help=_('The platform on which FlexVolume driver runs. '
|
||||||
|
'Optional values are: baremetal')),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
CONF = cfg.CONF
|
CONF = cfg.CONF
|
||||||
|
logging.register_options(CONF)
|
||||||
CONF.register_opts(flexvolume_driver_opts, flexvolume_driver_group.name)
|
CONF.register_opts(flexvolume_driver_opts, flexvolume_driver_group.name)
|
||||||
|
|
||||||
|
|
||||||
|
def init(args, **kwargs):
|
||||||
|
cfg.CONF(args=args, project=constants.PROJECT_NAME,
|
||||||
|
version=version_info.release_string(), **kwargs)
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
|
|
||||||
PROJECT_NAME = 'fuxi-kubernetes'
|
PROJECT_NAME = 'fuxi-kubernetes'
|
||||||
|
|
||||||
|
LOCAL_HOST = '0.0.0.0'
|
||||||
|
|
||||||
VOLUME_DRIVER_CMD = (
|
VOLUME_DRIVER_CMD = (
|
||||||
CMD_INIT,
|
CMD_INIT,
|
||||||
|
@ -66,3 +67,42 @@ VOLUME_DRIVER_CMD_RESULT_STATUS = (
|
||||||
'Failed',
|
'Failed',
|
||||||
'Not supported',
|
'Not supported',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
VOLUME_DRIVER_TYPE = (
|
||||||
|
VOLUME_DRIVER_CINDER,
|
||||||
|
VOLUME_DRIVER_MANICLA,
|
||||||
|
) = (
|
||||||
|
'Cinder',
|
||||||
|
'Manila'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
VOLUME_DRIVER_SERVER_API = (
|
||||||
|
SERVER_API_IS_ATTACHED,
|
||||||
|
SERVER_API_ATTACH,
|
||||||
|
SERVER_API_WAIT_FOR_ATTACH,
|
||||||
|
SERVER_API_MOUNT_DEVICE,
|
||||||
|
SERVER_API_DETACH,
|
||||||
|
SERVER_API_WAIT_FOR_DETACH,
|
||||||
|
SERVER_API_UNMOUNT_DEVICE,
|
||||||
|
SERVER_API_MOUNT,
|
||||||
|
SERVER_API_UNMOUNT
|
||||||
|
) = (
|
||||||
|
'/VolumeDriver.is_attached',
|
||||||
|
'/VolumeDriver.attach',
|
||||||
|
'/VolumeDriver.wait_for_attach',
|
||||||
|
'/VolumeDriver.mount_device',
|
||||||
|
'/VolumeDriver.detach',
|
||||||
|
'/VolumeDriver.wait_for_detach',
|
||||||
|
'/VolumeDriver.unmount_device',
|
||||||
|
'/VolumeDriver.mount',
|
||||||
|
'/VolumeDriver.unmount',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
CINDER_VOLUME_ATTR_KEY = (
|
||||||
|
CINDER_VOLUME_ATTR_VOLUME_ID,
|
||||||
|
) = (
|
||||||
|
'VolumeID',
|
||||||
|
)
|
||||||
|
|
|
@ -19,3 +19,9 @@ class InvalidVolumeDriverCmdParameter(FuxiKubernetesException):
|
||||||
def __init__(self, reason):
|
def __init__(self, reason):
|
||||||
super(InvalidVolumeDriverCmdParameter, self).__init__(
|
super(InvalidVolumeDriverCmdParameter, self).__init__(
|
||||||
"Invalid FlexVolume driver cmd parameter, reason:%s" % reason)
|
"Invalid FlexVolume driver cmd parameter, reason:%s" % reason)
|
||||||
|
|
||||||
|
|
||||||
|
class LoadVolumeDriverException(FuxiKubernetesException):
|
||||||
|
def __init__(self, reason):
|
||||||
|
super(LoadVolumeDriverException, self).__init__(
|
||||||
|
"Load volume driver failed, reason: %s" % reason)
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from oslo_serialization import jsonutils
|
from oslo_serialization import jsonutils
|
||||||
|
import requests
|
||||||
|
|
||||||
from fuxi_kubernetes.common import constants
|
from fuxi_kubernetes.common import constants
|
||||||
from fuxi_kubernetes import exceptions
|
from fuxi_kubernetes import exceptions
|
||||||
|
@ -35,6 +36,10 @@ class BaseVolumeDriver(object):
|
||||||
|
|
||||||
default_result = Result(status=constants.STATUS_NOT_SUPPORT)
|
default_result = Result(status=constants.STATUS_NOT_SUPPORT)
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._driver_server_port = ''
|
||||||
|
self._driver_name = ''
|
||||||
|
|
||||||
def init(self):
|
def init(self):
|
||||||
return Result(status=constants.STATUS_SUCCESS)
|
return Result(status=constants.STATUS_SUCCESS)
|
||||||
|
|
||||||
|
@ -68,14 +73,40 @@ class BaseVolumeDriver(object):
|
||||||
def unmount(self, mount_dir):
|
def unmount(self, mount_dir):
|
||||||
return self.default_result
|
return self.default_result
|
||||||
|
|
||||||
|
def _request_server(self, api, data):
|
||||||
|
def _send_and_receive():
|
||||||
|
try:
|
||||||
|
url = 'http://%(ip)s:%(port)d%(api)s' % {
|
||||||
|
'ip': constants.LOCAL_HOST,
|
||||||
|
'port': self._driver_server_port,
|
||||||
|
'api': api}
|
||||||
|
data['driver'] = self._driver_name
|
||||||
|
response = requests.post(url, json=data)
|
||||||
|
if not response.ok:
|
||||||
|
return False, response.text
|
||||||
|
|
||||||
|
return True, response.json()
|
||||||
|
|
||||||
|
except Exception as ex:
|
||||||
|
return (False,
|
||||||
|
'During request to server, '
|
||||||
|
'threw exception:(%s)' % str(ex))
|
||||||
|
|
||||||
|
ret, info = _send_and_receive()
|
||||||
|
if ret:
|
||||||
|
return Result(**info)
|
||||||
|
return Result(status=constants.STATUS_FAILURE, message=info)
|
||||||
|
|
||||||
def __call__(self, argv):
|
def __call__(self, argv):
|
||||||
if not argv:
|
if not argv or len(argv) < 2:
|
||||||
return self.default_result
|
return self.default_result
|
||||||
|
|
||||||
cmd = argv[0]
|
cmd = argv[1]
|
||||||
if cmd not in constants.VOLUME_DRIVER_CMD:
|
if cmd not in constants.VOLUME_DRIVER_CMD:
|
||||||
return self.default_result
|
return self.default_result
|
||||||
argv = argv[1:]
|
|
||||||
|
self._driver_server_port = int(argv[0])
|
||||||
|
argv = argv[2:]
|
||||||
|
|
||||||
cmd_info = self._get_cmd_info(cmd)
|
cmd_info = self._get_cmd_info(cmd)
|
||||||
if len(argv) != cmd_info['required_params_num']:
|
if len(argv) != cmd_info['required_params_num']:
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
from fuxi_kubernetes.common import constants
|
||||||
from fuxi_kubernetes.flex_volume_drivers.drivers import base
|
from fuxi_kubernetes.flex_volume_drivers.drivers import base
|
||||||
|
|
||||||
|
|
||||||
|
@ -17,4 +18,12 @@ class DriverCinder(base.BaseVolumeDriver):
|
||||||
# TODO(zengchen): implement it.
|
# TODO(zengchen): implement it.
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
raise NotImplemented()
|
super(DriverCinder, self).__init__()
|
||||||
|
self._driver_name = constants.VOLUME_DRIVER_CINDER
|
||||||
|
|
||||||
|
def is_attached(self, host_name, **kwargs):
|
||||||
|
return self._request_server(
|
||||||
|
constants.SERVER_API_IS_ATTACHED,
|
||||||
|
{'host_name': host_name,
|
||||||
|
'volume_id': kwargs.get(constants.CINDER_VOLUME_ATTR_VOLUME_ID)}
|
||||||
|
)
|
||||||
|
|
|
@ -43,7 +43,9 @@ if [ $# -lt 1 ]; then
|
||||||
usage
|
usage
|
||||||
fi
|
fi
|
||||||
|
|
||||||
out=$(fuxi-k8s-volume-driver-cinder "$@")
|
config_file=/etc/fuxi-kubernetes/fuxi_kubernetes.conf
|
||||||
|
port=$(grep driver_server_port $config_file | awk '{print $NF}')
|
||||||
|
out=$(fuxi-k8s-volume-driver-cinder $port "$@")
|
||||||
code=$?
|
code=$?
|
||||||
if [ $code -eq 0 ]; then
|
if [ $code -eq 0 ]; then
|
||||||
log "$out"
|
log "$out"
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
|
||||||
|
class ServerCinder(object):
|
||||||
|
# TODO(zengchen): implement all the interface of driver, such as
|
||||||
|
# is_attached, attach, detach, mount, unmount etc.
|
||||||
|
|
||||||
|
def __init__(self, host_platform):
|
||||||
|
self._cinder_client = None
|
||||||
|
self._host = None
|
||||||
|
|
||||||
|
def is_attached(self, volume_id, host_name, **kwargs):
|
||||||
|
return False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def is_support_host_platform(cls, host_platform):
|
||||||
|
return True
|
|
@ -12,4 +12,66 @@
|
||||||
|
|
||||||
"""Server of FlexVolume driver"""
|
"""Server of FlexVolume driver"""
|
||||||
|
|
||||||
# TODO(zengchen): implement it.
|
import flask
|
||||||
|
import functools
|
||||||
|
from oslo_log import log as logging
|
||||||
|
from stevedore import extension
|
||||||
|
|
||||||
|
from fuxi_kubernetes.common import config
|
||||||
|
from fuxi_kubernetes.common import constants
|
||||||
|
from fuxi_kubernetes import exceptions
|
||||||
|
from fuxi_kubernetes.flex_volume_drivers.drivers import base
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
APP = flask.Flask(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def start(host=None, port=None, debug=None, **options):
|
||||||
|
APP.run(host, port, debug, **options)
|
||||||
|
|
||||||
|
|
||||||
|
def init_volume_drivers():
|
||||||
|
mgr = extension.ExtensionManager(
|
||||||
|
namespace='flex_volume_drivers.server',
|
||||||
|
)
|
||||||
|
host_platform = config.CONF[
|
||||||
|
config.flexvolume_driver_group.name].host_platform
|
||||||
|
APP.volume_drivers = {
|
||||||
|
e.name: e.plugin(host_platform)
|
||||||
|
for e in mgr
|
||||||
|
if e.plugin.is_support_host_platform(host_platform)
|
||||||
|
}
|
||||||
|
|
||||||
|
if not APP.volume_drivers:
|
||||||
|
raise exceptions.LoadVolumeDriverException('No driver is loaded')
|
||||||
|
|
||||||
|
|
||||||
|
def api_wrapper(f):
|
||||||
|
def _response(ret, info):
|
||||||
|
if ret:
|
||||||
|
info['status'] = constants.STATUS_SUCCESS
|
||||||
|
else:
|
||||||
|
info = {'status': constants.STATUS_FAILURE, 'message': info}
|
||||||
|
return flask.jsonify(base.Result(**info)())
|
||||||
|
|
||||||
|
@functools.wraps(f)
|
||||||
|
def wrapper(*args, **kwargs):
|
||||||
|
data = flask.request.get_json(force=True)
|
||||||
|
driver = APP.volume_drivers.get(data.get('driver'))
|
||||||
|
if not driver:
|
||||||
|
return _response(
|
||||||
|
False, 'Unknow FlexVolume driver:%s' % data.get('driver'))
|
||||||
|
|
||||||
|
try:
|
||||||
|
return _response(True, f(driver, data))
|
||||||
|
except Exception as ex:
|
||||||
|
return _response(False, str(ex))
|
||||||
|
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
|
@APP.route(constants.SERVER_API_IS_ATTACHED, methods=['POST'])
|
||||||
|
@api_wrapper
|
||||||
|
def is_attached(driver=None, param=None):
|
||||||
|
return {'attached': driver.is_attached(**param)}
|
||||||
|
|
|
@ -15,6 +15,7 @@ __all__ = [
|
||||||
]
|
]
|
||||||
|
|
||||||
import itertools
|
import itertools
|
||||||
|
from oslo_log import _options
|
||||||
|
|
||||||
from fuxi_kubernetes.common import config
|
from fuxi_kubernetes.common import config
|
||||||
|
|
||||||
|
@ -22,6 +23,9 @@ from fuxi_kubernetes.common import config
|
||||||
def list_fuxi_k8s_opts():
|
def list_fuxi_k8s_opts():
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
('DEFAULT',
|
||||||
|
itertools.chain(_options.list_opts()[0][1],)),
|
||||||
|
|
||||||
(config.flexvolume_driver_group.name,
|
(config.flexvolume_driver_group.name,
|
||||||
itertools.chain(config.flexvolume_driver_opts,)),
|
itertools.chain(config.flexvolume_driver_opts,)),
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
# Copyright 2010-2011 OpenStack Foundation
|
|
||||||
# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
# 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
|
# not use this file except in compliance with the License. You may obtain
|
||||||
# a copy of the License at
|
# a copy of the License at
|
||||||
|
|
|
@ -30,6 +30,6 @@ class TestBaseVolumeDriver(base.TestCase):
|
||||||
self._driver(['abc']).status)
|
self._driver(['abc']).status)
|
||||||
|
|
||||||
def test_load_json_fail(self):
|
def test_load_json_fail(self):
|
||||||
r = self._driver(['attach', 'abc', 'abc'])
|
r = self._driver(['123', 'attach', 'abc', 'abc'])
|
||||||
self.assertEqual(constants.STATUS_FAILURE, r.status)
|
self.assertEqual(constants.STATUS_FAILURE, r.status)
|
||||||
self.assertIn('can not load json parameter', r.message)
|
self.assertIn('can not load json parameter', r.message)
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
# 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 pbr.version
|
||||||
|
|
||||||
|
version_info = pbr.version.VersionInfo('fuxi-kubernetes')
|
|
@ -4,3 +4,5 @@
|
||||||
|
|
||||||
pbr!=2.1.0,>=2.0.0 # Apache-2.0
|
pbr!=2.1.0,>=2.0.0 # Apache-2.0
|
||||||
oslo.serialization>=1.10.0 # Apache-2.0
|
oslo.serialization>=1.10.0 # Apache-2.0
|
||||||
|
stevedore>=1.20.0 # Apache-2.0
|
||||||
|
Flask!=0.11,<1.0,>=0.10 # BSD
|
||||||
|
|
|
@ -30,6 +30,9 @@ console_scripts =
|
||||||
fuxi-k8s-volume-driver-cinder = fuxi_kubernetes.cmd.cinder:main
|
fuxi-k8s-volume-driver-cinder = fuxi_kubernetes.cmd.cinder:main
|
||||||
fuxi-k8s-volume-driver-server = fuxi_kubernetes.cmd.driver_server:main
|
fuxi-k8s-volume-driver-server = fuxi_kubernetes.cmd.driver_server:main
|
||||||
|
|
||||||
|
flex_volume_drivers.server =
|
||||||
|
Cinder = fuxi_kubernetes.flex_volume_drivers.server.cinder.cinder:ServerCinder
|
||||||
|
|
||||||
[build_sphinx]
|
[build_sphinx]
|
||||||
source-dir = doc/source
|
source-dir = doc/source
|
||||||
build-dir = doc/build
|
build-dir = doc/build
|
||||||
|
|
2
setup.py
2
setup.py
|
@ -1,5 +1,3 @@
|
||||||
# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
# You may obtain a copy of the License at
|
# You may obtain a copy of the License at
|
||||||
|
|
Loading…
Reference in New Issue