From 42fcf4640ff11b0a4e8099c85268f239bdd643d1 Mon Sep 17 00:00:00 2001 From: zengchen Date: Wed, 7 Jun 2017 16:55:43 +0800 Subject: [PATCH] Implemet framework of flexvolume driver Change-Id: I95b1905811f2b640aadecd3ab5bd95f499831992 reference: https://review.openstack.org/#/c/474038/ --- fuxi_kubernetes/cmd/__init__.py | 0 fuxi_kubernetes/cmd/cinder.py | 31 ++++ fuxi_kubernetes/cmd/driver_server.py | 17 ++ fuxi_kubernetes/common/__init__.py | 0 fuxi_kubernetes/common/constants.py | 65 ++++++++ fuxi_kubernetes/exceptions.py | 21 +++ .../flex_volume_drivers/__init__.py | 0 .../flex_volume_drivers/drivers/__init__.py | 0 .../flex_volume_drivers/drivers/base.py | 153 ++++++++++++++++++ .../drivers/cinder/__init__.py | 0 .../drivers/cinder/cinder.py | 20 +++ .../drivers/cinder/cinder.sh | 53 ++++++ .../flex_volume_drivers/server/__init__.py | 0 .../flex_volume_drivers/server/controller.py | 15 ++ .../tests/unit/drivers/__init__.py | 0 .../unit/drivers/test_base_volume_driver.py | 35 ++++ requirements.txt | 1 + setup.cfg | 7 +- 18 files changed, 417 insertions(+), 1 deletion(-) create mode 100644 fuxi_kubernetes/cmd/__init__.py create mode 100644 fuxi_kubernetes/cmd/cinder.py create mode 100644 fuxi_kubernetes/cmd/driver_server.py create mode 100644 fuxi_kubernetes/common/__init__.py create mode 100644 fuxi_kubernetes/common/constants.py create mode 100644 fuxi_kubernetes/exceptions.py create mode 100644 fuxi_kubernetes/flex_volume_drivers/__init__.py create mode 100644 fuxi_kubernetes/flex_volume_drivers/drivers/__init__.py create mode 100644 fuxi_kubernetes/flex_volume_drivers/drivers/base.py create mode 100644 fuxi_kubernetes/flex_volume_drivers/drivers/cinder/__init__.py create mode 100644 fuxi_kubernetes/flex_volume_drivers/drivers/cinder/cinder.py create mode 100755 fuxi_kubernetes/flex_volume_drivers/drivers/cinder/cinder.sh create mode 100644 fuxi_kubernetes/flex_volume_drivers/server/__init__.py create mode 100644 fuxi_kubernetes/flex_volume_drivers/server/controller.py create mode 100644 fuxi_kubernetes/tests/unit/drivers/__init__.py create mode 100644 fuxi_kubernetes/tests/unit/drivers/test_base_volume_driver.py diff --git a/fuxi_kubernetes/cmd/__init__.py b/fuxi_kubernetes/cmd/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/fuxi_kubernetes/cmd/cinder.py b/fuxi_kubernetes/cmd/cinder.py new file mode 100644 index 0000000..74259fe --- /dev/null +++ b/fuxi_kubernetes/cmd/cinder.py @@ -0,0 +1,31 @@ +# 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. + +"""Start FlexVolume driver of Cinder""" + +from oslo_serialization import jsonutils +import sys + +from fuxi_kubernetes.common import constants +from fuxi_kubernetes.flex_volume_drivers.drivers.cinder import cinder + + +def main(): + """Entry of FlexVolume driver for Cinder + + /fuxi_kubernetes/flex_volume_drivers/driver/cinder/cinder.sh will + call this function, then read the output and send it to Kubernetes. + """ + + result = cinder.DriverCinder()(sys.argv[1:]) + print(jsonutils.dumps(result())) + sys.exit((0 if result.status == constants.STATUS_SUCCESS else 1)) diff --git a/fuxi_kubernetes/cmd/driver_server.py b/fuxi_kubernetes/cmd/driver_server.py new file mode 100644 index 0000000..369390e --- /dev/null +++ b/fuxi_kubernetes/cmd/driver_server.py @@ -0,0 +1,17 @@ +# 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. + +"""Start server of FlexVolume driver""" + + +def main(): + raise NotImplemented() diff --git a/fuxi_kubernetes/common/__init__.py b/fuxi_kubernetes/common/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/fuxi_kubernetes/common/constants.py b/fuxi_kubernetes/common/constants.py new file mode 100644 index 0000000..0ce52a6 --- /dev/null +++ b/fuxi_kubernetes/common/constants.py @@ -0,0 +1,65 @@ +# 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. + + +VOLUME_DRIVER_CMD = ( + CMD_INIT, + CMD_GET_VOLUME_NAME, + CMD_IS_ATTACHED, + CMD_ATTACH, + CMD_WAIT_FOR_ATTACH, + CMD_MOUNT_DEVICE, + CMD_DETACH, + CMD_WAIT_FOR_DETACH, + CMD_UNMOUNT_DEVICE, + CMD_MOUNT, + CMD_UNMOUNT +) = ( + "init", + "getvolumename", + "isattached", + "attach", + "waitforattach", + "mountdevice", + "detach", + "waitfordetach", + "unmountdevice", + "mount", + "unmount", +) + + +VOLUME_DRIVER_CMD_OPT_ARG = ( + ARG_FSTYPE, + ARG_RW, + ARG_SECRET, + ARG_FSGROUP, + ARG_MOUNTS_DIR +) = ( + "kubernetes.io/fsType", + "kubernetes.io/readwrite", + "kubernetes.io/secret", + "kubernetes.io/fsGroup", + "kubernetes.io/mountsDir", + +) + + +VOLUME_DRIVER_CMD_RESULT_STATUS = ( + STATUS_SUCCESS, + STATUS_FAILURE, + STATUS_NOT_SUPPORT +) = ( + 'Success', + 'Failed', + 'Not supported', +) diff --git a/fuxi_kubernetes/exceptions.py b/fuxi_kubernetes/exceptions.py new file mode 100644 index 0000000..78b8cfa --- /dev/null +++ b/fuxi_kubernetes/exceptions.py @@ -0,0 +1,21 @@ +# 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 FuxiKubernetesException(Exception): + """Default Fuxi-kubernetes exception""" + + +class InvalidVolumeDriverCmdParameter(FuxiKubernetesException): + def __init__(self, reason): + super(InvalidVolumeDriverCmdParameter, self).__init__( + "Invalid FlexVolume driver cmd parameter, reason:%s" % reason) diff --git a/fuxi_kubernetes/flex_volume_drivers/__init__.py b/fuxi_kubernetes/flex_volume_drivers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/fuxi_kubernetes/flex_volume_drivers/drivers/__init__.py b/fuxi_kubernetes/flex_volume_drivers/drivers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/fuxi_kubernetes/flex_volume_drivers/drivers/base.py b/fuxi_kubernetes/flex_volume_drivers/drivers/base.py new file mode 100644 index 0000000..b80b954 --- /dev/null +++ b/fuxi_kubernetes/flex_volume_drivers/drivers/base.py @@ -0,0 +1,153 @@ +# 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_serialization import jsonutils + +from fuxi_kubernetes.common import constants +from fuxi_kubernetes import exceptions + + +class Result(object): + __slots__ = ('status', 'message', 'device', 'volumeName', 'attached') + + def __init__(self, **kwargs): + for k, v in kwargs.items(): + if k in self.__slots__: + setattr(self, k, v) + + def __call__(self): + return { + k: getattr(self, k) + for k in self.__slots__ if hasattr(self, k) + } + + +class BaseVolumeDriver(object): + + default_result = Result(status=constants.STATUS_NOT_SUPPORT) + + def init(self): + return Result(status=constants.STATUS_SUCCESS) + + def get_volume_name(self, **kwargs): + return self.default_result + + def is_attached(self, host_name, **kwargs): + return self.default_result + + def attach(self, host_name, **kwargs): + return self.default_result + + def wait_for_attach(self, device_path, **kwargs): + return self.default_result + + def mount_device(self, device_mount_path, device_path, **kwargs): + return self.default_result + + def detach(self, device_path, host_name): + return self.default_result + + def wait_for_detach(self, device_path): + return self.default_result + + def unmount_device(self, device_mount_path): + return self.default_result + + def mount(self, mount_dir, **kwargs): + return self.default_result + + def unmount(self, mount_dir): + return self.default_result + + def __call__(self, argv): + if not argv: + return self.default_result + + cmd = argv[0] + if cmd not in constants.VOLUME_DRIVER_CMD: + return self.default_result + argv = argv[1:] + + cmd_info = self._get_cmd_info(cmd) + if len(argv) != cmd_info['required_params_num']: + return Result( + status=constants.STATUS_FAILURE, + message='Miss parameters, require %d parameters, ' + 'but receive %d' % (cmd_info['required_params_num'], + len(argv))) + try: + return cmd_info['func'](argv) + except Exception as ex: + return Result(status=constants.STATUS_FAILURE, + message=str(ex)) + + def _get_cmd_info(self, cmd): + + def _load_json_param(data): + try: + return jsonutils.loads(data) + except Exception: + raise exceptions.InvalidVolumeDriverCmdParameter( + "can not load json parameter:(%s)" % data) + + return { + constants.CMD_INIT: { + 'required_params_num': 0, + 'func': lambda argv: self.init() + }, + constants.CMD_GET_VOLUME_NAME: { + 'required_params_num': 1, + 'func': lambda argv: self.get_volume_name( + **(_load_json_param(argv[0]))) + }, + constants.CMD_IS_ATTACHED: { + 'required_params_num': 2, + 'func': lambda argv: self.is_attached( + argv[1], **(_load_json_param(argv[0]))) + }, + constants.CMD_ATTACH: { + 'required_params_num': 2, + 'func': lambda argv: self.attach( + argv[1], **(_load_json_param(argv[0]))) + }, + constants.CMD_WAIT_FOR_ATTACH: { + 'required_params_num': 2, + 'func': lambda argv: self.wait_for_attach( + argv[0], **(_load_json_param(argv[1]))) + }, + constants.CMD_MOUNT_DEVICE: { + 'required_params_num': 3, + 'func': lambda argv: self.mount_device( + argv[0], argv[1], **(_load_json_param(argv[2]))) + }, + constants.CMD_DETACH: { + 'required_params_num': 2, + 'func': lambda argv: self.detach(*argv) + }, + constants.CMD_WAIT_FOR_DETACH: { + 'required_params_num': 1, + 'func': lambda argv: self.wait_for_detach(*argv) + }, + constants.CMD_UNMOUNT_DEVICE: { + 'required_params_num': 1, + 'func': lambda argv: self.unmount_device(*argv) + }, + constants.CMD_MOUNT: { + 'required_params_num': 2, + 'func': lambda argv: self.mount( + argv[0], **(_load_json_param(argv[1]))) + }, + constants.CMD_UNMOUNT: { + 'required_params_num': 1, + 'func': lambda argv: self.unmount(*argv) + }, + }.get(cmd) diff --git a/fuxi_kubernetes/flex_volume_drivers/drivers/cinder/__init__.py b/fuxi_kubernetes/flex_volume_drivers/drivers/cinder/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/fuxi_kubernetes/flex_volume_drivers/drivers/cinder/cinder.py b/fuxi_kubernetes/flex_volume_drivers/drivers/cinder/cinder.py new file mode 100644 index 0000000..dbc19ab --- /dev/null +++ b/fuxi_kubernetes/flex_volume_drivers/drivers/cinder/cinder.py @@ -0,0 +1,20 @@ +# 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 fuxi_kubernetes.flex_volume_drivers.drivers import base + + +class DriverCinder(base.BaseVolumeDriver): + # TODO(zengchen): implement it. + + def __init__(self): + raise NotImplemented() diff --git a/fuxi_kubernetes/flex_volume_drivers/drivers/cinder/cinder.sh b/fuxi_kubernetes/flex_volume_drivers/drivers/cinder/cinder.sh new file mode 100755 index 0000000..96b6ab7 --- /dev/null +++ b/fuxi_kubernetes/flex_volume_drivers/drivers/cinder/cinder.sh @@ -0,0 +1,53 @@ +#!/bin/sh +# 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. + + +err() { + echo -ne "$@" 1>&2 +} + + +log() { + echo -ne "$@" >&1 +} + + +usage() { + err "Invalid usage. Usage: " + err "\t$0 init" + err "\t$0 getvolumename " + err "\t$0 isattached " + err "\t$0 attach " + err "\t$0 waitforattach " + err "\t$0 mountdevice " + err "\t$0 detach " + err "\t$0 waitfordetach " + err "\t$0 unmountdevice " + err "\t$0 mount " + err "\t$0 unmount " + exit 1 +} + + +if [ $# -lt 1 ]; then + usage +fi + +out=$(fuxi-k8s-volume-driver-cinder "$@") +code=$? +if [ $code -eq 0 ]; then + log "$out" +else + err "$out" +fi +exit $code diff --git a/fuxi_kubernetes/flex_volume_drivers/server/__init__.py b/fuxi_kubernetes/flex_volume_drivers/server/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/fuxi_kubernetes/flex_volume_drivers/server/controller.py b/fuxi_kubernetes/flex_volume_drivers/server/controller.py new file mode 100644 index 0000000..ec42b5f --- /dev/null +++ b/fuxi_kubernetes/flex_volume_drivers/server/controller.py @@ -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. + +"""Server of FlexVolume driver""" + +# TODO(zengchen): implement it. diff --git a/fuxi_kubernetes/tests/unit/drivers/__init__.py b/fuxi_kubernetes/tests/unit/drivers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/fuxi_kubernetes/tests/unit/drivers/test_base_volume_driver.py b/fuxi_kubernetes/tests/unit/drivers/test_base_volume_driver.py new file mode 100644 index 0000000..721d001 --- /dev/null +++ b/fuxi_kubernetes/tests/unit/drivers/test_base_volume_driver.py @@ -0,0 +1,35 @@ +# 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 fuxi_kubernetes.common import constants +from fuxi_kubernetes.flex_volume_drivers.drivers import base as base_driver +from fuxi_kubernetes.tests.unit import base + + +class TestBaseVolumeDriver(base.TestCase): + + def setUp(self): + super(TestBaseVolumeDriver, self).setUp() + self._driver = base_driver.BaseVolumeDriver() + + def test_empty_argument(self): + self.assertEqual(constants.STATUS_NOT_SUPPORT, + self._driver([]).status) + + def test_invalid_cmd(self): + self.assertEqual(constants.STATUS_NOT_SUPPORT, + self._driver(['abc']).status) + + def test_load_json_fail(self): + r = self._driver(['attach', 'abc', 'abc']) + self.assertEqual(constants.STATUS_FAILURE, r.status) + self.assertIn('can not load json parameter', r.message) diff --git a/requirements.txt b/requirements.txt index 6de9f4e..7f4089a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,3 +3,4 @@ # process, which may cause wedges in the gate later. pbr!=2.1.0,>=2.0.0 # Apache-2.0 +oslo.serialization>=1.10.0 # Apache-2.0 diff --git a/setup.cfg b/setup.cfg index b435e20..6f360a2 100644 --- a/setup.cfg +++ b/setup.cfg @@ -20,7 +20,12 @@ classifier = [files] packages = - fuxi-kubernetes + fuxi_kubernetes + +[entry_points] +console_scripts = + fuxi-k8s-volume-driver-cinder = fuxi_kubernetes.cmd.cinder:main + fuxi-k8s-volume-driver-server = fuxi_kubernetes.cmd.driver_server:main [build_sphinx] source-dir = doc/source