2
# Copyright 2012 Canonical Ltd.
4
# This file is sourced from lp:openstack-charm-helpers
7
# James Page <james.page@ubuntu.com>
8
# Adam Gandelman <adamg@ubuntu.com>
17
KEYRING = '/etc/ceph/ceph.client.%s.keyring'
18
KEYFILE = '/etc/ceph/ceph.client.%s.key'
20
CEPH_CONF = """[global]
21
auth supported = %(auth)s
23
mon host = %(mon_hosts)s
28
subprocess.check_call(cmd)
31
def execute_shell(cmd):
32
subprocess.check_call(cmd, shell=True)
36
ceph_dir = "/etc/ceph"
37
if not os.path.isdir(ceph_dir):
39
utils.install('ceph-common')
42
def rbd_exists(service, pool, rbd_img):
43
(rc, out) = commands.getstatusoutput('rbd list --id %s --pool %s' %\
48
def create_rbd_image(service, pool, image, sizemb):
63
def pool_exists(service, name):
64
(rc, out) = commands.getstatusoutput("rados --id %s lspools" % service)
68
def create_pool(service, name):
79
def keyfile_path(service):
80
return KEYFILE % service
83
def keyring_path(service):
84
return KEYRING % service
87
def create_keyring(service, key):
88
keyring = keyring_path(service)
89
if os.path.exists(keyring):
90
utils.juju_log('INFO', 'ceph: Keyring exists at %s.' % keyring)
95
'--name=client.%s' % service,
99
utils.juju_log('INFO', 'ceph: Created new ring at %s.' % keyring)
102
def create_key_file(service, key):
103
# create a file containing the key
104
keyfile = keyfile_path(service)
105
if os.path.exists(keyfile):
106
utils.juju_log('INFO', 'ceph: Keyfile exists at %s.' % keyfile)
107
fd = open(keyfile, 'w')
110
utils.juju_log('INFO', 'ceph: Created new keyfile at %s.' % keyfile)
113
def get_ceph_nodes():
115
for r_id in utils.relation_ids('ceph'):
116
for unit in utils.relation_list(r_id):
117
hosts.append(utils.relation_get('private-address',
118
unit=unit, rid=r_id))
122
def configure(service, key, auth):
123
create_keyring(service, key)
124
create_key_file(service, key)
125
hosts = get_ceph_nodes()
126
mon_hosts = ",".join(map(str, hosts))
127
keyring = keyring_path(service)
128
with open('/etc/ceph/ceph.conf', 'w') as ceph_conf:
129
ceph_conf.write(CEPH_CONF % locals())
130
modprobe_kernel_module('rbd')
133
def image_mapped(image_name):
134
(rc, out) = commands.getstatusoutput('rbd showmapped')
135
return image_name in out
138
def map_block_storage(service, pool, image):
142
'%s/%s' % (pool, image),
146
keyfile_path(service),
151
def filesystem_mounted(fs):
152
return subprocess.call(['grep', '-wqs', fs, '/proc/mounts']) == 0
155
def make_filesystem(blk_device, fstype='ext4'):
156
utils.juju_log('INFO',
157
'ceph: Formatting block device %s as filesystem %s.' %\
158
(blk_device, fstype))
159
cmd = ['mkfs', '-t', fstype, blk_device]
163
def place_data_on_ceph(service, blk_device, data_src_dst, fstype='ext4'):
164
# mount block device into /mnt
165
cmd = ['mount', '-t', fstype, blk_device, '/mnt']
170
copy_files(data_src_dst, '/mnt')
174
# umount block device
175
cmd = ['umount', '/mnt']
178
_dir = os.stat(data_src_dst)
182
# re-mount where the data should originally be
183
cmd = ['mount', '-t', fstype, blk_device, data_src_dst]
186
# ensure original ownership of new mount.
187
cmd = ['chown', '-R', '%s:%s' % (uid, gid), data_src_dst]
192
def modprobe_kernel_module(module):
193
utils.juju_log('INFO', 'Loading kernel module')
194
cmd = ['modprobe', module]
196
cmd = 'echo %s >> /etc/modules' % module
200
def copy_files(src, dst, symlinks=False, ignore=None):
201
for item in os.listdir(src):
202
s = os.path.join(src, item)
203
d = os.path.join(dst, item)
205
shutil.copytree(s, d, symlinks, ignore)
210
def ensure_ceph_storage(service, pool, rbd_img, sizemb, mount_point,
211
blk_device, fstype, system_services=[]):
213
To be called from the current cluster leader.
214
Ensures given pool and RBD image exists, is mapped to a block device,
215
and the device is formatted and mounted at the given mount_point.
217
If formatting a device for the first time, data existing at mount_point
218
will be migrated to the RBD device before being remounted.
220
All services listed in system_services will be stopped prior to data
221
migration and restarted when complete.
223
# Ensure pool, RBD image, RBD mappings are in place.
224
if not pool_exists(service, pool):
225
utils.juju_log('INFO', 'ceph: Creating new pool %s.' % pool)
226
create_pool(service, pool)
228
if not rbd_exists(service, pool, rbd_img):
229
utils.juju_log('INFO', 'ceph: Creating RBD image (%s).' % rbd_img)
230
create_rbd_image(service, pool, rbd_img, sizemb)
232
if not image_mapped(rbd_img):
233
utils.juju_log('INFO', 'ceph: Mapping RBD Image as a Block Device.')
234
map_block_storage(service, pool, rbd_img)
237
# TODO: What happens if for whatever reason this is run again and
238
# the data is already in the rbd device and/or is mounted??
239
# When it is mounted already, it will fail to make the fs
240
# XXX: This is really sketchy! Need to at least add an fstab entry
241
# otherwise this hook will blow away existing data if its executed
243
if not filesystem_mounted(mount_point):
244
make_filesystem(blk_device, fstype)
246
for svc in system_services:
247
if utils.running(svc):
248
utils.juju_log('INFO',
249
'Stopping services %s prior to migrating '\
253
place_data_on_ceph(service, blk_device, mount_point, fstype)
255
for svc in system_services: