Merge remote-tracking branch 'upstream/devel' into devel

reviewable/pr18780/r1
tobbe 9 years ago
commit 75fed6e6d8

@ -144,7 +144,7 @@ options:
instance_tags:
version_added: "1.0"
description:
- a hash/dictionary of tags to add to the new instance; '{"key":"value"}' and '{"key":"value","key":"value"}'
- a hash/dictionary of tags to add to the new instance or for for starting/stopping instance by tag; '{"key":"value"}' and '{"key":"value","key":"value"}'
required: false
default: null
aliases: []
@ -446,6 +446,15 @@ EXAMPLES = '''
vpc_subnet_id: subnet-29e63245
assign_public_ip: yes
#
# Start stopped instances specified by tag
#
- local_action:
module: ec2
instance_tags:
Name: ExtraPower
state: running
#
# Enforce that 5 instances with a tag "foo" are running
# (Highly recommended!)
@ -824,6 +833,9 @@ def create_instances(module, ec2, vpc, override_count=None):
vpc_id = None
if vpc_subnet_id:
if not vpc:
module.fail_json(msg="region must be specified")
else:
vpc_id = vpc.get_all_subnets(subnet_ids=[vpc_subnet_id])[0].vpc_id
else:
vpc_id = None
@ -1146,7 +1158,7 @@ def terminate_instances(module, ec2, instance_ids):
return (changed, instance_dict_array, terminated_instance_ids)
def startstop_instances(module, ec2, instance_ids, state):
def startstop_instances(module, ec2, instance_ids, state, instance_tags):
"""
Starts or stops a list of existing instances
@ -1154,6 +1166,8 @@ def startstop_instances(module, ec2, instance_ids, state):
ec2: authenticated ec2 connection object
instance_ids: The list of instances to start in the form of
[ {id: <inst-id>}, ..]
instance_tags: A dict of tag keys and values in the form of
{key: value, ... }
state: Intended state ("running" or "stopped")
Returns a dictionary of instance information
@ -1162,6 +1176,8 @@ def startstop_instances(module, ec2, instance_ids, state):
If the instance was not able to change state,
"changed" will be set to False.
Note that if instance_ids and instance_tags are both non-empty,
this method will process the intersection of the two
"""
wait = module.params.get('wait')
@ -1170,11 +1186,23 @@ def startstop_instances(module, ec2, instance_ids, state):
instance_dict_array = []
if not isinstance(instance_ids, list) or len(instance_ids) < 1:
# Fail unless the user defined instance tags
if not instance_tags:
module.fail_json(msg='instance_ids should be a list of instances, aborting')
# To make an EC2 tag filter, we need to prepend 'tag:' to each key.
# An empty filter does no filtering, so it's safe to pass it to the
# get_all_instances method even if the user did not specify instance_tags
filters = {}
if instance_tags:
for key, value in instance_tags.items():
filters["tag:" + key] = value
# Check that our instances are not in the state we want to take
# Check (and eventually change) instances attributes and instances state
running_instances_array = []
for res in ec2.get_all_instances(instance_ids):
for res in ec2.get_all_instances(instance_ids, filters=filters):
for inst in res.instances:
# Check "source_dest_check" attribute
@ -1281,7 +1309,7 @@ def main():
except boto.exception.NoAuthHandlerFound, e:
module.fail_json(msg = str(e))
else:
module.fail_json(msg="region must be specified")
vpc = None
tagged_instances = []
@ -1295,11 +1323,12 @@ def main():
(changed, instance_dict_array, new_instance_ids) = terminate_instances(module, ec2, instance_ids)
elif state in ('running', 'stopped'):
instance_ids = module.params['instance_ids']
if not instance_ids:
module.fail_json(msg='instance_ids list is requried for %s state' % state)
instance_ids = module.params.get('instance_ids')
instance_tags = module.params.get('instance_tags')
if not (isinstance(instance_ids, list) or isinstance(instance_tags, dict)):
module.fail_json(msg='running list needs to be a list of instances or set of tags to run: %s' % instance_ids)
(changed, instance_dict_array, new_instance_ids) = startstop_instances(module, ec2, instance_ids, state)
(changed, instance_dict_array, new_instance_ids) = startstop_instances(module, ec2, instance_ids, state, instance_tags)
elif state == 'present':
# Changed is always set to true when provisioning new instances

@ -126,6 +126,13 @@ options:
version_added: "1.9"
default: yes
required: False
termination_policies:
description:
- An ordered list of criteria used for selecting instances to be removed from the Auto Scaling group when reducing capacity.
required: false
default: Default. Eg, when used to create a new autoscaling group, the Default value is used. When used to change an existent autoscaling group, the current termination policies are mantained
choices: ['OldestInstance', 'NewestInstance', 'OldestLaunchConfiguration', 'ClosestToNextInstanceHour', 'Default']
version_added: "2.0"
extends_documentation_fragment: aws
"""
@ -421,7 +428,8 @@ def create_autoscaling_group(connection, module):
tags=asg_tags,
health_check_period=health_check_period,
health_check_type=health_check_type,
default_cooldown=default_cooldown)
default_cooldown=default_cooldown,
termination_policies=termination_policies)
try:
connection.create_auto_scaling_group(ag)
@ -783,7 +791,8 @@ def main():
health_check_period=dict(type='int', default=300),
health_check_type=dict(default='EC2', choices=['EC2', 'ELB']),
default_cooldown=dict(type='int', default=300),
wait_for_instances=dict(type='bool', default=True)
wait_for_instances=dict(type='bool', default=True),
termination_policies=dict(type='list', default=None)
),
)

@ -22,10 +22,12 @@ description:
- This module associates AWS EC2 elastic IP addresses with instances
version_added: "1.4"
options:
instance_id:
device_id:
description:
- The EC2 instance id
- The id of the device for the EIP. Can be an EC2 Instance id or Elastic Network Interface (ENI) id.
required: false
aliases: [ instance_id ]
version_added: "2.0"
public_ip:
description:
- The elastic IP address to associate with the instance.
@ -56,9 +58,15 @@ options:
required: false
default: false
version_added: "1.6"
release_on_disassociation:
description:
- whether or not to automatically release the EIP when it is disassociated
required: false
default: false
version_added: "2.0"
extends_documentation_fragment: aws
author: "Lorin Hochstein (@lorin) <lorin@nimbisservices.com>"
author: "Rick Mendes (@rickmendes) <rmendes@illumina.com>"
notes:
- This module will return C(public_ip) on success, which will contain the
public IP address associated with the instance.
@ -66,35 +74,36 @@ notes:
the cloud instance is reachable via the new address. Use wait_for and
pause to delay further playbook execution until the instance is reachable,
if necessary.
- This module returns multiple changed statuses on disassociation or release.
It returns an overall status based on any changes occuring. It also returns
individual changed statuses for disassociation and release.
'''
EXAMPLES = '''
- name: associate an elastic IP with an instance
ec2_eip: instance_id=i-1212f003 ip=93.184.216.119
ec2_eip: device_id=i-1212f003 ip=93.184.216.119
- name: associate an elastic IP with a device
ec2_eip: device_id=eni-c8ad70f3 ip=93.184.216.119
- name: disassociate an elastic IP from an instance
ec2_eip: instance_id=i-1212f003 ip=93.184.216.119 state=absent
ec2_eip: device_id=i-1212f003 ip=93.184.216.119 state=absent
- name: disassociate an elastic IP with a device
ec2_eip: device_id=eni-c8ad70f3 ip=93.184.216.119 state=absent
- name: allocate a new elastic IP and associate it with an instance
ec2_eip: instance_id=i-1212f003
ec2_eip: device_id=i-1212f003
- name: allocate a new elastic IP without associating it to anything
action: ec2_eip
register: eip
- name: output the IP
debug: msg="Allocated IP is {{ eip.public_ip }}"
- name: another way of allocating an elastic IP without associating it to anything
ec2_eip: state='present'
- name: provision new instances with ec2
ec2: keypair=mykey instance_type=c1.medium image=emi-40603AD1 wait=yes'''
''' group=webserver count=3
register: ec2
- name: associate new elastic IPs with each of the instances
ec2_eip: "instance_id={{ item }}"
ec2_eip: "device_id={{ item }}"
with_items: ec2.instance_ids
- name: allocate a new elastic IP inside a VPC in us-west-2
ec2_eip: region=us-west-2 in_vpc=yes
register: eip
@ -112,27 +121,27 @@ except ImportError:
class EIPException(Exception):
pass
def associate_ip_and_instance(ec2, address, instance_id, check_mode):
if address_is_associated_with_instance(ec2, address, instance_id):
def associate_ip_and_device(ec2, address, device_id, check_mode, isinstance=True):
if address_is_associated_with_device(ec2, address, device_id, isinstance):
return {'changed': False}
# If we're in check mode, nothing else to do
if not check_mode:
if address.domain == 'vpc':
res = ec2.associate_address(instance_id,
allocation_id=address.allocation_id)
if isinstance:
if address.domain == "vpc":
res = ec2.associate_address(device_id, allocation_id=address.allocation_id)
else:
res = ec2.associate_address(device_id, public_ip=address.public_ip)
else:
res = ec2.associate_address(instance_id,
public_ip=address.public_ip)
res = ec2.associate_address(network_interface_id=device_id, allocation_id=address.allocation_id)
if not res:
raise EIPException('association failed')
return {'changed': True}
def disassociate_ip_and_instance(ec2, address, instance_id, check_mode):
if not address_is_associated_with_instance(ec2, address, instance_id):
def disassociate_ip_and_device(ec2, address, device_id, check_mode, isinstance=True):
if not address_is_associated_with_device(ec2, address, device_id, isinstance):
return {'changed': False}
# If we're in check mode, nothing else to do
@ -157,24 +166,33 @@ def _find_address_by_ip(ec2, public_ip):
raise
def _find_address_by_instance_id(ec2, instance_id):
addresses = ec2.get_all_addresses(None, {'instance-id': instance_id})
def _find_address_by_device_id(ec2, device_id, isinstance=True):
if isinstance:
addresses = ec2.get_all_addresses(None, {'instance-id': device_id})
else:
addresses = ec2.get_all_addresses(None, {'network-interface-id': device_id})
if addresses:
return addresses[0]
def find_address(ec2, public_ip, instance_id):
def find_address(ec2, public_ip, device_id, isinstance=True):
""" Find an existing Elastic IP address """
if public_ip:
return _find_address_by_ip(ec2, public_ip)
elif instance_id:
return _find_address_by_instance_id(ec2, instance_id)
elif device_id and isinstance:
return _find_address_by_device_id(ec2, device_id)
elif device_id:
return _find_address_by_device_id(ec2, device_id, isinstance=False)
def address_is_associated_with_instance(ec2, address, instance_id):
""" Check if the elastic IP is currently associated with the instance """
def address_is_associated_with_device(ec2, address, device_id, isinstance=True):
""" Check if the elastic IP is currently associated with the device """
address = ec2.get_all_addresses(address.public_ip)
if address:
return address and address.instance_id == instance_id
if isinstance:
return address and address[0].instance_id == device_id
else:
return address and address[0].network_interface_id == device_id
return False
@ -185,7 +203,7 @@ def allocate_address(ec2, domain, reuse_existing_ip_allowed):
all_addresses = ec2.get_all_addresses(filters=domain_filter)
unassociated_addresses = [a for a in all_addresses
if not a.instance_id]
if not a.device_id]
if unassociated_addresses:
return unassociated_addresses[0]
@ -203,21 +221,33 @@ def release_address(ec2, address, check_mode):
return {'changed': True}
def find_instance(ec2, instance_id):
def find_device(ec2, device_id, isinstance=True):
""" Attempt to find the EC2 instance and return it """
reservations = ec2.get_all_reservations(instance_ids=[instance_id])
if isinstance:
try:
reservations = ec2.get_all_reservations(instance_ids=[device_id])
except boto.exception.EC2ResponseError, e:
module.fail_json(msg=str(e))
if len(reservations) == 1:
instances = reservations[0].instances
if len(instances) == 1:
return instances[0]
else:
try:
interfaces = ec2.get_all_network_interfaces(network_interface_ids=[device_id])
except boto.exception.EC2ResponseError, e:
module.fail_json(msg=str(e))
if len(interfaces) == 1:
return interfaces[0]
raise EIPException("could not find instance" + instance_id)
raise EIPException("could not find instance" + device_id)
def ensure_present(ec2, domain, address, instance_id,
reuse_existing_ip_allowed, check_mode):
def ensure_present(ec2, domain, address, device_id,
reuse_existing_ip_allowed, check_mode, isinstance=True):
changed = False
# Return the EIP object since we've been given a public IP
@ -228,28 +258,39 @@ def ensure_present(ec2, domain, address, instance_id,
address = allocate_address(ec2, domain, reuse_existing_ip_allowed)
changed = True
if instance_id:
if device_id:
# Allocate an IP for instance since no public_ip was provided
instance = find_instance(ec2, instance_id)
if isinstance:
instance = find_device(ec2, device_id)
# Associate address object (provided or allocated) with instance
assoc_result = associate_ip_and_device(ec2, address, device_id,
check_mode)
else:
instance = find_device(ec2, device_id, isinstance=False)
# Associate address object (provided or allocated) with instance
assoc_result = associate_ip_and_device(ec2, address, device_id,
check_mode, isinstance=False)
if instance.vpc_id:
domain = 'vpc'
# Associate address object (provided or allocated) with instance
assoc_result = associate_ip_and_instance(ec2, address, instance_id,
check_mode)
changed = changed or assoc_result['changed']
return {'changed': changed, 'public_ip': address.public_ip}
def ensure_absent(ec2, domain, address, instance_id, check_mode):
def ensure_absent(ec2, domain, address, device_id, check_mode, isinstance=True):
if not address:
return {'changed': False}
# disassociating address from instance
if instance_id:
return disassociate_ip_and_instance(ec2, address, instance_id,
if device_id:
if isinstance:
return disassociate_ip_and_device(ec2, address, device_id,
check_mode)
else:
return disassociate_ip_and_device(ec2, address, device_id,
check_mode, isinstance=False)
# releasing address
else:
return release_address(ec2, address, check_mode)
@ -258,13 +299,14 @@ def ensure_absent(ec2, domain, address, instance_id, check_mode):
def main():
argument_spec = ec2_argument_spec()
argument_spec.update(dict(
instance_id=dict(required=False),
device_id=dict(required=False, aliases=['instance_id']),
public_ip=dict(required=False, aliases=['ip']),
state=dict(required=False, default='present',
choices=['present', 'absent']),
in_vpc=dict(required=False, type='bool', default=False),
reuse_existing_ip_allowed=dict(required=False, type='bool',
default=False),
release_on_disassociation=dict(required=False, type='bool', default=False),
wait_timeout=dict(default=300),
))
@ -278,28 +320,52 @@ def main():
ec2 = ec2_connect(module)
instance_id = module.params.get('instance_id')
device_id = module.params.get('device_id')
public_ip = module.params.get('public_ip')
state = module.params.get('state')
in_vpc = module.params.get('in_vpc')
domain = 'vpc' if in_vpc else None
reuse_existing_ip_allowed = module.params.get('reuse_existing_ip_allowed')
release_on_disassociation = module.params.get('release_on_disassociation')
if device_id and device_id.startswith('i-'):
is_instance=True
elif device_id:
is_instance=False
try:
address = find_address(ec2, public_ip, instance_id)
if device_id:
address = find_address(ec2, public_ip, device_id, isinstance=is_instance)
else:
address = False
if state == 'present':
result = ensure_present(ec2, domain, address, instance_id,
if device_id:
result = ensure_present(ec2, domain, address, device_id,
reuse_existing_ip_allowed,
module.check_mode)
module.check_mode, isinstance=is_instance)
else:
result = ensure_absent(ec2, domain, address, instance_id, module.check_mode)
address = allocate_address(ec2, domain, reuse_existing_ip_allowed)
result = {'changed': True, 'public_ip': address.public_ip}
else:
if device_id:
disassociated = ensure_absent(ec2, domain, address, device_id, module.check_mode, isinstance=is_instance)
if release_on_disassociation and disassociated['changed']:
released = release_address(ec2, address, module.check_mode)
result = { 'changed': True, 'disassociated': disassociated, 'released': released }
else:
result = { 'changed': disassociated['changed'], 'disassociated': disassociated, 'released': { 'changed': False } }
else:
address = find_address(ec2, public_ip, None)
released = release_address(ec2, address, module.check_mode)
result = { 'changed': released['changed'], 'disassociated': { 'changed': False }, 'released': released }
except (boto.exception.EC2ResponseError, EIPException) as e:
module.fail_json(msg=str(e))
module.exit_json(**result)
# import module snippets
from ansible.module_utils.basic import * # noqa
from ansible.module_utils.ec2 import * # noqa

@ -573,8 +573,8 @@ class ElbManager(object):
# N.B. string manipulations on protocols below (str(), upper()) is to
# ensure format matches output from ELB API
listener_list = [
listener['load_balancer_port'],
listener['instance_port'],
int(listener['load_balancer_port']),
int(listener['instance_port']),
str(listener['protocol'].upper()),
]

@ -124,7 +124,7 @@ options:
version_added: "2.0"
classic_link_vpc_security_groups:
description:
- A list of security group ids with which to associate the ClassicLink VPC instances.
- A list of security group id's with which to associate the ClassicLink VPC instances.
required: false
default: null
version_added: "2.0"

@ -146,6 +146,7 @@ EXAMPLES = '''
# Example: Launch an instance and then add a volume if not already attached
# * Volume will be created with the given name if not already created.
# * Nothing will happen if the volume is already attached.
# * Requires Ansible 2.0
- ec2:
keypair: "{{ keypair }}"

