From d37d8e2b104a2be4e11bdc1db9851a3150547d1d Mon Sep 17 00:00:00 2001 From: Willem Jan Withagen Date: Tue, 21 Aug 2018 20:56:21 +0200 Subject: [PATCH] ceph-volume: zfs, the inital first submit. Does nothing other than invoce the ceph-volume-zfs modules when called with 'ceph-volume zfs Like: > ceph-volume zfs list Use ZFS as the underlying technology for OSDs --verbose Increase the verbosity level ['list'] --> TypeError: main() takes exactly 2 arguments (1 given) Exit 1 Signed-off-by: Willem Jan Withagen --- COPYING | 4 + src/ceph-volume/CMakeLists.txt | 5 + src/ceph-volume/plugin/zfs/CMakeLists.txt | 3 + src/ceph-volume/plugin/zfs/LICENSE | 32 ++++ src/ceph-volume/plugin/zfs/MANIFEST.in | 7 + .../plugin/zfs/ceph_volume_zfs/__init__.py | 6 + .../zfs/ceph_volume_zfs/api/__init__.py | 3 + .../zfs/ceph_volume_zfs/devices/__init__.py | 2 + .../ceph_volume_zfs/devices/zfs/__init__.py | 2 + .../zfs/ceph_volume_zfs/devices/zfs/main.py | 34 +++++ .../plugin/zfs/ceph_volume_zfs/main.py | 139 ++++++++++++++++++ .../zfs/ceph_volume_zfs/util/__init__.py | 1 + .../plugin/zfs/requirements_dev.txt | 5 + src/ceph-volume/plugin/zfs/setup.py | 47 ++++++ src/ceph-volume/plugin/zfs/tox.ini | 21 +++ 15 files changed, 311 insertions(+) create mode 100644 src/ceph-volume/plugin/zfs/CMakeLists.txt create mode 100644 src/ceph-volume/plugin/zfs/LICENSE create mode 100644 src/ceph-volume/plugin/zfs/MANIFEST.in create mode 100755 src/ceph-volume/plugin/zfs/ceph_volume_zfs/__init__.py create mode 100644 src/ceph-volume/plugin/zfs/ceph_volume_zfs/api/__init__.py create mode 100755 src/ceph-volume/plugin/zfs/ceph_volume_zfs/devices/__init__.py create mode 100755 src/ceph-volume/plugin/zfs/ceph_volume_zfs/devices/zfs/__init__.py create mode 100755 src/ceph-volume/plugin/zfs/ceph_volume_zfs/devices/zfs/main.py create mode 100755 src/ceph-volume/plugin/zfs/ceph_volume_zfs/main.py create mode 100644 src/ceph-volume/plugin/zfs/ceph_volume_zfs/util/__init__.py create mode 100644 src/ceph-volume/plugin/zfs/requirements_dev.txt create mode 100644 src/ceph-volume/plugin/zfs/setup.py create mode 100644 src/ceph-volume/plugin/zfs/tox.ini diff --git a/COPYING b/COPYING index d8afa9d28ef..22acddf0e0d 100644 --- a/COPYING +++ b/COPYING @@ -150,3 +150,7 @@ Files: src/pybind/mgr/diskprediction/predictor/models/* Copyright: None License: Public domain +Files: src/ceph-volume/plugin/zfs/* +Copyright: 2018, Willem Jan Withagen +License: BSD 3-clause + diff --git a/src/ceph-volume/CMakeLists.txt b/src/ceph-volume/CMakeLists.txt index 20841ff2e77..d49a9bfca34 100644 --- a/src/ceph-volume/CMakeLists.txt +++ b/src/ceph-volume/CMakeLists.txt @@ -2,3 +2,8 @@ include(Distutils) distutils_install_module(ceph_volume INSTALL_SCRIPT ${CMAKE_INSTALL_FULL_SBINDIR}) + +if(FREEBSD) + add_subdirectory(plugin/zfs) +endif() + diff --git a/src/ceph-volume/plugin/zfs/CMakeLists.txt b/src/ceph-volume/plugin/zfs/CMakeLists.txt new file mode 100644 index 00000000000..da10f46fd09 --- /dev/null +++ b/src/ceph-volume/plugin/zfs/CMakeLists.txt @@ -0,0 +1,3 @@ + +distutils_install_module(ceph_volume_zfs + INSTALL_SCRIPT ${CMAKE_INSTALL_FULL_SBINDIR}) diff --git a/src/ceph-volume/plugin/zfs/LICENSE b/src/ceph-volume/plugin/zfs/LICENSE new file mode 100644 index 00000000000..92cc048b8aa --- /dev/null +++ b/src/ceph-volume/plugin/zfs/LICENSE @@ -0,0 +1,32 @@ + + +BSD License + +Copyright (c) 2018, Willem Jan Withagen +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +OF THE POSSIBILITY OF SUCH DAMAGE. + diff --git a/src/ceph-volume/plugin/zfs/MANIFEST.in b/src/ceph-volume/plugin/zfs/MANIFEST.in new file mode 100644 index 00000000000..ed96496e6eb --- /dev/null +++ b/src/ceph-volume/plugin/zfs/MANIFEST.in @@ -0,0 +1,7 @@ +include LICENSE + +recursive-include ceph_volume_zfs * +recursive-exclude * __pycache__ +recursive-exclude * *.py[co] + +recursive-include *.rst conf.py Makefile *.jpg *.png *.gif diff --git a/src/ceph-volume/plugin/zfs/ceph_volume_zfs/__init__.py b/src/ceph-volume/plugin/zfs/ceph_volume_zfs/__init__.py new file mode 100755 index 00000000000..d81455b15c1 --- /dev/null +++ b/src/ceph-volume/plugin/zfs/ceph_volume_zfs/__init__.py @@ -0,0 +1,6 @@ +# -*- coding: utf-8 -*- + +"""Top-level package for Ceph volume on ZFS.""" + +__author__ = """Willem Jan Withagen""" +__email__ = 'wjw@digiware.nl' diff --git a/src/ceph-volume/plugin/zfs/ceph_volume_zfs/api/__init__.py b/src/ceph-volume/plugin/zfs/ceph_volume_zfs/api/__init__.py new file mode 100644 index 00000000000..ecc97129918 --- /dev/null +++ b/src/ceph-volume/plugin/zfs/ceph_volume_zfs/api/__init__.py @@ -0,0 +1,3 @@ +""" +Device API that can be shared among other implementations. +""" diff --git a/src/ceph-volume/plugin/zfs/ceph_volume_zfs/devices/__init__.py b/src/ceph-volume/plugin/zfs/ceph_volume_zfs/devices/__init__.py new file mode 100755 index 00000000000..c1a8fe6562b --- /dev/null +++ b/src/ceph-volume/plugin/zfs/ceph_volume_zfs/devices/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- +from . import zfs diff --git a/src/ceph-volume/plugin/zfs/ceph_volume_zfs/devices/zfs/__init__.py b/src/ceph-volume/plugin/zfs/ceph_volume_zfs/devices/zfs/__init__.py new file mode 100755 index 00000000000..bad522f9a76 --- /dev/null +++ b/src/ceph-volume/plugin/zfs/ceph_volume_zfs/devices/zfs/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- +from .main import ZFS diff --git a/src/ceph-volume/plugin/zfs/ceph_volume_zfs/devices/zfs/main.py b/src/ceph-volume/plugin/zfs/ceph_volume_zfs/devices/zfs/main.py new file mode 100755 index 00000000000..028d4876eda --- /dev/null +++ b/src/ceph-volume/plugin/zfs/ceph_volume_zfs/devices/zfs/main.py @@ -0,0 +1,34 @@ +import argparse +from textwrap import dedent +from ceph_volume import terminal + + +class ZFS(object): + + help = 'Use ZFS to deploy OSDs' + + _help = dedent(""" + Use ZFS to deploy OSDs + + {sub_help} + """) + + mapper = { + } + + def __init__(self, argv): + self.argv = argv + + def print_help(self, sub_help): + return self._help.format(sub_help=sub_help) + + def main(self): + terminal.dispatch(self.mapper, self.argv) + parser = argparse.ArgumentParser( + prog='ceph-volume zfs', + formatter_class=argparse.RawDescriptionHelpFormatter, + description=self.print_help(terminal.subhelp(self.mapper)), + ) + parser.parse_args(self.argv) + if len(self.argv) <= 1: + return parser.print_help() diff --git a/src/ceph-volume/plugin/zfs/ceph_volume_zfs/main.py b/src/ceph-volume/plugin/zfs/ceph_volume_zfs/main.py new file mode 100755 index 00000000000..b4bcd48ece8 --- /dev/null +++ b/src/ceph-volume/plugin/zfs/ceph_volume_zfs/main.py @@ -0,0 +1,139 @@ +# -*- coding: utf-8 -*- + +from __future__ import print_function +import argparse +import os +import sys +import logging + +import main +from ceph_volume import log, conf, configuration +from ceph_volume import exceptions +from ceph_volume import terminal + +if __name__ == '__main__': + main.ZFSVOL() + + +class ZFSVOL(object): + + help_menu = 'Deploy OSDs with ZFS' + _help = """ +Use ZFS as the underlying technology for OSDs + +--verbose Increase the verbosity level + """ + name = 'zfs' + + def __init__(self, argv=None, parse=True): + self.mapper = { + } + if argv is None: + self.argv = sys.argv + else: + self.argv = argv + if parse: + self.main(self.argv) + + def help(self, warning=False): + if warning: + warning = 'See "ceph-volume zfs --help" for full list of options.' + else: + warning = '' + return self._help.format( + warning=warning, + log_path=conf.log_path, + ceph_path=self.stat_ceph_conf(), + sub_help=terminal.subhelp(self.mapper), + environ_vars=self.get_environ_vars() + ) + + def get_environ_vars(self): + environ_vars = [] + for key, value in os.environ.items(): + if key.startswith('CEPH_'): + environ_vars.append("%s=%s" % (key, value)) + if not environ_vars: + return '' + else: + environ_vars.insert(0, '\nEnviron Variables:') + return '\n'.join(environ_vars) + + def load_ceph_conf_path(self, cluster_name='ceph'): + abspath = '/etc/ceph/%s.conf' % cluster_name + conf.path = os.getenv('CEPH_CONF', abspath) + conf.cluster = cluster_name + + def stat_ceph_conf(self): + try: + configuration.load(conf.path) + return terminal.green(conf.path) + except exceptions.ConfigurationError as error: + return terminal.red(error) + + def load_log_path(self): + conf.log_path = os.getenv('CEPH_VOLUME_LOG_PATH', '/var/log/ceph') + + def _get_split_args(self): + subcommands = self.mapper.keys() + slice_on_index = len(self.argv) + 1 + pruned_args = self.argv[1:] + for count, arg in enumerate(pruned_args): + if arg in subcommands: + slice_on_index = count + break + return pruned_args[:slice_on_index], pruned_args[slice_on_index:] + + def main(self, argv): + self.load_ceph_conf_path() + # these need to be available for the help, which gets parsed super + # early + self.load_ceph_conf_path() + self.load_log_path() + main_args, subcommand_args = self._get_split_args() + # no flags where passed in, return the help menu instead of waiting for + # argparse which will end up complaning that there are no args + if len(argv) <= 1: + print(self.help(warning=True)) + return + parser = argparse.ArgumentParser( + prog='ceph-volume-zfs', + formatter_class=argparse.RawDescriptionHelpFormatter, + description=self.help(), + ) + parser.add_argument( + '--cluster', + default='ceph', + help='Cluster name (defaults to "ceph")', + ) + parser.add_argument( + '--log-level', + default='debug', + help='Change the file log level (defaults to debug)', + ) + parser.add_argument( + '--log-path', + default='/var/log/ceph/', + help='Change the log path (defaults to /var/log/ceph)', + ) + args = parser.parse_args(main_args) + conf.log_path = args.log_path + if os.path.isdir(conf.log_path): + conf.log_path = os.path.join(args.log_path, 'ceph-volume-zfs.log') + log.setup() + logger = logging.getLogger(__name__) + logger.info("Running command: ceph-volume-zfs %s %s", + " ".join(main_args), " ".join(subcommand_args)) + # set all variables from args and load everything needed according to + # them + self.load_ceph_conf_path(cluster_name=args.cluster) + try: + conf.ceph = configuration.load(conf.path) + except exceptions.ConfigurationError as error: + # we warn only here, because it is possible that the configuration + # file is not needed, or that it will be loaded by some other means + # (like reading from zfs tags) + logger.exception('ignoring inability to load ceph.conf') + terminal.red(error) + # dispatch to sub-commands + terminal.dispatch(self.mapper, subcommand_args) diff --git a/src/ceph-volume/plugin/zfs/ceph_volume_zfs/util/__init__.py b/src/ceph-volume/plugin/zfs/ceph_volume_zfs/util/__init__.py new file mode 100644 index 00000000000..40a96afc6ff --- /dev/null +++ b/src/ceph-volume/plugin/zfs/ceph_volume_zfs/util/__init__.py @@ -0,0 +1 @@ +# -*- coding: utf-8 -*- diff --git a/src/ceph-volume/plugin/zfs/requirements_dev.txt b/src/ceph-volume/plugin/zfs/requirements_dev.txt new file mode 100644 index 00000000000..7263a68fa79 --- /dev/null +++ b/src/ceph-volume/plugin/zfs/requirements_dev.txt @@ -0,0 +1,5 @@ +pip==9.0.1 +wheel==0.30.0 +flake8==3.5.0 +tox==2.9.1 +coverage==4.5.1 diff --git a/src/ceph-volume/plugin/zfs/setup.py b/src/ceph-volume/plugin/zfs/setup.py new file mode 100644 index 00000000000..fe2e3e27a5f --- /dev/null +++ b/src/ceph-volume/plugin/zfs/setup.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +"""The setup script.""" + +from setuptools import setup, find_packages + +requirements = [ ] + +setup_requirements = [ ] + +setup( + author="Willem Jan Withagen", + author_email='wjw@digiware.nl', + classifiers=[ + 'Development Status :: 2 - Pre-Alpha', + 'Environment :: Console', + 'Intended Audience :: Information Technology', + 'Intended Audience :: System Administrators', + 'Operating System :: POSIX :: FreeBSD', + 'License :: OSI Approved :: BSD License', + 'Natural Language :: English', + "Programming Language :: Python :: 2", + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + ], + description="Manage Ceph OSDs on ZFS pool/volume/filesystem", + install_requires=requirements, + license="BSD license", + include_package_data=True, + keywords='ceph-volume-zfs', + name='ceph-volume-zfs', + packages=find_packages(include=['ceph_volume_zfs']), + scripts=['bin/ceph-volume-zfs'], + setup_requires=setup_requirements, + url='https://github.com/ceph/ceph/src/ceph-volume/plugin/zfs', + version='0.1.0', + zip_safe=False, + entry_points = dict( + ceph_volume_handlers = [ + 'zfs = ceph_volume_zfs.main:ZFSVOL', + ], + ), +) diff --git a/src/ceph-volume/plugin/zfs/tox.ini b/src/ceph-volume/plugin/zfs/tox.ini new file mode 100644 index 00000000000..80e35439f8d --- /dev/null +++ b/src/ceph-volume/plugin/zfs/tox.ini @@ -0,0 +1,21 @@ +[tox] +envlist = py27, py34, py35, py36, flake8 + +[travis] +python = + 3.6: py36 + 3.5: py35 + 3.4: py34 + 2.7: py27 + +[testenv:flake8] +basepython = python +deps = flake8 +commands = flake8 + +[testenv] +setenv = + PYTHONPATH = {toxinidir} + +commands = python setup.py test + -- 2.39.5