@ -89,9 +89,17 @@ options:
default : null
name :
description :
- identifier when working with a single instance . Will be deprecated in a future release .
Please ' instance_names ' instead .
- either a name of a single instance or when used with ' num_instances ' ,
the base name of a cluster of nodes
required : false
aliases : [ ' base_name ' ]
num_instances :
description :
- can be used with ' name ' , specifies
the number of nodes to provision using ' name '
as a base name
required : false
version_added : " 2.3 "
network :
description :
- name of the network , ' default ' will be used if not specified
@ -336,7 +344,7 @@ def get_instance_info(inst):
} )
def create_instances ( module , gce , instance_names ):
def create_instances ( module , gce , instance_names , number ):
""" Creates new instances. Attributes other than instance_names are picked
up from ' module '
@ -446,40 +454,62 @@ def create_instances(module, gce, instance_names):
module . fail_json ( msg = ' Missing required create instance variable ' ,
changed = False )
for name in instance_names :
pd = None
if lc_disks :
pd = lc_disks [ 0 ]
elif persistent_boot_disk :
gce_args = dict (
location = lc_zone ,
ex_network = network , ex_tags = tags , ex_metadata = metadata ,
ex_can_ip_forward = ip_forward ,
external_ip = instance_external_ip , ex_disk_auto_delete = disk_auto_delete ,
ex_service_accounts = ex_sa_perms
)
if preemptible is not None :
gce_args [ ' ex_preemptible ' ] = preemptible
if subnetwork is not None :
gce_args [ ' ex_subnetwork ' ] = subnetwork
if isinstance ( instance_names , str ) and not number :
instance_names = [ instance_names ]
if isinstance ( instance_names , str ) and number :
instance_responses = gce . ex_create_multiple_nodes ( instance_names , lc_machine_type ,
lc_image ( ) , number , * * gce_args )
for resp in instance_responses :
n = resp
if isinstance ( resp , libcloud . compute . drivers . gce . GCEFailedNode ) :
try :
n = gce . ex_get_node ( n . name , lc_zone )
except ResourceNotFoundError :
pass
else :
# Assure that at least one node has been created to set changed=True
changed = True
new_instances . append ( n )
else :
for instance in instance_names :
pd = None
if lc_disks :
pd = lc_disks [ 0 ]
elif persistent_boot_disk :
try :
pd = gce . ex_get_volume ( " %s " % instance , lc_zone )
except ResourceNotFoundError :
pd = gce . create_volume ( None , " %s " % instance , image = lc_image ( ) )
gce_args [ ' ex_boot_disk ' ] = pd
inst = None
try :
pd = gce . ex_get_volume ( " %s " % name , lc_zone )
inst = gce . ex_get_node ( instanc e, lc_zone )
except ResourceNotFoundError :
pd = gce . create_volume ( None , " %s " % name , image = lc_image ( ) )
gce_args = dict (
location = lc_zone ,
ex_network = network , ex_tags = tags , ex_metadata = metadata ,
ex_boot_disk = pd , ex_can_ip_forward = ip_forward ,
external_ip = instance_external_ip , ex_disk_auto_delete = disk_auto_delete ,
ex_service_accounts = ex_sa_perms
)
if preemptible is not None :
gce_args [ ' ex_preemptible ' ] = preemptible
if subnetwork is not None :
gce_args [ ' ex_subnetwork ' ] = subnetwork
inst = None
try :
inst = gce . ex_get_node ( name , lc_zone )
except ResourceNotFoundError :
inst = gce . create_node (
name , lc_machine_type , lc_image ( ) , * * gce_args
)
changed = True
except GoogleBaseError as e :
module . fail_json ( msg = ' Unexpected error attempting to create ' +
' instance %s , error: %s ' % ( name , e . value ) )
inst = gce . create_node (
instance , lc_machine_type , lc_image ( ) , * * gce_args
)
changed = True
except GoogleBaseError as e :
module . fail_json ( msg = ' Unexpected error attempting to create ' +
' instance %s , error: %s ' % ( instance , e . value ) )
if inst :
new_instances . append ( inst )
for inst in new_instances :
for i , lc_disk in enumerate ( lc_disks ) :
# Check whether the disk is already attached
if ( len ( inst . extra [ ' disks ' ] ) > i ) :
@ -502,9 +532,6 @@ def create_instances(module, gce, instance_names):
inst . extra [ ' disks ' ] . append (
{ ' source ' : lc_disk . extra [ ' selfLink ' ] , ' index ' : i } )
if inst :
new_instances . append ( inst )
instance_names = [ ]
instance_json_data = [ ]
for inst in new_instances :
@ -514,7 +541,7 @@ def create_instances(module, gce, instance_names):
return ( changed , instance_json_data , instance_names )
def change_instance_state ( module , gce , instance_names , zone_name, state ) :
def change_instance_state ( module , gce , instance_names , number, zone_name, state ) :
""" Changes the state of a list of instances. For example,
change from started to stopped , or started to absent .
@ -528,31 +555,46 @@ def change_instance_state(module, gce, instance_names, zone_name, state):
"""
changed = False
changed_instance_names = [ ]
for name in instance_names :
nodes = [ ]
state_instance_names = [ ]
if isinstance ( instance_names , str ) and number :
node_names = [ ' %s - %03d ' % ( instance_names , i ) for i in range ( number ) ]
elif isinstance ( instance_names , str ) and not number :
node_names = [ instance_names ]
else :
node_names = instance_names
for name in node_names :
inst = None
try :
inst = gce . ex_get_node ( name , zone_name )
except ResourceNotFoundError :
pass
state_instance_names . append ( name )
except Exception as e :
module . fail_json ( msg = unexpected_error_msg ( e ) , changed = False )
if inst and state in [ ' absent ' , ' deleted ' ] :
gce . destroy_node ( inst )
changed_instance_names . append ( inst . name )
changed = True
elif inst and state == ' started ' and \
inst . state == libcloud . compute . types . NodeState . STOPPED :
gce . ex_start_node ( inst )
changed_instance_names . append ( inst . name )
changed = True
elif inst and state in [ ' stopped ' , ' terminated ' ] and \
inst . state == libcloud . compute . types . NodeState . RUNNING :
gce . ex_stop_node ( inst )
changed_instance_names . append ( inst . name )
changed = True
return ( changed , changed_instance_names )
else :
nodes . append ( inst )
state_instance_names . append ( name )
if state in [ ' absent ' , ' deleted ' ] and number :
changed_nodes = gce . ex_destroy_multiple_nodes ( nodes ) or [ False ]
changed = reduce ( lambda x , y : x or y , changed_nodes )
else :
for node in nodes :
if state in [ ' absent ' , ' deleted ' ] :
gce . destroy_node ( node )
changed = True
elif state == ' started ' and \
node . state == libcloud . compute . types . NodeState . STOPPED :
gce . ex_start_node ( node )
changed = True
elif state in [ ' stopped ' , ' terminated ' ] and \
node . state == libcloud . compute . types . NodeState . RUNNING :
gce . ex_stop_node ( node )
changed = True
return ( changed , state_instance_names )
def main ( ) :
module = AnsibleModule (
@ -561,7 +603,8 @@ def main():
instance_names = dict ( ) ,
machine_type = dict ( default = ' n1-standard-1 ' ) ,
metadata = dict ( ) ,
name = dict ( ) ,
name = dict ( aliases = [ ' base_name ' ] ) ,
num_instances = dict ( type = ' int ' ) ,
network = dict ( default = ' default ' ) ,
subnetwork = dict ( ) ,
persistent_boot_disk = dict ( type = ' bool ' , default = False ) ,
@ -580,7 +623,8 @@ def main():
external_ip = dict ( default = ' ephemeral ' ) ,
disk_auto_delete = dict ( type = ' bool ' , default = True ) ,
preemptible = dict ( type = ' bool ' , default = None ) ,
)
) ,
mutually_exclusive = [ ( ' instance_names ' , ' name ' ) ]
)
if not HAS_PYTHON26 :
@ -595,6 +639,7 @@ def main():
machine_type = module . params . get ( ' machine_type ' )
metadata = module . params . get ( ' metadata ' )
name = module . params . get ( ' name ' )
number = module . params . get ( ' num_instances ' )
network = module . params . get ( ' network ' )
subnetwork = module . params . get ( ' subnetwork ' )
persistent_boot_disk = module . params . get ( ' persistent_boot_disk ' )
@ -605,13 +650,13 @@ def main():
preemptible = module . params . get ( ' preemptible ' )
changed = False
inames = [ ]
inames = None
if isinstance ( instance_names , list ) :
inames = instance_names
elif isinstance ( instance_names , str ) :
inames = instance_names . split ( ' , ' )
if name :
inames . append ( name )
inames = name
if not inames :
module . fail_json ( msg = ' Must specify a " name " or " instance_names " ' ,
changed = False )
@ -629,20 +674,20 @@ def main():
json_output = { ' zone ' : zone }
if state in [ ' absent ' , ' deleted ' , ' started ' , ' stopped ' , ' terminated ' ] :
json_output [ ' state ' ] = state
( changed , changed _instance_names) = change_instance_state (
module , gce , inames , zone, state )
( changed , state _instance_names) = change_instance_state (
module , gce , inames , number, zone, state )
# based on what user specified, return the same variable, although
# value could be different if an instance could not be destroyed
if instance_names :
json_output [ ' instance_names ' ] = changed _instance_names
if instance_names or name and number :
json_output [ ' instance_names ' ] = state _instance_names
elif name :
json_output [ ' name ' ] = name
elif state in [ ' active ' , ' present ' ] :
json_output [ ' state ' ] = ' present '
( changed , instance_data , instance_name_list ) = create_instances (
module , gce , inames )
module , gce , inames , number )
json_output [ ' instance_data ' ] = instance_data
if instance_names :
json_output [ ' instance_names ' ] = instance_name_list