@ -610,16 +610,16 @@ def await_resource(conn, resource, status, module):
while wait_timeout > time.time() and resource.status != status:
time.sleep(5)
if wait_timeout <= time.time():
module.fail_json(msg="Timeout waiting for resource %s" % resource.id)
module.fail_json(msg="Timeout waiting for RDS resource %s" % resource.name)
if module.params.get('command') == 'snapshot':
# Temporary until all the rds2 commands have their responses parsed
if resource.name is None:
module.fail_json(msg="Problem with snapshot %s" % resource.snapshot)
module.fail_json(msg="There was a problem waiting for RDS snapshot %s" % resource.snapshot)
resource = conn.get_db_snapshot(resource.name)
else:
# Temporary until all the rds2 commands have their responses parsed
if resource.name is None:
module.fail_json(msg="Problem with instance %s" % resource.instance)
module.fail_json(msg="There was a problem waiting for RDS instance %s" % resource.instance)
resource = conn.get_db_instance(resource.name)
if resource is None:
break
@ -653,7 +653,7 @@ def create_db_instance(module, conn):
module.params.get('username'), module.params.get('password'), **params)
changed = True
except RDSException, e:
module.fail_json(msg="failed to create instance: %s" % e.message)
module.fail_json(msg="Failed to create instance: %s" % e.message)
if module.params.get('wait'):
resource = await_resource(conn, result, 'available', module)
@ -680,7 +680,7 @@ def replicate_db_instance(module, conn):
result = conn.create_db_instance_read_replica(instance_name, source_instance, **params)
changed = True
except RDSException, e:
module.fail_json(msg="failed to create replica instance: %s " % e.message)
module.fail_json(msg="Failed to create replica instance: %s " % e.message)
if module.params.get('wait'):
resource = await_resource(conn, result, 'available', module)
@ -719,7 +719,7 @@ def delete_db_instance_or_snapshot(module, conn):
else:
result = conn.delete_db_snapshot(snapshot)
except RDSException, e:
module.fail_json(msg="failed to delete instance: %s" % e.message)
module.fail_json(msg="Failed to delete instance: %s" % e.message)
# If we're not waiting for a delete to complete then we're all done
# so just return
@ -745,11 +745,11 @@ def facts_db_instance_or_snapshot(module, conn):
snapshot = module.params.get('snapshot')
if instance_name and snapshot:
module.fail_json(msg="facts must be called with either instance_name or snapshot, not both")
module.fail_json(msg="Facts must be called with either instance_name or snapshot, not both")
if instance_name:
resource = conn.get_db_instance(instance_name)
if not resource:
module.fail_json(msg="DB Instance %s does not exist" % instance_name)
module.fail_json(msg="DB instance %s does not exist" % instance_name)
if snapshot:
resource = conn.get_db_snapshot(snapshot)
if not resource:
@ -1037,7 +1037,7 @@ def main():
region, ec2_url, aws_connect_params = get_aws_connection_info(module)
if not region:
module.fail_json(msg="region not specified and unable to determine region from EC2_REGION.")
module.fail_json(msg="Region not specified. Unable to determine region from EC2_REGION.")
# connect to the rds endpoint
if has_rds2:

