]>
Commit | Line | Data |
---|---|---|
1 | from __future__ import print_function | |
2 | import argparse | |
3 | import json | |
4 | import logging | |
5 | import os | |
6 | from textwrap import dedent | |
7 | from ceph_volume import process, decorators, terminal | |
8 | from ceph_volume.util import system, disk | |
9 | from ceph_volume.systemd import systemctl | |
10 | ||
11 | ||
12 | logger = logging.getLogger(__name__) | |
13 | ||
14 | ||
15 | class Activate(object): | |
16 | ||
17 | help = 'Enable systemd units to mount configured devices and start a Ceph OSD' | |
18 | ||
19 | def __init__(self, argv, systemd=False): | |
20 | self.argv = argv | |
21 | self.systemd = systemd | |
22 | ||
23 | @decorators.needs_root | |
24 | def activate(self, args): | |
25 | with open(args.json_config, 'r') as fp: | |
26 | osd_metadata = json.load(fp) | |
27 | ||
28 | osd_id = osd_metadata.get('whoami', args.osd_id) | |
29 | osd_fsid = osd_metadata.get('fsid', args.osd_fsid) | |
30 | ||
31 | cluster_name = osd_metadata.get('cluster_name', 'ceph') | |
32 | osd_dir = '/var/lib/ceph/osd/%s-%s' % (cluster_name, osd_id) | |
33 | data_uuid = osd_metadata.get('data', {}).get('uuid') | |
34 | if not data_uuid: | |
35 | raise RuntimeError( | |
36 | 'Unable to activate OSD %s - no "uuid" key found for data' % args.osd_id | |
37 | ) | |
38 | data_device = disk.get_device_from_partuuid(data_uuid) | |
39 | journal_device = disk.get_device_from_partuuid(osd_metadata.get('journal', {}).get('uuid')) | |
40 | block_device = disk.get_device_from_partuuid(osd_metadata.get('block', {}).get('uuid')) | |
41 | block_db_device = disk.get_device_from_partuuid(osd_metadata.get('block.db', {}).get('uuid')) | |
42 | block_wal_device = disk.get_device_from_partuuid( | |
43 | osd_metadata.get('block.wal', {}).get('uuid') | |
44 | ) | |
45 | ||
46 | if not system.device_is_mounted(data_device, destination=osd_dir): | |
47 | process.run(['sudo', 'mount', '-v', data_device, osd_dir]) | |
48 | ||
49 | device_map = { | |
50 | 'journal': journal_device, | |
51 | 'block': block_device, | |
52 | 'block.db': block_db_device, | |
53 | 'block.wal': block_wal_device | |
54 | } | |
55 | ||
56 | for name, device in device_map.items(): | |
57 | if not device: | |
58 | continue | |
59 | # always re-do the symlink regardless if it exists, so that the journal | |
60 | # device path that may have changed can be mapped correctly every time | |
61 | destination = os.path.join(osd_dir, name) | |
62 | process.run(['sudo', 'ln', '-snf', device, destination]) | |
63 | ||
64 | # make sure that the journal has proper permissions | |
65 | system.chown(device) | |
66 | ||
67 | if not self.systemd: | |
68 | # enable the ceph-volume unit for this OSD | |
69 | systemctl.enable_volume(osd_id, osd_fsid, 'simple') | |
70 | ||
71 | # disable any/all ceph-disk units | |
72 | systemctl.mask_ceph_disk() | |
73 | ||
74 | # enable the OSD | |
75 | systemctl.enable_osd(osd_id) | |
76 | ||
77 | # start the OSD | |
78 | systemctl.start_osd(osd_id) | |
79 | ||
80 | if not self.systemd: | |
81 | terminal.success('Successfully activated OSD %s with FSID %s' % (osd_id, osd_fsid)) | |
82 | terminal.warning( | |
83 | ('All ceph-disk systemd units have been disabled to ' | |
84 | 'prevent OSDs getting triggered by UDEV events') | |
85 | ) | |
86 | ||
87 | def main(self): | |
88 | sub_command_help = dedent(""" | |
89 | Activate OSDs by mounting devices previously configured to their | |
90 | appropriate destination:: | |
91 | ||
92 | ceph-volume simple activate {ID} {FSID} | |
93 | ||
94 | Or using a JSON file directly:: | |
95 | ||
96 | ceph-volume simple activate --file /etc/ceph/osd/{ID}-{FSID}.json | |
97 | ||
98 | The OSD must have been "scanned" previously (see ``ceph-volume simple | |
99 | scan``), so that all needed OSD device information and metadata exist. | |
100 | ||
101 | A previously scanned OSD would exist like:: | |
102 | ||
103 | /etc/ceph/osd/{ID}-{FSID}.json | |
104 | ||
105 | ||
106 | Environment variables supported: | |
107 | ||
108 | CEPH_VOLUME_SIMPLE_JSON_DIR: Directory location for scanned OSD JSON configs | |
109 | """) | |
110 | parser = argparse.ArgumentParser( | |
111 | prog='ceph-volume simple activate', | |
112 | formatter_class=argparse.RawDescriptionHelpFormatter, | |
113 | description=sub_command_help, | |
114 | ) | |
115 | parser.add_argument( | |
116 | 'osd_id', | |
117 | metavar='ID', | |
118 | nargs='?', | |
119 | help='The ID of the OSD, usually an integer, like 0' | |
120 | ) | |
121 | parser.add_argument( | |
122 | 'osd_fsid', | |
123 | metavar='FSID', | |
124 | nargs='?', | |
125 | help='The FSID of the OSD, similar to a SHA1' | |
126 | ) | |
127 | parser.add_argument( | |
128 | '--file', | |
129 | help='The path to a JSON file, from a scanned OSD' | |
130 | ) | |
131 | if len(self.argv) == 0: | |
132 | print(sub_command_help) | |
133 | return | |
134 | args = parser.parse_args(self.argv) | |
135 | if not args.file: | |
136 | if not args.osd_id and not args.osd_fsid: | |
137 | terminal.error('ID and FSID are required to find the right OSD to activate') | |
138 | terminal.error('from a scanned OSD location in /etc/ceph/osd/') | |
139 | raise RuntimeError('Unable to activate without both ID and FSID') | |
140 | # don't allow a CLI flag to specify the JSON dir, because that might | |
141 | # implicitly indicate that it would be possible to activate a json file | |
142 | # at a non-default location which would not work at boot time if the | |
143 | # custom location is not exposed through an ENV var | |
144 | json_dir = os.environ.get('CEPH_VOLUME_SIMPLE_JSON_DIR', '/etc/ceph/osd/') | |
145 | if args.file: | |
146 | json_config = args.file | |
147 | else: | |
148 | json_config = os.path.join(json_dir, '%s-%s.json' % (args.osd_id, args.osd_fsid)) | |
149 | if not os.path.exists(json_config): | |
150 | raise RuntimeError('Expected JSON config path not found: %s' % json_config) | |
151 | args.json_config = json_config | |
152 | self.activate(args) |