]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
ceph-daemon: initial checkin
authorSage Weil <sage@redhat.com>
Thu, 26 Sep 2019 19:13:47 +0000 (14:13 -0500)
committerSage Weil <sage@redhat.com>
Wed, 2 Oct 2019 12:11:12 +0000 (07:11 -0500)
Signed-off-by: Sage Weil <sage@redhat.com>
src/ceph-daemon [new file with mode: 0755]

diff --git a/src/ceph-daemon b/src/ceph-daemon
new file mode 100755 (executable)
index 0000000..0332d9b
--- /dev/null
@@ -0,0 +1,338 @@
+#!/usr/bin/env python3
+
+CEPH_USER_UID=167
+CEPH_USER_GID=167
+DEFAULT_IMAGE='ceph/daemon-base'
+DATA_DIR='/var/lib/ceph'
+LOG_DIR='/var/log/ceph'
+VERSION='unknown development version'
+
+import argparse
+import logging
+import os
+import sys
+from distutils.spawn import find_executable
+from subprocess import check_output, CalledProcessError
+
+logging.basicConfig(level=logging.DEBUG)
+
+##################################
+
+def get_hostname():
+    import socket
+    return socket.gethostname()
+
+def make_fsid():
+    import uuid
+    return str(uuid.uuid1())
+
+def makedirs(dir):
+    os.makedirs(dir, exist_ok=True)
+
+def find_program(filename):
+    name = find_executable(filename)
+    if name is None:
+        raise ValueError(f'{filename} not found')
+    return name
+
+def get_data_dir(base, fsid, t, n):
+    return base + '/' + fsid + '/' + t + '.' + n;
+
+def get_daemon_args():
+    r = [
+#        '--log-dir', args.log_dir,
+#        '--data-dir', args.data_dir,
+        ]
+#    if args.uid != 0:
+#        r = r + ['--setuser', args.uid]
+#    if args.gid != 0:
+#        r = r + ['--setgroup', args.gid]
+    return r
+
+##################################
+
+class CephContainer:
+    def __init__(self,
+                 image,
+                 entrypoint,
+                 args=[],
+                 volume_mounts={},
+                 name='',
+                 podman_args=[]):
+        self.image = image
+        self.entrypoint = entrypoint
+        self.args = args
+        self.volume_mounts = volume_mounts
+        self.name = name
+        self.podman_args = podman_args
+
+    def run_cmd(self):
+        vols = sum(
+            [['-v', f'{host_dir}:{container_dir}']
+             for host_dir, container_dir in self.volume_mounts.items()], [])
+        envs = [
+            '-e', f'CONTAINER_IMAGE={self.image}',
+            '-e', f'NODE_NAME={get_hostname()}',
+        ]
+        name = ['--name', self.name] if self.name else []
+        return [
+            find_program('podman'),
+            'run',
+            '--rm',
+            '--net=host',
+        ] + self.podman_args + name + envs + vols + [
+            '--entrypoint', f'/usr/bin/{self.entrypoint}',
+            self.image
+        ] + self.args
+
+    def run(self):
+        logging.debug(self.run_cmd())
+        print(' '.join(self.run_cmd()))
+        return check_output(self.run_cmd())
+
+##################################
+
+def command_version():
+    out = CephContainer(args.image, 'ceph', ['--version']).run()
+    print(out.decode('utf-8'), end='')
+    return 0
+
+##################################
+
+def command_bootstrap():
+    fsid = args.fsid or make_fsid()
+    mon_id = args.mon_id or get_hostname()
+    mgr_id = args.mgr_id or get_hostname()
+    logging.debug('fsid %s, mon_id %s, mgr_id %s' % (fsid, mon_id, mgr_id))
+    mon_dir = get_data_dir(args.data_dir, fsid, 'mon', mon_id)
+    makedirs(mon_dir)
+    log_dir = get_data_dir(args.log_dir, fsid, 'mon', mon_id)
+    makedirs(log_dir)
+
+    mounts = {
+        log_dir: '/var/log/ceph:z',
+        mon_dir: '/var/lib/ceph/mon/ceph-' + mon_id + ':z',
+        '/tmp': '/mytmp:z',
+    }
+
+    # create initial monmap
+    if args.mon_ip:
+        addr_arg = '[v2:%s:3300,v1:%s:6789]' % (args.mon_ip, args.mon_ip)
+    elif args.mon_addrv:
+        addr_arg = args.mon_addrv
+    else:
+        raise RuntimeError('must specify --mon-ip or --mon-addrv')
+    cmonpath = '/mytmp/monmap'
+    ckeyring = '/mytmp/keyring'
+    out = CephContainer(
+        image=args.image,
+        entrypoint='monmaptool',
+        args=['--create',
+              '--clobber',
+              '--fsid', fsid,
+              '--addv', mon_id, addr_arg,
+              cmonpath],
+        volume_mounts=mounts,
+    ).run()
+
+    # create initial keyring
+    mon_key = CephContainer(
+        image=args.image,
+        entrypoint='ceph-authtool',
+        args=['--gen-print-key'],
+        volume_mounts=mounts,
+    ).run().decode('utf-8').strip()
+    admin_key = CephContainer(
+        image=args.image,
+        entrypoint='ceph-authtool',
+        args=['--gen-print-key'],
+        volume_mounts=mounts,
+    ).run().decode('utf-8').strip()
+    with open('/tmp/keyring', 'w') as f:
+        f.write('[mon.]\n'
+                '\tkey = %s\n'
+                '\tcaps mon = *\n'
+                '[client.admin]\n'
+                '\tkey = %s\n'
+                '\tcaps mon = *\n'
+                '\tcaps mds = *\n'
+                '\tcaps mgr = *\n'
+                '\tcaps osd = *\n'
+            % (mon_key, admin_key));
+    """
+    CephContainer(
+        image=args.image,
+        entrypoint='ceph-authtool',
+        args=['--create-keyring',
+              '--gen-key',
+              '-n', 'mon.',
+              '--cap', 'mon', 'allow *',
+              ckeyring],
+        volume_mounts=mounts,
+    ).run()
+    CephContainer(
+        image=args.image,
+        entrypoint='ceph-authtool',
+        args=['--gen-key',
+              '-n', 'client.admin',
+              '--cap', 'mon', 'allow *',
+              '--cap', 'mgr', 'allow *',
+              '--cap', 'mds', 'allow *',
+              '--cap', 'osd', 'allow *',
+              ckeyring],
+        volume_mounts=mounts,
+    ).run()
+    """
+
+    # mkfs on the mon
+    out = CephContainer(
+        image=args.image,
+        entrypoint='ceph-mon',
+        args=['--mkfs',
+              '-i', mon_id,
+              '--fsid', fsid,
+              '-c', '/dev/null',
+              '--monmap', cmonpath,
+              '--keyring', ckeyring,
+              '--debug-mon', '20',
+              ] + get_daemon_args(),
+        volume_mounts=mounts,
+    ).run()
+    print(out.decode('utf-8'))
+
+
+    # create a mgr
+
+    # output
+    if args.output_keyring:
+        with open(args.output_keyring, 'w') as f:
+            f.write('[client.admin]\n'
+                    '\tkey = ' + admin_key + '\n')
+            os.fchmod(f.fileno(), 0o600)
+    if args.output_conf:
+        with open(args.output_conf, 'w') as f:
+            f.write('[global]\n'
+                    '\tmon host = ' + addr_arg + '\n')
+
+    return 1
+
+##################################
+
+def command_run():
+    fsid = args.fsid
+    name = args.name
+    (daemon_type, daemon_id) = name.split('.')
+
+    data_dir = get_data_dir(args.data_dir, fsid, daemon_type, daemon_id)
+    makedirs(data_dir)
+    log_dir = get_data_dir(args.log_dir, fsid, daemon_type, daemon_id)
+    makedirs(log_dir)
+
+    mounts = {
+        log_dir: '/var/log/ceph:z',
+        data_dir: '/var/lib/ceph/' + daemon_type + '/ceph-' + daemon_id + ':z',
+    }
+    out = CephContainer(
+        image=args.image,
+        entrypoint='ceph-' + daemon_type,
+        args=['-i', daemon_id,
+              '-c', '/dev/null',
+              '-f', '-d',
+        ] + get_daemon_args(),
+        volume_mounts=mounts,
+    ).run()
+
+
+##################################
+
+def command_ls():
+    import prettytable
+    ls = []
+    print('write me')
+
+##################################
+
+parser = argparse.ArgumentParser(
+    description='Bootstrap Ceph daemons with systemd and containers.',
+    formatter_class=argparse.ArgumentDefaultsHelpFormatter)
+parser.add_argument(
+    '--image',
+    default=DEFAULT_IMAGE,
+    help='container image')
+parser.add_argument(
+    '--uid',
+    default=CEPH_USER_UID,
+    help='UID to use for new folders/files')
+parser.add_argument(
+    '--gid',
+    default=CEPH_USER_GID,
+    help='GID to use for new folders/files')
+parser.add_argument(
+    '--conf', '-c',
+    help='ceph conf file to incorporate')
+parser.add_argument(
+    '--data-dir',
+    default=DATA_DIR,
+    help='base directory for daemon data')
+parser.add_argument(
+    '--log-dir',
+    default=LOG_DIR,
+    help='base directory for daemon logs')
+subparsers = parser.add_subparsers(help='sub-command')
+
+parser_version = subparsers.add_parser(
+    'version', help='get ceph version from container')
+parser_version.set_defaults(func=command_version)
+
+parser_ls = subparsers.add_parser(
+    'ls', help='list daemon instances on this host')
+parser_ls.set_defaults(func=command_ls)
+
+parser_run = subparsers.add_parser(
+    'run', help='run a ceph daemon, in a container, in the foreground')
+parser_run.set_defaults(func=command_run)
+parser_run.add_argument(
+    '--name', '-n',
+    required=True,
+    help='daemon name (type.id)')
+parser_run.add_argument(
+    '--fsid',
+    required=True,
+    help='cluster FSID')
+
+parser_bootstrap = subparsers.add_parser(
+    'bootstrap', help='bootstrap a cluster (mon + mgr daemons)')
+parser_bootstrap.set_defaults(func=command_bootstrap)
+parser_bootstrap.add_argument(
+    '--mon-id',
+    required=False,
+    help='mon id (default: local hostname)')
+parser_bootstrap.add_argument(
+    '--mon-addrv',
+    help='mon IPs (e.g., [v2:localipaddr:3300,v1:localipaddr:6789])')
+parser_bootstrap.add_argument(
+    '--mon-ip',
+    help='mon IP')
+parser_bootstrap.add_argument(
+    '--mgr-id',
+    required=False,
+    help='mgr id (default: local hostname)')
+parser_bootstrap.add_argument(
+    '--fsid',
+    help='cluster FSID')
+parser_bootstrap.add_argument(
+    '--output-keyring',
+    help='location to write keyring file with new cluster admin and mon keys')
+parser_bootstrap.add_argument(
+    '--output-conf',
+    help='location to write conf file to connect to new cluster')
+
+args = parser.parse_args()
+
+if 'func' not in args:
+    sys.stderr.write('No command specified; pass -h or --help for usage\n')
+    sys.exit(1)
+r = args.func()
+if not r:
+    r = 0
+sys.exit(r)