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