Skip to content
Snippets Groups Projects
kolla_ceph_keyring.py 4.75 KiB
Newer Older
  • Learn to ignore specific revisions
  • #!/usr/bin/env python
    
    # Copyright 2018 99cloud
    #
    # Licensed under the Apache License, Version 2.0 (the "License");
    # you may not use this file except in compliance with the License.
    # You may obtain a copy of the License at
    #
    #     http://www.apache.org/licenses/LICENSE-2.0
    #
    # Unless required by applicable law or agreed to in writing, software
    # distributed under the License is distributed on an "AS IS" BASIS,
    # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    # See the License for the specific language governing permissions and
    # limitations under the License.
    
    import json
    
    import subprocess  # nosec
    
    
    DOCUMENTATION = '''
    ---
    module: kolla_ceph_keyring
    short_description: >
      Module for update ceph client keyring caps in kolla.
    description:
      - A module used to update ceph client keyring caps in kolla.
    options:
      name:
        description:
          - the client name in ceph
        required: True
        type: str
      container_name:
        description:
          - the ceph mon container name
        required: True
        default: ceph_mon
        type: str
      caps:
        description:
          - the ceph auth caps
        required: True
        type: dict
    author: Jeffrey Zhang
    '''
    
    EXAMPLES = '''
    - name: configure admin client caps
      kolla_ceph_keyring:
        name: client.admin
        container_name: ceph_mon
        caps:
    
          mon: 'allow *'
          osd: 'allow *'
          mgr: 'allow *'
    '''
    
    
    
    enoent_re = re.compile(r"\bENOENT\b")
    
    
    
    class CephKeyring(object):
        def __init__(self, name, caps, container_name='ceph_mon'):
            self.name = name
            self.caps = caps
            self.container_name = container_name
            self.changed = False
            self.message = None
    
        def _run(self, cmd):
            _prefix = ['docker', 'exec', self.container_name]
            cmd = _prefix + cmd
            proc = subprocess.Popen(cmd,  # nosec
                                    stdout=subprocess.PIPE,
                                    stderr=subprocess.PIPE)
            stdout, stderr = proc.communicate()
            retcode = proc.poll()
            if retcode != 0:
                output = 'stdout: "%s", stderr: "%s"' % (stdout, stderr)
                raise subprocess.CalledProcessError(retcode, cmd, output)
            return stdout
    
        def _format_caps(self):
            caps = []
            for obj in sorted(self.caps):
                caps.extend([obj, self.caps[obj]])
            return caps
    
        def parse_stdout(self, stdout):
            keyring = json.loads(stdout)
            # there should be only one element
            return keyring[0]
    
        def ensure_keyring(self):
            try:
                stdout = self.get_keyring()
    
            except subprocess.CalledProcessError as e:
                if e.returncode != 2 or not enoent_re.search(e.output):
                    # this is not a missing keyring case
                    raise
    
                # keyring doesn't exsit, try to create it
                stdout = self.create_keyring()
                self.changed = True
                self.message = 'ceph keyring for %s is created' % self.name
            keyring = self.parse_stdout(stdout)
            if keyring['caps'] != self.caps:
                self.update_caps()
                stdout = self.get_keyring()
                keyring = self.parse_stdout(stdout)
                self.changed = True
                self.message = 'ceph keyring for %s is updated' % self.name
            self.keyring = keyring
            return self.keyring
    
        def get_keyring(self):
            ceph_cmd = ['ceph', '--format', 'json', 'auth', 'get', self.name]
            return self._run(ceph_cmd)
    
        def update_caps(self):
            ceph_cmd = ['ceph', '--format', 'json', 'auth', 'caps', self.name]
            caps = self._format_caps()
            ceph_cmd.extend(caps)
            self._run(ceph_cmd)
    
        def create_keyring(self):
            ceph_cmd = ['ceph', '--format', 'json', 'auth',
                        'get-or-create', self.name]
            caps = self._format_caps()
            ceph_cmd.extend(caps)
            return self._run(ceph_cmd)
    
    
    def main():
        specs = dict(
            name=dict(type='str', required=True),
            container_name=dict(type='str', default='ceph_mon'),
            caps=dict(type='dict', required=True)
        )
        module = AnsibleModule(argument_spec=specs)  # noqa
        params = module.params
        ceph_keyring = CephKeyring(params['name'],
                                   params['caps'],
                                   params['container_name'])
        try:
            keyring = ceph_keyring.ensure_keyring()
            module.exit_json(changed=ceph_keyring.changed,
                             keyring=keyring,
                             message=ceph_keyring.message)
        except subprocess.CalledProcessError as ex:
            msg = ('Failed to call command: %s returncode: %s output: %s' %
                   (ex.cmd, ex.returncode, ex.output))
            module.fail_json(msg=msg)
    
    
    from ansible.module_utils.basic import *  # noqa
    if __name__ == "__main__":
        main()