@ -1,18 +1,16 @@
#!/usr/bin/python
#!/usr/bin/python
# -*- coding: utf-8 -*-
# -*- coding: utf-8 -*-
# (c) 2014, Taneli Leppä <taneli@crasman.fi>
# 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)
# 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
from __future__ import absolute_import , division , print_function
__metaclass__ = type
__metaclass__ = type
ANSIBLE_METADATA = { ' metadata_version ' : ' 1.1 ' ,
ANSIBLE_METADATA = { ' metadata_version ' : ' 1.1 ' ,
' status ' : [ ' preview ' ] ,
' status ' : [ ' preview ' ] ,
' supported_by ' : ' community ' }
' supported_by ' : ' community ' }
DOCUMENTATION = """
DOCUMENTATION = """
module : gluster_volume
module : gluster_volume
short_description : Manage GlusterFS volumes
short_description : Manage GlusterFS volumes
@ -22,75 +20,76 @@ version_added: '1.9'
options :
options :
name :
name :
description :
description :
- The volume name
- The volume name .
required : true
required : true
state :
state :
description :
description :
- Use present / absent ensure if a volume exists or not .
- Use present / absent ensure if a volume exists or not .
Use started / stopped to control its availability .
Use started / stopped to control its availability .
required : true
required : true
choices : [ ' present' , ' ab sent' , ' started ' , ' stopped ' ]
choices : [ ' absent' , ' pre sent' , ' started ' , ' stopped ' ]
cluster :
cluster :
description :
description :
- List of hosts to use for probing and brick setup
- List of hosts to use for probing and brick setup .
host :
host :
description :
description :
- Override local hostname ( for peer probing purposes )
- Override local hostname ( for peer probing purposes ) .
replicas :
replicas :
description :
description :
- Replica count for volume
- Replica count for volume .
arbiter :
arbiter :
description :
description :
- Arbiter count for volume
- Arbiter count for volume .
version_added : ' 2.3 '
version_added : ' 2.3 '
stripes :
stripes :
description :
description :
- Stripe count for volume
- Stripe count for volume .
disperses :
disperses :
description :
description :
- Disperse count for volume
- Disperse count for volume .
version_added : ' 2.2 '
version_added : ' 2.2 '
redundancies :
redundancies :
description :
description :
- Redundancy count for volume
- Redundancy count for volume .
version_added : ' 2.2 '
version_added : ' 2.2 '
transport :
transport :
description :
description :
- Transport type for volume
- Transport type for volume .
default : ' tcp '
default : tcp
choices : [ ' tcp ' , ' rdma ' , ' tcp,rdma ' ]
choices : [ rdma , tcp , tcp , rdma ]
bricks :
bricks :
description :
description :
- Brick paths on servers . Multiple brick paths can be separated by commas .
- Brick paths on servers . Multiple brick paths can be separated by commas .
aliases : [ ' brick ' ]
aliases : [ brick ]
start_on_create :
start_on_create :
description :
description :
- Controls whether the volume is started after creation or not
- Controls whether the volume is started after creation or not .
default : ' yes '
type : bool
type : bool
default : ' yes '
rebalance :
rebalance :
description :
description :
- Controls whether the cluster is rebalanced after changes
- Controls whether the cluster is rebalanced after changes .
default : ' no '
type : bool
type : bool
default : ' no '
directory :
directory :
description :
description :
- Directory for limit - usage
- Directory for limit - usage .
options :
options :
description :
description :
- A dictionary / hash with options / settings for the volume
- A dictionary / hash with options / settings for the volume .
quota :
quota :
description :
description :
- Quota value for limit - usage ( be sure to use 10.0 MB instead of 10 MB , see quota list )
- Quota value for limit - usage ( be sure to use 10.0 MB instead of 10 MB , see quota list ) .
force :
force :
description :
description :
- If brick is being created in the root partition , module will fail .
- If brick is being created in the root partition , module will fail .
Set force to true to override this behaviour .
Set force to true to override this behaviour .
type : bool
type : bool
notes :
notes :
- Requires cli tools for GlusterFS on servers
- Requires cli tools for GlusterFS on servers .
- Will add new bricks , but not remove them
- Will add new bricks , but not remove them .
author : Taneli Leppä ( @rosmo )
author :
- Taneli Leppä ( @rosmo )
"""
"""
EXAMPLES = """
EXAMPLES = """
@ -153,7 +152,6 @@ import traceback
from ansible . module_utils . basic import AnsibleModule
from ansible . module_utils . basic import AnsibleModule
from ansible . module_utils . _text import to_native
from ansible . module_utils . _text import to_native
glusterbin = ' '
glusterbin = ' '
@ -166,12 +164,13 @@ def run_gluster(gargs, **kwargs):
rc , out , err = module . run_command ( args , * * kwargs )
rc , out , err = module . run_command ( args , * * kwargs )
if rc != 0 :
if rc != 0 :
module . fail_json ( msg = ' error running gluster ( %s ) command (rc= %d ): %s ' %
module . fail_json ( msg = ' error running gluster ( %s ) command (rc= %d ): %s ' %
( ' ' . join ( args ) , rc , out or err ) , exception = traceback . format_exc ( ) )
( ' ' . join ( args ) , rc , out or err ) , exception = traceback . format_exc ( ) )
except Exception as e :
except Exception as e :
module . fail_json ( msg = ' error running gluster ( %s ) command: %s ' % ( ' ' . join ( args ) ,
module . fail_json ( msg = ' error running gluster ( %s ) command: %s ' % ( ' ' . join ( args ) ,
to_native ( e ) ) , exception = traceback . format_exc ( ) )
to_native ( e ) ) , exception = traceback . format_exc ( ) )
return out
return out
def run_gluster_nofail ( gargs , * * kwargs ) :
def run_gluster_nofail ( gargs , * * kwargs ) :
global glusterbin
global glusterbin
global module
global module
@ -182,8 +181,9 @@ def run_gluster_nofail(gargs, **kwargs):
return None
return None
return out
return out
def get_peers ( ) :
def get_peers ( ) :
out = run_gluster ( [ ' peer ' , ' status ' ] )
out = run_gluster ( [ ' peer ' , ' status ' ] )
peers = { }
peers = { }
hostname = None
hostname = None
uuid = None
uuid = None
@ -208,8 +208,9 @@ def get_peers():
shortNames = False
shortNames = False
return peers
return peers
def get_volumes ( ) :
def get_volumes ( ) :
out = run_gluster ( [ ' volume ' , ' info ' ] )
out = run_gluster ( [ ' volume ' , ' info ' ] )
volumes = { }
volumes = { }
volume = { }
volume = { }
@ -227,17 +228,17 @@ def get_volumes():
if key . lower ( ) == ' transport-type ' :
if key . lower ( ) == ' transport-type ' :
volume [ ' transport ' ] = value
volume [ ' transport ' ] = value
if value . lower ( ) . endswith ( ' (arbiter) ' ) :
if value . lower ( ) . endswith ( ' (arbiter) ' ) :
if not ' arbiters ' in volume :
if ' arbiters ' not in volume :
volume [ ' arbiters ' ] = [ ]
volume [ ' arbiters ' ] = [ ]
value = value [ : - 10 ]
value = value [ : - 10 ]
volume [ ' arbiters ' ] . append ( value )
volume [ ' arbiters ' ] . append ( value )
if key . lower ( ) != ' bricks ' and key . lower ( ) [ : 5 ] == ' brick ' :
if key . lower ( ) != ' bricks ' and key . lower ( ) [ : 5 ] == ' brick ' :
if not ' bricks ' in volume :
if ' bricks ' not in volume :
volume [ ' bricks ' ] = [ ]
volume [ ' bricks ' ] = [ ]
volume [ ' bricks ' ] . append ( value )
volume [ ' bricks ' ] . append ( value )
# Volume options
# Volume options
if ' . ' in key :
if ' . ' in key :
if not ' options ' in volume :
if ' options ' not in volume :
volume [ ' options ' ] = { }
volume [ ' options ' ] = { }
volume [ ' options ' ] [ key ] = value
volume [ ' options ' ] [ key ] = value
if key == ' features.quota ' and value == ' on ' :
if key == ' features.quota ' and value == ' on ' :
@ -249,20 +250,22 @@ def get_volumes():
volume = { }
volume = { }
return volumes
return volumes
def get_quotas ( name , nofail ) :
def get_quotas ( name , nofail ) :
quotas = { }
quotas = { }
if nofail :
if nofail :
out = run_gluster_nofail ( [ ' volume ' , ' quota ' , name , ' list ' ] )
out = run_gluster_nofail ( [ ' volume ' , ' quota ' , name , ' list ' ] )
if not out :
if not out :
return quotas
return quotas
else :
else :
out = run_gluster ( [ ' volume ' , ' quota ' , name , ' list ' ] )
out = run_gluster ( [ ' volume ' , ' quota ' , name , ' list ' ] )
for row in out . split ( ' \n ' ) :
for row in out . split ( ' \n ' ) :
if row [ : 1 ] == ' / ' :
if row [ : 1 ] == ' / ' :
q = re . split ( ' \ s+ ' , row )
q = re . split ( ' \ s+ ' , row )
quotas [ q [ 0 ] ] = q [ 1 ]
quotas [ q [ 0 ] ] = q [ 1 ]
return quotas
return quotas
def wait_for_peer ( host ) :
def wait_for_peer ( host ) :
for x in range ( 0 , 4 ) :
for x in range ( 0 , 4 ) :
peers = get_peers ( )
peers = get_peers ( )
@ -271,20 +274,23 @@ def wait_for_peer(host):
time . sleep ( 1 )
time . sleep ( 1 )
return False
return False
def probe ( host , myhostname ) :
def probe ( host , myhostname ) :
global module
global module
out = run_gluster ( [ ' peer ' , ' probe ' , host ] )
out = run_gluster ( [ ' peer ' , ' probe ' , host ] )
if out . find ( ' localhost ' ) == - 1 and not wait_for_peer ( 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 ) )
module . fail_json ( msg = ' failed to probe peer %s on %s ' % ( host , myhostname ) )
def probe_all_peers ( hosts , peers , myhostname ) :
def probe_all_peers ( hosts , peers , myhostname ) :
for host in hosts :
for host in hosts :
host = host . strip ( ) # Clean up any extra space for exact comparison
host = host . strip ( ) # Clean up any extra space for exact comparison
if host not in peers :
if host not in peers :
probe ( host , myhostname )
probe ( host , myhostname )
def create_volume ( name , stripe , replica , arbiter , disperse , redundancy , transport , hosts , bricks , force ) :
def create_volume ( name , stripe , replica , arbiter , disperse , redundancy , transport , hosts , bricks , force ) :
args = [ ' volume ' , ' create ' ]
args = [ ' volume ' , ' create ' ]
args . append ( name )
args . append ( name )
if stripe :
if stripe :
args . append ( ' stripe ' )
args . append ( ' stripe ' )
@ -310,17 +316,21 @@ def create_volume(name, stripe, replica, arbiter, disperse, redundancy, transpor
args . append ( ' force ' )
args . append ( ' force ' )
run_gluster ( args )
run_gluster ( args )
def start_volume ( name ) :
def start_volume ( name ) :
run_gluster ( [ ' volume ' , ' start ' , name ] )
run_gluster ( [ ' volume ' , ' start ' , name ] )
def stop_volume ( name ) :
def stop_volume ( name ) :
run_gluster ( [ ' volume ' , ' stop ' , name ] )
run_gluster ( [ ' volume ' , ' stop ' , name ] )
def set_volume_option ( name , option , parameter ) :
def set_volume_option ( name , option , parameter ) :
run_gluster ( [ ' volume ' , ' set ' , name , option , parameter ] )
run_gluster ( [ ' volume ' , ' set ' , name , option , parameter ] )
def add_bricks ( name , new_bricks , stripe , replica , force ) :
def add_bricks ( name , new_bricks , stripe , replica , force ) :
args = [ ' volume ' , ' add-brick ' , name ]
args = [ ' volume ' , ' add-brick ' , name ]
if stripe :
if stripe :
args . append ( ' stripe ' )
args . append ( ' stripe ' )
args . append ( str ( stripe ) )
args . append ( str ( stripe ) )
@ -332,41 +342,44 @@ def add_bricks(name, new_bricks, stripe, replica, force):
args . append ( ' force ' )
args . append ( ' force ' )
run_gluster ( args )
run_gluster ( args )
def do_rebalance ( name ) :
def do_rebalance ( name ) :
run_gluster ( [ ' volume ' , ' rebalance ' , name , ' start ' ] )
run_gluster ( [ ' volume ' , ' rebalance ' , name , ' start ' ] )
def enable_quota ( name ) :
def enable_quota ( name ) :
run_gluster ( [ ' volume ' , ' quota ' , name , ' enable ' ] )
run_gluster ( [ ' volume ' , ' quota ' , name , ' enable ' ] )
def set_quota ( name , directory , value ) :
def set_quota ( name , directory , value ) :
run_gluster ( [ ' volume ' , ' quota ' , name , ' limit-usage ' , directory , value ] )
run_gluster ( [ ' volume ' , ' quota ' , name , ' limit-usage ' , directory , value ] )
def main ( ) :
def main ( ) :
# ## MAIN ###
# MAIN
global module
global module
module = AnsibleModule (
module = AnsibleModule (
argument_spec = dict (
argument_spec = dict (
name = dict ( required = True , aliases = [ ' volume ' ] ) ,
name = dict ( type = ' str ' , required = True , aliases = [ ' volume ' ] ) ,
state = dict ( required = True , choices = [ ' present' , ' absent' , ' started ' , ' stopped ' ] ) ,
state = dict ( type = ' str ' , required = True , choices = [ ' absent' , ' started ' , ' stopped ' , ' present ' ] ) ,
cluster = dict ( default = None , type = ' list ' ) ,
cluster = dict ( type = ' list ' ) ,
host = dict ( default = None ) ,
host = dict ( type = ' str ' ) ,
stripes = dict ( default = None , type = ' int ' ) ,
stripes = dict ( type = ' int ' ) ,
replicas = dict ( default = None , type = ' int ' ) ,
replicas = dict ( type = ' int ' ) ,
arbiters = dict ( default = None , type = ' int ' ) ,
arbiters = dict ( type = ' int ' ) ,
disperses = dict ( default = None , type = ' int ' ) ,
disperses = dict ( type = ' int ' ) ,
redundancies = dict ( default = None , type = ' int ' ) ,
redundancies = dict ( type = ' int ' ) ,
transport = dict ( default = ' tcp ' , choices = [ ' tcp ' , ' rdma ' , ' tcp,rdma ' ] ) ,
transport = dict ( type = ' str ' , default = ' tcp ' , choices = [ ' tcp ' , ' rdma ' , ' tcp,rdma ' ] ) ,
bricks = dict ( default = None , aliases = [ ' brick ' ] ) ,
bricks = dict ( type = ' str ' , aliases = [ ' brick ' ] ) ,
start_on_create = dict ( default = True , type = ' bool ' ) ,
start_on_create = dict ( type = ' bool ' , default = True ) ,
rebalance = dict ( default = False , type = ' bool ' ) ,
rebalance = dict ( type = ' bool ' , default = False ) ,
options = dict ( default = { } , type = ' dict ' ) ,
options = dict ( type = ' dict ' , default = { } ) ,
quota = dict ( ) ,
quota = dict ( type = ' str ' ) ,
directory = dict ( default = None ) ,
directory = dict ( type = ' str ' ) ,
force = dict ( default = False , type = ' bool ' ) ,
force = dict ( type = ' bool ' , default = False ) ,
)
) ,
)
)
global glusterbin
global glusterbin
glusterbin = module . get_bin_path ( ' gluster ' , True )
glusterbin = module . get_bin_path ( ' gluster ' , True )
@ -375,7 +388,7 @@ def main():
action = module . params [ ' state ' ]
action = module . params [ ' state ' ]
volume_name = module . params [ ' name ' ]
volume_name = module . params [ ' name ' ]
cluster = module . params [ ' cluster ' ]
cluster = module . params [ ' cluster ' ]
brick_paths = module . params [ ' bricks ' ]
brick_paths = module . params [ ' bricks ' ]
stripes = module . params [ ' stripes ' ]
stripes = module . params [ ' stripes ' ]
replicas = module . params [ ' replicas ' ]
replicas = module . params [ ' replicas ' ]
@ -408,7 +421,6 @@ def main():
quota = module . params [ ' quota ' ]
quota = module . params [ ' quota ' ]
directory = module . params [ ' directory ' ]
directory = module . params [ ' directory ' ]
# get current state info
# get current state info
peers = get_peers ( )
peers = get_peers ( )
volumes = get_volumes ( )
volumes = get_volumes ( )
@ -421,7 +433,7 @@ def main():
if volume_name in volumes :
if volume_name in volumes :
if volumes [ volume_name ] [ ' status ' ] . lower ( ) != ' stopped ' :
if volumes [ volume_name ] [ ' status ' ] . lower ( ) != ' stopped ' :
stop_volume ( volume_name )
stop_volume ( volume_name )
run_gluster ( [ ' volume ' , ' delete ' , volume_name ] )
run_gluster ( [ ' volume ' , ' delete ' , volume_name ] )
changed = True
changed = True
if action == ' present ' :
if action == ' present ' :
@ -495,7 +507,7 @@ def main():
do_rebalance ( volume_name )
do_rebalance ( volume_name )
facts = { }
facts = { }
facts [ ' glusterfs ' ] = { ' peers ' : peers , ' volumes ' : volumes , ' quotas ' : quotas }
facts [ ' glusterfs ' ] = { ' peers ' : peers , ' volumes ' : volumes , ' quotas ' : quotas }
module . exit_json ( changed = changed , ansible_facts = facts )
module . exit_json ( changed = changed , ansible_facts = facts )