summaryrefslogtreecommitdiff
path: root/lib/ansible/modules/storage/glusterfs
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ansible/modules/storage/glusterfs')
l---------lib/ansible/modules/storage/glusterfs/_gluster_heal_facts.py1
-rw-r--r--lib/ansible/modules/storage/glusterfs/gluster_heal_info.py204
-rw-r--r--lib/ansible/modules/storage/glusterfs/gluster_peer.py176
-rw-r--r--lib/ansible/modules/storage/glusterfs/gluster_volume.py611
4 files changed, 0 insertions, 992 deletions
diff --git a/lib/ansible/modules/storage/glusterfs/_gluster_heal_facts.py b/lib/ansible/modules/storage/glusterfs/_gluster_heal_facts.py
deleted file mode 120000
index e5a7565c18..0000000000
--- a/lib/ansible/modules/storage/glusterfs/_gluster_heal_facts.py
+++ /dev/null
@@ -1 +0,0 @@
-gluster_heal_info.py \ No newline at end of file
diff --git a/lib/ansible/modules/storage/glusterfs/gluster_heal_info.py b/lib/ansible/modules/storage/glusterfs/gluster_heal_info.py
deleted file mode 100644
index 0da1373b14..0000000000
--- a/lib/ansible/modules/storage/glusterfs/gluster_heal_info.py
+++ /dev/null
@@ -1,204 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright: (c) 2016, Red Hat, Inc.
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'}
-
-
-DOCUMENTATION = '''
----
-module: gluster_heal_info
-short_description: Gather information on self-heal or rebalance status
-author: "Devyani Kota (@devyanikota)"
-version_added: "2.8"
-description:
- - Gather facts about either self-heal or rebalance status.
- - This module was called C(gluster_heal_facts) before Ansible 2.9, returning C(ansible_facts).
- Note that the M(gluster_heal_info) module no longer returns C(ansible_facts)!
-options:
- name:
- description:
- - The volume name.
- required: true
- aliases: ['volume']
- status_filter:
- default: "self-heal"
- choices: ["self-heal", "rebalance"]
- description:
- - Determines which facts are to be returned.
- - If the C(status_filter) is C(self-heal), status of self-heal, along with the number of files still in process are returned.
- - If the C(status_filter) is C(rebalance), rebalance status is returned.
-requirements:
- - GlusterFS > 3.2
-'''
-
-EXAMPLES = '''
-- name: Gather self-heal facts about all gluster hosts in the cluster
- gluster_heal_info:
- name: test_volume
- status_filter: self-heal
- register: self_heal_status
-- debug:
- var: self_heal_status
-
-- name: Gather rebalance facts about all gluster hosts in the cluster
- gluster_heal_info:
- name: test_volume
- status_filter: rebalance
- register: rebalance_status
-- debug:
- var: rebalance_status
-'''
-
-RETURN = '''
-name:
- description: GlusterFS volume name
- returned: always
- type: str
-status_filter:
- description: Whether self-heal or rebalance status is to be returned
- returned: always
- type: str
-heal_info:
- description: List of files that still need healing process
- returned: On success
- type: list
-rebalance_status:
- description: Status of rebalance operation
- returned: On success
- type: list
-'''
-
-import traceback
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-from distutils.version import LooseVersion
-
-glusterbin = ''
-
-
-def run_gluster(gargs, **kwargs):
- global glusterbin
- global module
- args = [glusterbin, '--mode=script']
- args.extend(gargs)
- try:
- rc, out, err = module.run_command(args, **kwargs)
- if rc != 0:
- module.fail_json(msg='error running gluster (%s) command (rc=%d): %s' %
- (' '.join(args), rc, out or err), exception=traceback.format_exc())
- except Exception as e:
- module.fail_json(msg='error running gluster (%s) command: %s' % (' '.join(args),
- to_native(e)), exception=traceback.format_exc())
- return out
-
-
-def get_self_heal_status(name):
- out = run_gluster(['volume', 'heal', name, 'info'], environ_update=dict(LANG='C', LC_ALL='C', LC_MESSAGES='C'))
- raw_out = out.split("\n")
- heal_info = []
- # return files that still need healing.
- for line in raw_out:
- if 'Brick' in line:
- br_dict = {}
- br_dict['brick'] = line.strip().strip("Brick")
- elif 'Status' in line:
- br_dict['status'] = line.split(":")[1].strip()
- elif 'Number' in line:
- br_dict['no_of_entries'] = line.split(":")[1].strip()
- elif line.startswith('/') or line.startswith('<') or '\n' in line:
- continue
- else:
- br_dict and heal_info.append(br_dict)
- br_dict = {}
- return heal_info
-
-
-def get_rebalance_status(name):
- out = run_gluster(['volume', 'rebalance', name, 'status'], environ_update=dict(LANG='C', LC_ALL='C', LC_MESSAGES='C'))
- raw_out = out.split("\n")
- rebalance_status = []
- # return the files that are either still 'in progress' state or 'completed'.
- for line in raw_out:
- line = " ".join(line.split())
- line_vals = line.split(" ")
- if line_vals[0].startswith('-') or line_vals[0].startswith('Node'):
- continue
- node_dict = {}
- if len(line_vals) == 1 or len(line_vals) == 4:
- continue
- node_dict['node'] = line_vals[0]
- node_dict['rebalanced_files'] = line_vals[1]
- node_dict['failures'] = line_vals[4]
- if 'in progress' in line:
- node_dict['status'] = line_vals[5] + line_vals[6]
- rebalance_status.append(node_dict)
- elif 'completed' in line:
- node_dict['status'] = line_vals[5]
- rebalance_status.append(node_dict)
- return rebalance_status
-
-
-def is_invalid_gluster_version(module, required_version):
- cmd = module.get_bin_path('gluster', True) + ' --version'
- result = module.run_command(cmd)
- ver_line = result[1].split('\n')[0]
- version = ver_line.split(' ')[1]
- # If the installed version is less than 3.2, it is an invalid version
- # return True
- return LooseVersion(version) < LooseVersion(required_version)
-
-
-def main():
- global module
- global glusterbin
- module = AnsibleModule(
- argument_spec=dict(
- name=dict(type='str', required=True, aliases=['volume']),
- status_filter=dict(type='str', default='self-heal', choices=['self-heal', 'rebalance']),
- ),
- )
- is_old_facts = module._name == 'gluster_heal_facts'
- if is_old_facts:
- module.deprecate("The 'gluster_heal_facts' module has been renamed to 'gluster_heal_info', "
- "and the renamed one no longer returns ansible_facts", version='2.13')
-
- glusterbin = module.get_bin_path('gluster', True)
- required_version = "3.2"
- status_filter = module.params['status_filter']
- volume_name = module.params['name']
- heal_info = ''
- rebalance_status = ''
-
- # Verify if required GlusterFS version is installed
- if is_invalid_gluster_version(module, required_version):
- module.fail_json(msg="GlusterFS version > %s is required" %
- required_version)
-
- try:
- if status_filter == "self-heal":
- heal_info = get_self_heal_status(volume_name)
- elif status_filter == "rebalance":
- rebalance_status = get_rebalance_status(volume_name)
- except Exception as e:
- module.fail_json(msg='Error retrieving status: %s' % e, exception=traceback.format_exc())
-
- facts = {}
- facts['glusterfs'] = {'volume': volume_name, 'status_filter': status_filter, 'heal_info': heal_info, 'rebalance': rebalance_status}
-
- if is_old_facts:
- module.exit_json(ansible_facts=facts)
- else:
- module.exit_json(**facts)
-
-
-if __name__ == '__main__':
- main()
diff --git a/lib/ansible/modules/storage/glusterfs/gluster_peer.py b/lib/ansible/modules/storage/glusterfs/gluster_peer.py
deleted file mode 100644
index 987dc78b4c..0000000000
--- a/lib/ansible/modules/storage/glusterfs/gluster_peer.py
+++ /dev/null
@@ -1,176 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#
-# Copyright 2015 Nandaja Varma <nvarma@redhat.com>
-# Copyright 2018 Red Hat, Inc.
-#
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-#
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'}
-
-DOCUMENTATION = '''
----
-module: gluster_peer
-short_description: Attach/Detach peers to/from the cluster
-description:
- - Create or diminish a GlusterFS trusted storage pool. A set of nodes can be
- added into an existing trusted storage pool or a new storage pool can be
- formed. Or, nodes can be removed from an existing trusted storage pool.
-version_added: "2.6"
-author: Sachidananda Urs (@sac)
-options:
- state:
- choices: ["present", "absent"]
- default: "present"
- description:
- - Determines whether the nodes should be attached to the pool or
- removed from the pool. If the state is present, nodes will be
- attached to the pool. If state is absent, nodes will be detached
- from the pool.
- required: true
- nodes:
- description:
- - List of nodes that have to be probed into the pool.
- required: true
- force:
- type: bool
- default: "false"
- description:
- - Applicable only while removing the nodes from the pool. gluster
- will refuse to detach a node from the pool if any one of the node
- is down, in such cases force can be used.
-requirements:
- - GlusterFS > 3.2
-notes:
- - This module does not support check mode.
-'''
-
-EXAMPLES = '''
-- name: Create a trusted storage pool
- gluster_peer:
- state: present
- nodes:
- - 10.0.1.5
- - 10.0.1.10
-
-- name: Delete a node from the trusted storage pool
- gluster_peer:
- state: absent
- nodes:
- - 10.0.1.10
-
-- name: Delete a node from the trusted storage pool by force
- gluster_peer:
- state: absent
- nodes:
- - 10.0.0.1
- force: true
-'''
-
-RETURN = '''
-'''
-
-from ansible.module_utils.basic import AnsibleModule
-from distutils.version import LooseVersion
-
-
-class Peer(object):
- def __init__(self, module):
- self.module = module
- self.state = self.module.params['state']
- self.nodes = self.module.params['nodes']
- self.glustercmd = self.module.get_bin_path('gluster', True)
- self.lang = dict(LANG='C', LC_ALL='C', LC_MESSAGES='C')
- self.action = ''
- self.force = ''
-
- def gluster_peer_ops(self):
- if not self.nodes:
- self.module.fail_json(msg="nodes list cannot be empty")
- self.force = 'force' if self.module.params.get('force') else ''
- if self.state == 'present':
- self.nodes = self.get_to_be_probed_hosts(self.nodes)
- self.action = 'probe'
- # In case of peer probe, we do not need `force'
- self.force = ''
- else:
- self.action = 'detach'
- self.call_peer_commands()
-
- def get_to_be_probed_hosts(self, hosts):
- peercmd = [self.glustercmd, 'pool', 'list', '--mode=script']
- rc, output, err = self.module.run_command(peercmd,
- environ_update=self.lang)
- peers_in_cluster = [line.split('\t')[1].strip() for
- line in filter(None, output.split('\n')[1:])]
- try:
- peers_in_cluster.remove('localhost')
- except ValueError:
- # It is ok not to have localhost in list
- pass
- hosts_to_be_probed = [host for host in hosts if host not in
- peers_in_cluster]
- return hosts_to_be_probed
-
- def call_peer_commands(self):
- result = {}
- result['msg'] = ''
- result['changed'] = False
-
- for node in self.nodes:
- peercmd = [self.glustercmd, 'peer', self.action, node, '--mode=script']
- if self.force:
- peercmd.append(self.force)
- rc, out, err = self.module.run_command(peercmd,
- environ_update=self.lang)
- if rc:
- result['rc'] = rc
- result['msg'] = err
- # Fail early, do not wait for the loop to finish
- self.module.fail_json(**result)
- else:
- if 'already in peer' in out or \
- 'localhost not needed' in out:
- result['changed'] |= False
- else:
- result['changed'] = True
- self.module.exit_json(**result)
-
-
-def main():
- module = AnsibleModule(
- argument_spec=dict(
- force=dict(type='bool', required=False),
- nodes=dict(type='list', required=True),
- state=dict(type='str', choices=['absent', 'present'],
- default='present'),
- ),
- supports_check_mode=False
- )
- pops = Peer(module)
- required_version = "3.2"
- # Verify if required GlusterFS version is installed
- if is_invalid_gluster_version(module, required_version):
- module.fail_json(msg="GlusterFS version > %s is required" %
- required_version)
- pops.gluster_peer_ops()
-
-
-def is_invalid_gluster_version(module, required_version):
- cmd = module.get_bin_path('gluster', True) + ' --version'
- result = module.run_command(cmd)
- ver_line = result[1].split('\n')[0]
- version = ver_line.split(' ')[1]
- # If the installed version is less than 3.2, it is an invalid version
- # return True
- return LooseVersion(version) < LooseVersion(required_version)
-
-
-if __name__ == "__main__":
- main()
diff --git a/lib/ansible/modules/storage/glusterfs/gluster_volume.py b/lib/ansible/modules/storage/glusterfs/gluster_volume.py
deleted file mode 100644
index 30611e723b..0000000000
--- a/lib/ansible/modules/storage/glusterfs/gluster_volume.py
+++ /dev/null
@@ -1,611 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-
-# Copyright: (c) 2014, Taneli Leppä <taneli@crasman.fi>
-# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
-
-from __future__ import absolute_import, division, print_function
-__metaclass__ = type
-
-ANSIBLE_METADATA = {'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'}
-
-DOCUMENTATION = """
-module: gluster_volume
-short_description: Manage GlusterFS volumes
-description:
- - Create, remove, start, stop and tune GlusterFS volumes
-version_added: '1.9'
-options:
- name:
- description:
- - The volume name.
- required: true
- aliases: ['volume']
- state:
- description:
- - Use present/absent ensure if a volume exists or not.
- Use started/stopped to control its availability.
- required: true
- choices: ['absent', 'present', 'started', 'stopped']
- cluster:
- description:
- - List of hosts to use for probing and brick setup.
- host:
- description:
- - Override local hostname (for peer probing purposes).
- replicas:
- description:
- - Replica count for volume.
- arbiters:
- description:
- - Arbiter count for volume.
- version_added: '2.3'
- stripes:
- description:
- - Stripe count for volume.
- disperses:
- description:
- - Disperse count for volume.
- version_added: '2.2'
- redundancies:
- description:
- - Redundancy count for volume.
- version_added: '2.2'
- transport:
- description:
- - Transport type for volume.
- default: tcp
- choices: [ tcp, rdma, 'tcp,rdma' ]
- bricks:
- description:
- - Brick paths on servers. Multiple brick paths can be separated by commas.
- aliases: [ brick ]
- start_on_create:
- description:
- - Controls whether the volume is started after creation or not.
- type: bool
- default: 'yes'
- rebalance:
- description:
- - Controls whether the cluster is rebalanced after changes.
- type: bool
- default: 'no'
- directory:
- description:
- - Directory for limit-usage.
- options:
- description:
- - A dictionary/hash with options/settings for the volume.
- quota:
- description:
- - Quota value for limit-usage (be sure to use 10.0MB instead of 10MB, see quota list).
- force:
- description:
- - If brick is being created in the root partition, module will fail.
- Set force to true to override this behaviour.
- type: bool
-notes:
- - Requires cli tools for GlusterFS on servers.
- - Will add new bricks, but not remove them.
-author:
-- Taneli Leppä (@rosmo)
-"""
-
-EXAMPLES = """
-- name: create gluster volume
- gluster_volume:
- state: present
- name: test1
- bricks: /bricks/brick1/g1
- rebalance: yes
- cluster:
- - 192.0.2.10
- - 192.0.2.11
- run_once: true
-
-- name: tune
- gluster_volume:
- state: present
- name: test1
- options:
- performance.cache-size: 256MB
-
-- name: Set multiple options on GlusterFS volume
- gluster_volume:
- state: present
- name: test1
- options:
- { performance.cache-size: 128MB,
- write-behind: 'off',
- quick-read: 'on'
- }
-
-- name: start gluster volume
- gluster_volume:
- state: started
- name: test1
-
-- name: limit usage
- gluster_volume:
- state: present
- name: test1
- directory: /foo
- quota: 20.0MB
-
-- name: stop gluster volume
- gluster_volume:
- state: stopped
- name: test1
-
-- name: remove gluster volume
- gluster_volume:
- state: absent
- name: test1
-
-- name: create gluster volume with multiple bricks
- gluster_volume:
- state: present
- name: test2
- bricks: /bricks/brick1/g2,/bricks/brick2/g2
- cluster:
- - 192.0.2.10
- - 192.0.2.11
- run_once: true
-
-- name: Remove the bricks from gluster volume
- gluster_volume:
- state: present
- name: testvol
- bricks: /bricks/brick1/b1,/bricks/brick2/b2
- cluster:
- - 10.70.42.85
- force: true
- run_once: true
-
-- name: Reduce cluster configuration
- gluster_volume:
- state: present
- name: testvol
- bricks: /bricks/brick3/b1,/bricks/brick4/b2
- replicas: 2
- cluster:
- - 10.70.42.85
- force: true
- run_once: true
-"""
-
-import re
-import socket
-import time
-import traceback
-
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_native
-
-glusterbin = ''
-
-
-def run_gluster(gargs, **kwargs):
- global glusterbin
- global module
- args = [glusterbin, '--mode=script']
- args.extend(gargs)
- try:
- rc, out, err = module.run_command(args, **kwargs)
- if rc != 0:
- module.fail_json(msg='error running gluster (%s) command (rc=%d): %s' %
- (' '.join(args), rc, out or err), exception=traceback.format_exc())
- except Exception as e:
- module.fail_json(msg='error running gluster (%s) command: %s' % (' '.join(args),
- to_native(e)), exception=traceback.format_exc())
- return out
-
-
-def run_gluster_nofail(gargs, **kwargs):
- global glusterbin
- global module
- args = [glusterbin]
- args.extend(gargs)
- rc, out, err = module.run_command(args, **kwargs)
- if rc != 0:
- return None
- return out
-
-
-def get_peers():
- out = run_gluster(['peer', 'status'])
- peers = {}
- hostname = None
- uuid = None
- state = None
- shortNames = False
- for row in out.split('\n'):
- if ': ' in row:
- key, value = row.split(': ')
- if key.lower() == 'hostname':
- hostname = value
- shortNames = False
- if key.lower() == 'uuid':
- uuid = value
- if key.lower() == 'state':
- state = value
- peers[hostname] = [uuid, state]
- elif row.lower() == 'other names:':
- shortNames = True
- elif row != '' and shortNames is True:
- peers[row] = [uuid, state]
- elif row == '':
- shortNames = False
- return peers
-
-
-def get_volumes():
- out = run_gluster(['volume', 'info'])
-
- volumes = {}
- volume = {}
- for row in out.split('\n'):
- if ': ' in row:
- key, value = row.split(': ')
- if key.lower() == 'volume name':
- volume['name'] = value
- volume['options'] = {}
- volume['quota'] = False
- if key.lower() == 'volume id':
- volume['id'] = value
- if key.lower() == 'status':
- volume['status'] = value
- if key.lower() == 'transport-type':
- volume['transport'] = value
- if value.lower().endswith(' (arbiter)'):
- if 'arbiters' not in volume:
- volume['arbiters'] = []
- value = value[:-10]
- volume['arbiters'].append(value)
- elif key.lower() == 'number of bricks':
- volume['replicas'] = value[-1:]
- if key.lower() != 'bricks' and key.lower()[:5] == 'brick':
- if 'bricks' not in volume:
- volume['bricks'] = []
- volume['bricks'].append(value)
- # Volume options
- if '.' in key:
- if 'options' not in volume:
- volume['options'] = {}
- volume['options'][key] = value
- if key == 'features.quota' and value == 'on':
- volume['quota'] = True
- else:
- if row.lower() != 'bricks:' and row.lower() != 'options reconfigured:':
- if len(volume) > 0:
- volumes[volume['name']] = volume
- volume = {}
- return volumes
-
-
-def get_quotas(name, nofail):
- quotas = {}
- if nofail:
- out = run_gluster_nofail(['volume', 'quota', name, 'list'])
- if not out:
- return quotas
- else:
- out = run_gluster(['volume', 'quota', name, 'list'])
- for row in out.split('\n'):
- if row[:1] == '/':
- q = re.split(r'\s+', row)
- quotas[q[0]] = q[1]
- return quotas
-
-
-def wait_for_peer(host):
- for x in range(0, 4):
- peers = get_peers()
- if host in peers and peers[host][1].lower().find('peer in cluster') != -1:
- return True
- time.sleep(1)
- return False
-
-
-def probe(host, myhostname):
- global module
- out = run_gluster(['peer', 'probe', host])
- if out.find('localhost') == -1 and not wait_for_peer(host):
- module.fail_json(msg='failed to probe peer %s on %s' % (host, myhostname))
-
-
-def probe_all_peers(hosts, peers, myhostname):
- for host in hosts:
- host = host.strip() # Clean up any extra space for exact comparison
- if host not in peers:
- probe(host, myhostname)
-
-
-def create_volume(name, stripe, replica, arbiter, disperse, redundancy, transport, hosts, bricks, force):
- args = ['volume', 'create']
- args.append(name)
- if stripe:
- args.append('stripe')
- args.append(str(stripe))
- if replica:
- args.append('replica')
- args.append(str(replica))
- if arbiter:
- args.append('arbiter')
- args.append(str(arbiter))
- if disperse:
- args.append('disperse')
- args.append(str(disperse))
- if redundancy:
- args.append('redundancy')
- args.append(str(redundancy))
- args.append('transport')
- args.append(transport)
- for brick in bricks:
- for host in hosts:
- args.append(('%s:%s' % (host, brick)))
- if force:
- args.append('force')
- run_gluster(args)
-
-
-def start_volume(name):
- run_gluster(['volume', 'start', name])
-
-
-def stop_volume(name):
- run_gluster(['volume', 'stop', name])
-
-
-def set_volume_option(name, option, parameter):
- run_gluster(['volume', 'set', name, option, parameter])
-
-
-def add_bricks(name, new_bricks, stripe, replica, force):
- args = ['volume', 'add-brick', name]
- if stripe:
- args.append('stripe')
- args.append(str(stripe))
- if replica:
- args.append('replica')
- args.append(str(replica))
- args.extend(new_bricks)
- if force:
- args.append('force')
- run_gluster(args)
-
-
-def remove_bricks(name, removed_bricks, force):
- # max-tries=12 with default_interval=10 secs
- max_tries = 12
- retries = 0
- success = False
- args = ['volume', 'remove-brick', name]
- args.extend(removed_bricks)
- # create a copy of args to use for commit operation
- args_c = args[:]
- args.append('start')
- run_gluster(args)
- # remove-brick operation needs to be followed by commit operation.
- if not force:
- module.fail_json(msg="Force option is mandatory.")
- else:
- while retries < max_tries:
- last_brick = removed_bricks[-1]
- out = run_gluster(['volume', 'remove-brick', name, last_brick, 'status'])
- for row in out.split('\n')[1:]:
- if 'completed' in row:
- # remove-brick successful, call commit operation.
- args_c.append('commit')
- out = run_gluster(args_c)
- success = True
- break
- else:
- time.sleep(10)
- if success:
- break
- retries += 1
- if not success:
- # remove-brick still in process, needs to be committed after completion.
- module.fail_json(msg="Exceeded number of tries, check remove-brick status.\n"
- "Commit operation needs to be followed.")
-
-
-def reduce_config(name, removed_bricks, replicas, force):
- out = run_gluster(['volume', 'heal', name, 'info'])
- summary = out.split("\n")
- for line in summary:
- if 'Number' in line and int(line.split(":")[1].strip()) != 0:
- module.fail_json(msg="Operation aborted, self-heal in progress.")
- args = ['volume', 'remove-brick', name, 'replica', replicas]
- args.extend(removed_bricks)
- if force:
- args.append('force')
- else:
- module.fail_json(msg="Force option is mandatory")
- run_gluster(args)
-
-
-def do_rebalance(name):
- run_gluster(['volume', 'rebalance', name, 'start'])
-
-
-def enable_quota(name):
- run_gluster(['volume', 'quota', name, 'enable'])
-
-
-def set_quota(name, directory, value):
- run_gluster(['volume', 'quota', name, 'limit-usage', directory, value])
-
-
-def main():
- # MAIN
-
- global module
- module = AnsibleModule(
- argument_spec=dict(
- name=dict(type='str', required=True, aliases=['volume']),
- state=dict(type='str', required=True, choices=['absent', 'started', 'stopped', 'present']),
- cluster=dict(type='list'),
- host=dict(type='str'),
- stripes=dict(type='int'),
- replicas=dict(type='int'),
- arbiters=dict(type='int'),
- disperses=dict(type='int'),
- redundancies=dict(type='int'),
- transport=dict(type='str', default='tcp', choices=['tcp', 'rdma', 'tcp,rdma']),
- bricks=dict(type='str', aliases=['brick']),
- start_on_create=dict(type='bool', default=True),
- rebalance=dict(type='bool', default=False),
- options=dict(type='dict', default={}),
- quota=dict(type='str'),
- directory=dict(type='str'),
- force=dict(type='bool', default=False),
- ),
- )
-
- global glusterbin
- glusterbin = module.get_bin_path('gluster', True)
-
- changed = False
-
- action = module.params['state']
- volume_name = module.params['name']
- cluster = module.params['cluster']
- brick_paths = module.params['bricks']
- stripes = module.params['stripes']
- replicas = module.params['replicas']
- arbiters = module.params['arbiters']
- disperses = module.params['disperses']
- redundancies = module.params['redundancies']
- transport = module.params['transport']
- myhostname = module.params['host']
- start_on_create = module.boolean(module.params['start_on_create'])
- rebalance = module.boolean(module.params['rebalance'])
- force = module.boolean(module.params['force'])
-
- if not myhostname:
- myhostname = socket.gethostname()
-
- # Clean up if last element is empty. Consider that yml can look like this:
- # cluster="{% for host in groups['glusterfs'] %}{{ hostvars[host]['private_ip'] }},{% endfor %}"
- if cluster is not None and len(cluster) > 1 and cluster[-1] == '':
- cluster = cluster[0:-1]
-
- if cluster is None:
- cluster = []
-
- if brick_paths is not None and "," in brick_paths:
- brick_paths = brick_paths.split(",")
- else:
- brick_paths = [brick_paths]
-
- options = module.params['options']
- quota = module.params['quota']
- directory = module.params['directory']
-
- # get current state info
- peers = get_peers()
- volumes = get_volumes()
- quotas = {}
- if volume_name in volumes and volumes[volume_name]['quota'] and volumes[volume_name]['status'].lower() == 'started':
- quotas = get_quotas(volume_name, True)
-
- # do the work!
- if action == 'absent':
- if volume_name in volumes:
- if volumes[volume_name]['status'].lower() != 'stopped':
- stop_volume(volume_name)
- run_gluster(['volume', 'delete', volume_name])
- changed = True
-
- if action == 'present':
- probe_all_peers(cluster, peers, myhostname)
-
- # create if it doesn't exist
- if volume_name not in volumes:
- create_volume(volume_name, stripes, replicas, arbiters, disperses, redundancies, transport, cluster, brick_paths, force)
- volumes = get_volumes()
- changed = True
-
- if volume_name in volumes:
- if volumes[volume_name]['status'].lower() != 'started' and start_on_create:
- start_volume(volume_name)
- changed = True
-
- # switch bricks
- new_bricks = []
- removed_bricks = []
- all_bricks = []
- bricks_in_volume = volumes[volume_name]['bricks']
-
- for node in cluster:
- for brick_path in brick_paths:
- brick = '%s:%s' % (node, brick_path)
- all_bricks.append(brick)
- if brick not in bricks_in_volume:
- new_bricks.append(brick)
-
- if not new_bricks and len(all_bricks) > 0 and \
- len(all_bricks) < len(bricks_in_volume):
- for brick in bricks_in_volume:
- if brick not in all_bricks:
- removed_bricks.append(brick)
-
- if new_bricks:
- add_bricks(volume_name, new_bricks, stripes, replicas, force)
- changed = True
-
- if removed_bricks:
- if replicas and int(replicas) < int(volumes[volume_name]['replicas']):
- reduce_config(volume_name, removed_bricks, str(replicas), force)
- else:
- remove_bricks(volume_name, removed_bricks, force)
- changed = True
-
- # handle quotas
- if quota:
- if not volumes[volume_name]['quota']:
- enable_quota(volume_name)
- quotas = get_quotas(volume_name, False)
- if directory not in quotas or quotas[directory] != quota:
- set_quota(volume_name, directory, quota)
- changed = True
-
- # set options
- for option in options.keys():
- if option not in volumes[volume_name]['options'] or volumes[volume_name]['options'][option] != options[option]:
- set_volume_option(volume_name, option, options[option])
- changed = True
-
- else:
- module.fail_json(msg='failed to create volume %s' % volume_name)
-
- if action != 'absent' and volume_name not in volumes:
- module.fail_json(msg='volume not found %s' % volume_name)
-
- if action == 'started':
- if volumes[volume_name]['status'].lower() != 'started':
- start_volume(volume_name)
- changed = True
-
- if action == 'stopped':
- if volumes[volume_name]['status'].lower() != 'stopped':
- stop_volume(volume_name)
- changed = True
-
- if changed:
- volumes = get_volumes()
- if rebalance:
- do_rebalance(volume_name)
-
- facts = {}
- facts['glusterfs'] = {'peers': peers, 'volumes': volumes, 'quotas': quotas}
-
- module.exit_json(changed=changed, ansible_facts=facts)
-
-
-if __name__ == '__main__':
- main()