@ -93,6 +93,12 @@ options:
- Keyname of the object inside the bucket. Can be used to create "virtual directories", see examples.
required: false
default: null
permission:
description:
- This option let's the user set the canned permissions on the object/bucket that are created. The permissions that can be set are 'private', 'public-read', 'public-read-write', 'authenticated-read'.
required: false
default: private
version_added: "2.0"
prefix:
description:
- Limits the response to keys that begin with the specified prefix for list mode
@ -167,7 +173,7 @@ EXAMPLES = '''
- s3: bucket=mybucket mode=list prefix=/my/desired/ marker=/my/desired/0023.txt max_keys=472
# Create an empty bucket
- s3: bucket=mybucket mode=create
- s3: bucket=mybucket mode=create permission=public-read
# Create a bucket with key as directory, in the EU region
- s3: bucket=mybucket object=/my/directory/path mode=create region=eu-west-1
@ -236,6 +242,7 @@ def create_bucket(module, s3, bucket, location=None):
location = Location.DEFAULT
try:
bucket = s3.create_bucket(bucket, location=location)
bucket.set_acl(module.params.get('permission'))
except s3.provider.storage_response_error, e:
module.fail_json(msg= str(e))
if bucket:
@ -281,15 +288,6 @@ def create_dirkey(module, s3, bucket, obj):
except s3.provider.storage_response_error, e:
module.fail_json(msg= str(e))
def upload_file_check(src):
if os.path.exists(src):
file_exists is True
else:
file_exists is False
if os.path.isdir(src):
module.fail_json(msg="Specifying a directory is not a valid source for upload.", failed=True)
return file_exists
def path_check(path):
if os.path.exists(path):
return True
@ -306,6 +304,7 @@ def upload_s3file(module, s3, bucket, obj, src, expiry, metadata, encrypt, heade
key.set_metadata(meta_key, metadata[meta_key])
key.set_contents_from_filename(src, encrypt_key=encrypt, headers=headers)
key.set_acl(module.params.get('permission'))
url = key.generate_url(expiry)
module.exit_json(msg="PUT operation complete", url=url, changed=True)
except s3.provider.storage_copy_error, e:
@ -378,6 +377,7 @@ def main():
metadata = dict(type='dict'),
mode = dict(choices=['get', 'put', 'delete', 'create', 'geturl', 'getstr', 'delobj', 'list'], required=True),
object = dict(),
permission = dict(choices=['private', 'public-read', 'public-read-write', 'authenticated-read'], default='private'),
version = dict(default=None),
overwrite = dict(aliases=['force'], default='always'),
prefix = dict(default=None),

@ -268,7 +268,7 @@ options:
read_only:
description:
- Mount the container's root filesystem as read only
default: false
default: null
aliases: []
version_added: "2.0"
restart_policy:
@ -796,12 +796,12 @@ class DockerManager(object):
'privileged': self.module.params.get('privileged'),
'links': self.links,
'network_mode': self.module.params.get('net'),
'read_only': self.module.params.get('read_only'),
}
optionals = {}
for optional_param in ('dns', 'volumes_from', 'restart_policy',
'restart_policy_retry', 'pid'):
'restart_policy_retry', 'pid', 'extra_hosts', 'log_driver',
'cap_add', 'cap_drop', 'read_only'):
optionals[optional_param] = self.module.params.get(optional_param)
if optionals['dns'] is not None:
@ -818,13 +818,39 @@ class DockerManager(object):
if params['restart_policy']['Name'] == 'on-failure':
params['restart_policy']['MaximumRetryCount'] = optionals['restart_policy_retry']
# docker_py only accepts 'host' or None
if 'pid' in optionals and not optionals['pid']:
optionals['pid'] = None
if optionals['pid'] is not None:
self.ensure_capability('pid')
params['pid_mode'] = optionals['pid']
if optionals['extra_hosts'] is not None:
self.ensure_capability('extra_hosts')
params['extra_hosts'] = optionals['extra_hosts']
if optionals['log_driver'] is not None:
self.ensure_capability('log_driver')
log_config = docker.utils.LogConfig(type=docker.utils.LogConfig.types.JSON)
log_config.type = optionals['log_driver']
params['log_config'] = log_config
if optionals['cap_add'] is not None:
self.ensure_capability('cap_add')
params['cap_add'] = optionals['cap_add']
if optionals['cap_drop'] is not None:
self.ensure_capability('cap_drop')
params['cap_drop'] = optionals['cap_drop']
if optionals['read_only'] is not None:
self.ensure_capability('read_only')
params['read_only'] = optionals['read_only']
return params
def get_host_config(self):
def create_host_config(self):
"""
Create HostConfig object
"""
@ -1020,7 +1046,7 @@ class DockerManager(object):
expected_volume_keys = set((image['ContainerConfig']['Volumes'] or {}).keys())
if self.volumes:
expected_volume_keys.update(self.volumes.keys())
expected_volume_keys.update(self.volumes)
actual_volume_keys = set((container['Config']['Volumes'] or {}).keys())
@ -1340,65 +1366,6 @@ class DockerManager(object):
except Exception as e:
self.module.fail_json(msg="Failed to pull the specified image: %s" % resource, error=repr(e))
def create_host_config(self):
params = {
'lxc_conf': self.lxc_conf,
'binds': self.binds,
'port_bindings': self.port_bindings,
'publish_all_ports': self.module.params.get('publish_all_ports'),
'privileged': self.module.params.get('privileged'),
'links': self.links,
'network_mode': self.module.params.get('net'),
}
optionals = {}
for optional_param in ('dns', 'volumes_from', 'restart_policy',
'restart_policy_retry', 'pid', 'extra_hosts', 'log_driver',
'cap_add', 'cap_drop'):
optionals[optional_param] = self.module.params.get(optional_param)
if optionals['dns'] is not None:
self.ensure_capability('dns')
params['dns'] = optionals['dns']
if optionals['volumes_from'] is not None:
self.ensure_capability('volumes_from')
params['volumes_from'] = optionals['volumes_from']
if optionals['restart_policy'] is not None:
self.ensure_capability('restart_policy')
params['restart_policy'] = { 'Name': optionals['restart_policy'] }
if params['restart_policy']['Name'] == 'on-failure':
params['restart_policy']['MaximumRetryCount'] = optionals['restart_policy_retry']
# docker_py only accepts 'host' or None
if 'pid' in optionals and not optionals['pid']:
optionals['pid'] = None
if optionals['pid'] is not None:
self.ensure_capability('pid')
params['pid_mode'] = optionals['pid']
if optionals['extra_hosts'] is not None:
self.ensure_capability('extra_hosts')
params['extra_hosts'] = optionals['extra_hosts']
if optionals['log_driver'] is not None:
self.ensure_capability('log_driver')
log_config = docker.utils.LogConfig(type=docker.utils.LogConfig.types.JSON)
log_config.type = optionals['log_driver']
params['log_config'] = log_config
if optionals['cap_add'] is not None:
self.ensure_capability('cap_add')
params['cap_add'] = optionals['cap_add']
if optionals['cap_drop'] is not None:
self.ensure_capability('cap_drop')
params['cap_drop'] = optionals['cap_drop']
return docker.utils.create_host_config(**params)
def create_containers(self, count=1):
try:
mem_limit = _human_to_bytes(self.module.params.get('memory_limit'))
@ -1418,17 +1385,16 @@ class DockerManager(object):
'stdin_open': self.module.params.get('stdin_open'),
'tty': self.module.params.get('tty'),
'cpuset': self.module.params.get('cpu_set'),
'host_config': self.create_host_config(),
'user': self.module.params.get('docker_user'),
}
if self.ensure_capability('host_config', fail=False):
params['host_config'] = self.get_host_config()
params['host_config'] = self.create_host_config()
#For v1.19 API and above use HostConfig, otherwise use Config
if api_version < 1.19:
params['mem_limit'] = mem_limit
else:
params['host_config']['mem_limit'] = mem_limit
params['host_config']['Memory'] = mem_limit
def do_create(count, params):
@ -1664,7 +1630,7 @@ def main():
cpu_set = dict(default=None),
cap_add = dict(default=None, type='list'),
cap_drop = dict(default=None, type='list'),
read_only = dict(default=False, type='bool'),
read_only = dict(default=None, type='bool'),
),
required_together = (
['tls_client_cert', 'tls_client_key'],

@ -211,15 +211,6 @@ def create_dirkey(module, gs, bucket, obj):
except gs.provider.storage_response_error, e:
module.fail_json(msg= str(e))
def upload_file_check(src):
if os.path.exists(src):
file_exists is True
else:
file_exists is False
if os.path.isdir(src):
module.fail_json(msg="Specifying a directory is not a valid source for upload.", failed=True)
return file_exists
def path_check(path):
if os.path.exists(path):
return True

@ -252,8 +252,20 @@ def ensure_user_exists(keystone, user_name, password, email, tenant_name,
email=email, tenant_id=tenant.id)
return (True, user.id)
def ensure_role_exists(keystone, role_name):
# Get the role if it exists
try:
role = get_role(keystone, role_name)
# Role does exist, we're done
return (False, role.id)
except KeyError:
# Role doesn't exist yet
pass
def ensure_role_exists(keystone, user_name, tenant_name, role_name,
role = keystone.roles.create(role_name)
return (True, role.id)
def ensure_user_role_exists(keystone, user_name, tenant_name, role_name,
check_mode):
""" Check if role exists
@ -297,9 +309,11 @@ def ensure_user_absent(keystone, user, check_mode):
raise NotImplementedError("Not yet implemented")
def ensure_role_absent(keystone, uesr, tenant, role, check_mode):
def ensure_user_role_absent(keystone, uesr, tenant, role, check_mode):
raise NotImplementedError("Not yet implemented")
def ensure_role_absent(keystone, role_name):
raise NotImplementedError("Not yet implemented")
def main():
@ -378,14 +392,18 @@ def dispatch(keystone, user=None, password=None, tenant=None,
X absent ensure_tenant_absent
X X present ensure_user_exists
X X absent ensure_user_absent
X X X present ensure_role_exists
X X X absent ensure_role_absent
X X X present ensure_user_role_exists
X X X absent ensure_user_role_absent
X present ensure_role_exists
X absent ensure_role_absent
"""
changed = False
id = None
if tenant and not user and not role and state == "present":
if not tenant and not user and role and state == "present":
changed, id = ensure_role_exists(keystone, role)
elif not tenant and not user and role and state == "absent":
changed = ensure_role_absent(keystone, role)
elif tenant and not user and not role and state == "present":
changed, id = ensure_tenant_exists(keystone, tenant,
tenant_description, check_mode)
elif tenant and not user and not role and state == "absent":
@ -396,10 +414,10 @@ def dispatch(keystone, user=None, password=None, tenant=None,
elif tenant and user and not role and state == "absent":
changed = ensure_user_absent(keystone, user, check_mode)
elif tenant and user and role and state == "present":
changed, id = ensure_role_exists(keystone, user, tenant, role,
changed, id = ensure_user_role_exists(keystone, user, tenant, role,
check_mode)
elif tenant and user and role and state == "absent":
changed = ensure_role_absent(keystone, user, tenant, role, check_mode)
changed = ensure_user_role_absent(keystone, user, tenant, role, check_mode)
else:
# Should never reach here
raise ValueError("Code should never reach here")

@ -40,12 +40,12 @@ author: "Monty Taylor (@emonty)"
EXAMPLES = '''
# Get list of clouds that do not support security groups
- os-client-config:
- os_client_config:
- debug: var={{ item }}
with_items: "{{ openstack.clouds|rejectattr('secgroup_source', 'none')|list() }}"
# Get the information back just about the mordred cloud
- os-client-config:
- os_client_config:
clouds:
- mordred
'''

@ -57,8 +57,13 @@ requirements: ["shade"]
EXAMPLES = '''
- os_network:
name=t1network
state=present
name: t1network
state: present
auth:
auth_url: https://your_api_url.com:9000/v2.0
username: user
password: password
project_name: someproject
'''

@ -213,12 +213,14 @@ def _find_matching_rule(module, secgroup):
remote_ip_prefix = module.params['remote_ip_prefix']
ethertype = module.params['ethertype']
direction = module.params['direction']
remote_group_id = module.params['remote_group']
for rule in secgroup['security_group_rules']:
if (protocol == rule['protocol']
and remote_ip_prefix == rule['remote_ip_prefix']
and ethertype == rule['ethertype']
and direction == rule['direction']
and remote_group_id == rule['remote_group_id']
and _ports_match(protocol,
module.params['port_range_min'],
module.params['port_range_max'],

@ -287,8 +287,12 @@ def _create_server(module, cloud):
if flavor:
flavor_dict = cloud.get_flavor(flavor)
if not flavor_dict:
module.fail_json(msg="Could not find flavor %s" % flavor)
else:
flavor_dict = cloud.get_flavor_by_ram(flavor_ram, flavor_include)
if not flavor_dict:
module.fail_json(msg="Could not find any matching flavor")
nics = _network_args(module, cloud)
@ -392,7 +396,7 @@ def main():
flavor_include = dict(default=None),
key_name = dict(default=None),
security_groups = dict(default='default'),
nics = dict(default=[]),
nics = dict(default=[], type='list'),
meta = dict(default=None),
userdata = dict(default=None),
config_drive = dict(default=False, type='bool'),

@ -98,6 +98,8 @@ def rax_facts(module, address, name, server_id):
except Exception, e:
pass
servers[:] = [server for server in servers if server.status != "DELETED"]
if len(servers) > 1:
module.fail_json(msg='Multiple servers found matching provided '
'search parameters')

@ -152,6 +152,7 @@ EXAMPLES = '''
# Returns changed = True and a adds ansible_facts from the new VM
# State will set the power status of a guest upon creation. Use powered_on to create and boot.
# Options ['state', 'vm_extra_config', 'vm_disk', 'vm_nic', 'vm_hardware', 'esxi'] are required together
# Note: vm_floppy support added in 2.0
- vsphere_guest:
vcenter_hostname: vcenter.mydomain.local
@ -185,6 +186,9 @@ EXAMPLES = '''
vm_cdrom:
type: "iso"
iso_path: "DatastoreName/cd-image.iso"
vm_floppy:
type: "image"
image_path: "DatastoreName/floppy-image.flp"
esxi:
datacenter: MyDatacenter
hostname: esx001.mydomain.local
@ -376,6 +380,44 @@ def add_cdrom(module, s, config_target, config, devices, default_devs, type="cli
devices.append(cd_spec)
def add_floppy(module, s, config_target, config, devices, default_devs, type="image", vm_floppy_image_path=None):
# Add a floppy
# Make sure the datastore exists.
if vm_floppy_image_path:
image_location = vm_floppy_image_path.split('/', 1)
datastore, ds = find_datastore(
module, s, image_location[0], config_target)
image_path = image_location[1]
floppy_spec = config.new_deviceChange()
floppy_spec.set_element_operation('add')
floppy_ctrl = VI.ns0.VirtualFloppy_Def("floppy_ctrl").pyclass()
if type == "image":
image = VI.ns0.VirtualFloppyImageBackingInfo_Def("image").pyclass()
ds_ref = image.new_datastore(ds)
ds_ref.set_attribute_type(ds.get_attribute_type())
image.set_element_datastore(ds_ref)
image.set_element_fileName("%s %s" % (datastore, image_path))
floppy_ctrl.set_element_backing(image)
floppy_ctrl.set_element_key(3)
floppy_spec.set_element_device(floppy_ctrl)
elif type == "client":
client = VI.ns0.VirtualFloppyRemoteDeviceBackingInfo_Def(
"client").pyclass()
client.set_element_deviceName("/dev/fd0")
floppy_ctrl.set_element_backing(client)
floppy_ctrl.set_element_key(3)
floppy_spec.set_element_device(floppy_ctrl)
else:
s.disconnect()
module.fail_json(
msg="Error adding floppy of type %s to vm spec. "
" floppy type can either be image or client" % (type))
devices.append(floppy_spec)
def add_nic(module, s, nfmor, config, devices, nic_type="vmxnet3", network_name="VM Network", network_type="standard"):
# add a NIC
# Different network card types are: "VirtualE1000",
@ -946,6 +988,27 @@ def create_vm(vsphere_client, module, esxi, resource_pool, cluster_name, guest,
# Add a CD-ROM device to the VM.
add_cdrom(module, vsphere_client, config_target, config, devices,
default_devs, cdrom_type, cdrom_iso_path)
if 'vm_floppy' in vm_hardware:
floppy_image_path = None
floppy_type = None
try:
floppy_type = vm_hardware['vm_floppy']['type']
except KeyError:
vsphere_client.disconnect()
module.fail_json(
msg="Error on %s definition. floppy type needs to be"
" specified." % vm_hardware['vm_floppy'])
if floppy_type == 'image':
try:
floppy_image_path = vm_hardware['vm_floppy']['image_path']
except KeyError:
vsphere_client.disconnect()
module.fail_json(
msg="Error on %s definition. floppy image_path needs"
" to be specified." % vm_hardware['vm_floppy'])
# Add a floppy to the VM.
add_floppy(module, vsphere_client, config_target, config, devices,
default_devs, floppy_type, floppy_image_path)
if vm_nic:
for nic in sorted(vm_nic.iterkeys()):
try:

@ -91,9 +91,11 @@ options:
validate is passed in via '%s' which must be present as in the sshd example below.
The command is passed securely so shell features like expansion and pipes won't work.
required: false
default: ""
default: null
version_added: "2.0"
author: "Stephen Fromm (@sfromm)"
extends_documentation_fragment: files
extends_documentation_fragment:
- files
'''
EXAMPLES = '''
@ -104,7 +106,7 @@ EXAMPLES = '''
- assemble: src=/etc/someapp/fragments dest=/etc/someapp/someapp.conf delimiter='### START FRAGMENT ###'
# Copy a new "sshd_config" file into place, after passing validation with sshd
- assemble: src=/etc/ssh/conf.d/ dest=/etc/ssh/sshd_config validate='sshd -t -f %s'
- assemble: src=/etc/ssh/conf.d/ dest=/etc/ssh/sshd_config validate='/usr/sbin/sshd -t -f %s'
'''
# ===========================================

@ -179,8 +179,8 @@ APT_ENV_VARS = dict(
)
DPKG_OPTIONS = 'force-confdef,force-confold'
APT_GET_ZERO = "0 upgraded, 0 newly installed"
APTITUDE_ZERO = "0 packages upgraded, 0 newly installed"
APT_GET_ZERO = "\n0 upgraded, 0 newly installed"
APTITUDE_ZERO = "\n0 packages upgraded, 0 newly installed"
APT_LISTS_PATH = "/var/lib/apt/lists"
APT_UPDATE_SUCCESS_STAMP_PATH = "/var/lib/apt/periodic/update-success-stamp"

@ -76,6 +76,12 @@ EXAMPLES = '''
- redhat_subscription: state=present
activationkey=1-222333444
pool='^(Red Hat Enterprise Server|Red Hat Virtualization)$'
# Update the consumed subscriptions from the previous example (remove the Red
# Hat Virtualization subscription)
- redhat_subscription: state=present
activationkey=1-222333444
pool='^Red Hat Enterprise Server$'
'''
import os
@ -226,14 +232,26 @@ class Rhsm(RegistrationBase):
rc, stderr, stdout = self.module.run_command(args, check_rc=True)
def unsubscribe(self):
def unsubscribe(self, serials=None):
'''
Unsubscribe a system from all subscribed channels
Unsubscribe a system from subscribed channels
Args:
serials(list or None): list of serials to unsubscribe. If
serials is none or an empty list, then
all subscribed channels will be removed.
Raises:
* Exception - if error occurs while running command
'''
args = ['subscription-manager', 'unsubscribe', '--all']
items = []
if serials is not None and serials:
items = ["--serial=%s" % s for s in serials]
if serials is None:
items = ["--all"]
if items:
args = ['subscription-manager', 'unsubscribe'] + items
rc, stderr, stdout = self.module.run_command(args, check_rc=True)
return serials
def unregister(self):
'''
@ -255,8 +273,27 @@ class Rhsm(RegistrationBase):
# Available pools ready for subscription
available_pools = RhsmPools(self.module)
subscribed_pool_ids = []
for pool in available_pools.filter(regexp):
pool.subscribe()
subscribed_pool_ids.append(pool.get_pool_id())
return subscribed_pool_ids
def update_subscriptions(self, regexp):
changed=False
consumed_pools = RhsmPools(self.module, consumed=True)
pool_ids_to_keep = [p.get_pool_id() for p in consumed_pools.filter(regexp)]
serials_to_remove=[p.Serial for p in consumed_pools if p.get_pool_id() not in pool_ids_to_keep]
serials = self.unsubscribe(serials=serials_to_remove)
subscribed_pool_ids = self.subscribe(regexp)
if subscribed_pool_ids or serials:
changed=True
return {'changed': changed, 'subscribed_pool_ids': subscribed_pool_ids,
'unsubscribed_serials': serials}
class RhsmPool(object):
@ -272,8 +309,11 @@ class RhsmPool(object):
def __str__(self):
return str(self.__getattribute__('_name'))
def get_pool_id(self):
return getattr(self, 'PoolId', getattr(self, 'PoolID'))
def subscribe(self):
args = "subscription-manager subscribe --pool %s" % self.PoolId
args = "subscription-manager subscribe --pool %s" % self.get_pool_id()
rc, stdout, stderr = self.module.run_command(args, check_rc=True)
if rc == 0:
return True
@ -285,18 +325,25 @@ class RhsmPools(object):
"""
This class is used for manipulating pools subscriptions with RHSM
"""
def __init__(self, module):
def __init__(self, module, consumed=False):
self.module = module
self.products = self._load_product_list()
self.products = self._load_product_list(consumed)
def __iter__(self):
return self.products.__iter__()
def _load_product_list(self):
def _load_product_list(self, consumed=False):
"""
Loads list of all available pools for system in data structure
Loads list of all available or consumed pools for system in data structure
Args:
consumed(bool): if True list consumed pools, else list available pools (default False)
"""
args = "subscription-manager list --available"
args = "subscription-manager list"
if consumed:
args += " --consumed"
else:
args += " --available"
rc, stdout, stderr = self.module.run_command(args, check_rc=True)
products = []
@ -375,18 +422,27 @@ def main():
# Register system
if rhn.is_registered:
if pool != '^$':
try:
result = rhn.update_subscriptions(pool)
except Exception, e:
module.fail_json(msg="Failed to update subscriptions for '%s': %s" % (server_hostname, e))
else:
module.exit_json(**result)
else:
module.exit_json(changed=False, msg="System already registered.")
else:
try:
rhn.enable()
rhn.configure(**module.params)
rhn.register(username, password, autosubscribe, activationkey, org_id)
rhn.subscribe(pool)
subscribed_pool_ids = rhn.subscribe(pool)
except Exception, e:
module.fail_json(msg="Failed to register with '%s': %s" % (server_hostname, e))
else:
module.exit_json(changed=True, msg="System successfully registered to '%s'." % server_hostname)
module.exit_json(changed=True,
msg="System successfully registered to '%s'." % server_hostname,
subscribed_pool_ids=subscribed_pool_ids)
# Ensure system is *not* registered
if state == 'absent':
if not rhn.is_registered:

