-#!/usr/bin/env python
-import argparse
-import errno
-import json
-import logging
-import os
-import subprocess
-import sys
-import time
-import pwd
-import grp
-
-
-LOG = logging.getLogger(os.path.basename(sys.argv[0]))
-
-QUORUM_STATES = ['leader', 'peon']
-
-def get_ceph_uid():
- try:
- uid = pwd.getpwnam('ceph').pw_uid
- except:
- uid = -1
- return uid
-
-def get_ceph_gid():
- try:
- gid = grp.getgrnam('ceph').gr_gid
- except:
- gid = -1
- return gid
-
-def wait_for_quorum(cluster, mon_id, wait_count=600):
- # wait 10 minutes by default
- while wait_count > 0:
- 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)
- wait_count -= 1
- continue
-
- if out == '':
- LOG.info('ceph-mon admin socket returned no data')
- time.sleep(1)
- wait_count -= 1
- continue
-
- try:
- data = json.loads(out)
- except:
- LOG.info('failed to parse json %s', out)
- sys.exit(errno.EINVAL)
-
- state = data['state']
- if state not in QUORUM_STATES:
- LOG.info('ceph-mon is not in quorum: %r', state)
- time.sleep(1)
- wait_count -= 1
- continue
-
- break
-
- if wait_count == 0:
- raise SystemExit("ceph-mon was not able to join quorum within %d seconds" % wait_count)
-
-
-def get_key(cluster, mon_id, wait_count=600):
- 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(),
- )
- pathdir = os.path.dirname(path)
- if not os.path.exists(pathdir):
- os.makedirs(pathdir)
- os.chmod(pathdir, 0770)
- os.chown(pathdir, get_ceph_uid(), get_ceph_gid())
- while wait_count > 0:
- try:
- with file(tmp, 'w') as f:
- os.fchmod(f.fileno(), 0600)
- os.fchown(f.fileno(), get_ceph_uid(), get_ceph_gid())
- LOG.info('Talking to monitor...')
-
- args_prefix = [
- "ceph",
- '--connect-timeout=20',
- '--cluster={cluster}'.format(cluster=cluster),
- '--name=mon.',
- '--keyring=/var/lib/ceph/mon/{cluster}-{mon_id}/keyring'.format(
- cluster=cluster,
- mon_id=mon_id,
- ),
- ]
-
- # First try getting the key if it already exists, to handle
- # the case where it exists but doesn't match the caps
- # we would pass into get-or-create.
- returncode = subprocess.call(
- args=args_prefix + [
- 'auth',
- 'get',
- 'client.admin',
- ],
- stdout=f,
- )
- if returncode == errno.ENOENT:
- returncode = subprocess.call(
- args=args_prefix + [
- 'auth',
- 'get-or-create',
- 'client.admin',
- 'mon', 'allow *',
- 'osd', 'allow *',
- 'mds', 'allow *',
- 'mgr', 'allow *',
- ],
- stdout=f,
- )
- else:
- returncode = subprocess.call(
- args=args_prefix + [
- 'auth',
- 'caps',
- 'client.admin',
- 'mon', 'allow *',
- 'osd', 'allow *',
- 'mds', 'allow *',
- 'mgr', 'allow *',
- ],
- stdout=f,
- )
-
- if returncode != 0:
- if returncode == errno.EPERM or returncode == errno.EACCES:
- LOG.info('Cannot get or create admin key, permission denied')
- sys.exit(returncode)
- else:
- LOG.info('Cannot get or create admin key')
- time.sleep(1)
- wait_count -= 1
- continue
-
- os.rename(tmp, path)
- break
- finally:
- try:
- os.unlink(tmp)
- except OSError as e:
- if e.errno == errno.ENOENT:
- pass
- else:
- raise
-
- if wait_count == 0:
- raise SystemExit("Could not get or create the admin key after %d seconds" % wait_count)
-
-
-def bootstrap_key(cluster, type_, wait_count=600):
- path = '/var/lib/ceph/bootstrap-{type}/{cluster}.keyring'.format(
- type=type_,
- 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(),
- )
-
- args = [
- 'ceph',
- '--connect-timeout=20',
- '--cluster={cluster}'.format(cluster=cluster),
- 'auth',
- 'get-or-create',
- 'client.bootstrap-{type}'.format(type=type_),
- 'mon',
- 'allow profile bootstrap-{type}'.format(type=type_),
- ]
-
- pathdir = os.path.dirname(path)
- if not os.path.exists(pathdir):
- os.makedirs(pathdir)
- os.chmod(pathdir, 0770)
- os.chown(pathdir, get_ceph_uid(), get_ceph_gid())
-
- while wait_count > 0:
- try:
- with file(tmp, 'w') as f:
- os.fchmod(f.fileno(), 0600)
- os.fchown(f.fileno(), get_ceph_uid(), get_ceph_gid())
- LOG.info('Talking to monitor...')
- returncode = subprocess.call(
- args=args,
- stdout=f,
- )
- if returncode != 0:
- if returncode == errno.EPERM or returncode == errno.EACCES:
- LOG.info('Cannot get or create bootstrap key for %s, permission denied', type_)
- break
- else:
- LOG.info('Cannot get or create bootstrap key for %s', type_)
- time.sleep(1)
- wait_count -= 1
- continue
-
- os.rename(tmp, path)
- break
- finally:
- try:
- os.unlink(tmp)
- except OSError as e:
- if e.errno == errno.ENOENT:
- pass
- else:
- raise
- if wait_count == 0:
- raise SystemExit("Could not get or create %s bootstrap key after %d seconds" % (type_, wait_count))
-
-
-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.add_argument(
- '--timeout', '-t',
- metavar='TIMEOUT',
- type=int,
- help='timeout in seconds to wait',
- )
- parser.set_defaults(
- cluster='ceph',
- timeout=600,
- )
- 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,
- )
-
- wait_for_quorum(cluster=args.cluster, mon_id=args.id, wait_count=args.timeout)
- get_key(cluster=args.cluster, mon_id=args.id, wait_count=args.timeout)
-
- bootstrap_key(
- cluster=args.cluster,
- type_='osd',
- wait_count=args.timeout,
- )
- bootstrap_key(
- cluster=args.cluster,
- type_='rgw',
- wait_count=args.timeout,
- )
- bootstrap_key(
- cluster=args.cluster,
- type_='mds',
- wait_count=args.timeout,
- )
- bootstrap_key(
- cluster=args.cluster,
- type_='rbd',
- wait_count=args.timeout,
- )
-
-if __name__ == '__main__':
- main()