]>
Commit | Line | Data |
---|---|---|
d2e6a577 FG |
1 | from __future__ import print_function |
2 | import json | |
3 | import os | |
4 | from textwrap import dedent | |
5 | from ceph_volume.util import prepare as prepare_utils | |
6 | from ceph_volume.util import system | |
7 | from ceph_volume import conf, decorators | |
8 | from . import api | |
9 | from .common import prepare_parser | |
10 | ||
11 | ||
d2e6a577 FG |
12 | def prepare_filestore(device, journal, secrets, id_=None, fsid=None): |
13 | """ | |
14 | :param device: The name of the volume group or lvm to work with | |
15 | :param journal: similar to device but can also be a regular/plain disk | |
16 | :param secrets: A dict with the secrets needed to create the osd (e.g. cephx) | |
17 | :param id_: The OSD id | |
18 | :param fsid: The OSD fsid, also known as the OSD UUID | |
19 | """ | |
20 | cephx_secret = secrets.get('cephx_secret', prepare_utils.create_key()) | |
21 | json_secrets = json.dumps(secrets) | |
22 | ||
23 | # allow re-using an existing fsid, in case prepare failed | |
24 | fsid = fsid or system.generate_uuid() | |
25 | # allow re-using an id, in case a prepare failed | |
26 | osd_id = id_ or prepare_utils.create_id(fsid, json_secrets) | |
27 | # create the directory | |
28 | prepare_utils.create_path(osd_id) | |
29 | # format the device | |
30 | prepare_utils.format_device(device) | |
31 | # mount the data device | |
32 | prepare_utils.mount_osd(device, osd_id) | |
33 | # symlink the journal | |
34 | prepare_utils.link_journal(journal, osd_id) | |
35 | # get the latest monmap | |
36 | prepare_utils.get_monmap(osd_id) | |
37 | # prepare the osd filesystem | |
38 | prepare_utils.osd_mkfs(osd_id, fsid) | |
39 | # write the OSD keyring if it doesn't exist already | |
40 | prepare_utils.write_keyring(osd_id, cephx_secret) | |
41 | ||
42 | ||
43 | def prepare_bluestore(): | |
44 | raise NotImplemented() | |
45 | ||
46 | ||
47 | class Prepare(object): | |
48 | ||
49 | help = 'Format an LVM device and associate it with an OSD' | |
50 | ||
51 | def __init__(self, argv): | |
52 | self.argv = argv | |
53 | ||
b5b8bbf5 FG |
54 | def get_journal_lv(self, argument): |
55 | """ | |
56 | Perform some parsing of the value of ``--journal`` so that the process | |
57 | can determine correctly if it got a device path or an lv | |
58 | :param argument: The value of ``--journal``, that will need to be split | |
59 | to retrieve the actual lv | |
60 | """ | |
61 | try: | |
62 | vg_name, lv_name = argument.split('/') | |
63 | except (ValueError, AttributeError): | |
64 | return None | |
65 | return api.get_lv(lv_name=lv_name, vg_name=vg_name) | |
66 | ||
d2e6a577 FG |
67 | @decorators.needs_root |
68 | def prepare(self, args): | |
69 | # FIXME we don't allow re-using a keyring, we always generate one for the | |
70 | # OSD, this needs to be fixed. This could either be a file (!) or a string | |
71 | # (!!) or some flags that we would need to compound into a dict so that we | |
72 | # can convert to JSON (!!!) | |
73 | secrets = {'cephx_secret': prepare_utils.create_key()} | |
74 | ||
75 | cluster_fsid = conf.ceph.get('global', 'fsid') | |
76 | fsid = args.osd_fsid or system.generate_uuid() | |
77 | #osd_id = args.osd_id or prepare_utils.create_id(fsid) | |
78 | # allow re-using an id, in case a prepare failed | |
79 | osd_id = args.osd_id or prepare_utils.create_id(fsid, json.dumps(secrets)) | |
b5b8bbf5 | 80 | vg_name, lv_name = args.data.split('/') |
d2e6a577 | 81 | if args.filestore: |
b5b8bbf5 | 82 | data_lv = api.get_lv(lv_name=lv_name, vg_name=vg_name) |
d2e6a577 | 83 | |
d2e6a577 FG |
84 | # we must have either an existing data_lv or a newly created, so lets make |
85 | # sure that the tags are correct | |
86 | if not data_lv: | |
87 | raise RuntimeError('no data logical volume found with: %s' % args.data) | |
b5b8bbf5 FG |
88 | |
89 | if not args.journal: | |
90 | raise RuntimeError('--journal is required when using --filestore') | |
91 | journal_device = None | |
92 | journal_lv = self.get_journal_lv(args.journal) | |
93 | ||
94 | # check if we have an actual path to a device, which is allowed | |
95 | if not journal_lv: | |
96 | if os.path.exists(args.journal): | |
97 | journal_device = args.journal | |
98 | else: | |
99 | raise RuntimeError( | |
100 | '--journal specified an invalid or non-existent device: %s' % args.journal | |
101 | ) | |
102 | # Otherwise the journal_device is the path to the lv | |
103 | else: | |
104 | journal_device = journal_lv.lv_path | |
105 | journal_lv.set_tags({ | |
106 | 'ceph.type': 'journal', | |
107 | 'ceph.osd_fsid': fsid, | |
108 | 'ceph.osd_id': osd_id, | |
109 | 'ceph.cluster_fsid': cluster_fsid, | |
110 | 'ceph.journal_device': journal_device, | |
111 | 'ceph.data_device': data_lv.lv_path, | |
112 | }) | |
113 | ||
d2e6a577 FG |
114 | data_lv.set_tags({ |
115 | 'ceph.type': 'data', | |
116 | 'ceph.osd_fsid': fsid, | |
117 | 'ceph.osd_id': osd_id, | |
118 | 'ceph.cluster_fsid': cluster_fsid, | |
119 | 'ceph.journal_device': journal_device, | |
120 | 'ceph.data_device': data_lv.lv_path, | |
121 | }) | |
122 | ||
123 | prepare_filestore( | |
124 | data_lv.lv_path, | |
125 | journal_device, | |
126 | secrets, | |
127 | id_=osd_id, | |
128 | fsid=fsid, | |
129 | ) | |
130 | elif args.bluestore: | |
131 | prepare_bluestore(args) | |
132 | ||
133 | def main(self): | |
134 | sub_command_help = dedent(""" | |
135 | Prepare an OSD by assigning an ID and FSID, registering them with the | |
136 | cluster with an ID and FSID, formatting and mounting the volume, and | |
137 | finally by adding all the metadata to the logical volumes using LVM | |
138 | tags, so that it can later be discovered. | |
139 | ||
140 | Once the OSD is ready, an ad-hoc systemd unit will be enabled so that | |
141 | it can later get activated and the OSD daemon can get started. | |
142 | ||
143 | Most basic Usage looks like (journal will be collocated from the same volume group): | |
144 | ||
145 | ceph-volume lvm prepare --data {volume group name} | |
146 | ||
147 | ||
148 | Example calls for supported scenarios: | |
149 | ||
150 | Dedicated volume group for Journal(s) | |
151 | ------------------------------------- | |
152 | ||
153 | Existing logical volume (lv) or device: | |
154 | ||
155 | ceph-volume lvm prepare --data {logical volume} --journal /path/to/{lv}|{device} | |
156 | ||
157 | Or: | |
158 | ||
159 | ceph-volume lvm prepare --data {data volume group} --journal {journal volume group} | |
160 | ||
161 | Collocated (same group) for data and journal | |
162 | -------------------------------------------- | |
163 | ||
164 | ceph-volume lvm prepare --data {volume group} | |
165 | ||
166 | """) | |
167 | parser = prepare_parser( | |
168 | prog='ceph-volume lvm prepare', | |
169 | description=sub_command_help, | |
170 | ) | |
171 | if len(self.argv) == 0: | |
172 | print(sub_command_help) | |
173 | return | |
174 | args = parser.parse_args(self.argv) | |
175 | self.prepare(args) |