mirror of
https://github.com/ceph/ceph
synced 2025-01-17 16:34:22 +00:00
f2c4510848
This should help simplify Chef etc deployments. Now (when using the Upstart jobs), when a ceph-mon is started, ceph-create-admin-key is triggered. If /etc/ceph/$cluster.client.admin.keyring already exists, it does nothing; otherwise, it waits for ceph-mon to reach quorum, and then does a "ceph auth get-or-create" to create the key, and writes it atomically to disk. The equivalent code can be removed from the Chef cookbook once this is in.
146 lines
3.7 KiB
Python
Executable File
146 lines
3.7 KiB
Python
Executable File
#!/usr/bin/python
|
|
import argparse
|
|
import errno
|
|
import json
|
|
import logging
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
import time
|
|
|
|
|
|
log = logging.getLogger(os.path.basename(sys.argv[0]))
|
|
|
|
QUORUM_STATES = ['leader', 'peon']
|
|
|
|
def wait_for_quorum(cluster, mon_id):
|
|
while True:
|
|
p = subprocess.Popen(
|
|
args=[
|
|
'ceph',
|
|
'--cluster={cluster}'.format(cluster=cluster),
|
|
'--admin-daemon=/var/run/ceph/{cluster}-mon.{mon_id}.asok'.format(
|
|
cluster=cluster,
|
|
mon_id=mon_id,
|
|
),
|
|
'mon_status',
|
|
],
|
|
stdout=subprocess.PIPE,
|
|
)
|
|
out = p.stdout.read()
|
|
returncode = p.wait()
|
|
if returncode != 0:
|
|
log.info('ceph-mon admin socket not ready yet.')
|
|
time.sleep(1)
|
|
continue
|
|
|
|
data = json.loads(out)
|
|
state = data['state']
|
|
if state not in QUORUM_STATES:
|
|
log.info('ceph-mon is not in quorum: %r', state)
|
|
time.sleep(1)
|
|
continue
|
|
|
|
break
|
|
|
|
|
|
def get_key(cluster, mon_id):
|
|
path = '/etc/ceph/{cluster}.client.admin.keyring'.format(
|
|
cluster=cluster,
|
|
)
|
|
if os.path.exists(path):
|
|
log.info('Key exists already: %s', path)
|
|
return
|
|
tmp = '{path}.{pid}.tmp'.format(
|
|
path=path,
|
|
pid=os.getpid(),
|
|
)
|
|
wait_for_quorum(cluster=cluster, mon_id=mon_id)
|
|
while True:
|
|
try:
|
|
with file(tmp, 'w') as f:
|
|
os.fchmod(f.fileno(), 0600)
|
|
log.info('Talking to monitor...')
|
|
returncode = subprocess.call(
|
|
args=[
|
|
'ceph',
|
|
'--cluster={cluster}'.format(cluster=cluster),
|
|
'--name=mon.',
|
|
'--keyring=/var/lib/ceph/mon/{cluster}-{mon_id}/keyring'.format(
|
|
cluster=cluster,
|
|
mon_id=mon_id,
|
|
),
|
|
'auth',
|
|
'get-or-create',
|
|
'client.admin',
|
|
'mon', 'allow *',
|
|
'osd', 'allow *',
|
|
'mds', 'allow',
|
|
],
|
|
stdout=f,
|
|
)
|
|
if returncode != 0:
|
|
log.info('Cannot get or create admin key')
|
|
time.sleep(1)
|
|
continue
|
|
|
|
os.rename(tmp, path)
|
|
break
|
|
finally:
|
|
try:
|
|
os.unlink(tmp)
|
|
except OSError as e:
|
|
if e.errno == errno.ENOENT:
|
|
pass
|
|
else:
|
|
raise
|
|
|
|
|
|
def parse_args():
|
|
parser = argparse.ArgumentParser(
|
|
description='Create Ceph client.admin key when ceph-mon is ready',
|
|
)
|
|
parser.add_argument(
|
|
'-v', '--verbose',
|
|
action='store_true', default=None,
|
|
help='be more verbose',
|
|
)
|
|
parser.add_argument(
|
|
'--cluster',
|
|
metavar='NAME',
|
|
help='name of the cluster',
|
|
)
|
|
parser.add_argument(
|
|
'--id', '-i',
|
|
metavar='ID',
|
|
help='id of a ceph-mon that is coming up',
|
|
required=True,
|
|
)
|
|
parser.set_defaults(
|
|
cluster='ceph',
|
|
)
|
|
parser.set_defaults(
|
|
# we want to hold on to this, for later
|
|
prog=parser.prog,
|
|
)
|
|
args = parser.parse_args()
|
|
return args
|
|
|
|
|
|
def main():
|
|
args = parse_args()
|
|
|
|
loglevel = logging.INFO
|
|
if args.verbose:
|
|
loglevel = logging.DEBUG
|
|
|
|
logging.basicConfig(
|
|
level=loglevel,
|
|
)
|
|
|
|
get_key(cluster=args.cluster, mon_id=args.id)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|