1 from __future__
import print_function
5 from textwrap
import dedent
6 from ceph_volume
import process
, conf
, decorators
, terminal
, configuration
7 from ceph_volume
.util
import system
, disk
8 from ceph_volume
.util
import prepare
as prepare_utils
9 from ceph_volume
.util
import encryption
as encryption_utils
10 from ceph_volume
.systemd
import systemctl
11 from ceph_volume
.api
import lvm
as api
12 from .listing
import direct_report
15 logger
= logging
.getLogger(__name__
)
19 def get_osd_device_path(osd_lvs
, device_type
, dmcrypt_secret
=None):
21 ``device_type`` can be one of ``db``, ``wal`` or ``block`` so that we can
22 query LVs on system and fallback to querying the uuid if that is not
25 Return a path if possible, failing to do that a ``None``, since some of
26 these devices are optional.
30 if lv
.tags
.get('ceph.type') == 'block':
34 is_encrypted
= osd_block_lv
.tags
.get('ceph.encrypted', '0') == '1'
35 logger
.debug('Found block device (%s) with encryption: %s', osd_block_lv
.name
, is_encrypted
)
36 uuid_tag
= 'ceph.%s_uuid' % device_type
37 device_uuid
= osd_block_lv
.tags
.get(uuid_tag
)
43 if lv
.tags
.get('ceph.type') == device_type
:
48 encryption_utils
.luks_open(dmcrypt_secret
, device_lv
.lv_path
, device_uuid
)
49 return '/dev/mapper/%s' % device_uuid
50 return device_lv
.lv_path
52 # this could be a regular device, so query it with blkid
53 physical_device
= disk
.get_device_from_partuuid(device_uuid
)
56 encryption_utils
.luks_open(dmcrypt_secret
, physical_device
, device_uuid
)
57 return '/dev/mapper/%s' % device_uuid
58 return physical_device
60 raise RuntimeError('could not find %s with uuid %s' % (device_type
, device_uuid
))
63 def activate_bluestore(osd_lvs
, no_systemd
=False, no_tmpfs
=False):
65 if lv
.tags
.get('ceph.type') == 'block':
69 raise RuntimeError('could not find a bluestore OSD to activate')
71 is_encrypted
= osd_block_lv
.tags
.get('ceph.encrypted', '0') == '1'
73 osd_id
= osd_block_lv
.tags
['ceph.osd_id']
74 conf
.cluster
= osd_block_lv
.tags
['ceph.cluster_name']
75 osd_fsid
= osd_block_lv
.tags
['ceph.osd_fsid']
76 configuration
.load_ceph_conf_path(osd_block_lv
.tags
['ceph.cluster_name'])
79 # mount on tmpfs the osd directory
80 osd_path
= '/var/lib/ceph/osd/%s-%s' % (conf
.cluster
, osd_id
)
81 if not system
.path_is_mounted(osd_path
):
82 # mkdir -p and mount as tmpfs
83 prepare_utils
.create_osd_path(osd_id
, tmpfs
=not no_tmpfs
)
84 # XXX This needs to be removed once ceph-bluestore-tool can deal with
85 # symlinks that exist in the osd dir
86 for link_name
in ['block', 'block.db', 'block.wal']:
87 link_path
= os
.path
.join(osd_path
, link_name
)
88 if os
.path
.exists(link_path
):
89 os
.unlink(os
.path
.join(osd_path
, link_name
))
90 # encryption is handled here, before priming the OSD dir
92 osd_lv_path
= '/dev/mapper/%s' % osd_block_lv
.lv_uuid
93 lockbox_secret
= osd_block_lv
.tags
['ceph.cephx_lockbox_secret']
94 encryption_utils
.write_lockbox_keyring(osd_id
, osd_fsid
, lockbox_secret
)
95 dmcrypt_secret
= encryption_utils
.get_dmcrypt_key(osd_id
, osd_fsid
)
96 encryption_utils
.luks_open(dmcrypt_secret
, osd_block_lv
.lv_path
, osd_block_lv
.lv_uuid
)
98 osd_lv_path
= osd_block_lv
.lv_path
100 db_device_path
= get_osd_device_path(osd_lvs
, 'db', dmcrypt_secret
=dmcrypt_secret
)
101 wal_device_path
= get_osd_device_path(osd_lvs
, 'wal', dmcrypt_secret
=dmcrypt_secret
)
103 # Once symlinks are removed, the osd dir can be 'primed again. chown first,
104 # regardless of what currently exists so that ``prime-osd-dir`` can succeed
105 # even if permissions are somehow messed up
106 system
.chown(osd_path
)
108 'ceph-bluestore-tool', '--cluster=%s' % conf
.cluster
,
109 'prime-osd-dir', '--dev', osd_lv_path
,
110 '--path', osd_path
, '--no-mon-config']
112 process
.run(prime_command
)
113 # always re-do the symlink regardless if it exists, so that the block,
114 # block.wal, and block.db devices that may have changed can be mapped
115 # correctly every time
116 process
.run(['ln', '-snf', osd_lv_path
, os
.path
.join(osd_path
, 'block')])
117 system
.chown(os
.path
.join(osd_path
, 'block'))
118 system
.chown(osd_path
)
120 destination
= os
.path
.join(osd_path
, 'block.db')
121 process
.run(['ln', '-snf', db_device_path
, destination
])
122 system
.chown(db_device_path
)
123 system
.chown(destination
)
125 destination
= os
.path
.join(osd_path
, 'block.wal')
126 process
.run(['ln', '-snf', wal_device_path
, destination
])
127 system
.chown(wal_device_path
)
128 system
.chown(destination
)
130 if no_systemd
is False:
131 # enable the ceph-volume unit for this OSD
132 systemctl
.enable_volume(osd_id
, osd_fsid
, 'lvm')
135 systemctl
.enable_osd(osd_id
)
138 systemctl
.start_osd(osd_id
)
139 terminal
.success("ceph-volume lvm activate successful for osd ID: %s" % osd_id
)
142 class Activate(object):
144 help = 'Discover and mount the LVM device associated with an OSD ID and start the Ceph OSD'
146 def __init__(self
, argv
):
149 @decorators.needs_root
150 def activate_all(self
, args
):
151 listed_osds
= direct_report()
153 for osd_id
, devices
in listed_osds
.items():
154 # the metadata for all devices in each OSD will contain
155 # the FSID which is required for activation
156 for device
in devices
:
157 fsid
= device
.get('tags', {}).get('ceph.osd_fsid')
162 terminal
.warning('Was unable to find any OSDs to activate')
163 terminal
.warning('Verify OSDs are present with "ceph-volume lvm list"')
165 for osd_fsid
, osd_id
in osds
.items():
166 if not args
.no_systemd
and systemctl
.osd_is_active(osd_id
):
168 'OSD ID %s FSID %s process is active. Skipping activation' % (osd_id
, osd_fsid
)
171 terminal
.info('Activating OSD ID %s FSID %s' % (osd_id
, osd_fsid
))
172 self
.activate(args
, osd_id
=osd_id
, osd_fsid
=osd_fsid
)
174 @decorators.needs_root
175 def activate(self
, args
, osd_id
=None, osd_fsid
=None):
177 :param args: The parsed arguments coming from the CLI
178 :param osd_id: When activating all, this gets populated with an
180 :param osd_fsid: When activating all, this gets populated with an
183 osd_id
= osd_id
if osd_id
else args
.osd_id
184 osd_fsid
= osd_fsid
if osd_fsid
else args
.osd_fsid
186 if osd_id
and osd_fsid
:
187 tags
= {'ceph.osd_id': osd_id
, 'ceph.osd_fsid': osd_fsid
}
188 elif not osd_id
and osd_fsid
:
189 tags
= {'ceph.osd_fsid': osd_fsid
}
190 elif osd_id
and not osd_fsid
:
191 raise RuntimeError('could not activate osd.{}, please provide the '
192 'osd_fsid too'.format(osd_id
))
194 raise RuntimeError('Please provide both osd_id and osd_fsid')
195 lvs
= api
.get_lvs(tags
=tags
)
197 raise RuntimeError('could not find osd.%s with osd_fsid %s' %
200 # This argument is only available when passed in directly or via
201 # systemd, not when ``create`` is being used
202 # placeholder when a new objectstore support will be added
203 if getattr(args
, 'auto_detect_objectstore', False):
204 logger
.info('auto detecting objectstore')
205 return activate_bluestore(lvs
, args
.no_systemd
)
207 # explicit 'objectstore' flags take precedence
208 if getattr(args
, 'bluestore', False):
209 activate_bluestore(lvs
, args
.no_systemd
, getattr(args
, 'no_tmpfs', False))
210 elif any('ceph.block_device' in lv
.tags
for lv
in lvs
):
211 activate_bluestore(lvs
, args
.no_systemd
, getattr(args
, 'no_tmpfs', False))
214 sub_command_help
= dedent("""
215 Activate OSDs by discovering them with LVM and mounting them in their
216 appropriate destination:
218 ceph-volume lvm activate {ID} {FSID}
220 The lvs associated with the OSD need to have been prepared previously,
221 so that all needed tags and metadata exist.
223 When migrating OSDs, or a multiple-osd activation is needed, the
224 ``--all`` flag can be used instead of the individual ID and FSID:
226 ceph-volume lvm activate --all
229 parser
= argparse
.ArgumentParser(
230 prog
='ceph-volume lvm activate',
231 formatter_class
=argparse
.RawDescriptionHelpFormatter
,
232 description
=sub_command_help
,
239 help='The ID of the OSD, usually an integer, like 0'
245 help='The FSID of the OSD, similar to a SHA1'
248 '--auto-detect-objectstore',
250 help='Autodetect the objectstore by inspecting the OSD',
255 help='force bluestore objectstore activation',
261 help='Activate all OSDs found in the system',
267 help='Skip creating and enabling systemd units and starting OSD services',
272 help='Do not use a tmpfs mount for OSD data dir'
274 if len(self
.argv
) == 0:
275 print(sub_command_help
)
277 args
= parser
.parse_args(self
.argv
)
278 if args
.activate_all
:
279 self
.activate_all(args
)