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