@ -28,7 +28,7 @@ options:
required: true
required: true
default: null
default: null
aliases: []
aliases: []
choices: [ 'create', 'replicate', 'delete', 'facts', 'modify' , 'promote' ]
choices: [ 'create', 'replicate', 'delete', 'facts', 'modify' , 'promote', 'snapshot', 'restore' ]
instance_name:
instance_name:
description:
description:
- Database instance identifier.
- Database instance identifier.
@ -56,7 +56,7 @@ options:
aliases: []
aliases: []
instance_type:
instance_type:
description:
description:
- The instance type of the database. Must be specified when command=create. Optional when command=replicate or command=modify . If not specified then the replica inherits the same instance type as the source instance.
- The instance type of the database. Must be specified when command=create. Optional when command=replicate, command=modify or command=restore . If not specified then the replica inherits the same instance type as the source instance.
required: false
required: false
default: null
default: null
aliases: []
aliases: []
@ -99,7 +99,7 @@ options:
aliases: []
aliases: []
license_model:
license_model:
description:
description:
- The license model for this DB instance. Used only when command=create.
- The license model for this DB instance. Used only when command=create or command=restore .
required: false
required: false
default: null
default: null
aliases: []
aliases: []
@ -162,7 +162,7 @@ options:
aliases: []
aliases: []
zone:
zone:
description:
description:
- availability zone in which to launch the instance. Used only when command=create or command=replicat e.
- availability zone in which to launch the instance. Used only when command=create, command=replicate or command=restor e.
required: false
required: false
default: null
default: null
aliases: ['aws_zone', 'ec2_zone']
aliases: ['aws_zone', 'ec2_zone']
@ -174,7 +174,7 @@ options:
aliases: []
aliases: []
snapshot:
snapshot:
description:
description:
- Name of final snapshot to take when deleting an instance. I f no snapshot name is provided then no snapshot is taken. Used only when command=delete.
- Name of snapshot to take. When command=delete, i f no snapshot name is provided then no snapshot is taken. Used only when command=delete or command=snapshot .
required: false
required: false
default: null
default: null
aliases: []
aliases: []
@ -192,7 +192,7 @@ options:
aliases: [ 'ec2_access_key', 'access_key' ]
aliases: [ 'ec2_access_key', 'access_key' ]
wait:
wait:
description:
description:
- When command=create, replicate, or modify then wait for the database to enter the 'available' state. When command=delete wait for the database to be terminated.
- When command=create, replicate, modify or restore then wait for the database to enter the 'available' state. When command=delete wait for the database to be terminated.
required: false
required: false
default: "no"
default: "no"
choices: [ "yes", "no" ]
choices: [ "yes", "no" ]
@ -268,10 +268,18 @@ except ImportError:
print "failed=True msg='boto required for this module'"
print "failed=True msg='boto required for this module'"
sys.exit(1)
sys.exit(1)
def get_current_resource(conn, resource, command):
# There will be exceptions but we want the calling code to handle them
if command == 'snapshot':
return conn.get_all_dbsnapshots(snapshot_id=resource)[0]
else:
return conn.get_all_dbinstances(resource)[0]
def main():
def main():
module = AnsibleModule(
module = AnsibleModule(
argument_spec = dict(
argument_spec = dict(
command = dict(choices=['create', 'replicate', 'delete', 'facts', 'modify', 'promote'], required=True),
command = dict(choices=['create', 'replicate', 'delete', 'facts', 'modify', 'promote', 'snapshot', 'restore' ], required=True),
instance_name = dict(required=True),
instance_name = dict(required=True),
source_instance = dict(required=False),
source_instance = dict(required=False),
db_engine = dict(choices=['MySQL', 'oracle-se1', 'oracle-se', 'oracle-ee', 'sqlserver-ee', 'sqlserver-se', 'sqlserver-ex', 'sqlserver-web', 'postgres'], required=False),
db_engine = dict(choices=['MySQL', 'oracle-se1', 'oracle-se', 'oracle-ee', 'sqlserver-ee', 'sqlserver-se', 'sqlserver-ex', 'sqlserver-web', 'postgres'], required=False),
@ -374,6 +382,14 @@ def main():
required_vars = [ 'instance_name' ]
required_vars = [ 'instance_name' ]
invalid_vars = [ 'db_engine', 'size', 'username', 'password', 'db_name', 'engine_version', 'parameter_group', 'license_model', 'multi_zone', 'iops', 'security_groups', 'option_group', 'maint_window', 'subnet', 'source_instance', 'snapshot', 'apply_immediately', 'new_instance_name' ]
invalid_vars = [ 'db_engine', 'size', 'username', 'password', 'db_name', 'engine_version', 'parameter_group', 'license_model', 'multi_zone', 'iops', 'security_groups', 'option_group', 'maint_window', 'subnet', 'source_instance', 'snapshot', 'apply_immediately', 'new_instance_name' ]
elif command == 'snapshot':
required_vars = [ 'instance_name', 'snapshot']
invalid_vars = [ 'db_engine', 'size', 'username', 'password', 'db_name', 'engine_version', 'parameter_group', 'license_model', 'multi_zone', 'iops', 'security_groups', 'option_group', 'maint_window', 'subnet', 'source_instance', 'apply_immediately', 'new_instance_name' ]
elif command == 'restore':
required_vars = [ 'instance_name', 'snapshot', 'instance_type' ]
invalid_vars = [ 'db_engine', 'db_name', 'usernmae', 'password', 'engine_version', 'option_group', 'source_instance', 'apply_immediately', 'new_instance_name' ]
for v in required_vars:
for v in required_vars:
if not module.params.get(v):
if not module.params.get(v):
module.fail_json(msg = str("Parameter %s required for %s command" % (v, command)))
module.fail_json(msg = str("Parameter %s required for %s command" % (v, command)))
@ -439,49 +455,86 @@ def main():
if new_instance_name:
if new_instance_name:
params["new_instance_id"] = new_instance_name
params["new_instance_id"] = new_instance_name
try:
changed = True
if command == 'create':
db = conn.create_dbinstance(instance_name, size, instance_type, username, password, **params)
if command in ['create', 'restore', 'facts']:
elif command == 'replicate':
try:
if instance_type:
result = conn.get_all_dbinstances(instance_name)[0]
params["instance_class"] = instance_type
changed = False
db = conn.create_dbinstance_read_replica(instance_name, source_instance, **params)
except boto.exception.BotoServerError, e:
elif command == 'delete':
try:
if command == 'create':
result = conn.create_dbinstance(instance_name, size, instance_type, username, password, **params)
if command == 'restore':
result = conn.restore_dbinstance_from_dbsnapshot(snapshot, instance_name, instance_type, **params)
if command == 'facts':
module.fail_json(msg = "DB Instance %s does not exist" % instance_name)
except boto.exception.BotoServerError, e:
module.fail_json(msg = e.error_message)
if command == 'snapshot':
try:
result = conn.get_all_dbsnapshots(snapshot)[0]
changed = False
except boto.exception.BotoServerError, e:
try:
result = conn.create_dbsnapshot(snapshot, instance_name)
except boto.exception.BotoServerError, e:
module.fail_json(msg = e.error_message)
if command == 'delete':
try:
result = conn.get_all_dbinstances(instance_name)[0]
if result.status == 'deleting':
module.exit_json(changed=False)
except boto.exception.BotoServerError, e:
module.exit_json(changed=False)
try:
if snapshot:
if snapshot:
params["skip_final_snapshot"] = False
params["skip_final_snapshot"] = False
params["final_snapshot_id"] = snapshot
params["final_snapshot_id"] = snapshot
else:
else:
params["skip_final_snapshot"] = True
params["skip_final_snapshot"] = True
result = conn.delete_dbinstance(instance_name, **params)
except boto.exception.BotoServerError, e:
module.fail_json(msg = e.error_message)
if command == 'replicate':
try:
if instance_type:
params["instance_class"] = instance_type
result = conn.create_dbinstance_read_replica(instance_name, source_instance, **params)
except boto.exception.BotoServerError, e:
module.fail_json(msg = e.error_message)
db = conn.delete_dbinstance(instance_name, **params)
if command == 'modify':
elif command == 'modify':
try :
params["apply_immediately"] = apply_immediately
params["apply_immediately"] = apply_immediately
db = conn.modify_dbinstance(instance_name, **params)
result = conn.modify_dbinstance(instance_name, **params)
if apply_immediately:
except boto.exception.BotoServerError, e:
if new_instance_name:
module.fail_json(msg = e.error_message)
# Wait until the new instance name is valid
if apply_immediately:
found = 0
if new_instance_name:
while found == 0:
# Wait until the new instance name is valid
instances = conn.get_all_dbinstances()
found = 0
for i in instances:
while found == 0:
if i.id == new_instance_name:
instances = conn.get_all_dbinstances()
instance_name = new_instance_name
for i in instances:
found = 1
if i.id == new_instance_name:
if found == 0:
instance_name = new_instance_name
time.sleep(5)
found = 1
else:
if found == 0:
# Wait for a few seconds since it takes a while for AWS
time.sleep(5)
# to change the instance from 'available' to 'modifying'
else:
time.sleep(5)
# Wait for a few seconds since it takes a while for AWS
# to change the instance from 'available' to 'modifying'
elif command == 'promote':
time.sleep(5)
db = conn.promote_read_replica(instance_name, **params)
# Don't do anything for the 'facts' command since we'll just drop down
# to get_all_dbinstances below to collect the facts
except boto.exception.BotoServerError, e:
if command == 'promote':
module.fail_json(msg = e.error_message)
try:
result = conn.promote_read_replica(instance_name, **params)
except boto.exception.BotoServerError, e:
module.fail_json(msg = e.error_message)
# If we're not waiting for a delete to complete then we're all done
# If we're not waiting for a delete to complete then we're all done
# so just return
# so just return
@ -489,24 +542,21 @@ def main():
module.exit_json(changed=True)
module.exit_json(changed=True)
try:
try:
instances = conn.get_all_dbinstances(instance_name)
resource = get_current_resource(conn, result.id, command)
my_inst = instances[0]
except boto.exception.BotoServerError, e:
except boto.exception.BotoServerError, e:
module.fail_json(msg = e.error_message)
module.fail_json(msg = e.error_message)
# Wait for the resource to be available if requested
# Wait for the instance to be available if requested
if wait:
if wait:
try:
try:
wait_timeout = time.time() + wait_timeout
wait_timeout = time.time() + wait_timeout
time.sleep(5)
time.sleep(5)
while wait_timeout > time.time() and my_inst .status != 'available':
while wait_timeout > time.time() and resource .status != 'available':
time.sleep(5)
time.sleep(5)
if wait_timeout <= time.time():
if wait_timeout <= time.time():
module.fail_json(msg = "Timeout waiting for database instance %s" % instance_name)
module.fail_json(msg = "Timeout waiting for resource %s" % resource.id)
instances = conn.get_all_dbinstances(instance_name)
resource = get_current_resource(conn, result.id, command)
my_inst = instances[0]
except boto.exception.BotoServerError, e:
except boto.exception.BotoServerError, e:
# If we're waiting for an instance to be deleted then
# If we're waiting for an instance to be deleted then
# get_all_dbinstances will eventually throw a
# get_all_dbinstances will eventually throw a
@ -518,35 +568,52 @@ def main():
# If we got here then pack up all the instance details to send
# If we got here then pack up all the instance details to send
# back to ansible
# back to ansible
if command == 'snapshot':
d = {
'id' : resource.id,
'create_time' : resource.snapshot_create_time,
'status' : resource.status,
'availability_zone' : resource.availability_zone,
'instance_id' : resource.instance_id,
'instance_created' : resource.instance_create_time,
}
try:
d["snapshot_type"] = resource.snapshot_type
d["iops"] = resource.iops
except AttributeError, e:
pass # needs boto >= 2.21.0
return module.exit_json(changed=changed, snapshot=d)
d = {
d = {
'id' : my_inst.id,
'id' : resource .id,
'create_time' : my_inst.create_time,
'create_time' : resource .create_time,
'status' : my_inst.status,
'status' : resource .status,
'availability_zone' : my_inst.availability_zone,
'availability_zone' : resource .availability_zone,
'backup_retention' : my_inst.backup_retention_period,
'backup_retention' : resource .backup_retention_period,
'backup_window' : my_inst.preferred_backup_window,
'backup_window' : resource .preferred_backup_window,
'maintenance_window' : my_inst.preferred_maintenance_window,
'maintenance_window' : resource .preferred_maintenance_window,
'multi_zone' : my_inst.multi_az,
'multi_zone' : resource .multi_az,
'instance_type' : my_inst.instance_class,
'instance_type' : resource .instance_class,
'username' : my_inst.master_username,
'username' : resource .master_username,
'iops' : my_inst.iops
'iops' : resource .iops
}
}
# Endpoint exists only if the instance is available
# Endpoint exists only if the instance is available
if my_inst.status == 'available':
if resource.status == 'available' and command != 'snapshot ':
d["endpoint"] = my_inst.endpoint[0]
d["endpoint"] = resource .endpoint[0]
d["port"] = my_inst .endpoint[1]
d["port"] = resource .endpoint[1]
else:
else:
d["endpoint"] = None
d["endpoint"] = None
d["port"] = None
d["port"] = None
# ReadReplicaSourceDBInstanceIdentifier may or may not exist
# ReadReplicaSourceDBInstanceIdentifier may or may not exist
try:
try:
d["replication_source"] = my_inst .ReadReplicaSourceDBInstanceIdentifier
d["replication_source"] = resource .ReadReplicaSourceDBInstanceIdentifier
except Exception, e:
except Exception, e:
d["replication_source"] = None
d["replication_source"] = None
module.exit_json(changed=True , instance=d)
module.exit_json(changed=changed , instance=d)
# import module snippets
# import module snippets
from ansible.module_utils.basic import *
from ansible.module_utils.basic import *