initial code repo
[stor4nfv.git] / src / ceph / src / ceph-volume / ceph_volume / main.py
diff --git a/src/ceph/src/ceph-volume/ceph_volume/main.py b/src/ceph/src/ceph-volume/ceph_volume/main.py
new file mode 100644 (file)
index 0000000..70cb6be
--- /dev/null
@@ -0,0 +1,182 @@
+from __future__ import print_function
+import argparse
+import os
+import pkg_resources
+import sys
+import logging
+
+import ceph_volume
+from ceph_volume.decorators import catches
+from ceph_volume import log, devices, configuration, conf, exceptions, terminal
+
+
+class Volume(object):
+    _help = """
+ceph-volume: Deploy Ceph OSDs using different device technologies like lvm or
+physical disks.
+
+Version: {version}
+
+Log Path: {log_path}
+Ceph Conf: {ceph_path}
+
+{sub_help}
+{plugins}
+{environ_vars}
+{warning}
+    """
+
+    def __init__(self, argv=None, parse=True):
+        self.mapper = {'lvm': devices.lvm.LVM, 'simple': devices.simple.Simple}
+        self.plugin_help = "No plugins found/loaded"
+        if argv is None:
+            self.argv = sys.argv
+        else:
+            self.argv = argv
+        if parse:
+            self.main(self.argv)
+
+    def help(self, warning=False):
+        warning = 'See "ceph-volume --help" for full list of options.' if warning else ''
+        return self._help.format(
+            warning=warning,
+            version=ceph_volume.__version__,
+            log_path=conf.log_path,
+            ceph_path=self.stat_ceph_conf(),
+            plugins=self.plugin_help,
+            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 enable_plugins(self):
+        """
+        Load all plugins available, add them to the mapper and extend the help
+        string with the information from each one
+        """
+        plugins = _load_library_extensions()
+        for plugin in plugins:
+            self.mapper[plugin._ceph_volume_name_] = plugin
+        self.plugin_help = '\n'.join(['%-19s %s\n' % (
+            plugin.name, getattr(plugin, 'help_menu', ''))
+            for plugin in plugins])
+        if self.plugin_help:
+            self.plugin_help = '\nPlugins:\n' + self.plugin_help
+
+    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 load_log_path(self):
+        conf.log_path = os.getenv('CEPH_VOLUME_LOG_PATH', '/var/log/ceph')
+
+    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 _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:]
+
+    @catches()
+    def main(self, argv):
+        # these need to be available for the help, which gets parsed super
+        # early
+        self.load_ceph_conf_path()
+        self.load_log_path()
+        self.enable_plugins()
+        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',
+            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.log')
+        log.setup()
+        logger = logging.getLogger(__name__)
+        # 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 lvm tags)
+            logger.exception('ignoring inability to load ceph.conf')
+            terminal.red(error)
+        # dispatch to sub-commands
+        terminal.dispatch(self.mapper, subcommand_args)
+
+
+def _load_library_extensions():
+    """
+    Locate all setuptools entry points by the name 'ceph_volume_handlers'
+    and initialize them.
+    Any third-party library may register an entry point by adding the
+    following to their setup.py::
+
+        entry_points = {
+            'ceph_volume_handlers': [
+                'plugin_name = mylib.mymodule:Handler_Class',
+            ],
+        },
+
+    `plugin_name` will be used to load it as a sub command.
+    """
+    logger = logging.getLogger('ceph_volume.plugins')
+    group = 'ceph_volume_handlers'
+    entry_points = pkg_resources.iter_entry_points(group=group)
+    plugins = []
+    for ep in entry_points:
+        try:
+            logger.debug('loading %s' % ep.name)
+            plugin = ep.load()
+            plugin._ceph_volume_name_ = ep.name
+            plugins.append(plugin)
+        except Exception as error:
+            logger.exception("Error initializing plugin %s: %s" % (ep, error))
+    return plugins