@ -620,7 +620,8 @@ def install(module, items, repoq, yum_basecmd, conf_file, en_repos, dis_repos):
shutil.rmtree(tempdir)
except Exception, e:
module.fail_json(msg="Failure deleting temp directory %s, %s" % (tempdir, e))
module.exit_json(changed=True)
module.exit_json(changed=True, results=res['results'], changes=dict(installed=pkgs))
changed = True
@ -688,7 +689,7 @@ def remove(module, items, repoq, yum_basecmd, conf_file, en_repos, dis_repos):
cmd = yum_basecmd + ["remove"] + pkgs
if module.check_mode:
module.exit_json(changed=True)
module.exit_json(changed=True, results=res['results'], changes=dict(removed=pkgs))
rc, out, err = module.run_command(cmd)
@ -723,46 +724,68 @@ def latest(module, items, repoq, yum_basecmd, conf_file, en_repos, dis_repos):
res['msg'] = ''
res['changed'] = False
res['rc'] = 0
pkgs = {}
pkgs['update'] = []
pkgs['install'] = []
updates = {}
update_all = False
cmd = None
# determine if we're doing an update all
if '*' in items:
update_all = True
# run check-update to see if we have packages pending
rc, out, err = module.run_command(yum_basecmd + ['check-update'])
if rc == 0 and update_all:
res['results'].append('Nothing to do here, all packages are up to date')
return res
elif rc == 100:
available_updates = out.split('\n')
# build update dictionary
for line in available_updates:
line = line.split()
# ignore irrelevant lines
# FIXME... revisit for something less kludgy
if '*' in line or len(line) != 3 or '.' not in line[0]:
continue
else:
pkg, version, repo = line
name, dist = pkg.rsplit('.', 1)
updates.update({name: {'version': version, 'dist': dist, 'repo': repo}})
elif rc == 1:
res['msg'] = err
res['rc'] = rc
module.fail_json(**res)
if update_all:
cmd = yum_basecmd + ['update']
else:
for spec in items:
pkg = None
basecmd = 'update'
cmd = ''
# groups, again
# some guess work involved with groups. update @<group> will install the group if missing
if spec.startswith('@'):
pkg = spec
elif spec == '*': #update all
# use check-update to see if there is any need
rc,out,err = module.run_command(yum_basecmd + ['check-update'])
if rc == 100:
cmd = yum_basecmd + [basecmd]
else:
res['results'].append('All packages up to date')
pkgs['update'].append(spec)
continue
# dep/pkgname - find it
else:
if is_installed(module, repoq, spec, conf_file, en_repos=en_repos, dis_repos=dis_repos):
basecmd = 'update'
pkgs['update'].append(spec)
else:
basecmd = 'install'
pkgs['install'].append(spec)
pkglist = what_provides(module, repoq, spec, conf_file, en_repos=en_repos, dis_repos=dis_repos)
# FIXME..? may not be desirable to throw an exception here if a single package is missing
if not pkglist:
res['msg'] += "No Package matching '%s' found available, installed or updated" % spec
module.fail_json(**res)
nothing_to_do = True
for this in pkglist:
if basecmd == 'install' and is_available(module, repoq, this, conf_file, en_repos=en_repos, dis_repos=dis_repos):
if spec in pkgs['install'] and is_available(module, repoq, this, conf_file, en_repos=en_repos, dis_repos=dis_repos):
nothing_to_do = False
break
if basecmd == 'update' and is_update(module, repoq, this, conf_file, en_repos=en_repos, dis_repos=dis_repos):
if spec in pkgs['update'] and spec in updates.keys():
nothing_to_do = False
break
if nothing_to_do:
res['results'].append("All packages providing %s are up to date" % spec)
@ -775,26 +798,59 @@ def latest(module, items, repoq, yum_basecmd, conf_file, en_repos, dis_repos):
res['msg'] += "The following packages have pending transactions: %s" % ", ".join(conflicts)
module.fail_json(**res)
pkg = spec
if not cmd:
cmd = yum_basecmd + [basecmd, pkg]
# list of package updates
if update_all:
will_update = updates.keys()
else:
will_update = [u for u in pkgs['update'] if u in updates.keys() or u.startswith('@')]
# check_mode output
if module.check_mode:
return module.exit_json(changed=True)
to_update = []
for w in will_update:
if w.startswith('@'):
to_update.append((w, None))
msg = '%s will be updated' % w
else:
to_update.append((w, '%s.%s from %s' % (updates[w]['version'], updates[w]['dist'], updates[w]['repo'])))
res['changes'] = dict(installed=pkgs['install'], updated=to_update)
if len(will_update) > 0 or len(pkgs['install']) > 0:
res['changed'] = True
return res
# run commands
if cmd: # update all
rc, out, err = module.run_command(cmd)
res['changed'] = True
else:
if len(pkgs['install']) > 0: # install missing
cmd = yum_basecmd + ['install'] + pkgs['install']
rc, out, err = module.run_command(cmd)
res['changed'] = True
else:
rc, out, err = [0, '', '']
if len(will_update) > 0: # update present
cmd = yum_basecmd + ['update'] + pkgs['update']
rc2, out2, err2 = module.run_command(cmd)
res['changed'] = True
else:
rc2, out2, err2 = [0, '', '']
if not update_all:
rc += rc2
out += out2
err += err2
res['rc'] += rc
res['results'].append(out)
res['msg'] += err
# FIXME if it is - update it and check to see if it applied
# check to see if there is no longer an update available for the pkgspec
res['results'].append(out)
if rc:
res['failed'] = True
else:
res['changed'] = True
return res
@ -916,7 +972,12 @@ def main():
# loaded and plugins are discovered
my.conf
repoquery = None
if 'rhnplugin' in my.plugins._plugins:
try:
yum_plugins = my.plugins._plugins
except AttributeError:
pass
else:
if 'rhnplugin' in yum_plugins:
repoquerybin = ensure_yum_utils(module)
if repoquerybin:
repoquery = [repoquerybin, '--show-duplicates', '--plugins', '--quiet']
@ -939,4 +1000,3 @@ from ansible.module_utils.basic import *
from ansible.module_utils.urls import *
if __name__ == '__main__':
main()

