tripleo-ansible/tripleo_ansible/ansible_plugins/modules/ceph_mkspec.py

280 lines
7.4 KiB
Python

# Copyright 2020, Red Hat, Inc.
#
# 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.
from __future__ import absolute_import, division, print_function
from ansible.module_utils.basic import AnsibleModule
try:
from ansible.module_utils.ca_common import is_containerized, \
exec_command, generate_ceph_cmd, exit_module
except ImportError:
from tripleo_ansible.ansible_plugins.module_utils.ca_common import is_containerized, \
exec_command, generate_ceph_cmd, exit_module
try:
from ansible.module_utils import ceph_spec
except ImportError:
from tripleo_ansible.ansible_plugins.module_utils import ceph_spec
import datetime
import json
import os
import stat
import time
import yaml
__metaclass__ = type
ANSIBLE_METADATA = {
'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'
}
DOCUMENTATION = """
---
module: ceph_mkspec
short_description: Build cephadm spec
version_added: "2.8"
description:
- Build a cephadm compatible spec, rendering the daemon specified
options:
cluster:
description:
- The ceph cluster name.
required: false
default: ceph
type: str
service_type:
description:
- The Ceph daemon that is going to be applied
required: true
type: str
choices: ['host', 'mon', 'osd', 'mds', 'rgw', 'nfs', 'node-exporter', 'prometheus', 'alertmanager', 'grafana']
service_id:
description:
- The ID associated to the Ceph daemon
required: false
type: str
service_name:
description:
- The name of the Ceph Daemon
required: false
type: str
hosts:
description:
- The host list where the daemon is going to be applied
required: false
type: list
host_pattern:
description:
- The host pattern where the daemon is going to be applied
required: false
type: str
networks:
description:
- The list of networks on the host where the daemon is bound.
required: false
type: list
labels:
description:
- The list of labels used to apply the daemon on the Ceph custer
nodes.
required: false
type: list
spec:
description:
- The spec definition of the daemon
type: dict
required: false
extra:
description:
- The extra top level key definition for the daemon
type: dict
required: false
render_path:
description:
- Where the spec will be rendered
type: str
required: false
apply:
description:
- If truem the spec rendered will be applied by the orchestrator
type: bool
required: false
default: false
"""
EXAMPLES = '''
- name: create the Ceph MDS daemon spec
ceph_spec:
service_type: mds
service_id: mds
service_name: mds
render_path: '/home/ceph-admin/specs'
hosts:
- host1
- host2
- hostN
apply: true
- name: create the Ceph MDS daemon spec
ceph_spec:
service_type: mds
service_id: mds
service_name: mds
host_pattern: "*mon*"
apply: false
- name: create the Ceph MDS daemon spec
ceph_spec:
service_type: mds
service_id: mds
service_name: mds
render_path: '/home/ceph-admin/specs'
labels:
- "controller"
apply: true
- name: create the Ceph RGW daemon spec
ceph_spec:
service_type: rgw
service_id: rgw.default
service_name: rgw.default
networks:
- 1.2.3.0/24
- 4.5.6.0/24
render_path: '/home/ceph-admin/specs'
labels:
- "controller"
apply: true
'''
RETURN = '''# '''
ALLOWED_DAEMONS = ['host', 'mon', 'mgr', 'mds', 'nfs', 'osd', 'rgw', 'grafana',
'crash', 'prometheus', 'alertmanager', 'node-exporter']
def generate_orch_cli(cluster, spec_path, container_image):
args = ['apply', '--in-file', spec_path]
cmd = generate_ceph_cmd(sub_cmd=['orch'], args=args,
spec_path=spec_path, cluster=cluster,
container_image=container_image)
return cmd
def render(path, content):
if len(content) > 0:
if path is not None and len(path) > 0:
with open(path, 'w') as f:
f.write('---\n')
f.write(yaml.safe_dump(content, indent=2))
else:
print('Nothing to dump!')
def repr_str(dumper, data):
if '\n' in data:
return dumper.represent_scalar(u'tag:yaml.org,2002:str', data, style='|')
return dumper.org_represent_str(data)
yaml.SafeDumper.org_represent_str = yaml.SafeDumper.represent_str
yaml.add_representer(str, repr_str, Dumper=yaml.SafeDumper)
def run_module():
module = AnsibleModule(
argument_spec=yaml.safe_load(DOCUMENTATION)['options'],
supports_check_mode=True,
required_if=[['apply', True, ['render_path']]],
)
# Gather module parameters in variables
cluster = module.params.get('cluster')
service_type = module.params.get('service_type')
service_id = module.params.get('service_type')
service_name = module.params.get('service_name')
hosts = module.params.get('hosts')
host_pattern = module.params.get('host_pattern')
networks = module.params.get('networks')
labels = module.params.get('labels')
spec = module.params.get('spec')
extra = module.params.get('extra')
apply = module.params.get('apply')
render_path = module.params.get('render_path')
if module.check_mode:
module.exit_json(
changed=False,
stdout='',
stderr='',
rc=0,
start='',
end='',
delta='',
)
startd = datetime.datetime.now()
changed = False
# PROCESSING PARAMETERS
if service_id is None:
service_id = service_type
if service_name is None:
service_name = "{}.{}".format(service_type, service_id)
# no spec is provided
if spec is None:
spec = {}
# no spec is provided
if extra is None:
extra = {}
# no labels are defined
if labels is None:
labels = []
# no networks are defined
if networks is None:
networks = []
d = ceph_spec.CephDaemonSpec(service_type, service_id, service_name,
hosts, host_pattern, networks, spec, labels, **extra)
if apply:
container_image = is_containerized()
render('{}/{}'.format(render_path, service_type), d.make_daemon_spec())
cmd = generate_orch_cli(cluster, '{}/{}'.format(render_path, service_type), container_image)
rc, cmd, out, err = exec_command(module, cmd)
exit_module(module=module, out=out, rc=rc, cmd=cmd, err=err, startd=startd, changed=changed)
else:
# render the dict as the output of the module
module.exit_json(changed=True, result=d.make_daemon_spec())
def main():
run_module()
if __name__ == '__main__':
main()