]> git.proxmox.com Git - ceph.git/blob - ceph/src/ceph-volume/ceph_volume/main.py
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / ceph-volume / ceph_volume / main.py
1 from __future__ import print_function
2 import argparse
3 import os
4 import pkg_resources
5 import sys
6 import logging
7
8 from ceph_volume.decorators import catches
9 from ceph_volume import log, devices, configuration, conf, exceptions, terminal, inventory
10
11
12 class Volume(object):
13 _help = """
14 ceph-volume: Deploy Ceph OSDs using different device technologies like lvm or
15 physical disks.
16
17 Log Path: {log_path}
18 Ceph Conf: {ceph_path}
19
20 {sub_help}
21 {plugins}
22 {environ_vars}
23 {warning}
24 """
25
26 def __init__(self, argv=None, parse=True):
27 self.mapper = {
28 'lvm': devices.lvm.LVM,
29 'simple': devices.simple.Simple,
30 'raw': devices.raw.Raw,
31 'inventory': inventory.Inventory,
32 }
33 self.plugin_help = "No plugins found/loaded"
34 if argv is None:
35 self.argv = sys.argv
36 else:
37 self.argv = argv
38 if parse:
39 self.main(self.argv)
40
41 def help(self, warning=False):
42 warning = 'See "ceph-volume --help" for full list of options.' if warning else ''
43 return self._help.format(
44 warning=warning,
45 log_path=conf.log_path,
46 ceph_path=self.stat_ceph_conf(),
47 plugins=self.plugin_help,
48 sub_help=terminal.subhelp(self.mapper),
49 environ_vars=self.get_environ_vars()
50 )
51
52 def get_environ_vars(self):
53 environ_vars = []
54 for key, value in os.environ.items():
55 if key.startswith('CEPH_'):
56 environ_vars.append("%s=%s" % (key, value))
57 if not environ_vars:
58 return ''
59 else:
60 environ_vars.insert(0, '\nEnviron Variables:')
61 return '\n'.join(environ_vars)
62
63 def enable_plugins(self):
64 """
65 Load all plugins available, add them to the mapper and extend the help
66 string with the information from each one
67 """
68 plugins = _load_library_extensions()
69 for plugin in plugins:
70 self.mapper[plugin._ceph_volume_name_] = plugin
71 self.plugin_help = '\n'.join(['%-19s %s\n' % (
72 plugin.name, getattr(plugin, 'help_menu', ''))
73 for plugin in plugins])
74 if self.plugin_help:
75 self.plugin_help = '\nPlugins:\n' + self.plugin_help
76
77 def load_log_path(self):
78 conf.log_path = os.getenv('CEPH_VOLUME_LOG_PATH', '/var/log/ceph')
79
80 def stat_ceph_conf(self):
81 try:
82 configuration.load(conf.path)
83 return terminal.green(conf.path)
84 except exceptions.ConfigurationError as error:
85 return terminal.red(error)
86
87 def _get_split_args(self):
88 subcommands = self.mapper.keys()
89 slice_on_index = len(self.argv) + 1
90 pruned_args = self.argv[1:]
91 for count, arg in enumerate(pruned_args):
92 if arg in subcommands:
93 slice_on_index = count
94 break
95 return pruned_args[:slice_on_index], pruned_args[slice_on_index:]
96
97 @catches()
98 def main(self, argv):
99 # these need to be available for the help, which gets parsed super
100 # early
101 configuration.load_ceph_conf_path()
102 self.load_log_path()
103 self.enable_plugins()
104 main_args, subcommand_args = self._get_split_args()
105 # no flags where passed in, return the help menu instead of waiting for
106 # argparse which will end up complaning that there are no args
107 if len(argv) <= 1:
108 print(self.help(warning=True))
109 raise SystemExit(0)
110 parser = argparse.ArgumentParser(
111 prog='ceph-volume',
112 formatter_class=argparse.RawDescriptionHelpFormatter,
113 description=self.help(),
114 )
115 parser.add_argument(
116 '--cluster',
117 default='ceph',
118 help='Cluster name (defaults to "ceph")',
119 )
120 parser.add_argument(
121 '--log-level',
122 default='debug',
123 help='Change the file log level (defaults to debug)',
124 )
125 parser.add_argument(
126 '--log-path',
127 default='/var/log/ceph/',
128 help='Change the log path (defaults to /var/log/ceph)',
129 )
130 args = parser.parse_args(main_args)
131 conf.log_path = args.log_path
132 if os.path.isdir(conf.log_path):
133 conf.log_path = os.path.join(args.log_path, 'ceph-volume.log')
134 log.setup()
135 log.setup_console()
136 logger = logging.getLogger(__name__)
137 logger.info("Running command: ceph-volume %s %s", " ".join(main_args), " ".join(subcommand_args))
138 # set all variables from args and load everything needed according to
139 # them
140 configuration.load_ceph_conf_path(cluster_name=args.cluster)
141 try:
142 conf.ceph = configuration.load(conf.path)
143 except exceptions.ConfigurationError as error:
144 # we warn only here, because it is possible that the configuration
145 # file is not needed, or that it will be loaded by some other means
146 # (like reading from lvm tags)
147 logger.exception('ignoring inability to load ceph.conf')
148 terminal.red(error)
149 # dispatch to sub-commands
150 terminal.dispatch(self.mapper, subcommand_args)
151
152
153 def _load_library_extensions():
154 """
155 Locate all setuptools entry points by the name 'ceph_volume_handlers'
156 and initialize them.
157 Any third-party library may register an entry point by adding the
158 following to their setup.py::
159
160 entry_points = {
161 'ceph_volume_handlers': [
162 'plugin_name = mylib.mymodule:Handler_Class',
163 ],
164 },
165
166 `plugin_name` will be used to load it as a sub command.
167 """
168 logger = logging.getLogger('ceph_volume.plugins')
169 group = 'ceph_volume_handlers'
170 entry_points = pkg_resources.iter_entry_points(group=group)
171 plugins = []
172 for ep in entry_points:
173 try:
174 logger.debug('loading %s' % ep.name)
175 plugin = ep.load()
176 plugin._ceph_volume_name_ = ep.name
177 plugins.append(plugin)
178 except Exception as error:
179 logger.exception("Error initializing plugin %s: %s" % (ep, error))
180 return plugins