@ -491,10 +491,20 @@ def get_head_branch(git_path, module, dest, remote, bare=False):
f.close()
return branch
def fetch(git_path, module, repo, dest, version, remote, bare, refspec):
def set_remote_url(git_path, module, repo, dest, remote):
''' updates repo from remote sources '''
commands = [("set a new url %s for %s" % (repo, remote), [git_path, 'remote', 'set-url', remote, repo])]
for (label,command) in commands:
(rc,out,err) = module.run_command(command, cwd=dest)
if rc != 0:
module.fail_json(msg="Failed to %s: %s %s" % (label, out, err))
def fetch(git_path, module, repo, dest, version, remote, bare, refspec):
''' updates repo from remote sources '''
set_remote_url(git_path, module, repo, dest, remote)
commands = []
fetch_str = 'download remote objects and refs'
if bare:
@ -741,6 +751,7 @@ def main():
if not module.check_mode:
reset(git_path, module, dest)
# exit if already at desired sha version
set_remote_url(git_path, module, repo, dest, remote)
remote_head = get_remote_head(git_path, module, dest, version, remote, bare)
if before == remote_head:
if local_mods:

@ -112,8 +112,10 @@ EXAMPLES = '''
key_options='no-port-forwarding,from="10.0.1.1"'
# Set up authorized_keys exclusively with one key
- authorized_key: user=root key=public_keys/doe-jane state=present
- authorized_key: user=root key="{{ item }}" state=present
exclusive=yes
with_file:
- public_keys/doe-jane
'''
# Makes sure the public key line is present or absent in the user's .ssh/authorized_keys.
@ -169,16 +171,15 @@ def keyfile(module, user, write=False, path=None, manage_dir=True):
:return: full path string to authorized_keys for user
"""
if module.check_mode:
if path is None:
module.fail_json(msg="You must provide full path to key file in check mode")
else:
if module.check_mode and path is not None:
keysfile = path
return keysfile
try:
user_entry = pwd.getpwnam(user)
except KeyError, e:
if module.check_mode and path is None:
module.fail_json(msg="Either user must exist or you must provide full path to key file in check mode")
module.fail_json(msg="Failed to lookup user %s: %s" % (user, str(e)))
if path is None:
homedir = user_entry.pw_dir

@ -491,6 +491,11 @@ class DebianHostname(Hostname):
distribution = 'Debian'
strategy_class = DebianStrategy
class KaliHostname(Hostname):
platform = 'Linux'
distribution = 'Kali'
strategy_class = DebianStrategy
class UbuntuHostname(Hostname):
platform = 'Linux'
distribution = 'Ubuntu'

@ -520,9 +520,14 @@ class LinuxService(Service):
return False
def get_systemd_status_dict(self):
(rc, out, err) = self.execute_command("%s show %s" % (self.enable_cmd, self.__systemd_unit,))
# Check status first as show will not fail if service does not exist
(rc, out, err) = self.execute_command("%s show '%s'" % (self.enable_cmd, self.__systemd_unit,))
if rc != 0:
self.module.fail_json(msg='failure %d running systemctl show for %r: %s' % (rc, self.__systemd_unit, err))
elif 'LoadState=not-found' in out:
self.module.fail_json(msg='systemd could not find the requested service "%r": %s' % (self.__systemd_unit, err))
key = None
value_buffer = []
status_dict = {}

@ -585,11 +585,13 @@ class User(object):
def ssh_key_gen(self):
info = self.user_info()
if not os.path.exists(info[5]):
if not os.path.exists(info[5]) and not self.module.check_mode:
return (1, '', 'User %s home directory does not exist' % self.name)
ssh_key_file = self.get_ssh_key_path()
ssh_dir = os.path.dirname(ssh_key_file)
if not os.path.exists(ssh_dir):
if self.module.check_mode:
return (0, '', '')
try:
os.mkdir(ssh_dir, 0700)
os.chown(ssh_dir, info[2], info[3])
@ -597,6 +599,8 @@ class User(object):
return (1, '', 'Failed to create %s: %s' % (ssh_dir, str(e)))
if os.path.exists(ssh_key_file):
return (None, 'Key already exists', '')
if self.module.check_mode:
return (0, '', '')
cmd = [self.module.get_bin_path('ssh-keygen', True)]
cmd.append('-t')
cmd.append(self.ssh_type)
@ -2158,6 +2162,7 @@ def main():
# deal with ssh key
if user.sshkeygen:
# generate ssh key (note: this function is check mode aware)
(rc, out, err) = user.ssh_key_gen()
if rc is not None and rc != 0:
module.fail_json(name=user.name, msg=err, rc=rc)

@ -25,7 +25,7 @@ $result = New-Object psobject @{
changed = $false
};
$win32_os = Get-WmiObject Win32_OperatingSystem
$win32_os = Get-CimInstance Win32_OperatingSystem
$osversion = [Environment]::OSVersion
$memory = @()
$memory += Get-WmiObject win32_Physicalmemory
@ -60,12 +60,15 @@ Set-Attr $result.ansible_facts "ansible_hostname" $env:COMPUTERNAME;
Set-Attr $result.ansible_facts "ansible_fqdn" "$([System.Net.Dns]::GetHostByName((hostname)).HostName)"
Set-Attr $result.ansible_facts "ansible_system" $osversion.Platform.ToString()
Set-Attr $result.ansible_facts "ansible_os_family" "Windows"
Set-Attr $result.ansible_facts "ansible_os_name" $win32_os.Name.Split('|')[0]
Set-Attr $result.ansible_facts "ansible_os_name" ($win32_os.Name.Split('|')[0]).Trim()
Set-Attr $result.ansible_facts "ansible_distribution" $osversion.VersionString
Set-Attr $result.ansible_facts "ansible_distribution_version" $osversion.Version.ToString()
Set-Attr $result.ansible_facts "ansible_totalmem" $capacity
Set-Attr $result.ansible_facts "ansible_lastboot" $win32_os.lastbootuptime.ToString("u")
Set-Attr $result.ansible_facts "ansible_uptime_seconds" $([System.Convert]::ToInt64($(Get-Date).Subtract($win32_os.lastbootuptime).TotalSeconds))
$ips = @()
Foreach ($ip in $netcfg.IPAddress) { If ($ip) { $ips += $ip } }
Set-Attr $result.ansible_facts "ansible_ip_addresses" $ips

@ -27,48 +27,18 @@ $result = New-Object PSObject -Property @{
changed = $false
}
If ($params.name) {
$name = $params.name -split ',' | % { $_.Trim() }
}
Else {
Fail-Json $result "mising required argument: name"
}
$name = Get-Attr $params "name" -failifempty $true
$name = $name -split ',' | % { $_.Trim() }
If ($params.state) {
$state = $params.state.ToString().ToLower()
$state = Get-Attr $params "state" "present"
$state = $state.ToString().ToLower()
If (($state -ne 'present') -and ($state -ne 'absent')) {
Fail-Json $result "state is '$state'; must be 'present' or 'absent'"
}
}
Elseif (!$params.state) {
$state = "present"
}
If ($params.restart) {
$restart = $params.restart | ConvertTo-Bool
}
Else
{
$restart = $false
}
if ($params.include_sub_features)
{
$includesubfeatures = $params.include_sub_features | ConvertTo-Bool
}
Else
{
$includesubfeatures = $false
}
if ($params.include_management_tools)
{
$includemanagementtools = $params.include_management_tools | ConvertTo-Bool
}
Else
{
$includemanagementtools = $false
}
$restart = Get-Attr $params "restart" $false | ConvertTo-Bool
$includesubfeatures = Get-Attr $params "include_sub_features" $false | ConvertTo-Bool
$includemanagementtools = Get-Attr $params "include_management_tools" $false | ConvertTo-Bool
If ($state -eq "present") {
try {

@ -40,22 +40,39 @@ Else {
Fail-Json $result "missing required argument: dest"
}
$skip_certificate_validation = Get-Attr $params "skip_certificate_validation" $false | ConvertTo-Bool
$username = Get-Attr $params "username"
$password = Get-Attr $params "password"
if($skip_certificate_validation){
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}
}
$force = Get-Attr -obj $params -name "force" "yes" | ConvertTo-Bool
If ($force -or -not (Test-Path $dest)) {
$client = New-Object System.Net.WebClient
if($username -and $password){
$client.Credentials = New-Object System.Net.NetworkCredential($username, $password)
}
Try {
$client.DownloadFile($url, $dest)
$result.changed = $true
}
Catch {
Fail-Json $result "Error downloading $url to $dest"
Fail-Json $result "Error downloading $url to $dest $($_.Exception.Message)"
}
}
Else {
Try {
$webRequest = [System.Net.HttpWebRequest]::Create($url)
if($username -and $password){
$webRequest.Credentials = New-Object System.Net.NetworkCredential($username, $password)
}
$webRequest.IfModifiedSince = ([System.IO.FileInfo]$dest).LastWriteTime
$webRequest.Method = "GET"
[System.Net.HttpWebResponse]$webResponse = $webRequest.GetResponse()
@ -68,11 +85,11 @@ Else {
}
Catch [System.Net.WebException] {
If ($_.Exception.Response.StatusCode -ne [System.Net.HttpStatusCode]::NotModified) {
Fail-Json $result "Error downloading $url to $dest"
Fail-Json $result "Error downloading $url to $dest $($_.Exception.Message)"
}
}
Catch {
Fail-Json $result "Error downloading $url to $dest"
Fail-Json $result "Error downloading $url to $dest $($_.Exception.Message)"
}
}

@ -28,6 +28,7 @@ version_added: "1.7"
short_description: Fetches a file from a given URL
description:
- Fetches a file from a URL and saves to locally
author: "Paul Durivage (@angstwad)"
options:
url:
description:
@ -49,7 +50,21 @@ options:
required: false
choices: [ "yes", "no" ]
default: yes
author: "Paul Durivage (@angstwad)"
username:
description:
- Basic authentication username
required: false
default: null
password:
description:
- Basic authentication password
required: false
default: null
skip_certificate_validation:
description:
- Skip SSL certificate validation if true
required: false
default: false
'''
EXAMPLES = '''

@ -24,35 +24,31 @@ $params = Parse-Args $args;
$result = New-Object PSObject;
Set-Attr $result "changed" $false;
If (-not $params.name.GetType) {
Fail-Json $result "missing required arguments: name"
}
$name = Get-Attr $params "name" -failifempty $true
If ($params.state) {
$state = $params.state.ToString().ToLower()
$state = Get-Attr $params "state" "present"
$state = $state.ToString().ToLower()
If (($state -ne "present") -and ($state -ne "absent")) {
Fail-Json $result "state is '$state'; must be 'present' or 'absent'"
}
}
Elseif (-not $params.state) {
$state = "present"
}
$description = Get-Attr $params "description" $null
$adsi = [ADSI]"WinNT://$env:COMPUTERNAME"
$group = $adsi.Children | Where-Object {$_.SchemaClassName -eq 'group' -and $_.Name -eq $params.name }
$group = $adsi.Children | Where-Object {$_.SchemaClassName -eq 'group' -and $_.Name -eq $name }
try {
If ($state -eq "present") {
If (-not $group) {
$group = $adsi.Create("Group", $params.name)
$group = $adsi.Create("Group", $name)
$group.SetInfo()
Set-Attr $result "changed" $true
}
If ($params.description.GetType) {
IF (-not $group.description -or $group.description -ne $params.description) {
$group.description = $params.description
If ($null -ne $description) {
IF (-not $group.description -or $group.description -ne $description) {
$group.description = $description
$group.SetInfo()
Set-Attr $result "changed" $true
}

@ -21,36 +21,28 @@
$params = Parse-Args $args;
$result = New-Object psobject;
Set-Attr $result "changed" $false;
$path = Get-Attr $params "path" -failifempty $true
$state = Get-Attr $params "state" "present"
$creates = Get-Attr $params "creates" $false
$extra_args = Get-Attr $params "extra_args" ""
If (-not $params.path.GetType)
{
Fail-Json $result "missing required arguments: path"
}
$result = New-Object psobject @{
changed = $false
};
$extra_args = ""
If ($params.extra_args.GetType)
{
$extra_args = $params.extra_args;
}
If ($params.creates.GetType -and $params.state.GetType -and $params.state -ne "absent")
{
If (Test-File $creates)
If (($creates -ne $false) -and ($state -ne "absent") -and (Test-Path $creates))
{
Exit-Json $result;
}
}
$logfile = [IO.Path]::GetTempFileName();
if ($params.state.GetType -and $params.state -eq "absent")
if ($state -eq "absent")
{
msiexec.exe /x $params.path /qb /l $logfile $extra_args;
msiexec.exe /x $path /qn /l $logfile $extra_args
}
Else
{
msiexec.exe /i $params.path /qb /l $logfile $extra_args;
msiexec.exe /i $path /qn /l $logfile $extra_args
}
Set-Attr $result "changed" $true;

@ -24,26 +24,25 @@ $params = Parse-Args $args;
$result = New-Object PSObject;
Set-Attr $result "changed" $false;
If (-not $params.name.GetType)
{
Fail-Json $result "missing required arguments: name"
}
$name = Get-Attr $params "name" -failifempty $true
$state = Get-Attr $params "state" $false
$startMode = Get-Attr $params "start_mode" $false
If ($params.state) {
$state = $params.state.ToString().ToLower()
If ($state) {
$state = $state.ToString().ToLower()
If (($state -ne 'started') -and ($state -ne 'stopped') -and ($state -ne 'restarted')) {
Fail-Json $result "state is '$state'; must be 'started', 'stopped', or 'restarted'"
}
}
If ($params.start_mode) {
$startMode = $params.start_mode.ToString().ToLower()
If ($startMode) {
$startMode = $startMode.ToString().ToLower()
If (($startMode -ne 'auto') -and ($startMode -ne 'manual') -and ($startMode -ne 'disabled')) {
Fail-Json $result "start mode is '$startMode'; must be 'auto', 'manual', or 'disabled'"
}
}
$svcName = $params.name
$svcName = $name
$svc = Get-Service -Name $svcName -ErrorAction SilentlyContinue
If (-not $svc) {
Fail-Json $result "Service '$svcName' not installed"

@ -42,14 +42,14 @@ If (Test-Path $path)
Set-Attr $result.stat "exists" $TRUE;
$info = Get-Item $path;
$epoch_date = Get-Date -Date "01/01/1970"
If ($info.Directory) # Only files have the .Directory attribute.
If ($info.PSIsContainer)
{
Set-Attr $result.stat "isdir" $FALSE;
Set-Attr $result.stat "size" $info.Length;
Set-Attr $result.stat "isdir" $TRUE;
}
Else
{
Set-Attr $result.stat "isdir" $TRUE;
Set-Attr $result.stat "isdir" $FALSE;
Set-Attr $result.stat "size" $info.Length;
}
Set-Attr $result.stat "extension" $info.Extension;
Set-Attr $result.stat "attributes" $info.Attributes.ToString();

@ -16,7 +16,6 @@
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
# WANT_JSON
# POWERSHELL_COMMON
########
@ -55,34 +54,22 @@ $result = New-Object psobject @{
changed = $false
};
If (-not $params.name.GetType) {
Fail-Json $result "missing required arguments: name"
}
$username = Get-Attr $params "name"
$username = Get-Attr $params "name" -failifempty $true
$fullname = Get-Attr $params "fullname"
$description = Get-Attr $params "description"
$password = Get-Attr $params "password"
If ($params.state) {
$state = $params.state.ToString().ToLower()
$state = Get-Attr $params "state" "present"
$state = $state.ToString().ToLower()
If (($state -ne 'present') -and ($state -ne 'absent') -and ($state -ne 'query')) {
Fail-Json $result "state is '$state'; must be 'present', 'absent' or 'query'"
}
}
ElseIf (!$params.state) {
$state = "present"
}
If ($params.update_password) {
$update_password = $params.update_password.ToString().ToLower()
$update_password = Get-Attr $params "update_password" "always"
$update_password = $update_password.ToString().ToLower()
If (($update_password -ne 'always') -and ($update_password -ne 'on_create')) {
Fail-Json $result "update_password is '$update_password'; must be 'always' or 'on_create'"
}
}
ElseIf (!$params.update_password) {
$update_password = "always"
}
$password_expired = Get-Attr $params "password_expired" $null
If ($password_expired -ne $null) {
@ -126,22 +113,18 @@ If ($groups -ne $null) {
}
}
If ($params.groups_action) {
$groups_action = $params.groups_action.ToString().ToLower()
$groups_action = Get-Attr $params "groups_action" "replace"
$groups_action = $groups_action.ToString().ToLower()
If (($groups_action -ne 'replace') -and ($groups_action -ne 'add') -and ($groups_action -ne 'remove')) {
Fail-Json $result "groups_action is '$groups_action'; must be 'replace', 'add' or 'remove'"
}
}
ElseIf (!$params.groups_action) {
$groups_action = "replace"
}
$user_obj = Get-User $username
If ($state -eq 'present') {
# Add or update user
try {
If (!$user_obj.GetType) {
If (-not $user_obj -or -not $user_obj.GetType) {
$user_obj = $adsi.Create("User", $username)
If ($password -ne $null) {
$user_obj.SetPassword($password)
@ -200,13 +183,13 @@ If ($state -eq 'present') {
If ($result.changed) {
$user_obj.SetInfo()
}
If ($groups.GetType) {
If ($null -ne $groups) {
[string[]]$current_groups = $user_obj.Groups() | ForEach { $_.GetType().InvokeMember("Name", "GetProperty", $null, $_, $null) }
If (($groups_action -eq "remove") -or ($groups_action -eq "replace")) {
ForEach ($grp in $current_groups) {
If ((($groups_action -eq "remove") -and ($groups -contains $grp)) -or (($groups_action -eq "replace") -and ($groups -notcontains $grp))) {
$group_obj = $adsi.Children | where { $_.SchemaClassName -eq 'Group' -and $_.Name -eq $grp }
If ($group_obj.GetType) {
If ($group_obj -and $group_obj.GetType) {
$group_obj.Remove($user_obj.Path)
$result.changed = $true
}
@ -239,7 +222,7 @@ If ($state -eq 'present') {
ElseIf ($state -eq 'absent') {
# Remove user
try {
If ($user_obj.GetType) {
If ($user_obj -and $user_obj.GetType) {
$username = $user_obj.Name.Value
$adsi.delete("User", $user_obj.Name.Value)
$result.changed = $true
@ -252,7 +235,7 @@ ElseIf ($state -eq 'absent') {
}
try {
If ($user_obj.GetType) {
If ($user_obj -and $user_obj.GetType) {
$user_obj.RefreshCache()
Set-Attr $result "name" $user_obj.Name[0]
Set-Attr $result "fullname" $user_obj.FullName[0]

Loading…
Cancel
Save