summaryrefslogtreecommitdiffstats
path: root/src/ceph-create-keys
diff options
context:
space:
mode:
authorTommi Virtanen <tv@inktank.com>2012-08-30 16:16:52 +0200
committerTommi Virtanen <tv@inktank.com>2012-08-30 19:41:20 +0200
commitf2c451084875b7e927c4deebe58495ff12596451 (patch)
tree26870ac6de2cb8ba431fc31d3548712857b0a511 /src/ceph-create-keys
parentupstart: Make instance jobs export their cluster and id variables. (diff)
downloadceph-f2c451084875b7e927c4deebe58495ff12596451.tar.xz
ceph-f2c451084875b7e927c4deebe58495ff12596451.zip
upstart, ceph-create-keys: Make client.admin key generation automatic.
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.
Diffstat (limited to 'src/ceph-create-keys')
-rwxr-xr-xsrc/ceph-create-keys145
1 files changed, 145 insertions, 0 deletions
diff --git a/src/ceph-create-keys b/src/ceph-create-keys
new file mode 100755
index 00000000000..7c56b0e8a52
--- /dev/null
+++ b/src/ceph-create-keys
@@ -0,0 +1,145 @@
+#!/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()