From 61b4a1bedcf7259f4ee00af9297754e0edd7bf0c Mon Sep 17 00:00:00 2001 From: Andrew Schoen Date: Fri, 1 Dec 2017 07:25:13 -0600 Subject: [PATCH] adds a ceph_volume module This module uses ceph-volume to create OSDs. Currently it only supports the 'lvm' subcommand and 'create'. Signed-off-by: Andrew Schoen --- library/ceph_volume.py | 212 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 212 insertions(+) create mode 100644 library/ceph_volume.py diff --git a/library/ceph_volume.py b/library/ceph_volume.py new file mode 100644 index 000000000..9b1ad24c9 --- /dev/null +++ b/library/ceph_volume.py @@ -0,0 +1,212 @@ +#!/usr/bin/python +import datetime + +ANSIBLE_METADATA = { + 'metadata_version': '1.0', + 'status': ['preview'], + 'supported_by': 'community' +} + +DOCUMENTATION = ''' +--- +module: ceph_volume + +short_description: Create ceph OSDs with ceph-volume + +description: + - Using the ceph-volume utility available in Ceph this module + can be used to create ceph OSDs that are backed by logical volumes. + - Only available in ceph versions luminous or greater. + +options: + subcommand: + description: + - The ceph-volume subcommand to use. + required: false + default: lvm + choices: ['lvm'] + objectstore: + description: + - The objectstore of the OSD, either filestore or bluestore + required: true + choices: ['bluestore', 'filestore'] + data: + description: + - The logical volume name or device to use for the OSD data. + required: true + data_vg: + description: + - If data is a lv, this must be the name of the volume group it belongs to. + required: false + journal: + description: + - The logical volume name or partition to use as a filestore journal. + - Only applicable if objectstore is 'filestore'. + required: false + journal_vg: + description: + - If journal is a lv, this must be the name of the volume group it belongs to. + - Only applicable if objectstore is 'filestore'. + required: false + db: + description: + - A partition or logical volume name to use for block.db. + - Only applicable if objectstore is 'bluestore'. + required: false + db_vg: + description: + - If db is a lv, this must be the name of the volume group it belongs to. + - Only applicable if objectstore is 'bluestore'. + required: false + wal: + description: + - A partition or logical volume name to use for block.wal. + - Only applicable if objectstore is 'bluestore'. + required: false + wal_vg: + description: + - If wal is a lv, this must be the name of the volume group it belongs to. + - Only applicable if objectstore is 'bluestore'. + required: false + + +author: + - Andrew Schoen (@andrewschoen) +''' + +EXAMPLES = ''' +- name: set up a filestore osd with an lv data and a journal partition + ceph_volume: + objectstore: filestore + data: data-lv + data_vg: data-vg + journal: /dev/sdc1 + +- name: set up a bluestore osd with a raw device for data + ceph_volume: + objectstore: bluestore + data: /dev/sdc + +- name: set up a bluestore osd with an lv for data and partitions for block.wal and block.db + ceph_volume: + objectstore: bluestore + data: data-lv + data_vg: data-vg + db: /dev/sdc1 + wal: /dev/sdc2 +''' + + +from ansible.module_utils.basic import AnsibleModule + + +def run_module(): + module_args = dict( + subcommand=dict(type='str', required=False, default='lvm'), + objectstore=dict(type='str', required=True), + data=dict(type='str', required=True), + data_vg=dict(type='str', required=False), + journal=dict(type='str', required=False), + journal_vg=dict(type='str', required=False), + db=dict(type='str', required=False), + db_vg=dict(type='str', required=False), + wal=dict(type='str', required=False), + wal_vg=dict(type='str', required=False), + ) + + module = AnsibleModule( + argument_spec=module_args, + supports_check_mode=True + ) + + subcommand = module.params['subcommand'] + objectstore = module.params['objectstore'] + data = module.params['data'] + data_vg = module.params.get('data_vg', None) + journal = module.params.get('journal', None) + journal_vg = module.params.get('journal_vg', None) + db = module.params.get('db', None) + db_vg = module.params.get('db_vg', None) + wal = module.params.get('wal', None) + wal_vg = module.params.get('wal_vg', None) + + cmd = [ + 'ceph-volume', + subcommand, + 'create', + '--%s' % objectstore, + '--data', + ] + + if data_vg: + data = "{0}/{1}".format(data_vg, data) + + cmd.append(data) + + if journal: + if journal_vg: + journal = "{0}/{1}".format(journal_vg, journal) + cmd.extend(["--journal", journal]) + + if db: + if db_vg: + db = "{0}/{1}".format(db_vg, db) + cmd.extend(["--block.db", db]) + + if wal: + if wal_vg: + wal = "{0}/{1}".format(wal_vg, wal) + cmd.extend(["--block.wal", wal]) + + result = dict( + changed=False, + cmd=cmd, + stdout='', + stderr='', + rc='', + start='', + end='', + delta='', + ) + + if module.check_mode: + return result + + # check to see if osd already exists + # FIXME: this does not work when data is a raw device + rc, out, err = module.run_command(["ceph-volume", "lvm", "list", data], encoding=None) + if rc == 0: + result["stdout"] = "skipped, since {0} is already used for an osd".format(data) + result['rc'] = 0 + module.exit_json(**result) + + startd = datetime.datetime.now() + + rc, out, err = module.run_command(cmd, encoding=None) + + endd = datetime.datetime.now() + delta = endd - startd + + result = dict( + cmd=cmd, + stdout=out.rstrip(b"\r\n"), + stderr=err.rstrip(b"\r\n"), + rc=rc, + start=str(startd), + end=str(endd), + delta=str(delta), + changed=True, + ) + + if rc != 0: + module.fail_json(msg='non-zero return code', **result) + + module.exit_json(**result) + + +def main(): + run_module() + + +if __name__ == '__main__': + main()