]>
Commit | Line | Data |
---|---|---|
d2e6a577 FG |
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} | |
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 | # set all variables from args and load everything needed according to | |
140 | # them | |
141 | self.load_ceph_conf_path(cluster_name=args.cluster) | |
142 | conf.ceph = configuration.load(conf.path) | |
143 | # dispatch to sub-commands | |
144 | terminal.dispatch(self.mapper, subcommand_args) | |
145 | ||
146 | ||
147 | def _load_library_extensions(): | |
148 | """ | |
149 | Locate all setuptools entry points by the name 'ceph_volume_handlers' | |
150 | and initialize them. | |
151 | Any third-party library may register an entry point by adding the | |
152 | following to their setup.py:: | |
153 | ||
154 | entry_points = { | |
155 | 'ceph_volume_handlers': [ | |
156 | 'plugin_name = mylib.mymodule:Handler_Class', | |
157 | ], | |
158 | }, | |
159 | ||
160 | `plugin_name` will be used to load it as a sub command. | |
161 | """ | |
162 | logger = logging.getLogger('ceph_volume.plugins') | |
163 | group = 'ceph_volume_handlers' | |
164 | entry_points = pkg_resources.iter_entry_points(group=group) | |
165 | plugins = [] | |
166 | for ep in entry_points: | |
167 | try: | |
168 | logger.debug('loading %s' % ep.name) | |
169 | plugin = ep.load() | |
170 | plugin._ceph_volume_name_ = ep.name | |
171 | plugins.append(plugin) | |
172 | except Exception as error: | |
173 | logger.exception("Error initializing plugin %s: %s" % (ep, error)) | |
174 | return plugins |