mirror of
https://github.com/ansible-collections/community.general.git
synced 2026-05-08 06:12:51 +00:00
Merge remote-tracking branch 'upstream/devel' into locale
This commit is contained in:
@@ -112,7 +112,7 @@ EXAMPLES = '''
|
||||
- digital_ocean: >
|
||||
state=present
|
||||
command=droplet
|
||||
name=my_new_droplet
|
||||
name=mydroplet
|
||||
client_id=XXX
|
||||
api_key=XXX
|
||||
size_id=1
|
||||
@@ -131,7 +131,7 @@ EXAMPLES = '''
|
||||
state=present
|
||||
command=droplet
|
||||
id=123
|
||||
name=my_new_droplet
|
||||
name=mydroplet
|
||||
client_id=XXX
|
||||
api_key=XXX
|
||||
size_id=1
|
||||
@@ -147,7 +147,7 @@ EXAMPLES = '''
|
||||
- digital_ocean: >
|
||||
state=present
|
||||
ssh_key_ids=id1,id2
|
||||
name=my_new_droplet
|
||||
name=mydroplet
|
||||
client_id=XXX
|
||||
api_key=XXX
|
||||
size_id=1
|
||||
@@ -221,7 +221,7 @@ class Droplet(JsonfyMixIn):
|
||||
raise TimeoutError('Wait for droplet running timeout', self.id)
|
||||
|
||||
def destroy(self):
|
||||
return self.manager.destroy_droplet(self.id)
|
||||
return self.manager.destroy_droplet(self.id, scrub_data=True)
|
||||
|
||||
@classmethod
|
||||
def setup(cls, client_id, api_key):
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
#!/usr/bin/python
|
||||
|
||||
# (c) 2013, Cove Schneider
|
||||
#
|
||||
|
||||
@@ -294,15 +294,6 @@ local_action:
|
||||
import sys
|
||||
import time
|
||||
|
||||
AWS_REGIONS = ['ap-northeast-1',
|
||||
'ap-southeast-1',
|
||||
'ap-southeast-2',
|
||||
'eu-west-1',
|
||||
'sa-east-1',
|
||||
'us-east-1',
|
||||
'us-west-1',
|
||||
'us-west-2']
|
||||
|
||||
try:
|
||||
import boto.ec2
|
||||
from boto.exception import EC2ResponseError
|
||||
@@ -653,24 +644,7 @@ def main():
|
||||
)
|
||||
)
|
||||
|
||||
# def get_ec2_creds(module):
|
||||
# return ec2_url, ec2_access_key, ec2_secret_key, region
|
||||
ec2_url, aws_access_key, aws_secret_key, region = get_ec2_creds(module)
|
||||
|
||||
# If we have a region specified, connect to its endpoint.
|
||||
if region:
|
||||
try:
|
||||
ec2 = boto.ec2.connect_to_region(region, aws_access_key_id=aws_access_key, aws_secret_access_key=aws_secret_key)
|
||||
except boto.exception.NoAuthHandlerFound, e:
|
||||
module.fail_json(msg = str(e))
|
||||
# If we specified an ec2_url then try connecting to it
|
||||
elif ec2_url:
|
||||
try:
|
||||
ec2 = boto.connect_ec2_endpoint(ec2_url, aws_access_key, aws_secret_key)
|
||||
except boto.exception.NoAuthHandlerFound, e:
|
||||
module.fail_json(msg = str(e))
|
||||
else:
|
||||
module.fail_json(msg="Either region or ec2_url must be specified")
|
||||
ec2 = ec2_connect(module)
|
||||
|
||||
if module.params.get('state') == 'absent':
|
||||
instance_ids = module.params.get('instance_ids')
|
||||
|
||||
@@ -156,15 +156,6 @@ EXAMPLES = '''
|
||||
import sys
|
||||
import time
|
||||
|
||||
AWS_REGIONS = ['ap-northeast-1',
|
||||
'ap-southeast-1',
|
||||
'ap-southeast-2',
|
||||
'eu-west-1',
|
||||
'sa-east-1',
|
||||
'us-east-1',
|
||||
'us-west-1',
|
||||
'us-west-2']
|
||||
|
||||
try:
|
||||
import boto
|
||||
import boto.ec2
|
||||
@@ -279,24 +270,7 @@ def main():
|
||||
)
|
||||
)
|
||||
|
||||
# def get_ec2_creds(module):
|
||||
# return ec2_url, ec2_access_key, ec2_secret_key, region
|
||||
ec2_url, aws_access_key, aws_secret_key, region = get_ec2_creds(module)
|
||||
|
||||
# If we have a region specified, connect to its endpoint.
|
||||
if region:
|
||||
try:
|
||||
ec2 = boto.ec2.connect_to_region(region, aws_access_key_id=aws_access_key, aws_secret_access_key=aws_secret_key)
|
||||
except boto.exception.NoAuthHandlerFound, e:
|
||||
module.fail_json(msg = str(e))
|
||||
# If we specified an ec2_url then try connecting to it
|
||||
elif ec2_url:
|
||||
try:
|
||||
ec2 = boto.connect_ec2_endpoint(ec2_url, aws_access_key, aws_secret_key)
|
||||
except boto.exception.NoAuthHandlerFound, e:
|
||||
module.fail_json(msg = str(e))
|
||||
else:
|
||||
module.fail_json(msg="Either region or ec2_url must be specified")
|
||||
ec2 = ec2_connect(module)
|
||||
|
||||
if module.params.get('state') == 'absent':
|
||||
if not module.params.get('image_id'):
|
||||
|
||||
@@ -102,38 +102,6 @@ else:
|
||||
boto_found = True
|
||||
|
||||
|
||||
def connect(ec2_url, ec2_access_key, ec2_secret_key, region, module):
|
||||
|
||||
""" Return an ec2 connection"""
|
||||
# allow environment variables to be used if ansible vars aren't set
|
||||
if not ec2_url and 'EC2_URL' in os.environ:
|
||||
ec2_url = os.environ['EC2_URL']
|
||||
if not ec2_secret_key and 'EC2_SECRET_KEY' in os.environ:
|
||||
ec2_secret_key = os.environ['EC2_SECRET_KEY']
|
||||
if not ec2_access_key and 'EC2_ACCESS_KEY' in os.environ:
|
||||
ec2_access_key = os.environ['EC2_ACCESS_KEY']
|
||||
|
||||
# If we have a region specified, connect to its endpoint.
|
||||
if region:
|
||||
try:
|
||||
ec2 = boto.ec2.connect_to_region(region,
|
||||
aws_access_key_id=ec2_access_key,
|
||||
aws_secret_access_key=ec2_secret_key)
|
||||
except boto.exception.NoAuthHandlerFound, e:
|
||||
module.fail_json(msg = str(" %s %s %s " % (region, ec2_access_key,
|
||||
ec2_secret_key)))
|
||||
# Otherwise, no region so we fallback to the old connection method
|
||||
else:
|
||||
try:
|
||||
if ec2_url: # if we have an URL set, connect to the specified endpoint
|
||||
ec2 = boto.connect_ec2_endpoint(ec2_url, ec2_access_key, ec2_secret_key)
|
||||
else: # otherwise it's Amazon.
|
||||
ec2 = boto.connect_ec2(ec2_access_key, ec2_secret_key)
|
||||
except boto.exception.NoAuthHandlerFound, e:
|
||||
module.fail_json(msg = str(e))
|
||||
return ec2
|
||||
|
||||
|
||||
def associate_ip_and_instance(ec2, address, instance_id, module):
|
||||
if ip_is_associated_with_instance(ec2, address.public_ip, instance_id, module):
|
||||
module.exit_json(changed=False, public_ip=address.public_ip)
|
||||
@@ -248,8 +216,8 @@ def main():
|
||||
state = dict(required=False, default='present',
|
||||
choices=['present', 'absent']),
|
||||
ec2_url = dict(required=False, aliases=['EC2_URL']),
|
||||
ec2_secret_key = dict(required=False, aliases=['EC2_SECRET_KEY'], no_log=True),
|
||||
ec2_access_key = dict(required=False, aliases=['EC2_ACCESS_KEY']),
|
||||
ec2_secret_key = dict(aliases=['aws_secret_key', 'secret_key'], no_log=True),
|
||||
ec2_access_key = dict(aliases=['aws_access_key', 'access_key']),
|
||||
region = dict(required=False, aliases=['ec2_region']),
|
||||
in_vpc = dict(required=False, choices=BOOLEANS, default=False),
|
||||
),
|
||||
@@ -259,13 +227,7 @@ def main():
|
||||
if not boto_found:
|
||||
module.fail_json(msg="boto is required")
|
||||
|
||||
ec2_url, ec2_access_key, ec2_secret_key, region = get_ec2_creds(module)
|
||||
|
||||
ec2 = connect(ec2_url,
|
||||
ec2_access_key,
|
||||
ec2_secret_key,
|
||||
region,
|
||||
module)
|
||||
ec2 = ec2_connect(module)
|
||||
|
||||
instance_id = module.params.get('instance_id')
|
||||
public_ip = module.params.get('public_ip')
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
DOCUMENTATION = """
|
||||
---
|
||||
module: ec2_elb
|
||||
short_description: De-registers or registers instances from EC2 ELB(s)
|
||||
short_description: De-registers or registers instances from EC2 ELBs
|
||||
description:
|
||||
- This module de-registers or registers an AWS EC2 instance from the ELB(s)
|
||||
- This module de-registers or registers an AWS EC2 instance from the ELBs
|
||||
that it belongs to.
|
||||
- Returns fact "ec2_elbs" which is a list of elbs attached to the instance
|
||||
if state=absent is passed as an argument.
|
||||
@@ -32,6 +32,7 @@ options:
|
||||
description:
|
||||
- register or deregister the instance
|
||||
required: true
|
||||
choices: ['present', 'absent']
|
||||
|
||||
instance_id:
|
||||
description:
|
||||
@@ -102,15 +103,6 @@ import time
|
||||
import sys
|
||||
import os
|
||||
|
||||
AWS_REGIONS = ['ap-northeast-1',
|
||||
'ap-southeast-1',
|
||||
'ap-southeast-2',
|
||||
'eu-west-1',
|
||||
'sa-east-1',
|
||||
'us-east-1',
|
||||
'us-west-1',
|
||||
'us-west-2']
|
||||
|
||||
try:
|
||||
import boto
|
||||
import boto.ec2
|
||||
|
||||
@@ -113,16 +113,12 @@ def main():
|
||||
ec2_url=dict(aliases=['EC2_URL']),
|
||||
ec2_secret_key=dict(aliases=['EC2_SECRET_KEY', 'aws_secret_key'], no_log=True),
|
||||
ec2_access_key=dict(aliases=['EC2_ACCESS_KEY', 'aws_access_key']),
|
||||
region=dict(choices=['eu-west-1', 'sa-east-1', 'us-east-1', 'ap-northeast-1', 'us-west-2', 'us-west-1', 'ap-southeast-1', 'ap-southeast-2']),
|
||||
region=dict(choices=AWS_REGIONS),
|
||||
state = dict(default='present', choices=['present', 'absent']),
|
||||
),
|
||||
supports_check_mode=True,
|
||||
)
|
||||
|
||||
# def get_ec2_creds(module):
|
||||
# return ec2_url, ec2_access_key, ec2_secret_key, region
|
||||
ec2_url, ec2_access_key, ec2_secret_key, region = get_ec2_creds(module)
|
||||
|
||||
name = module.params['name']
|
||||
description = module.params['description']
|
||||
vpc_id = module.params['vpc_id']
|
||||
@@ -131,21 +127,7 @@ def main():
|
||||
|
||||
changed = False
|
||||
|
||||
# If we have a region specified, connect to its endpoint.
|
||||
if region:
|
||||
try:
|
||||
ec2 = boto.ec2.connect_to_region(region, aws_access_key_id=ec2_access_key, aws_secret_access_key=ec2_secret_key)
|
||||
except boto.exception.NoAuthHandlerFound, e:
|
||||
module.fail_json(msg=str(e))
|
||||
# Otherwise, no region so we fallback to the old connection method
|
||||
else:
|
||||
try:
|
||||
if ec2_url: # if we have an URL set, connect to the specified endpoint
|
||||
ec2 = boto.connect_ec2_endpoint(ec2_url, ec2_access_key, ec2_secret_key)
|
||||
else: # otherwise it's Amazon.
|
||||
ec2 = boto.connect_ec2(ec2_access_key, ec2_secret_key)
|
||||
except boto.exception.NoAuthHandlerFound, e:
|
||||
module.fail_json(msg=str(e))
|
||||
ec2 = ec2_connect(module)
|
||||
|
||||
# find the group if present
|
||||
group = None
|
||||
|
||||
@@ -102,15 +102,6 @@ except ImportError:
|
||||
print "failed=True msg='boto required for this module'"
|
||||
sys.exit(1)
|
||||
|
||||
AWS_REGIONS = ['ap-northeast-1',
|
||||
'ap-southeast-1',
|
||||
'ap-southeast-2',
|
||||
'eu-west-1',
|
||||
'sa-east-1',
|
||||
'us-east-1',
|
||||
'us-west-1',
|
||||
'us-west-2']
|
||||
|
||||
def main():
|
||||
module = AnsibleModule(
|
||||
argument_spec = dict(
|
||||
@@ -124,28 +115,11 @@ def main():
|
||||
)
|
||||
)
|
||||
|
||||
# def get_ec2_creds(module):
|
||||
# return ec2_url, ec2_access_key, ec2_secret_key, region
|
||||
ec2_url, aws_access_key, aws_secret_key, region = get_ec2_creds(module)
|
||||
|
||||
resource = module.params.get('resource')
|
||||
tags = module.params['tags']
|
||||
state = module.params.get('state')
|
||||
|
||||
# If we have a region specified, connect to its endpoint.
|
||||
if region:
|
||||
try:
|
||||
ec2 = boto.ec2.connect_to_region(region, aws_access_key_id=aws_access_key, aws_secret_access_key=aws_secret_key)
|
||||
except boto.exception.NoAuthHandlerFound, e:
|
||||
module.fail_json(msg = str(e))
|
||||
# Otherwise, no region so we fallback to the old connection method
|
||||
elif ec2_url:
|
||||
try:
|
||||
ec2 = boto.connect_ec2_endpoint(ec2_url, aws_access_key, aws_secret_key)
|
||||
except boto.exception.NoAuthHandlerFound, e:
|
||||
module.fail_json(msg = str(e))
|
||||
else:
|
||||
module.fail_json(msg="Either region or ec2_url must be specified")
|
||||
ec2 = ec2_connect(module)
|
||||
|
||||
# We need a comparison here so that we can accurately report back changed status.
|
||||
# Need to expand the gettags return format and compare with "tags" and then tag or detag as appropriate.
|
||||
|
||||
@@ -127,15 +127,6 @@ except ImportError:
|
||||
print "failed=True msg='boto required for this module'"
|
||||
sys.exit(1)
|
||||
|
||||
AWS_REGIONS = ['ap-northeast-1',
|
||||
'ap-southeast-1',
|
||||
'ap-southeast-2',
|
||||
'eu-west-1',
|
||||
'sa-east-1',
|
||||
'us-east-1',
|
||||
'us-west-1',
|
||||
'us-west-2']
|
||||
|
||||
def main():
|
||||
module = AnsibleModule(
|
||||
argument_spec = dict(
|
||||
@@ -151,30 +142,13 @@ def main():
|
||||
)
|
||||
)
|
||||
|
||||
# def get_ec2_creds(module):
|
||||
# return ec2_url, ec2_access_key, ec2_secret_key, region
|
||||
ec2_url, aws_access_key, aws_secret_key, region = get_ec2_creds(module)
|
||||
|
||||
instance = module.params.get('instance')
|
||||
volume_size = module.params.get('volume_size')
|
||||
iops = module.params.get('iops')
|
||||
device_name = module.params.get('device_name')
|
||||
zone = module.params.get('zone')
|
||||
|
||||
# If we have a region specified, connect to its endpoint.
|
||||
if region:
|
||||
try:
|
||||
ec2 = boto.ec2.connect_to_region(region, aws_access_key_id=aws_access_key, aws_secret_access_key=aws_secret_key)
|
||||
except boto.exception.NoAuthHandlerFound, e:
|
||||
module.fail_json(msg = str(e))
|
||||
# Otherwise, no region so we fallback to the old connection method
|
||||
elif ec2_url:
|
||||
try:
|
||||
ec2 = boto.connect_ec2_endpoint(ec2_url, aws_access_key, aws_secret_key)
|
||||
except boto.exception.NoAuthHandlerFound, e:
|
||||
module.fail_json(msg = str(e))
|
||||
else:
|
||||
module.fail_json(msg="Either region or ec2_url must be specified")
|
||||
ec2 = ec2_connect(module)
|
||||
|
||||
# Here we need to get the zone info for the instance. This covers situation where
|
||||
# instance is specified but zone isn't.
|
||||
|
||||
@@ -164,15 +164,6 @@ except ImportError:
|
||||
print "failed=True msg='boto required for this module'"
|
||||
sys.exit(1)
|
||||
|
||||
AWS_REGIONS = ['ap-northeast-1',
|
||||
'ap-southeast-1',
|
||||
'ap-southeast-2',
|
||||
'eu-west-1',
|
||||
'sa-east-1',
|
||||
'us-east-1',
|
||||
'us-west-1',
|
||||
'us-west-2']
|
||||
|
||||
def get_vpc_info(vpc):
|
||||
"""
|
||||
Retrieves vpc information from an instance
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
DOCUMENTATION = """
|
||||
---
|
||||
module: elasticache
|
||||
short_description: Manage cache clusters in Amazon Elasticache.
|
||||
description:
|
||||
- Manage cache clusters in Amazon Elasticache.
|
||||
short_description: Manage cache clusters in Amazon Elasticache.
|
||||
- Returns information about the specified cache cluster.
|
||||
version_added: "1.4"
|
||||
requirements: [ "boto" ]
|
||||
@@ -137,15 +137,6 @@ import sys
|
||||
import os
|
||||
import time
|
||||
|
||||
AWS_REGIONS = ['ap-northeast-1',
|
||||
'ap-southeast-1',
|
||||
'ap-southeast-2',
|
||||
'eu-west-1',
|
||||
'sa-east-1',
|
||||
'us-east-1',
|
||||
'us-west-1',
|
||||
'us-west-2']
|
||||
|
||||
try:
|
||||
import boto
|
||||
from boto.elasticache.layer1 import ElastiCacheConnection
|
||||
|
||||
@@ -18,11 +18,14 @@
|
||||
|
||||
try:
|
||||
from novaclient.v1_1 import client as nova_client
|
||||
from quantumclient.quantum import client
|
||||
try:
|
||||
from neutronclient.neutron import client
|
||||
except ImportError:
|
||||
from quantumclient.quantum import client
|
||||
from keystoneclient.v2_0 import client as ksclient
|
||||
import time
|
||||
except ImportError:
|
||||
print("failed=True msg='glanceclient,keystoneclient and quantumclient client are required'")
|
||||
print("failed=True msg='novaclient,keystoneclient and quantumclient (or neutronclient) are required'")
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
@@ -64,7 +67,7 @@ options:
|
||||
default: present
|
||||
network_name:
|
||||
description:
|
||||
- Name of the network from which IP has to be assigned to VM. Please make sure the network is an external network
|
||||
- Name of the network from which IP has to be assigned to VM. Please make sure the network is an external network
|
||||
required: true
|
||||
default: None
|
||||
instance_name:
|
||||
@@ -72,14 +75,19 @@ options:
|
||||
- The name of the instance to which the IP address should be assigned
|
||||
required: true
|
||||
default: None
|
||||
requirements: ["novaclient", "quantumclient", "keystoneclient"]
|
||||
internal_network_name:
|
||||
description:
|
||||
- The name of the network of the port to associate with the floating ip. Necessary when VM multiple networks.
|
||||
required: false
|
||||
default: None
|
||||
requirements: ["novaclient", "quantumclient", "neutronclient", "keystoneclient"]
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
# Assign a floating ip to the instance from an external network
|
||||
- quantum_floating_ip: state=present login_username=admin login_password=admin
|
||||
login_tenant_name=admin network_name=external_network
|
||||
instance_name=vm1
|
||||
instance_name=vm1 internal_network_name=internal_network
|
||||
'''
|
||||
|
||||
def _get_ksclient(module, kwargs):
|
||||
@@ -99,10 +107,10 @@ def _get_endpoint(module, ksclient):
|
||||
try:
|
||||
endpoint = ksclient.service_catalog.url_for(service_type='network', endpoint_type='publicURL')
|
||||
except Exception as e:
|
||||
module.fail_json(msg = "Error getting endpoint for glance: %s" % e.message)
|
||||
module.fail_json(msg = "Error getting network endpoint: %s" % e.message)
|
||||
return endpoint
|
||||
|
||||
def _get_quantum_client(module, kwargs):
|
||||
def _get_neutron_client(module, kwargs):
|
||||
_ksclient = _get_ksclient(module, kwargs)
|
||||
token = _ksclient.auth_token
|
||||
endpoint = _get_endpoint(module, _ksclient)
|
||||
@@ -111,10 +119,10 @@ def _get_quantum_client(module, kwargs):
|
||||
'endpoint_url': endpoint
|
||||
}
|
||||
try:
|
||||
quantum = client.Client('2.0', **kwargs)
|
||||
neutron = client.Client('2.0', **kwargs)
|
||||
except Exception as e:
|
||||
module.fail_json(msg = "Error in connecting to quantum: %s " % e.message)
|
||||
return quantum
|
||||
module.fail_json(msg = "Error in connecting to neutron: %s " % e.message)
|
||||
return neutron
|
||||
|
||||
def _get_server_state(module, nova):
|
||||
server_info = None
|
||||
@@ -130,68 +138,81 @@ def _get_server_state(module, nova):
|
||||
break
|
||||
except Exception as e:
|
||||
module.fail_json(msg = "Error in getting the server list: %s" % e.message)
|
||||
return server_info, server
|
||||
|
||||
def _get_port_info(quantum, module, instance_id):
|
||||
return server_info, server
|
||||
|
||||
def _get_port_info(neutron, module, instance_id, internal_network_name=None):
|
||||
if internal_network_name:
|
||||
kwargs = {
|
||||
'name': internal_network_name,
|
||||
}
|
||||
networks = neutron.list_networks(**kwargs)
|
||||
subnet_id = networks['networks'][0]['subnets'][0]
|
||||
kwargs = {
|
||||
'device_id': instance_id,
|
||||
}
|
||||
try:
|
||||
ports = quantum.list_ports(**kwargs)
|
||||
ports = neutron.list_ports(**kwargs)
|
||||
except Exception as e:
|
||||
module.fail_json( msg = "Error in listing ports: %s" % e.message)
|
||||
if subnet_id:
|
||||
port = next(port for port in ports['ports'] if port['fixed_ips'][0]['subnet_id'] == subnet_id)
|
||||
port_id = port['id']
|
||||
fixed_ip_address = port['fixed_ips'][0]['ip_address']
|
||||
else:
|
||||
port_id = ports['ports'][0]['id']
|
||||
fixed_ip_address = ports['ports'][0]['fixed_ips'][0]['ip_address']
|
||||
if not ports['ports']:
|
||||
return None, None
|
||||
return ports['ports'][0]['fixed_ips'][0]['ip_address'], ports['ports'][0]['id']
|
||||
|
||||
def _get_floating_ip(module, quantum, fixed_ip_address):
|
||||
return fixed_ip_address, port_id
|
||||
|
||||
def _get_floating_ip(module, neutron, fixed_ip_address):
|
||||
kwargs = {
|
||||
'fixed_ip_address': fixed_ip_address
|
||||
}
|
||||
try:
|
||||
ips = quantum.list_floatingips(**kwargs)
|
||||
ips = neutron.list_floatingips(**kwargs)
|
||||
except Exception as e:
|
||||
module.fail_json(msg = "error in fetching the floatingips's %s" % e.message)
|
||||
if not ips['floatingips']:
|
||||
return None, None
|
||||
return ips['floatingips'][0]['id'], ips['floatingips'][0]['floating_ip_address']
|
||||
|
||||
def _create_floating_ip(quantum, module, port_id, net_id):
|
||||
def _create_floating_ip(neutron, module, port_id, net_id):
|
||||
kwargs = {
|
||||
'port_id': port_id,
|
||||
'floating_network_id': net_id
|
||||
}
|
||||
try:
|
||||
result = quantum.create_floatingip({'floatingip': kwargs})
|
||||
result = neutron.create_floatingip({'floatingip': kwargs})
|
||||
except Exception as e:
|
||||
module.fail_json(msg="There was an error in updating the floating ip address: %s" % e.message)
|
||||
module.exit_json(changed=True, result=result, public_ip=result['floatingip']['floating_ip_address'])
|
||||
|
||||
def _get_net_id(quantum, module):
|
||||
def _get_net_id(neutron, module):
|
||||
kwargs = {
|
||||
'name': module.params['network_name'],
|
||||
}
|
||||
try:
|
||||
networks = quantum.list_networks(**kwargs)
|
||||
networks = neutron.list_networks(**kwargs)
|
||||
except Exception as e:
|
||||
module.fail_json("Error in listing quantum networks: %s" % e.message)
|
||||
module.fail_json("Error in listing neutron networks: %s" % e.message)
|
||||
if not networks['networks']:
|
||||
return None
|
||||
return networks['networks'][0]['id']
|
||||
|
||||
def _update_floating_ip(quantum, module, port_id, floating_ip_id):
|
||||
def _update_floating_ip(neutron, module, port_id, floating_ip_id):
|
||||
kwargs = {
|
||||
'port_id': port_id
|
||||
}
|
||||
try:
|
||||
result = quantum.update_floatingip(floating_ip_id, {'floatingip': kwargs})
|
||||
result = neutron.update_floatingip(floating_ip_id, {'floatingip': kwargs})
|
||||
except Exception as e:
|
||||
module.fail_json(msg="There was an error in updating the floating ip address: %s" % e.message)
|
||||
module.exit_json(changed=True, result=result)
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
|
||||
module = AnsibleModule(
|
||||
argument_spec = dict(
|
||||
login_username = dict(default='admin'),
|
||||
@@ -200,39 +221,40 @@ def main():
|
||||
auth_url = dict(default='http://127.0.0.1:35357/v2.0/'),
|
||||
region_name = dict(default=None),
|
||||
network_name = dict(required=True),
|
||||
instance_name = dict(required=True),
|
||||
state = dict(default='present', choices=['absent', 'present'])
|
||||
instance_name = dict(required=True),
|
||||
state = dict(default='present', choices=['absent', 'present']),
|
||||
internal_network_name = dict(default=None),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
try:
|
||||
nova = nova_client.Client(module.params['login_username'], module.params['login_password'],
|
||||
nova = nova_client.Client(module.params['login_username'], module.params['login_password'],
|
||||
module.params['login_tenant_name'], module.params['auth_url'], service_type='compute')
|
||||
quantum = _get_quantum_client(module, module.params)
|
||||
neutron = _get_neutron_client(module, module.params)
|
||||
except Exception as e:
|
||||
module.fail_json(msg="Error in authenticating to nova: %s" % e.message)
|
||||
|
||||
|
||||
server_info, server_obj = _get_server_state(module, nova)
|
||||
if not server_info:
|
||||
module.fail_json(msg="The instance name provided cannot be found")
|
||||
|
||||
fixed_ip, port_id = _get_port_info(quantum, module, server_info['id'])
|
||||
fixed_ip, port_id = _get_port_info(neutron, module, server_info['id'], module.params['internal_network_name'])
|
||||
if not port_id:
|
||||
module.fail_json(msg="Cannot find a port for this instance, maybe fixed ip is not assigned")
|
||||
|
||||
floating_id, floating_ip = _get_floating_ip(module, quantum, fixed_ip)
|
||||
floating_id, floating_ip = _get_floating_ip(module, neutron, fixed_ip)
|
||||
|
||||
if module.params['state'] == 'present':
|
||||
if floating_ip:
|
||||
module.exit_json(changed = False, public_ip=floating_ip)
|
||||
net_id = _get_net_id(quantum, module)
|
||||
net_id = _get_net_id(neutron, module)
|
||||
if not net_id:
|
||||
module.fail_json(msg = "cannot find the network specified, please check")
|
||||
_create_floating_ip(quantum, module, port_id, net_id)
|
||||
_create_floating_ip(neutron, module, port_id, net_id)
|
||||
|
||||
if module.params['state'] == 'absent':
|
||||
if floating_ip:
|
||||
_update_floating_ip(quantum, module, None, floating_id)
|
||||
_update_floating_ip(neutron, module, None, floating_id)
|
||||
module.exit_json(changed=False)
|
||||
|
||||
# this is magic, see lib/ansible/module.params['common.py
|
||||
|
||||
@@ -18,11 +18,14 @@
|
||||
|
||||
try:
|
||||
from novaclient.v1_1 import client as nova_client
|
||||
from quantumclient.quantum import client
|
||||
try:
|
||||
from neutronclient.neutron import client
|
||||
except ImportError:
|
||||
from quantumclient.quantum import client
|
||||
from keystoneclient.v2_0 import client as ksclient
|
||||
import time
|
||||
except ImportError:
|
||||
print "failed=True msg='glanceclient,novaclient and keystone client are required'"
|
||||
print "failed=True msg='novaclient, keystone, and quantumclient (or neutronclient) client are required'"
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
@@ -72,7 +75,7 @@ options:
|
||||
- floating ip that should be assigned to the instance
|
||||
required: true
|
||||
default: None
|
||||
requirements: ["quantumclient", "keystoneclient"]
|
||||
requirements: ["quantumclient", "neutronclient", "keystoneclient"]
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
@@ -103,10 +106,10 @@ def _get_endpoint(module, ksclient):
|
||||
try:
|
||||
endpoint = ksclient.service_catalog.url_for(service_type='network', endpoint_type='publicURL')
|
||||
except Exception as e:
|
||||
module.fail_json(msg = "Error getting endpoint for glance: %s" % e.message)
|
||||
module.fail_json(msg = "Error getting network endpoint: %s" % e.message)
|
||||
return endpoint
|
||||
|
||||
def _get_quantum_client(module, kwargs):
|
||||
def _get_neutron_client(module, kwargs):
|
||||
_ksclient = _get_ksclient(module, kwargs)
|
||||
token = _ksclient.auth_token
|
||||
endpoint = _get_endpoint(module, _ksclient)
|
||||
@@ -115,10 +118,10 @@ def _get_quantum_client(module, kwargs):
|
||||
'endpoint_url': endpoint
|
||||
}
|
||||
try:
|
||||
quantum = client.Client('2.0', **kwargs)
|
||||
neutron = client.Client('2.0', **kwargs)
|
||||
except Exception as e:
|
||||
module.fail_json(msg = "Error in connecting to quantum: %s " % e.message)
|
||||
return quantum
|
||||
module.fail_json(msg = "Error in connecting to neutron: %s " % e.message)
|
||||
return neutron
|
||||
|
||||
def _get_server_state(module, nova):
|
||||
server_info = None
|
||||
@@ -134,24 +137,24 @@ def _get_server_state(module, nova):
|
||||
break
|
||||
except Exception as e:
|
||||
module.fail_json(msg = "Error in getting the server list: %s" % e.message)
|
||||
return server_info, server
|
||||
|
||||
def _get_port_id(quantum, module, instance_id):
|
||||
return server_info, server
|
||||
|
||||
def _get_port_id(neutron, module, instance_id):
|
||||
kwargs = dict(device_id = instance_id)
|
||||
try:
|
||||
ports = quantum.list_ports(**kwargs)
|
||||
ports = neutron.list_ports(**kwargs)
|
||||
except Exception as e:
|
||||
module.fail_json( msg = "Error in listing ports: %s" % e.message)
|
||||
if not ports['ports']:
|
||||
return None
|
||||
return ports['ports'][0]['id']
|
||||
|
||||
def _get_floating_ip_id(module, quantum):
|
||||
|
||||
def _get_floating_ip_id(module, neutron):
|
||||
kwargs = {
|
||||
'floating_ip_address': module.params['ip_address']
|
||||
}
|
||||
try:
|
||||
ips = quantum.list_floatingips(**kwargs)
|
||||
ips = neutron.list_floatingips(**kwargs)
|
||||
except Exception as e:
|
||||
module.fail_json(msg = "error in fetching the floatingips's %s" % e.message)
|
||||
if not ips['floatingips']:
|
||||
@@ -163,18 +166,18 @@ def _get_floating_ip_id(module, quantum):
|
||||
state = "attached"
|
||||
return state, ip
|
||||
|
||||
def _update_floating_ip(quantum, module, port_id, floating_ip_id):
|
||||
def _update_floating_ip(neutron, module, port_id, floating_ip_id):
|
||||
kwargs = {
|
||||
'port_id': port_id
|
||||
}
|
||||
try:
|
||||
result = quantum.update_floatingip(floating_ip_id, {'floatingip': kwargs})
|
||||
result = neutron.update_floatingip(floating_ip_id, {'floatingip': kwargs})
|
||||
except Exception as e:
|
||||
module.fail_json(msg = "There was an error in updating the floating ip address: %s" % e.message)
|
||||
module.exit_json(changed = True, result = result, public_ip=module.params['ip_address'])
|
||||
|
||||
def main():
|
||||
|
||||
|
||||
module = AnsibleModule(
|
||||
argument_spec = dict(
|
||||
login_username = dict(default='admin'),
|
||||
@@ -183,33 +186,34 @@ def main():
|
||||
auth_url = dict(default='http://127.0.0.1:35357/v2.0/'),
|
||||
region_name = dict(default=None),
|
||||
ip_address = dict(required=True),
|
||||
instance_name = dict(required=True),
|
||||
instance_name = dict(required=True),
|
||||
state = dict(default='present', choices=['absent', 'present'])
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
try:
|
||||
nova = nova_client.Client(module.params['login_username'], module.params['login_password'], module.params['login_tenant_name'], module.params['auth_url'], service_type='compute')
|
||||
nova = nova_client.Client(module.params['login_username'], module.params['login_password'],
|
||||
module.params['login_tenant_name'], module.params['auth_url'], service_type='compute')
|
||||
except Exception as e:
|
||||
module.fail_json( msg = " Error in authenticating to nova: %s" % e.message)
|
||||
quantum = _get_quantum_client(module, module.params)
|
||||
state, floating_ip_id = _get_floating_ip_id(module, quantum)
|
||||
neutron = _get_neutron_client(module, module.params)
|
||||
state, floating_ip_id = _get_floating_ip_id(module, neutron)
|
||||
if module.params['state'] == 'present':
|
||||
if state == 'attached':
|
||||
module.exit_json(changed = False, result = 'attached', public_ip=module.params['ip_address'])
|
||||
server_info, server_obj = _get_server_state(module, nova)
|
||||
if not server_info:
|
||||
module.fail_json(msg = " The instance name provided cannot be found")
|
||||
port_id = _get_port_id(quantum, module, server_info['id'])
|
||||
port_id = _get_port_id(neutron, module, server_info['id'])
|
||||
if not port_id:
|
||||
module.fail_json(msg = "Cannot find a port for this instance, maybe fixed ip is not assigned")
|
||||
_update_floating_ip(quantum, module, port_id, floating_ip_id)
|
||||
_update_floating_ip(neutron, module, port_id, floating_ip_id)
|
||||
|
||||
if module.params['state'] == 'absent':
|
||||
if state == 'detached':
|
||||
module.exit_json(changed = False, result = 'detached')
|
||||
if state == 'attached':
|
||||
_update_floating_ip(quantum, module, None, floating_ip_id)
|
||||
_update_floating_ip(neutron, module, None, floating_ip_id)
|
||||
module.exit_json(changed = True, result = "detached")
|
||||
|
||||
# this is magic, see lib/ansible/module.params['common.py
|
||||
|
||||
@@ -17,10 +17,13 @@
|
||||
# along with this software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
try:
|
||||
from quantumclient.quantum import client
|
||||
try:
|
||||
from neutronclient.neutron import client
|
||||
except ImportError:
|
||||
from quantumclient.quantum import client
|
||||
from keystoneclient.v2_0 import client as ksclient
|
||||
except ImportError:
|
||||
print("failed=True msg='quantumclient and keystone client are required'")
|
||||
print("failed=True msg='quantumclient (or neutronclient) and keystone client are required'")
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
@@ -67,7 +70,7 @@ options:
|
||||
default: present
|
||||
name:
|
||||
description:
|
||||
- Name to be assigned to the nework
|
||||
- Name to be assigned to the nework
|
||||
required: true
|
||||
default: None
|
||||
provider_network_type:
|
||||
@@ -100,7 +103,7 @@ options:
|
||||
- Whether the state should be marked as up or down
|
||||
required: false
|
||||
default: true
|
||||
requirements: ["quantumclient", "keystoneclient"]
|
||||
requirements: ["quantumclient", "neutronclient", "keystoneclient"]
|
||||
|
||||
'''
|
||||
|
||||
@@ -125,21 +128,21 @@ def _get_ksclient(module, kwargs):
|
||||
password=kwargs.get('login_password'),
|
||||
tenant_name=kwargs.get('login_tenant_name'),
|
||||
auth_url=kwargs.get('auth_url'))
|
||||
except Exception as e:
|
||||
except Exception as e:
|
||||
module.fail_json(msg = "Error authenticating to the keystone: %s" %e.message)
|
||||
global _os_keystone
|
||||
global _os_keystone
|
||||
_os_keystone = kclient
|
||||
return kclient
|
||||
|
||||
return kclient
|
||||
|
||||
|
||||
def _get_endpoint(module, ksclient):
|
||||
try:
|
||||
endpoint = ksclient.service_catalog.url_for(service_type='network', endpoint_type='publicURL')
|
||||
except Exception as e:
|
||||
module.fail_json(msg = "Error getting endpoint for Quantum: %s " %e.message)
|
||||
module.fail_json(msg = "Error getting network endpoint: %s " %e.message)
|
||||
return endpoint
|
||||
|
||||
def _get_quantum_client(module, kwargs):
|
||||
def _get_neutron_client(module, kwargs):
|
||||
_ksclient = _get_ksclient(module, kwargs)
|
||||
token = _ksclient.auth_token
|
||||
endpoint = _get_endpoint(module, _ksclient)
|
||||
@@ -148,10 +151,10 @@ def _get_quantum_client(module, kwargs):
|
||||
'endpoint_url': endpoint
|
||||
}
|
||||
try:
|
||||
quantum = client.Client('2.0', **kwargs)
|
||||
neutron = client.Client('2.0', **kwargs)
|
||||
except Exception as e:
|
||||
module.fail_json(msg = " Error in connecting to quantum: %s " %e.message)
|
||||
return quantum
|
||||
module.fail_json(msg = " Error in connecting to neutron: %s " %e.message)
|
||||
return neutron
|
||||
|
||||
def _set_tenant_id(module):
|
||||
global _os_tenant_id
|
||||
@@ -159,7 +162,7 @@ def _set_tenant_id(module):
|
||||
tenant_name = module.params['login_tenant_name']
|
||||
else:
|
||||
tenant_name = module.params['tenant_name']
|
||||
|
||||
|
||||
for tenant in _os_keystone.tenants.list():
|
||||
if tenant.name == tenant_name:
|
||||
_os_tenant_id = tenant.id
|
||||
@@ -168,22 +171,22 @@ def _set_tenant_id(module):
|
||||
module.fail_json(msg = "The tenant id cannot be found, please check the paramters")
|
||||
|
||||
|
||||
def _get_net_id(quantum, module):
|
||||
def _get_net_id(neutron, module):
|
||||
kwargs = {
|
||||
'tenant_id': _os_tenant_id,
|
||||
'name': module.params['name'],
|
||||
}
|
||||
try:
|
||||
networks = quantum.list_networks(**kwargs)
|
||||
networks = neutron.list_networks(**kwargs)
|
||||
except Exception as e:
|
||||
module.fail_json(msg = "Error in listing quantum networks: %s" % e.message)
|
||||
if not networks['networks']:
|
||||
module.fail_json(msg = "Error in listing neutron networks: %s" % e.message)
|
||||
if not networks['networks']:
|
||||
return None
|
||||
return networks['networks'][0]['id']
|
||||
|
||||
def _create_network(module, quantum):
|
||||
def _create_network(module, neutron):
|
||||
|
||||
quantum.format = 'json'
|
||||
neutron.format = 'json'
|
||||
|
||||
network = {
|
||||
'name': module.params.get('name'),
|
||||
@@ -212,21 +215,21 @@ def _create_network(module, quantum):
|
||||
network.pop('provider:segmentation_id', None)
|
||||
|
||||
try:
|
||||
net = quantum.create_network({'network':network})
|
||||
net = neutron.create_network({'network':network})
|
||||
except Exception as e:
|
||||
module.fail_json(msg = "Error in creating network: %s" % e.message)
|
||||
return net['network']['id']
|
||||
|
||||
def _delete_network(module, net_id, quantum):
|
||||
|
||||
def _delete_network(module, net_id, neutron):
|
||||
|
||||
try:
|
||||
id = quantum.delete_network(net_id)
|
||||
except Exception as e:
|
||||
id = neutron.delete_network(net_id)
|
||||
except Exception as e:
|
||||
module.fail_json(msg = "Error in deleting the network: %s" % e.message)
|
||||
return True
|
||||
|
||||
def main():
|
||||
|
||||
|
||||
module = AnsibleModule(
|
||||
argument_spec = dict(
|
||||
login_username = dict(default='admin'),
|
||||
@@ -237,8 +240,8 @@ def main():
|
||||
name = dict(required=True),
|
||||
tenant_name = dict(default=None),
|
||||
provider_network_type = dict(default=None, choices=['local', 'vlan', 'flat', 'gre']),
|
||||
provider_physical_network = dict(default=None),
|
||||
provider_segmentation_id = dict(default=None),
|
||||
provider_physical_network = dict(default=None),
|
||||
provider_segmentation_id = dict(default=None),
|
||||
router_external = dict(default=False, type='bool'),
|
||||
shared = dict(default=False, type='bool'),
|
||||
admin_state_up = dict(default=True, type='bool'),
|
||||
@@ -254,24 +257,24 @@ def main():
|
||||
if not module.params['provider_segmentation_id']:
|
||||
module.fail_json(msg = " for vlan & gre networks, variable provider_segmentation_id should be set.")
|
||||
|
||||
quantum = _get_quantum_client(module, module.params)
|
||||
neutron = _get_neutron_client(module, module.params)
|
||||
|
||||
_set_tenant_id(module)
|
||||
_set_tenant_id(module)
|
||||
|
||||
if module.params['state'] == 'present':
|
||||
network_id = _get_net_id(quantum, module)
|
||||
if module.params['state'] == 'present':
|
||||
network_id = _get_net_id(neutron, module)
|
||||
if not network_id:
|
||||
network_id = _create_network(module, quantum)
|
||||
network_id = _create_network(module, neutron)
|
||||
module.exit_json(changed = True, result = "Created", id = network_id)
|
||||
else:
|
||||
module.exit_json(changed = False, result = "Success", id = network_id)
|
||||
|
||||
if module.params['state'] == 'absent':
|
||||
network_id = _get_net_id(quantum, module)
|
||||
network_id = _get_net_id(neutron, module)
|
||||
if not network_id:
|
||||
module.exit_json(changed = False, result = "Success")
|
||||
else:
|
||||
_delete_network(module, network_id, quantum)
|
||||
_delete_network(module, network_id, neutron)
|
||||
module.exit_json(changed = True, result = "Deleted")
|
||||
|
||||
# this is magic, see lib/ansible/module.params['common.py
|
||||
|
||||
@@ -17,10 +17,13 @@
|
||||
# along with this software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
try:
|
||||
from quantumclient.quantum import client
|
||||
try:
|
||||
from neutronclient.neutron import client
|
||||
except ImportError:
|
||||
from quantumclient.quantum import client
|
||||
from keystoneclient.v2_0 import client as ksclient
|
||||
except ImportError:
|
||||
print("failed=True msg='quantumclient and keystone client are required'")
|
||||
print("failed=True msg='quantumclient (or neutronclient) and keystone client are required'")
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
@@ -75,7 +78,7 @@ options:
|
||||
- desired admin state of the created router .
|
||||
required: false
|
||||
default: true
|
||||
requirements: ["quantumclient", "keystoneclient"]
|
||||
requirements: ["quantumclient", "neutronclient", "keystoneclient"]
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
@@ -96,21 +99,21 @@ def _get_ksclient(module, kwargs):
|
||||
password=kwargs.get('login_password'),
|
||||
tenant_name=kwargs.get('login_tenant_name'),
|
||||
auth_url=kwargs.get('auth_url'))
|
||||
except Exception as e:
|
||||
except Exception as e:
|
||||
module.fail_json(msg = "Error authenticating to the keystone: %s " % e.message)
|
||||
global _os_keystone
|
||||
global _os_keystone
|
||||
_os_keystone = kclient
|
||||
return kclient
|
||||
|
||||
return kclient
|
||||
|
||||
|
||||
def _get_endpoint(module, ksclient):
|
||||
try:
|
||||
endpoint = ksclient.service_catalog.url_for(service_type='network', endpoint_type='publicURL')
|
||||
except Exception as e:
|
||||
module.fail_json(msg = "Error getting endpoint for glance: %s" % e.message)
|
||||
module.fail_json(msg = "Error getting network endpoint: %s" % e.message)
|
||||
return endpoint
|
||||
|
||||
def _get_quantum_client(module, kwargs):
|
||||
def _get_neutron_client(module, kwargs):
|
||||
_ksclient = _get_ksclient(module, kwargs)
|
||||
token = _ksclient.auth_token
|
||||
endpoint = _get_endpoint(module, _ksclient)
|
||||
@@ -119,10 +122,10 @@ def _get_quantum_client(module, kwargs):
|
||||
'endpoint_url': endpoint
|
||||
}
|
||||
try:
|
||||
quantum = client.Client('2.0', **kwargs)
|
||||
neutron = client.Client('2.0', **kwargs)
|
||||
except Exception as e:
|
||||
module.fail_json(msg = "Error in connecting to quantum: %s " % e.message)
|
||||
return quantum
|
||||
module.fail_json(msg = "Error in connecting to neutron: %s " % e.message)
|
||||
return neutron
|
||||
|
||||
def _set_tenant_id(module):
|
||||
global _os_tenant_id
|
||||
@@ -139,38 +142,38 @@ def _set_tenant_id(module):
|
||||
module.fail_json(msg = "The tenant id cannot be found, please check the paramters")
|
||||
|
||||
|
||||
def _get_router_id(module, quantum):
|
||||
def _get_router_id(module, neutron):
|
||||
kwargs = {
|
||||
'name': module.params['name'],
|
||||
'tenant_id': _os_tenant_id,
|
||||
}
|
||||
try:
|
||||
routers = quantum.list_routers(**kwargs)
|
||||
routers = neutron.list_routers(**kwargs)
|
||||
except Exception as e:
|
||||
module.fail_json(msg = "Error in getting the router list: %s " % e.message)
|
||||
if not routers['routers']:
|
||||
return None
|
||||
return routers['routers'][0]['id']
|
||||
|
||||
def _create_router(module, quantum):
|
||||
def _create_router(module, neutron):
|
||||
router = {
|
||||
'name': module.params['name'],
|
||||
'tenant_id': _os_tenant_id,
|
||||
'admin_state_up': module.params['admin_state_up'],
|
||||
}
|
||||
try:
|
||||
new_router = quantum.create_router(dict(router=router))
|
||||
new_router = neutron.create_router(dict(router=router))
|
||||
except Exception as e:
|
||||
module.fail_json( msg = "Error in creating router: %s" % e.message)
|
||||
return new_router['router']['id']
|
||||
|
||||
def _delete_router(module, quantum, router_id):
|
||||
def _delete_router(module, neutron, router_id):
|
||||
try:
|
||||
quantum.delete_router(router_id)
|
||||
neutron.delete_router(router_id)
|
||||
except:
|
||||
module.fail_json("Error in deleting the router")
|
||||
return True
|
||||
|
||||
|
||||
def main():
|
||||
module = AnsibleModule(
|
||||
argument_spec = dict(
|
||||
@@ -185,26 +188,26 @@ def main():
|
||||
admin_state_up = dict(type='bool', default=True),
|
||||
),
|
||||
)
|
||||
|
||||
quantum = _get_quantum_client(module, module.params)
|
||||
|
||||
neutron = _get_neutron_client(module, module.params)
|
||||
_set_tenant_id(module)
|
||||
|
||||
if module.params['state'] == 'present':
|
||||
router_id = _get_router_id(module, quantum)
|
||||
router_id = _get_router_id(module, neutron)
|
||||
if not router_id:
|
||||
router_id = _create_router(module, quantum)
|
||||
router_id = _create_router(module, neutron)
|
||||
module.exit_json(changed=True, result="Created", id=router_id)
|
||||
else:
|
||||
module.exit_json(changed=False, result="success" , id=router_id)
|
||||
|
||||
else:
|
||||
router_id = _get_router_id(module, quantum)
|
||||
router_id = _get_router_id(module, neutron)
|
||||
if not router_id:
|
||||
module.exit_json(changed=False, result="success")
|
||||
else:
|
||||
_delete_router(module, quantum, router_id)
|
||||
_delete_router(module, neutron, router_id)
|
||||
module.exit_json(changed=True, result="deleted")
|
||||
|
||||
|
||||
# this is magic, see lib/ansible/module.params['common.py
|
||||
from ansible.module_utils.basic import *
|
||||
main()
|
||||
|
||||
@@ -17,10 +17,13 @@
|
||||
# along with this software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
try:
|
||||
from quantumclient.quantum import client
|
||||
try:
|
||||
from neutronclient.neutron import client
|
||||
except ImportError:
|
||||
from quantumclient.quantum import client
|
||||
from keystoneclient.v2_0 import client as ksclient
|
||||
except ImportError:
|
||||
print("failed=True msg='quantumclient and keystone client are required'")
|
||||
print("failed=True msg='quantumclient (or neutronclient) and keystone client are required'")
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: quantum_router_gateway
|
||||
@@ -69,7 +72,7 @@ options:
|
||||
- Name of the external network which should be attached to the router.
|
||||
required: true
|
||||
default: None
|
||||
requirements: ["quantumclient", "keystoneclient"]
|
||||
requirements: ["quantumclient", "neutronclient", "keystoneclient"]
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
@@ -86,21 +89,21 @@ def _get_ksclient(module, kwargs):
|
||||
password=kwargs.get('login_password'),
|
||||
tenant_name=kwargs.get('login_tenant_name'),
|
||||
auth_url=kwargs.get('auth_url'))
|
||||
except Exception as e:
|
||||
except Exception as e:
|
||||
module.fail_json(msg = "Error authenticating to the keystone: %s " % e.message)
|
||||
global _os_keystone
|
||||
global _os_keystone
|
||||
_os_keystone = kclient
|
||||
return kclient
|
||||
|
||||
return kclient
|
||||
|
||||
|
||||
def _get_endpoint(module, ksclient):
|
||||
try:
|
||||
endpoint = ksclient.service_catalog.url_for(service_type='network', endpoint_type='publicURL')
|
||||
except Exception as e:
|
||||
module.fail_json(msg = "Error getting endpoint for glance: %s" % e.message)
|
||||
module.fail_json(msg = "Error getting network endpoint: %s" % e.message)
|
||||
return endpoint
|
||||
|
||||
def _get_quantum_client(module, kwargs):
|
||||
def _get_neutron_client(module, kwargs):
|
||||
_ksclient = _get_ksclient(module, kwargs)
|
||||
token = _ksclient.auth_token
|
||||
endpoint = _get_endpoint(module, _ksclient)
|
||||
@@ -109,68 +112,68 @@ def _get_quantum_client(module, kwargs):
|
||||
'endpoint_url': endpoint
|
||||
}
|
||||
try:
|
||||
quantum = client.Client('2.0', **kwargs)
|
||||
neutron = client.Client('2.0', **kwargs)
|
||||
except Exception as e:
|
||||
module.fail_json(msg = "Error in connecting to quantum: %s " % e.message)
|
||||
return quantum
|
||||
module.fail_json(msg = "Error in connecting to neutron: %s " % e.message)
|
||||
return neutron
|
||||
|
||||
def _get_router_id(module, quantum):
|
||||
def _get_router_id(module, neutron):
|
||||
kwargs = {
|
||||
'name': module.params['router_name'],
|
||||
}
|
||||
try:
|
||||
routers = quantum.list_routers(**kwargs)
|
||||
routers = neutron.list_routers(**kwargs)
|
||||
except Exception as e:
|
||||
module.fail_json(msg = "Error in getting the router list: %s " % e.message)
|
||||
if not routers['routers']:
|
||||
return None
|
||||
return routers['routers'][0]['id']
|
||||
|
||||
def _get_net_id(quantum, module):
|
||||
def _get_net_id(neutron, module):
|
||||
kwargs = {
|
||||
'name': module.params['network_name'],
|
||||
'router:external': True
|
||||
}
|
||||
try:
|
||||
networks = quantum.list_networks(**kwargs)
|
||||
networks = neutron.list_networks(**kwargs)
|
||||
except Exception as e:
|
||||
module.fail_json("Error in listing quantum networks: %s" % e.message)
|
||||
module.fail_json("Error in listing neutron networks: %s" % e.message)
|
||||
if not networks['networks']:
|
||||
return None
|
||||
return networks['networks'][0]['id']
|
||||
|
||||
def _get_port_id(quantum, module, router_id, network_id):
|
||||
def _get_port_id(neutron, module, router_id, network_id):
|
||||
kwargs = {
|
||||
'device_id': router_id,
|
||||
'network_id': network_id,
|
||||
}
|
||||
try:
|
||||
ports = quantum.list_ports(**kwargs)
|
||||
ports = neutron.list_ports(**kwargs)
|
||||
except Exception as e:
|
||||
module.fail_json( msg = "Error in listing ports: %s" % e.message)
|
||||
if not ports['ports']:
|
||||
return None
|
||||
return ports['ports'][0]['id']
|
||||
|
||||
def _add_gateway_router(quantum, module, router_id, network_id):
|
||||
def _add_gateway_router(neutron, module, router_id, network_id):
|
||||
kwargs = {
|
||||
'network_id': network_id
|
||||
}
|
||||
try:
|
||||
quantum.add_gateway_router(router_id, kwargs)
|
||||
neutron.add_gateway_router(router_id, kwargs)
|
||||
except Exception as e:
|
||||
module.fail_json(msg = "Error in adding gateway to router: %s" % e.message)
|
||||
return True
|
||||
|
||||
def _remove_gateway_router(quantum, module, router_id):
|
||||
|
||||
def _remove_gateway_router(neutron, module, router_id):
|
||||
try:
|
||||
quantum.remove_gateway_router(router_id)
|
||||
neutron.remove_gateway_router(router_id)
|
||||
except Exception as e:
|
||||
module.fail_json(msg = "Error in removing gateway to router: %s" % e.message)
|
||||
return True
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
|
||||
module = AnsibleModule(
|
||||
argument_spec = dict(
|
||||
login_username = dict(default='admin'),
|
||||
@@ -183,29 +186,29 @@ def main():
|
||||
state = dict(default='present', choices=['absent', 'present']),
|
||||
),
|
||||
)
|
||||
|
||||
quantum = _get_quantum_client(module, module.params)
|
||||
router_id = _get_router_id(module, quantum)
|
||||
|
||||
neutron = _get_neutron_client(module, module.params)
|
||||
router_id = _get_router_id(module, neutron)
|
||||
|
||||
if not router_id:
|
||||
module.fail_json(msg="failed to get the router id, please check the router name")
|
||||
|
||||
network_id = _get_net_id(quantum, module)
|
||||
network_id = _get_net_id(neutron, module)
|
||||
if not network_id:
|
||||
module.fail_json(msg="failed to get the network id, please check the network name and make sure it is external")
|
||||
|
||||
|
||||
if module.params['state'] == 'present':
|
||||
port_id = _get_port_id(quantum, module, router_id, network_id)
|
||||
port_id = _get_port_id(neutron, module, router_id, network_id)
|
||||
if not port_id:
|
||||
_add_gateway_router(quantum, module, router_id, network_id)
|
||||
_add_gateway_router(neutron, module, router_id, network_id)
|
||||
module.exit_json(changed=True, result="created")
|
||||
module.exit_json(changed=False, result="success")
|
||||
|
||||
if module.params['state'] == 'absent':
|
||||
port_id = _get_port_id(quantum, module, router_id, network_id)
|
||||
port_id = _get_port_id(neutron, module, router_id, network_id)
|
||||
if not port_id:
|
||||
module.exit_json(changed=False, result="Success")
|
||||
_remove_gateway_router(quantum, module, router_id)
|
||||
_remove_gateway_router(neutron, module, router_id)
|
||||
module.exit_json(changed=True, result="Deleted")
|
||||
|
||||
# this is magic, see lib/ansible/module.params['common.py
|
||||
|
||||
@@ -17,10 +17,13 @@
|
||||
# along with this software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
try:
|
||||
from quantumclient.quantum import client
|
||||
try:
|
||||
from neutronclient.neutron import client
|
||||
except ImportError:
|
||||
from quantumclient.quantum import client
|
||||
from keystoneclient.v2_0 import client as ksclient
|
||||
except ImportError:
|
||||
print("failed=True msg='quantumclient and keystone client are required'")
|
||||
print("failed=True msg='quantumclient (or neutronclient) and keystone client are required'")
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: quantum_router_interface
|
||||
@@ -81,7 +84,7 @@ EXAMPLES = '''
|
||||
# Attach tenant1's subnet to the external router
|
||||
- quantum_router_interface: state=present login_username=admin
|
||||
login_password=admin
|
||||
login_tenant_name=admin
|
||||
login_tenant_name=admin
|
||||
tenant_name=tenant1
|
||||
router_name=external_route
|
||||
subnet_name=t1subnet
|
||||
@@ -97,21 +100,21 @@ def _get_ksclient(module, kwargs):
|
||||
password=kwargs.get('login_password'),
|
||||
tenant_name=kwargs.get('login_tenant_name'),
|
||||
auth_url=kwargs.get('auth_url'))
|
||||
except Exception as e:
|
||||
except Exception as e:
|
||||
module.fail_json(msg = "Error authenticating to the keystone: %s " % e.message)
|
||||
global _os_keystone
|
||||
global _os_keystone
|
||||
_os_keystone = kclient
|
||||
return kclient
|
||||
|
||||
return kclient
|
||||
|
||||
|
||||
def _get_endpoint(module, ksclient):
|
||||
try:
|
||||
endpoint = ksclient.service_catalog.url_for(service_type='network', endpoint_type='publicURL')
|
||||
except Exception as e:
|
||||
module.fail_json(msg = "Error getting endpoint for glance: %s" % e.message)
|
||||
module.fail_json(msg = "Error getting network endpoint: %s" % e.message)
|
||||
return endpoint
|
||||
|
||||
def _get_quantum_client(module, kwargs):
|
||||
def _get_neutron_client(module, kwargs):
|
||||
_ksclient = _get_ksclient(module, kwargs)
|
||||
token = _ksclient.auth_token
|
||||
endpoint = _get_endpoint(module, _ksclient)
|
||||
@@ -120,10 +123,10 @@ def _get_quantum_client(module, kwargs):
|
||||
'endpoint_url': endpoint
|
||||
}
|
||||
try:
|
||||
quantum = client.Client('2.0', **kwargs)
|
||||
neutron = client.Client('2.0', **kwargs)
|
||||
except Exception as e:
|
||||
module.fail_json(msg = "Error in connecting to quantum: %s " % e.message)
|
||||
return quantum
|
||||
module.fail_json(msg = "Error in connecting to neutron: %s " % e.message)
|
||||
return neutron
|
||||
|
||||
def _set_tenant_id(module):
|
||||
global _os_tenant_id
|
||||
@@ -140,12 +143,12 @@ def _set_tenant_id(module):
|
||||
module.fail_json(msg = "The tenant id cannot be found, please check the paramters")
|
||||
|
||||
|
||||
def _get_router_id(module, quantum):
|
||||
def _get_router_id(module, neutron):
|
||||
kwargs = {
|
||||
'name': module.params['router_name'],
|
||||
}
|
||||
try:
|
||||
routers = quantum.list_routers(**kwargs)
|
||||
routers = neutron.list_routers(**kwargs)
|
||||
except Exception as e:
|
||||
module.fail_json(msg = "Error in getting the router list: %s " % e.message)
|
||||
if not routers['routers']:
|
||||
@@ -153,27 +156,27 @@ def _get_router_id(module, quantum):
|
||||
return routers['routers'][0]['id']
|
||||
|
||||
|
||||
def _get_subnet_id(module, quantum):
|
||||
def _get_subnet_id(module, neutron):
|
||||
subnet_id = None
|
||||
kwargs = {
|
||||
'tenant_id': _os_tenant_id,
|
||||
'name': module.params['subnet_name'],
|
||||
}
|
||||
try:
|
||||
subnets = quantum.list_subnets(**kwargs)
|
||||
subnets = neutron.list_subnets(**kwargs)
|
||||
except Exception as e:
|
||||
module.fail_json( msg = " Error in getting the subnet list:%s " % e.message)
|
||||
if not subnets['subnets']:
|
||||
return None
|
||||
return subnets['subnets'][0]['id']
|
||||
|
||||
def _get_port_id(quantum, module, router_id, subnet_id):
|
||||
|
||||
def _get_port_id(neutron, module, router_id, subnet_id):
|
||||
kwargs = {
|
||||
'tenant_id': _os_tenant_id,
|
||||
'device_id': router_id,
|
||||
}
|
||||
try:
|
||||
ports = quantum.list_ports(**kwargs)
|
||||
ports = neutron.list_ports(**kwargs)
|
||||
except Exception as e:
|
||||
module.fail_json( msg = "Error in listing ports: %s" % e.message)
|
||||
if not ports['ports']:
|
||||
@@ -184,26 +187,26 @@ def _get_port_id(quantum, module, router_id, subnet_id):
|
||||
return port['id']
|
||||
return None
|
||||
|
||||
def _add_interface_router(quantum, module, router_id, subnet_id):
|
||||
def _add_interface_router(neutron, module, router_id, subnet_id):
|
||||
kwargs = {
|
||||
'subnet_id': subnet_id
|
||||
}
|
||||
try:
|
||||
quantum.add_interface_router(router_id, kwargs)
|
||||
neutron.add_interface_router(router_id, kwargs)
|
||||
except Exception as e:
|
||||
module.fail_json(msg = "Error in adding interface to router: %s" % e.message)
|
||||
return True
|
||||
|
||||
def _remove_interface_router(quantum, module, router_id, subnet_id):
|
||||
|
||||
def _remove_interface_router(neutron, module, router_id, subnet_id):
|
||||
kwargs = {
|
||||
'subnet_id': subnet_id
|
||||
}
|
||||
try:
|
||||
quantum.remove_interface_router(router_id, kwargs)
|
||||
neutron.remove_interface_router(router_id, kwargs)
|
||||
except Exception as e:
|
||||
module.fail_json(msg="Error in removing interface from router: %s" % e.message)
|
||||
return True
|
||||
|
||||
|
||||
def main():
|
||||
module = AnsibleModule(
|
||||
argument_spec = dict(
|
||||
@@ -218,32 +221,32 @@ def main():
|
||||
state = dict(default='present', choices=['absent', 'present']),
|
||||
),
|
||||
)
|
||||
|
||||
quantum = _get_quantum_client(module, module.params)
|
||||
|
||||
neutron = _get_neutron_client(module, module.params)
|
||||
_set_tenant_id(module)
|
||||
|
||||
router_id = _get_router_id(module, quantum)
|
||||
router_id = _get_router_id(module, neutron)
|
||||
if not router_id:
|
||||
module.fail_json(msg="failed to get the router id, please check the router name")
|
||||
|
||||
subnet_id = _get_subnet_id(module, quantum)
|
||||
subnet_id = _get_subnet_id(module, neutron)
|
||||
if not subnet_id:
|
||||
module.fail_json(msg="failed to get the subnet id, please check the subnet name")
|
||||
|
||||
|
||||
if module.params['state'] == 'present':
|
||||
port_id = _get_port_id(quantum, module, router_id, subnet_id)
|
||||
port_id = _get_port_id(neutron, module, router_id, subnet_id)
|
||||
if not port_id:
|
||||
_add_interface_router(quantum, module, router_id, subnet_id)
|
||||
_add_interface_router(neutron, module, router_id, subnet_id)
|
||||
module.exit_json(changed=True, result="created", id=port_id)
|
||||
module.exit_json(changed=False, result="success", id=port_id)
|
||||
|
||||
if module.params['state'] == 'absent':
|
||||
port_id = _get_port_id(quantum, module, router_id, subnet_id)
|
||||
port_id = _get_port_id(neutron, module, router_id, subnet_id)
|
||||
if not port_id:
|
||||
module.exit_json(changed = False, result = "Success")
|
||||
_remove_interface_router(quantum, module, router_id, subnet_id)
|
||||
_remove_interface_router(neutron, module, router_id, subnet_id)
|
||||
module.exit_json(changed=True, result="Deleted")
|
||||
|
||||
|
||||
# this is magic, see lib/ansible/module.params['common.py
|
||||
from ansible.module_utils.basic import *
|
||||
main()
|
||||
|
||||
@@ -17,10 +17,13 @@
|
||||
# along with this software. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
try:
|
||||
from quantumclient.quantum import client
|
||||
try:
|
||||
from neutronclient.neutron import client
|
||||
except ImportError:
|
||||
from quantumclient.quantum import client
|
||||
from keystoneclient.v2_0 import client as ksclient
|
||||
except ImportError:
|
||||
print("failed=True msg='quantum and keystone client are required'")
|
||||
print("failed=True msg='quantumclient (or neutronclient) and keystoneclient are required'")
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
@@ -77,7 +80,7 @@ options:
|
||||
default: None
|
||||
ip_version:
|
||||
description:
|
||||
- The IP version of the subnet 4 or 6
|
||||
- The IP version of the subnet 4 or 6
|
||||
required: false
|
||||
default: 4
|
||||
enable_dhcp:
|
||||
@@ -105,7 +108,7 @@ options:
|
||||
- From the subnet pool the last IP that should be assigned to the virtual machines
|
||||
required: false
|
||||
default: None
|
||||
requirements: ["quantum", "keystoneclient"]
|
||||
requirements: ["quantumclient", "neutronclient", "keystoneclient"]
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
@@ -125,21 +128,21 @@ def _get_ksclient(module, kwargs):
|
||||
password=kwargs.get('login_password'),
|
||||
tenant_name=kwargs.get('login_tenant_name'),
|
||||
auth_url=kwargs.get('auth_url'))
|
||||
except Exception as e:
|
||||
except Exception as e:
|
||||
module.fail_json(msg = "Error authenticating to the keystone: %s" %e.message)
|
||||
global _os_keystone
|
||||
global _os_keystone
|
||||
_os_keystone = kclient
|
||||
return kclient
|
||||
|
||||
return kclient
|
||||
|
||||
|
||||
def _get_endpoint(module, ksclient):
|
||||
try:
|
||||
endpoint = ksclient.service_catalog.url_for(service_type='network', endpoint_type='publicURL')
|
||||
except Exception as e:
|
||||
module.fail_json(msg = "Error getting endpoint for glance: %s" % e.message)
|
||||
module.fail_json(msg = "Error getting network endpoint: %s" % e.message)
|
||||
return endpoint
|
||||
|
||||
def _get_quantum_client(module, kwargs):
|
||||
def _get_neutron_client(module, kwargs):
|
||||
_ksclient = _get_ksclient(module, kwargs)
|
||||
token = _ksclient.auth_token
|
||||
endpoint = _get_endpoint(module, _ksclient)
|
||||
@@ -148,10 +151,10 @@ def _get_quantum_client(module, kwargs):
|
||||
'endpoint_url': endpoint
|
||||
}
|
||||
try:
|
||||
quantum = client.Client('2.0', **kwargs)
|
||||
neutron = client.Client('2.0', **kwargs)
|
||||
except Exception as e:
|
||||
module.fail_json(msg = " Error in connecting to quantum: %s" % e.message)
|
||||
return quantum
|
||||
module.fail_json(msg = " Error in connecting to neutron: %s" % e.message)
|
||||
return neutron
|
||||
|
||||
def _set_tenant_id(module):
|
||||
global _os_tenant_id
|
||||
@@ -167,24 +170,24 @@ def _set_tenant_id(module):
|
||||
if not _os_tenant_id:
|
||||
module.fail_json(msg = "The tenant id cannot be found, please check the paramters")
|
||||
|
||||
def _get_net_id(quantum, module):
|
||||
def _get_net_id(neutron, module):
|
||||
kwargs = {
|
||||
'tenant_id': _os_tenant_id,
|
||||
'name': module.params['network_name'],
|
||||
}
|
||||
try:
|
||||
networks = quantum.list_networks(**kwargs)
|
||||
networks = neutron.list_networks(**kwargs)
|
||||
except Exception as e:
|
||||
module.fail_json("Error in listing quantum networks: %s" % e.message)
|
||||
module.fail_json("Error in listing neutron networks: %s" % e.message)
|
||||
if not networks['networks']:
|
||||
return None
|
||||
return networks['networks'][0]['id']
|
||||
|
||||
|
||||
def _get_subnet_id(module, quantum):
|
||||
def _get_subnet_id(module, neutron):
|
||||
global _os_network_id
|
||||
subnet_id = None
|
||||
_os_network_id = _get_net_id(quantum, module)
|
||||
_os_network_id = _get_net_id(neutron, module)
|
||||
if not _os_network_id:
|
||||
module.fail_json(msg = "network id of network not found.")
|
||||
else:
|
||||
@@ -193,15 +196,15 @@ def _get_subnet_id(module, quantum):
|
||||
'name': module.params['name'],
|
||||
}
|
||||
try:
|
||||
subnets = quantum.list_subnets(**kwargs)
|
||||
subnets = neutron.list_subnets(**kwargs)
|
||||
except Exception as e:
|
||||
module.fail_json( msg = " Error in getting the subnet list:%s " % e.message)
|
||||
if not subnets['subnets']:
|
||||
return None
|
||||
return subnets['subnets'][0]['id']
|
||||
|
||||
def _create_subnet(module, quantum):
|
||||
quantum.format = 'json'
|
||||
def _create_subnet(module, neutron):
|
||||
neutron.format = 'json'
|
||||
subnet = {
|
||||
'name': module.params['name'],
|
||||
'ip_version': module.params['ip_version'],
|
||||
@@ -214,7 +217,7 @@ def _create_subnet(module, quantum):
|
||||
}
|
||||
if module.params['allocation_pool_start'] and module.params['allocation_pool_end']:
|
||||
allocation_pools = [
|
||||
{
|
||||
{
|
||||
'start' : module.params['allocation_pool_start'],
|
||||
'end' : module.params['allocation_pool_end']
|
||||
}
|
||||
@@ -227,22 +230,22 @@ def _create_subnet(module, quantum):
|
||||
else:
|
||||
subnet.pop('dns_nameservers')
|
||||
try:
|
||||
new_subnet = quantum.create_subnet(dict(subnet=subnet))
|
||||
new_subnet = neutron.create_subnet(dict(subnet=subnet))
|
||||
except Exception, e:
|
||||
module.fail_json(msg = "Failure in creating subnet: %s" % e.message)
|
||||
module.fail_json(msg = "Failure in creating subnet: %s" % e.message)
|
||||
return new_subnet['subnet']['id']
|
||||
|
||||
|
||||
def _delete_subnet(module, quantum, subnet_id):
|
||||
|
||||
|
||||
def _delete_subnet(module, neutron, subnet_id):
|
||||
try:
|
||||
quantum.delete_subnet(subnet_id)
|
||||
neutron.delete_subnet(subnet_id)
|
||||
except Exception as e:
|
||||
module.fail_json( msg = "Error in deleting subnet: %s" % e.message)
|
||||
return True
|
||||
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
|
||||
module = AnsibleModule(
|
||||
argument_spec = dict(
|
||||
login_username = dict(default='admin'),
|
||||
@@ -263,23 +266,23 @@ def main():
|
||||
allocation_pool_end = dict(default=None),
|
||||
),
|
||||
)
|
||||
quantum = _get_quantum_client(module, module.params)
|
||||
neutron = _get_neutron_client(module, module.params)
|
||||
_set_tenant_id(module)
|
||||
if module.params['state'] == 'present':
|
||||
subnet_id = _get_subnet_id(module, quantum)
|
||||
subnet_id = _get_subnet_id(module, neutron)
|
||||
if not subnet_id:
|
||||
subnet_id = _create_subnet(module, quantum)
|
||||
subnet_id = _create_subnet(module, neutron)
|
||||
module.exit_json(changed = True, result = "Created" , id = subnet_id)
|
||||
else:
|
||||
module.exit_json(changed = False, result = "success" , id = subnet_id)
|
||||
else:
|
||||
subnet_id = _get_subnet_id(module, quantum)
|
||||
subnet_id = _get_subnet_id(module, neutron)
|
||||
if not subnet_id:
|
||||
module.exit_json(changed = False, result = "success")
|
||||
else:
|
||||
_delete_subnet(module, quantum, subnet_id)
|
||||
_delete_subnet(module, neutron, subnet_id)
|
||||
module.exit_json(changed = True, result = "deleted")
|
||||
|
||||
|
||||
# this is magic, see lib/ansible/module.params['common.py
|
||||
from ansible.module_utils.basic import *
|
||||
main()
|
||||
|
||||
@@ -26,6 +26,13 @@ options:
|
||||
api_key:
|
||||
description:
|
||||
- Rackspace API key (overrides I(credentials))
|
||||
auto_increment:
|
||||
description:
|
||||
- Whether or not to increment a single number with the name of the
|
||||
created servers. Only applicable when used with the I(group) attribute
|
||||
or meta key.
|
||||
default: yes
|
||||
version_added: 1.5
|
||||
count:
|
||||
description:
|
||||
- number of instances to launch
|
||||
@@ -147,6 +154,26 @@ EXAMPLES = '''
|
||||
networks:
|
||||
- private
|
||||
- public
|
||||
register: rax
|
||||
|
||||
- name: Build an exact count of cloud servers with incremented names
|
||||
hosts: local
|
||||
gather_facts: False
|
||||
tasks:
|
||||
- name: Server build requests
|
||||
local_action:
|
||||
module: rax
|
||||
credentials: ~/.raxpub
|
||||
name: test%03d.example.org
|
||||
flavor: performance1-1
|
||||
image: ubuntu-1204-lts-precise-pangolin
|
||||
state: present
|
||||
count: 10
|
||||
count_offset: 10
|
||||
exact_count: yes
|
||||
group: test
|
||||
wait: yes
|
||||
register: rax
|
||||
'''
|
||||
|
||||
import sys
|
||||
@@ -199,7 +226,7 @@ def create(module, names, flavor, image, meta, key_name, files,
|
||||
lpath = os.path.expanduser(files[rpath])
|
||||
try:
|
||||
fileobj = open(lpath, 'r')
|
||||
files[rpath] = fileobj
|
||||
files[rpath] = fileobj.read()
|
||||
except Exception, e:
|
||||
module.fail_json(msg='Failed to load %s' % lpath)
|
||||
try:
|
||||
@@ -347,7 +374,8 @@ def delete(module, instance_ids, wait, wait_timeout):
|
||||
|
||||
def cloudservers(module, state, name, flavor, image, meta, key_name, files,
|
||||
wait, wait_timeout, disk_config, count, group,
|
||||
instance_ids, exact_count, networks, count_offset):
|
||||
instance_ids, exact_count, networks, count_offset,
|
||||
auto_increment):
|
||||
cs = pyrax.cloudservers
|
||||
cnw = pyrax.cloud_networks
|
||||
servers = []
|
||||
@@ -358,6 +386,15 @@ def cloudservers(module, state, name, flavor, image, meta, key_name, files,
|
||||
elif 'group' in meta and group is None:
|
||||
group = meta['group']
|
||||
|
||||
# When using state=absent with group, the absent block won't match the
|
||||
# names properly. Use the exact_count functionality to decrease the count
|
||||
# to the desired level
|
||||
was_absent = False
|
||||
if group is not None and state == 'absent':
|
||||
exact_count = True
|
||||
state = 'present'
|
||||
was_absent = True
|
||||
|
||||
# Check if the provided image is a UUID and if not, search for an
|
||||
# appropriate image using human_id and name
|
||||
if image:
|
||||
@@ -416,27 +453,43 @@ def cloudservers(module, state, name, flavor, image, meta, key_name, files,
|
||||
module.fail_json(msg='"group" must be provided when using '
|
||||
'"exact_count"')
|
||||
else:
|
||||
numbers = set()
|
||||
if auto_increment:
|
||||
numbers = set()
|
||||
|
||||
try:
|
||||
name % 0
|
||||
except TypeError, e:
|
||||
if e.message.startswith('not all'):
|
||||
name = '%s%%d' % name
|
||||
try:
|
||||
name % 0
|
||||
except TypeError, e:
|
||||
if e.message.startswith('not all'):
|
||||
name = '%s%%d' % name
|
||||
else:
|
||||
module.fail_json(msg=e.message)
|
||||
|
||||
pattern = re.sub(r'%\d+[sd]', r'(\d+)', name)
|
||||
for server in cs.servers.list():
|
||||
if server.metadata.get('group') == group:
|
||||
servers.append(server)
|
||||
match = re.search(pattern, server.name)
|
||||
if match:
|
||||
number = int(match.group(1))
|
||||
numbers.add(number)
|
||||
|
||||
number_range = xrange(count_offset, count_offset + count)
|
||||
available_numbers = list(set(number_range)
|
||||
.difference(numbers))
|
||||
else:
|
||||
for server in cs.servers.list():
|
||||
if server.metadata.get('group') == group:
|
||||
servers.append(server)
|
||||
|
||||
# If state was absent but the count was changed,
|
||||
# assume we only wanted to remove that number of instances
|
||||
if was_absent:
|
||||
diff = len(servers) - count
|
||||
if diff < 0:
|
||||
count = 0
|
||||
else:
|
||||
module.fail_json(msg=e.message)
|
||||
count = diff
|
||||
|
||||
pattern = re.sub(r'%\d+[sd]', r'(\d+)', name)
|
||||
for server in cs.servers.list():
|
||||
if server.metadata.get('group') == group:
|
||||
servers.append(server)
|
||||
match = re.search(pattern, server.name)
|
||||
if match:
|
||||
number = int(match.group(1))
|
||||
numbers.add(number)
|
||||
|
||||
number_range = xrange(count_offset, count_offset + count)
|
||||
available_numbers = list(set(number_range).difference(numbers))
|
||||
if len(servers) > count:
|
||||
state = 'absent'
|
||||
del servers[:count]
|
||||
@@ -445,45 +498,52 @@ def cloudservers(module, state, name, flavor, image, meta, key_name, files,
|
||||
instance_ids.append(server.id)
|
||||
delete(module, instance_ids, wait, wait_timeout)
|
||||
elif len(servers) < count:
|
||||
names = []
|
||||
numbers_to_use = available_numbers[:count - len(servers)]
|
||||
for number in numbers_to_use:
|
||||
names.append(name % number)
|
||||
if auto_increment:
|
||||
names = []
|
||||
name_slice = count - len(servers)
|
||||
numbers_to_use = available_numbers[:name_slice]
|
||||
for number in numbers_to_use:
|
||||
names.append(name % number)
|
||||
else:
|
||||
names = [name] * (count - len(servers))
|
||||
else:
|
||||
module.exit_json(changed=False, action=None, instances=[],
|
||||
success=[], error=[], timeout=[],
|
||||
instance_ids={'instances': [],
|
||||
'success': [], 'error': [],
|
||||
'timeout': []})
|
||||
|
||||
else:
|
||||
if group is not None:
|
||||
numbers = set()
|
||||
if auto_increment:
|
||||
numbers = set()
|
||||
|
||||
try:
|
||||
name % 0
|
||||
except TypeError, e:
|
||||
if e.message.startswith('not all'):
|
||||
name = '%s%%d' % name
|
||||
else:
|
||||
module.fail_json(msg=e.message)
|
||||
try:
|
||||
name % 0
|
||||
except TypeError, e:
|
||||
if e.message.startswith('not all'):
|
||||
name = '%s%%d' % name
|
||||
else:
|
||||
module.fail_json(msg=e.message)
|
||||
|
||||
pattern = re.sub(r'%\d+[sd]', r'(\d+)', name)
|
||||
for server in cs.servers.list():
|
||||
if server.metadata.get('group') == group:
|
||||
servers.append(server)
|
||||
match = re.search(pattern, server.name)
|
||||
if match:
|
||||
number = int(match.group(1))
|
||||
numbers.add(number)
|
||||
pattern = re.sub(r'%\d+[sd]', r'(\d+)', name)
|
||||
for server in cs.servers.list():
|
||||
if server.metadata.get('group') == group:
|
||||
servers.append(server)
|
||||
match = re.search(pattern, server.name)
|
||||
if match:
|
||||
number = int(match.group(1))
|
||||
numbers.add(number)
|
||||
|
||||
number_range = xrange(count_offset,
|
||||
count_offset + count + len(numbers))
|
||||
available_numbers = list(set(number_range).difference(numbers))
|
||||
names = []
|
||||
numbers_to_use = available_numbers[:count]
|
||||
for number in numbers_to_use:
|
||||
names.append(name % number)
|
||||
number_range = xrange(count_offset,
|
||||
count_offset + count + len(numbers))
|
||||
available_numbers = list(set(number_range)
|
||||
.difference(numbers))
|
||||
names = []
|
||||
numbers_to_use = available_numbers[:count]
|
||||
for number in numbers_to_use:
|
||||
names.append(name % number)
|
||||
else:
|
||||
names = [name] * count
|
||||
else:
|
||||
search_opts = {
|
||||
'name': name,
|
||||
@@ -552,6 +612,7 @@ def main():
|
||||
argument_spec = rax_argument_spec()
|
||||
argument_spec.update(
|
||||
dict(
|
||||
auto_increment=dict(choices=BOOLEANS, default=True, type='bool'),
|
||||
count=dict(default=1, type='int'),
|
||||
count_offset=dict(default=1, type='int'),
|
||||
disk_config=dict(default='auto', choices=['auto', 'manual']),
|
||||
@@ -584,6 +645,7 @@ def main():
|
||||
'please remove "service: cloudservers" from your '
|
||||
'playbook pertaining to the "rax" module')
|
||||
|
||||
auto_increment = module.params.get('auto_increment')
|
||||
count = module.params.get('count')
|
||||
count_offset = module.params.get('count_offset')
|
||||
disk_config = module.params.get('disk_config').upper()
|
||||
@@ -605,7 +667,8 @@ def main():
|
||||
|
||||
cloudservers(module, state, name, flavor, image, meta, key_name, files,
|
||||
wait, wait_timeout, disk_config, count, group,
|
||||
instance_ids, exact_count, networks, count_offset)
|
||||
instance_ids, exact_count, networks, count_offset,
|
||||
auto_increment)
|
||||
|
||||
|
||||
# import module snippets
|
||||
|
||||
@@ -118,7 +118,6 @@ EXAMPLES = '''
|
||||
'''
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
from types import NoneType
|
||||
|
||||
@@ -136,6 +135,12 @@ PROTOCOLS = ['DNS_TCP', 'DNS_UDP', 'FTP', 'HTTP', 'HTTPS', 'IMAPS', 'IMAPv4',
|
||||
'TCP_CLIENT_FIRST', 'UDP', 'UDP_STREAM', 'SFTP']
|
||||
|
||||
|
||||
def node_to_dict(obj):
|
||||
node = obj.to_dict()
|
||||
node['id'] = obj.id
|
||||
return node
|
||||
|
||||
|
||||
def to_dict(obj):
|
||||
instance = {}
|
||||
for key in dir(obj):
|
||||
@@ -151,7 +156,7 @@ def to_dict(obj):
|
||||
elif key == 'nodes':
|
||||
instance[key] = []
|
||||
for node in value:
|
||||
instance[key].append(node.to_dict())
|
||||
instance[key].append(node_to_dict(node))
|
||||
elif (isinstance(value, NON_CALLABLES) and
|
||||
not key.startswith('_')):
|
||||
instance[key] = value
|
||||
|
||||
@@ -262,15 +262,6 @@ EXAMPLES = '''
|
||||
import sys
|
||||
import time
|
||||
|
||||
AWS_REGIONS = ['ap-northeast-1',
|
||||
'ap-southeast-1',
|
||||
'ap-southeast-2',
|
||||
'eu-west-1',
|
||||
'sa-east-1',
|
||||
'us-east-1',
|
||||
'us-west-1',
|
||||
'us-west-2']
|
||||
|
||||
try:
|
||||
import boto.rds
|
||||
except ImportError:
|
||||
@@ -346,25 +337,7 @@ def main():
|
||||
apply_immediately = module.params.get('apply_immediately')
|
||||
new_instance_name = module.params.get('new_instance_name')
|
||||
|
||||
# allow environment variables to be used if ansible vars aren't set
|
||||
if not region:
|
||||
if 'AWS_REGION' in os.environ:
|
||||
region = os.environ['AWS_REGION']
|
||||
elif 'EC2_REGION' in os.environ:
|
||||
region = os.environ['EC2_REGION']
|
||||
|
||||
if not aws_secret_key:
|
||||
if 'AWS_SECRET_KEY' in os.environ:
|
||||
aws_secret_key = os.environ['AWS_SECRET_KEY']
|
||||
elif 'EC2_SECRET_KEY' in os.environ:
|
||||
aws_secret_key = os.environ['EC2_SECRET_KEY']
|
||||
|
||||
if not aws_access_key:
|
||||
if 'AWS_ACCESS_KEY' in os.environ:
|
||||
aws_access_key = os.environ['AWS_ACCESS_KEY']
|
||||
elif 'EC2_ACCESS_KEY' in os.environ:
|
||||
aws_access_key = os.environ['EC2_ACCESS_KEY']
|
||||
|
||||
ec2_url, aws_access_key, aws_secret_key, region = get_ec2_creds(module)
|
||||
if not region:
|
||||
module.fail_json(msg = str("region not specified and unable to determine region from EC2_REGION."))
|
||||
|
||||
@@ -577,5 +550,6 @@ def main():
|
||||
|
||||
# import module snippets
|
||||
from ansible.module_utils.basic import *
|
||||
from ansible.module_utils.ec2 import *
|
||||
|
||||
main()
|
||||
|
||||
@@ -7,20 +7,26 @@ DOCUMENTATION = '''
|
||||
module: shell
|
||||
short_description: Execute commands in nodes.
|
||||
description:
|
||||
- The shell module takes the command name followed by a list of arguments,
|
||||
space delimited. It is almost exactly like the M(command) module but runs
|
||||
- The M(shell) module takes the command name followed by a list of space-delimited arguments.
|
||||
It is almost exactly like the M(command) module but runs
|
||||
the command through a shell (C(/bin/sh)) on the remote node.
|
||||
version_added: "0.2"
|
||||
options:
|
||||
(free form):
|
||||
free_form:
|
||||
description:
|
||||
- The command module takes a free form command to run
|
||||
required: null
|
||||
- The shell module takes a free form command to run
|
||||
required: true
|
||||
default: null
|
||||
creates:
|
||||
description:
|
||||
- a filename, when it already exists, this step will NOT be run
|
||||
required: false
|
||||
- a filename, when it already exists, this step will B(not) be run.
|
||||
required: no
|
||||
default: null
|
||||
removes:
|
||||
description:
|
||||
- a filename, when it does not exist, this step will B(not) be run.
|
||||
version_added: "0.8"
|
||||
required: no
|
||||
default: null
|
||||
chdir:
|
||||
description:
|
||||
|
||||
@@ -116,13 +116,13 @@ def db_delete(cursor, db):
|
||||
cursor.execute(query)
|
||||
return True
|
||||
|
||||
def db_dump(module, host, user, password, db_name, target, socket=None):
|
||||
def db_dump(module, host, user, password, db_name, target, port, socket=None):
|
||||
cmd = module.get_bin_path('mysqldump', True)
|
||||
cmd += " --quick --user=%s --password=%s" %(user, password)
|
||||
cmd += " --quick --user=%s --password='%s'" %(user, password)
|
||||
if socket is not None:
|
||||
cmd += " --socket=%s" % socket
|
||||
else:
|
||||
cmd += " --host=%s" % host
|
||||
cmd += " --host=%s --port=%s" % (host, port)
|
||||
cmd += " %s" % db_name
|
||||
if os.path.splitext(target)[-1] == '.gz':
|
||||
cmd = cmd + ' | gzip > ' + target
|
||||
@@ -133,13 +133,13 @@ def db_dump(module, host, user, password, db_name, target, socket=None):
|
||||
rc, stdout, stderr = module.run_command(cmd)
|
||||
return rc, stdout, stderr
|
||||
|
||||
def db_import(module, host, user, password, db_name, target, socket=None):
|
||||
def db_import(module, host, user, password, db_name, target, port, socket=None):
|
||||
cmd = module.get_bin_path('mysql', True)
|
||||
cmd += " --user=%s --password=%s" %(user, password)
|
||||
cmd += " --user=%s --password='%s'" %(user, password)
|
||||
if socket is not None:
|
||||
cmd += " --socket=%s" % socket
|
||||
else:
|
||||
cmd += " --host=%s" % host
|
||||
cmd += " --host=%s --port=%s" % (host, port)
|
||||
cmd += " -D %s" % db_name
|
||||
if os.path.splitext(target)[-1] == '.gz':
|
||||
cmd = 'gunzip < ' + target + ' | ' + cmd
|
||||
@@ -282,6 +282,7 @@ def main():
|
||||
elif state == "dump":
|
||||
rc, stdout, stderr = db_dump(module, login_host, login_user,
|
||||
login_password, db, target,
|
||||
port=module.params['login_port'],
|
||||
socket=module.params['login_unix_socket'])
|
||||
if rc != 0:
|
||||
module.fail_json(msg="%s" % stderr)
|
||||
@@ -290,6 +291,7 @@ def main():
|
||||
elif state == "import":
|
||||
rc, stdout, stderr = db_import(module, login_host, login_user,
|
||||
login_password, db, target,
|
||||
port=module.params['login_port'],
|
||||
socket=module.params['login_unix_socket'])
|
||||
if rc != 0:
|
||||
module.fail_json(msg="%s" % stderr)
|
||||
|
||||
@@ -114,6 +114,9 @@ EXAMPLES = """
|
||||
# Create database user with name 'bob' and password '12345' with all database privileges
|
||||
- mysql_user: name=bob password=12345 priv=*.*:ALL state=present
|
||||
|
||||
# Creates database user 'bob' and password '12345' with all database privileges and 'WITH GRANT OPTION'
|
||||
- mysql_user: name=bob password=12345 priv=*.*:ALL,GRANT state=present
|
||||
|
||||
# Ensure no user named 'sally' exists, also passing in the auth credentials.
|
||||
- mysql_user: login_user=root login_password=123456 name=sally state=absent
|
||||
|
||||
|
||||
@@ -124,7 +124,7 @@ options:
|
||||
choices: [ "yes", "no" ]
|
||||
description:
|
||||
- 'force the creation of the symlinks in two cases: the source file does
|
||||
not exist (but will appear later); the destination exists and a file (so, we need to unlink the
|
||||
not exist (but will appear later); the destination exists and is a file (so, we need to unlink the
|
||||
"path" file and create symlink to the "src" file in place of it).'
|
||||
notes:
|
||||
- See also M(copy), M(template), M(assemble)
|
||||
@@ -245,7 +245,7 @@ def main():
|
||||
module.exit_json(path=path, changed=True)
|
||||
|
||||
if prev_state != 'absent' and prev_state != state:
|
||||
if not (force and (prev_state == 'file' or prev_state == 'directory') and state == 'link') and state != 'touch':
|
||||
if not (force and (prev_state == 'file' or prev_state == 'hard' or prev_state == 'directory') and state == 'link') and state != 'touch':
|
||||
module.fail_json(path=path, msg='refusing to convert between %s and %s for %s' % (prev_state, state, src))
|
||||
|
||||
if prev_state == 'absent' and state == 'absent':
|
||||
@@ -307,6 +307,10 @@ def main():
|
||||
if not force:
|
||||
module.fail_json(dest=path, src=src, msg='Cannot link, file exists at destination')
|
||||
changed = True
|
||||
elif prev_state == 'directory':
|
||||
if not force:
|
||||
module.fail_json(dest=path, src=src, msg='Cannot link, directory exists at destination')
|
||||
changed = True
|
||||
else:
|
||||
module.fail_json(dest=path, src=src, msg='unexpected position reached')
|
||||
|
||||
|
||||
@@ -47,9 +47,12 @@ options:
|
||||
- all arguments accepted by the M(file) module also work here
|
||||
required: false
|
||||
notes:
|
||||
- Since Ansible version 0.9, templates are loaded with C(trim_blocks=True).
|
||||
- 'You can override jinja2 settings by adding a special header to template file.
|
||||
i.e. C(#jinja2: trim_blocks: False)'
|
||||
- "Since Ansible version 0.9, templates are loaded with C(trim_blocks=True)."
|
||||
|
||||
- "Also, you can override jinja2 settings by adding a special header to template file.
|
||||
i.e. C(#jinja2:variable_start_string:'[%' , variable_end_string:'%]')
|
||||
which changes the variable interpolation markers to [% var %] instead of {{ var }}. This is the best way to prevent evaluation of things that look like, but should not be Jinja2. raw/endraw in Jinja2 will not work as you expect because templates in Ansible are recursively evaluated."
|
||||
|
||||
requirements: []
|
||||
author: Michael DeHaan
|
||||
'''
|
||||
|
||||
@@ -94,19 +94,19 @@ options:
|
||||
required: true
|
||||
default: none
|
||||
ip:
|
||||
description:
|
||||
description:
|
||||
- IP address part of the ipport definition. The default API setting
|
||||
is "0.0.0.0".
|
||||
required: false
|
||||
default: none
|
||||
port:
|
||||
description:
|
||||
description:
|
||||
- port address part op the ipport definition. Tyhe default API
|
||||
setting is 0.
|
||||
required: false
|
||||
default: none
|
||||
interval:
|
||||
description:
|
||||
description:
|
||||
- The interval specifying how frequently the monitor instance
|
||||
of this template will run. By default, this interval is used for up and
|
||||
down states. The default API setting is 5.
|
||||
@@ -199,7 +199,7 @@ def check_monitor_exists(module, api, monitor, parent):
|
||||
|
||||
def create_monitor(api, monitor, template_attributes):
|
||||
|
||||
try:
|
||||
try:
|
||||
api.LocalLB.Monitor.create_template(templates=[{'template_name': monitor, 'template_type': TEMPLATE_TYPE}], template_attributes=[template_attributes])
|
||||
except bigsuds.OperationFailed, e:
|
||||
if "already exists" in str(e):
|
||||
@@ -282,7 +282,7 @@ def set_ipport(api, monitor, ipport):
|
||||
# ===========================================
|
||||
# main loop
|
||||
#
|
||||
# writing a module for other monitor types should
|
||||
# writing a module for other monitor types should
|
||||
# only need an updated main() (and monitor specific functions)
|
||||
|
||||
def main():
|
||||
@@ -345,19 +345,19 @@ def main():
|
||||
if port is None:
|
||||
port = cur_ipport['ipport']['port']
|
||||
else: # use API defaults if not defined to create it
|
||||
if interval is None:
|
||||
if interval is None:
|
||||
interval = 5
|
||||
if timeout is None:
|
||||
if timeout is None:
|
||||
timeout = 16
|
||||
if ip is None:
|
||||
if ip is None:
|
||||
ip = '0.0.0.0'
|
||||
if port is None:
|
||||
if port is None:
|
||||
port = 0
|
||||
if send is None:
|
||||
if send is None:
|
||||
send = ''
|
||||
if receive is None:
|
||||
if receive is None:
|
||||
receive = ''
|
||||
if receive_disable is None:
|
||||
if receive_disable is None:
|
||||
receive_disable = ''
|
||||
|
||||
# define and set address type
|
||||
@@ -394,7 +394,7 @@ def main():
|
||||
{'type': 'ITYPE_TIMEOUT',
|
||||
'value': timeout},
|
||||
{'type': 'ITYPE_TIME_UNTIL_UP',
|
||||
'value': interval}]
|
||||
'value': time_until_up}]
|
||||
|
||||
# main logic, monitor generic
|
||||
|
||||
@@ -405,7 +405,7 @@ def main():
|
||||
if state == 'absent':
|
||||
if monitor_exists:
|
||||
if not module.check_mode:
|
||||
# possible race condition if same task
|
||||
# possible race condition if same task
|
||||
# on other node deleted it first
|
||||
result['changed'] |= delete_monitor(api, monitor)
|
||||
else:
|
||||
@@ -414,26 +414,24 @@ def main():
|
||||
else: # state present
|
||||
## check for monitor itself
|
||||
if not monitor_exists: # create it
|
||||
if not module.check_mode:
|
||||
if not module.check_mode:
|
||||
# again, check changed status here b/c race conditions
|
||||
# if other task already created it
|
||||
result['changed'] |= create_monitor(api, monitor, template_attributes)
|
||||
else:
|
||||
else:
|
||||
result['changed'] |= True
|
||||
|
||||
## check for monitor parameters
|
||||
# whether it already existed, or was just created, now update
|
||||
# the update functions need to check for check mode but
|
||||
# cannot update settings if it doesn't exist which happens in check mode
|
||||
if monitor_exists and not module.check_mode:
|
||||
result['changed'] |= update_monitor_properties(api, module, monitor,
|
||||
template_string_properties,
|
||||
template_integer_properties)
|
||||
# else assume nothing changed
|
||||
result['changed'] |= update_monitor_properties(api, module, monitor,
|
||||
template_string_properties,
|
||||
template_integer_properties)
|
||||
|
||||
# we just have to update the ipport if monitor already exists and it's different
|
||||
if monitor_exists and cur_ipport != ipport:
|
||||
set_ipport(api, monitor, ipport)
|
||||
set_ipport(api, monitor, ipport)
|
||||
result['changed'] |= True
|
||||
#else: monitor doesn't exist (check mode) or ipport is already ok
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python2
|
||||
#!/usr/bin/python
|
||||
#coding: utf-8 -*-
|
||||
|
||||
# This module is free software: you can redistribute it and/or modify
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python2
|
||||
#!/usr/bin/python
|
||||
#coding: utf-8 -*-
|
||||
|
||||
# This module is free software: you can redistribute it and/or modify
|
||||
|
||||
@@ -324,7 +324,10 @@ def upgrade(m, mode="yes", force=False,
|
||||
upgrade_command = "safe-upgrade"
|
||||
|
||||
if force:
|
||||
force_yes = '--force-yes'
|
||||
if apt_cmd == APT_GET_CMD:
|
||||
force_yes = '--force-yes'
|
||||
else:
|
||||
force_yes = ''
|
||||
else:
|
||||
force_yes = ''
|
||||
|
||||
|
||||
@@ -124,7 +124,7 @@ def all_keys(module, keyring):
|
||||
return results
|
||||
|
||||
def key_present(module, key_id):
|
||||
(rc, out, err) = module.run_command("apt-key list | 2>&1 grep -q %s" % key_id)
|
||||
(rc, out, err) = module.run_command("apt-key list | 2>&1 grep -i -q %s" % key_id)
|
||||
return rc == 0
|
||||
|
||||
def download_key(module, url):
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
# (c) 2012, Matt Wright <matt@nobien.net>
|
||||
# (c) 2013, Alexander Saltanov <asd@mokote.com>
|
||||
# (c) 2014, Rutger Spiertz <rutger@kumina.nl>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
@@ -111,8 +112,9 @@ class SourcesList(object):
|
||||
self.files = {} # group sources by file
|
||||
self.default_file = apt_pkg.config.find_file('Dir::Etc::sourcelist')
|
||||
|
||||
# read sources.list
|
||||
self.load(self.default_file)
|
||||
# read sources.list if it exists
|
||||
if os.path.isfile(self.default_file):
|
||||
self.load(self.default_file)
|
||||
|
||||
# read sources.list.d
|
||||
for file in glob.iglob('%s/*.list' % apt_pkg.config.find_dir('Dir::Etc::sourceparts')):
|
||||
|
||||
@@ -135,7 +135,6 @@ def main():
|
||||
name = module.params['name']
|
||||
env = module.params['virtualenv']
|
||||
executable = module.params['executable']
|
||||
easy_install = _get_easy_install(module, env, executable)
|
||||
site_packages = module.params['virtualenv_site_packages']
|
||||
virtualenv_command = module.params['virtualenv_command']
|
||||
|
||||
@@ -159,6 +158,8 @@ def main():
|
||||
out += out_venv
|
||||
err += err_venv
|
||||
|
||||
easy_install = _get_easy_install(module, env, executable)
|
||||
|
||||
cmd = None
|
||||
changed = False
|
||||
installed = _is_package_installed(module, name, easy_install)
|
||||
|
||||
@@ -71,7 +71,7 @@ def query_package(module, brew_path, name, state="present"):
|
||||
""" Returns whether a package is installed or not. """
|
||||
|
||||
if state == "present":
|
||||
rc, out, err = module.run_command("%s list -m1 | grep -q '^%s$'" % (brew_path, name))
|
||||
rc, out, err = module.run_command("%s list %s" % (brew_path, name))
|
||||
if rc == 0:
|
||||
return True
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ options:
|
||||
name:
|
||||
description:
|
||||
- The name of a node.js library to install
|
||||
requires: false
|
||||
required: false
|
||||
path:
|
||||
description:
|
||||
- The base path where to install the node.js libraries
|
||||
@@ -101,7 +101,7 @@ class Npm(object):
|
||||
self.version = kwargs['version']
|
||||
self.path = kwargs['path']
|
||||
self.production = kwargs['production']
|
||||
|
||||
|
||||
if kwargs['executable']:
|
||||
self.executable = kwargs['executable']
|
||||
else:
|
||||
@@ -119,7 +119,7 @@ class Npm(object):
|
||||
if self.glbl:
|
||||
cmd.append('--global')
|
||||
if self.production:
|
||||
cmd.append('--production')
|
||||
cmd.append('--production')
|
||||
if self.name:
|
||||
cmd.append(self.name_version)
|
||||
|
||||
@@ -180,7 +180,7 @@ def main():
|
||||
executable=dict(default=None),
|
||||
state=dict(default='present', choices=['present', 'absent', 'latest'])
|
||||
)
|
||||
arg_spec['global']=dict(default='no', type='bool')
|
||||
arg_spec['global'] = dict(default='no', type='bool')
|
||||
module = AnsibleModule(
|
||||
argument_spec=arg_spec,
|
||||
supports_check_mode=True
|
||||
|
||||
@@ -147,9 +147,8 @@ EXAMPLES = '''
|
||||
def _get_cmd_options(module, cmd):
|
||||
thiscmd = cmd + " --help"
|
||||
rc, stdout, stderr = module.run_command(thiscmd)
|
||||
#import epdb; epdb.serve()
|
||||
if rc != 0:
|
||||
module.fail_json(msg="Could not get --help output from %s" % virtualenv)
|
||||
module.fail_json(msg="Could not get output from %s: %s" % (thiscmd, stdout + stderr))
|
||||
|
||||
words = stdout.strip().split()
|
||||
cmd_options = [ x for x in words if x.startswith('--') ]
|
||||
@@ -275,6 +274,7 @@ def main():
|
||||
pip = _get_pip(module, env, module.params['executable'])
|
||||
|
||||
cmd = '%s %s' % (pip, state_map[state])
|
||||
cmd_opts = None
|
||||
|
||||
# If there's a virtualenv we want things we install to be able to use other
|
||||
# installations that exist as binaries within this virtualenv. Example: we
|
||||
@@ -319,7 +319,11 @@ def main():
|
||||
is_local_path = True
|
||||
# for tarball or vcs source, applying --use-mirrors doesn't really make sense
|
||||
is_package = is_vcs or is_tar or is_local_path # just a shortcut for bool
|
||||
if not is_package and state != 'absent' and use_mirrors:
|
||||
|
||||
if cmd_opts is None:
|
||||
cmd_opts = _get_cmd_options(module, '%s %s' % (pip, state_map[state]))
|
||||
|
||||
if not is_package and state != 'absent' and use_mirrors and '--use-mirrors' in cmd_opts:
|
||||
cmd += ' --use-mirrors'
|
||||
cmd += ' %s' % _get_full_name(name, version)
|
||||
elif requirements:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/python2
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
|
||||
@@ -31,7 +31,7 @@ module: yum
|
||||
version_added: historical
|
||||
short_description: Manages packages with the I(yum) package manager
|
||||
description:
|
||||
- Will install, upgrade, remove, and list packages with the I(yum) package manager.
|
||||
- Installs, upgrade, removes, and lists packages and groups with the I(yum) package manager.
|
||||
options:
|
||||
name:
|
||||
description:
|
||||
@@ -41,7 +41,7 @@ options:
|
||||
aliases: []
|
||||
list:
|
||||
description:
|
||||
- Various non-idempotent commands for usage with C(/usr/bin/ansible) and I(not) playbooks. See examples.
|
||||
- Various (non-idempotent) commands for usage with C(/usr/bin/ansible) and I(not) playbooks. See examples.
|
||||
required: false
|
||||
default: null
|
||||
state:
|
||||
@@ -94,13 +94,26 @@ author: Seth Vidal
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- yum: name=httpd state=latest
|
||||
- yum: name=httpd state=removed
|
||||
- yum: name=httpd enablerepo=testing state=installed
|
||||
- yum: name=* state=latest
|
||||
- yum: name=http://nginx.org/packages/centos/6/noarch/RPMS/nginx-release-centos-6-0.el6.ngx.noarch.rpm state=present
|
||||
- yum: name=/usr/local/src/nginx-release-centos-6-0.el6.ngx.noarch.rpm state=present
|
||||
- yum: name="@Development tools" state=present
|
||||
- name: install the latest version of Apache
|
||||
yum: name=httpd state=latest
|
||||
|
||||
- name: remove the Apache package
|
||||
yum: name=httpd state=removed
|
||||
|
||||
- name: install the latest version of Apche from the testing repo
|
||||
yum: name=httpd enablerepo=testing state=installed
|
||||
|
||||
- name: upgrade all packages
|
||||
yum: name=* state=latest
|
||||
|
||||
- name: install the nginx rpm from a remote repo
|
||||
yum: name=http://nginx.org/packages/centos/6/noarch/RPMS/nginx-release-centos-6-0.el6.ngx.noarch.rpm state=present
|
||||
|
||||
- name: install nginx rpm from a local file
|
||||
yum: name=/usr/local/src/nginx-release-centos-6-0.el6.ngx.noarch.rpm state=present
|
||||
|
||||
- name: install the 'Development tools' package group
|
||||
yum: name="@Development tools" state=present
|
||||
'''
|
||||
|
||||
def_qf = "%{name}-%{version}-%{release}.%{arch}"
|
||||
|
||||
@@ -120,7 +120,7 @@ def main():
|
||||
description=dict(required=False),
|
||||
disable_gpg_check = dict(required=False, default='no', type='bool'),
|
||||
),
|
||||
supports_check_mode=True,
|
||||
supports_check_mode=False,
|
||||
)
|
||||
|
||||
repo = module.params['repo']
|
||||
|
||||
@@ -43,6 +43,12 @@ options:
|
||||
- What version of the repository to check out. This can be the
|
||||
full 40-character I(SHA-1) hash, the literal string C(HEAD), a
|
||||
branch name, or a tag name.
|
||||
accept_hostkey:
|
||||
required: false
|
||||
default: false
|
||||
version_added: "1.5"
|
||||
description:
|
||||
- Add the hostkey for the repo url if not already added.
|
||||
reference:
|
||||
required: false
|
||||
default: null
|
||||
@@ -118,6 +124,7 @@ EXAMPLES = '''
|
||||
import re
|
||||
import tempfile
|
||||
|
||||
|
||||
def get_version(git_path, dest, ref="HEAD"):
|
||||
''' samples the version of the git repo '''
|
||||
os.chdir(dest)
|
||||
@@ -352,6 +359,7 @@ def main():
|
||||
force=dict(default='yes', type='bool'),
|
||||
depth=dict(default=None, type='int'),
|
||||
update=dict(default='yes', type='bool'),
|
||||
accept_hostkey=dict(default='no', type='bool'),
|
||||
executable=dict(default=None),
|
||||
bare=dict(default='no', type='bool'),
|
||||
),
|
||||
@@ -369,6 +377,10 @@ def main():
|
||||
reference = module.params['reference']
|
||||
git_path = module.params['executable'] or module.get_bin_path('git', True)
|
||||
|
||||
# add the git repo's hostkey
|
||||
#if module.params['accept_hostkey']:
|
||||
add_git_host_key(module, repo, accept_hostkey=module.params['accept_hostkey'])
|
||||
|
||||
if bare:
|
||||
gitconfig = os.path.join(dest, 'config')
|
||||
else:
|
||||
@@ -430,4 +442,6 @@ def main():
|
||||
|
||||
# import module snippets
|
||||
from ansible.module_utils.basic import *
|
||||
from ansible.module_utils.known_hosts import *
|
||||
|
||||
main()
|
||||
|
||||
@@ -59,9 +59,7 @@ options:
|
||||
choices: [ "yes", "no" ]
|
||||
purge:
|
||||
description:
|
||||
- Deletes untracked files. Runs C(hg purge). Note this requires C(purge) extension to
|
||||
be enabled if C(purge=yes). This module will modify hgrc file on behalf of the user
|
||||
and undo the changes before exiting the task.
|
||||
- Deletes untracked files. Runs C(hg purge).
|
||||
required: false
|
||||
default: "no"
|
||||
choices: [ "yes", "no" ]
|
||||
@@ -85,36 +83,6 @@ EXAMPLES = '''
|
||||
- hg: repo=https://bitbucket.org/user/repo1 dest=/home/user/repo1 revision=stable purge=yes
|
||||
'''
|
||||
|
||||
def _set_hgrc(hgrc, vals):
|
||||
parser = ConfigParser.SafeConfigParser()
|
||||
parser.read(hgrc)
|
||||
|
||||
# val is a list of triple-tuple of the form [(section, option, value),...]
|
||||
for each in vals:
|
||||
(section, option, value) = each
|
||||
if not parser.has_section(section):
|
||||
parser.add_section(section)
|
||||
parser.set(section, option, value)
|
||||
|
||||
f = open(hgrc, 'w')
|
||||
parser.write(f)
|
||||
f.close()
|
||||
|
||||
|
||||
def _undo_hgrc(hgrc, vals):
|
||||
parser = ConfigParser.SafeConfigParser()
|
||||
parser.read(hgrc)
|
||||
|
||||
for each in vals:
|
||||
(section, option, value) = each
|
||||
if parser.has_section(section):
|
||||
parser.remove_option(section, option)
|
||||
|
||||
f = open(hgrc, 'w')
|
||||
parser.write(f)
|
||||
f.close()
|
||||
|
||||
|
||||
class Hg(object):
|
||||
|
||||
def __init__(self, module, dest, repo, revision, hg_path):
|
||||
@@ -129,7 +97,8 @@ class Hg(object):
|
||||
return (rc, out, err)
|
||||
|
||||
def _list_untracked(self):
|
||||
return self._command(['purge', '-R', self.dest, '--print'])
|
||||
args = ['purge', '--config', 'extensions.purge=', '-R', self.dest, '--print']
|
||||
return self._command(args)
|
||||
|
||||
def get_revision(self):
|
||||
"""
|
||||
@@ -168,10 +137,6 @@ class Hg(object):
|
||||
return True
|
||||
|
||||
def purge(self):
|
||||
hgrc = os.path.join(self.dest, '.hg/hgrc')
|
||||
purge_option = [('extensions', 'purge', '')]
|
||||
_set_hgrc(hgrc, purge_option) # enable purge extension
|
||||
|
||||
# before purge, find out if there are any untracked files
|
||||
(rc1, out1, err1) = self._list_untracked()
|
||||
if rc1 != 0:
|
||||
@@ -179,10 +144,9 @@ class Hg(object):
|
||||
|
||||
# there are some untrackd files
|
||||
if out1 != '':
|
||||
(rc2, out2, err2) = self._command(['purge', '-R', self.dest])
|
||||
if rc2 == 0:
|
||||
_undo_hgrc(hgrc, purge_option)
|
||||
else:
|
||||
args = ['purge', '--config', 'extensions.purge=', '-R', self.dest]
|
||||
(rc2, out2, err2) = self._command(args)
|
||||
if rc2 != 0:
|
||||
self.module.fail_json(msg=err2)
|
||||
return True
|
||||
else:
|
||||
|
||||
@@ -94,6 +94,7 @@ class Subversion(object):
|
||||
|
||||
def _exec(self, args):
|
||||
bits = [
|
||||
'LANG=C',
|
||||
self.svn_path,
|
||||
'--non-interactive',
|
||||
'--trust-server-cert',
|
||||
|
||||
@@ -114,6 +114,27 @@ import tempfile
|
||||
import re
|
||||
import shlex
|
||||
|
||||
class keydict(dict):
|
||||
|
||||
""" a dictionary that maintains the order of keys as they are added """
|
||||
|
||||
# http://stackoverflow.com/questions/2328235/pythonextend-the-dict-class
|
||||
|
||||
def __init__(self, *args, **kw):
|
||||
super(keydict,self).__init__(*args, **kw)
|
||||
self.itemlist = super(keydict,self).keys()
|
||||
def __setitem__(self, key, value):
|
||||
self.itemlist.append(key)
|
||||
super(keydict,self).__setitem__(key, value)
|
||||
def __iter__(self):
|
||||
return iter(self.itemlist)
|
||||
def keys(self):
|
||||
return self.itemlist
|
||||
def values(self):
|
||||
return [self[key] for key in self]
|
||||
def itervalues(self):
|
||||
return (self[key] for key in self)
|
||||
|
||||
def keyfile(module, user, write=False, path=None, manage_dir=True):
|
||||
"""
|
||||
Calculate name of authorized keys file, optionally creating the
|
||||
@@ -176,7 +197,7 @@ def parseoptions(module, options):
|
||||
reads a string containing ssh-key options
|
||||
and returns a dictionary of those options
|
||||
'''
|
||||
options_dict = {}
|
||||
options_dict = keydict() #ordered dict
|
||||
if options:
|
||||
token_exp = [
|
||||
# matches separator
|
||||
@@ -246,9 +267,8 @@ def parsekey(module, raw_key):
|
||||
# check for options
|
||||
if type_index is None:
|
||||
return None
|
||||
elif type_index == 1:
|
||||
# parse the options and store them
|
||||
options = key_parts[0]
|
||||
elif type_index > 0:
|
||||
options = " ".join(key_parts[:type_index])
|
||||
|
||||
# parse the options (if any)
|
||||
options = parseoptions(module, options)
|
||||
@@ -292,7 +312,7 @@ def writekeys(module, filename, keys):
|
||||
option_str = ""
|
||||
if options:
|
||||
option_strings = []
|
||||
for option_key in sorted(options.keys()):
|
||||
for option_key in options.keys():
|
||||
if options[option_key]:
|
||||
option_strings.append("%s=\"%s\"" % (option_key, options[option_key]))
|
||||
else:
|
||||
@@ -321,7 +341,9 @@ def enforce_state(module, params):
|
||||
state = params.get("state", "present")
|
||||
key_options = params.get("key_options", None)
|
||||
|
||||
key = key.split('\n')
|
||||
# extract indivial keys into an array, skipping blank lines and comments
|
||||
key = [s for s in key.splitlines() if s and not s.startswith('#')]
|
||||
|
||||
|
||||
# check current state -- just get the filename, don't create file
|
||||
do_write = False
|
||||
@@ -330,10 +352,11 @@ def enforce_state(module, params):
|
||||
|
||||
# Check our new keys, if any of them exist we'll continue.
|
||||
for new_key in key:
|
||||
if key_options is not None:
|
||||
new_key = "%s %s" % (key_options, new_key)
|
||||
|
||||
parsed_new_key = parsekey(module, new_key)
|
||||
if key_options is not None:
|
||||
parsed_options = parseoptions(module, key_options)
|
||||
parsed_new_key = (parsed_new_key[0], parsed_new_key[1], parsed_options, parsed_new_key[3])
|
||||
|
||||
if not parsed_new_key:
|
||||
module.fail_json(msg="invalid key specified: %s" % new_key)
|
||||
|
||||
|
||||
@@ -146,6 +146,12 @@ class DebianStrategy(GenericStrategy):
|
||||
HOSTNAME_FILE = '/etc/hostname'
|
||||
|
||||
def get_permanent_hostname(self):
|
||||
if not os.path.isfile(self.HOSTNAME_FILE):
|
||||
try:
|
||||
open(self.HOSTNAME_FILE, "a").write("")
|
||||
except IOError, err:
|
||||
self.module.fail_json(msg="failed to write file: %s" %
|
||||
str(err))
|
||||
try:
|
||||
f = open(self.HOSTNAME_FILE)
|
||||
try:
|
||||
@@ -250,6 +256,11 @@ class AmazonLinuxHostname(Hostname):
|
||||
distribution = 'Amazon'
|
||||
strategy_class = RedHatStrategy
|
||||
|
||||
class ScientificLinuxHostname(Hostname):
|
||||
platform = 'Linux'
|
||||
distribution = 'Scientific'
|
||||
strategy_class = RedHatStrategy
|
||||
|
||||
# ===========================================
|
||||
|
||||
class FedoraStrategy(GenericStrategy):
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python2
|
||||
#!/usr/bin/python
|
||||
#coding: utf-8 -*-
|
||||
|
||||
# This module is free software: you can redistribute it and/or modify
|
||||
|
||||
@@ -431,10 +431,10 @@ class LinuxService(Service):
|
||||
if check_systemd(self.name):
|
||||
# service is managed by systemd
|
||||
self.enable_cmd = location['systemctl']
|
||||
elif os.path.exists("/etc/init/%s.conf" % self.name):
|
||||
elif location['initctl'] and os.path.exists("/etc/init/%s.conf" % self.name):
|
||||
# service is managed by upstart
|
||||
self.enable_cmd = location['initctl']
|
||||
elif os.path.exists("/etc/init.d/%s" % self.name):
|
||||
elif location['update-rc.d'] and os.path.exists("/etc/init.d/%s" % self.name):
|
||||
# service is managed by with SysV init scripts, but with update-rc.d
|
||||
self.enable_cmd = location['update-rc.d']
|
||||
else:
|
||||
@@ -649,7 +649,7 @@ class LinuxService(Service):
|
||||
return
|
||||
|
||||
if self.enable:
|
||||
# make sure the init.d symlinks are created
|
||||
# make sure the init.d symlinks are created
|
||||
# otherwise enable might not work
|
||||
(rc, out, err) = self.execute_command("%s %s defaults" \
|
||||
% (self.enable_cmd, self.name))
|
||||
|
||||
@@ -83,7 +83,7 @@ ansible all -m setup -a 'filter=ansible_*_mb'
|
||||
# Display only facts returned by facter.
|
||||
ansible all -m setup -a 'filter=facter_*'
|
||||
|
||||
# Display only facts returned by facter.
|
||||
# Display only facts about certain interfaces.
|
||||
ansible all -m setup -a 'filter=ansible_eth[0-2]'
|
||||
"""
|
||||
|
||||
@@ -118,7 +118,8 @@ class Facts(object):
|
||||
'/etc/alpine-release': 'Alpine',
|
||||
'/etc/release': 'Solaris',
|
||||
'/etc/arch-release': 'Archlinux',
|
||||
'/etc/SuSE-release': 'SuSE' }
|
||||
'/etc/SuSE-release': 'SuSE',
|
||||
'/etc/os-release': 'Debian' }
|
||||
SELINUX_MODE_DICT = { 1: 'enforcing', 0: 'permissive', -1: 'disabled' }
|
||||
|
||||
# A list of dicts. If there is a platform with more than one
|
||||
@@ -328,6 +329,11 @@ class Facts(object):
|
||||
elif name == 'SuSE':
|
||||
data = get_file_content(path).splitlines()
|
||||
self.facts['distribution_release'] = data[2].split('=')[1].strip()
|
||||
elif name == 'Debian':
|
||||
data = get_file_content(path).split('\n')[0]
|
||||
release = re.search("PRETTY_NAME.+ \(?([^ ]+?)\)?\"", data)
|
||||
if release:
|
||||
self.facts['distribution_release'] = release.groups()[0]
|
||||
else:
|
||||
self.facts['distribution'] = name
|
||||
|
||||
@@ -1540,8 +1546,7 @@ class LinuxNetwork(Network):
|
||||
iface = words[-1]
|
||||
if iface != device:
|
||||
interfaces[iface] = {}
|
||||
interfaces[iface].update(interfaces[device])
|
||||
if "ipv4_secondaries" not in interfaces[iface]:
|
||||
if not secondary and "ipv4_secondaries" not in interfaces[iface]:
|
||||
interfaces[iface]["ipv4_secondaries"] = []
|
||||
if not secondary or "ipv4" not in interfaces[iface]:
|
||||
interfaces[iface]['ipv4'] = {'address': address,
|
||||
@@ -1553,6 +1558,15 @@ class LinuxNetwork(Network):
|
||||
'netmask': netmask,
|
||||
'network': network,
|
||||
})
|
||||
|
||||
# add this secondary IP to the main device
|
||||
if secondary:
|
||||
interfaces[device]["ipv4_secondaries"].append({
|
||||
'address': address,
|
||||
'netmask': netmask,
|
||||
'network': network,
|
||||
})
|
||||
|
||||
# If this is the default address, update default_ipv4
|
||||
if 'address' in default_ipv4 and default_ipv4['address'] == address:
|
||||
default_ipv4['netmask'] = netmask
|
||||
@@ -2072,6 +2086,11 @@ class LinuxVirtual(Virtual):
|
||||
self.facts['virtualization_role'] = 'guest'
|
||||
return
|
||||
|
||||
if product_name == 'RHEV Hypervisor':
|
||||
self.facts['virtualization_type'] = 'RHEV'
|
||||
self.facts['virtualization_role'] = 'guest'
|
||||
return
|
||||
|
||||
if product_name == 'VMware Virtual Platform':
|
||||
self.facts['virtualization_type'] = 'VMware'
|
||||
self.facts['virtualization_role'] = 'guest'
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# (c) 2012, David "DaviXX" CHANIAL <david.chanial@gmail.com>
|
||||
# (c) 2014, James Tanner <tanner.jc@gmail.com>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
@@ -41,19 +42,9 @@ options:
|
||||
aliases: [ 'val' ]
|
||||
state:
|
||||
description:
|
||||
- Whether the entry should be present or absent.
|
||||
- Whether the entry should be present or absent in the sysctl file.
|
||||
choices: [ "present", "absent" ]
|
||||
default: present
|
||||
checks:
|
||||
description:
|
||||
- If C(none), no smart/facultative checks will be made. If
|
||||
C(before), some checks are performed before any update (i.e. is
|
||||
the sysctl key writable?). If C(after), some checks are performed
|
||||
after an update (i.e. does kernel return the set value?). If
|
||||
C(both), all of the smart checks (C(before) and C(after)) are
|
||||
performed.
|
||||
choices: [ "none", "before", "after", "both" ]
|
||||
default: both
|
||||
reload:
|
||||
description:
|
||||
- If C(yes), performs a I(/sbin/sysctl -p) if the C(sysctl_file) is
|
||||
@@ -66,6 +57,13 @@ options:
|
||||
- Specifies the absolute path to C(sysctl.conf), if not C(/etc/sysctl.conf).
|
||||
required: false
|
||||
default: /etc/sysctl.conf
|
||||
sysctl_set:
|
||||
description:
|
||||
- Verify token value with the sysctl command and set with -w if necessary
|
||||
choices: [ "yes", "no" ]
|
||||
required: false
|
||||
version_added: 1.5
|
||||
default: False
|
||||
notes: []
|
||||
requirements: []
|
||||
author: David "DaviXX" CHANIAL <david.chanial@gmail.com>
|
||||
@@ -78,10 +76,14 @@ EXAMPLES = '''
|
||||
# Remove kernel.panic entry from /etc/sysctl.conf
|
||||
- sysctl: name=kernel.panic state=absent sysctl_file=/etc/sysctl.conf
|
||||
|
||||
# Set kernel.panic to 3 in /tmp/test_sysctl.conf, check if the sysctl key
|
||||
# seems writable, but do not reload sysctl, and do not check kernel value
|
||||
# after (not needed, because the real /etc/sysctl.conf was not updated)
|
||||
- sysctl: name=kernel.panic value=3 sysctl_file=/tmp/test_sysctl.conf check=before reload=no
|
||||
# Set kernel.panic to 3 in /tmp/test_sysctl.conf
|
||||
- sysctl: name=kernel.panic value=3 sysctl_file=/tmp/test_sysctl.conf reload=no
|
||||
|
||||
# Set ip fowarding on in /proc and do not reload the sysctl file
|
||||
- sysctl: name="net.ipv4.ip_forward" value=1 sysctl_set=yes
|
||||
|
||||
# Set ip forwarding on in /proc and in the sysctl file and reload if necessary
|
||||
- sysctl: name="net.ipv4.ip_forward" value=1 sysctl_set=yes state=present reload=yes
|
||||
'''
|
||||
|
||||
# ==============================================================
|
||||
@@ -90,137 +92,174 @@ import os
|
||||
import tempfile
|
||||
import re
|
||||
|
||||
# ==============================================================
|
||||
class SysctlModule(object):
|
||||
|
||||
def reload_sysctl(module, **sysctl_args):
|
||||
# update needed ?
|
||||
if not sysctl_args['reload']:
|
||||
return 0, ''
|
||||
def __init__(self, module):
|
||||
self.module = module
|
||||
self.args = self.module.params
|
||||
|
||||
# do it
|
||||
if get_platform().lower() == 'freebsd':
|
||||
# freebsd doesn't support -p, so reload the sysctl service
|
||||
rc,out,err = module.run_command('/etc/rc.d/sysctl reload')
|
||||
else:
|
||||
# system supports reloading via the -p flag to sysctl, so we'll use that
|
||||
sysctl_cmd = module.get_bin_path('sysctl', required=True)
|
||||
rc,out,err = module.run_command([sysctl_cmd, '-p', sysctl_args['sysctl_file']])
|
||||
|
||||
return rc,out+err
|
||||
self.sysctl_cmd = self.module.get_bin_path('sysctl', required=True)
|
||||
self.sysctl_file = self.args['sysctl_file']
|
||||
|
||||
# ==============================================================
|
||||
self.proc_value = None # current token value in proc fs
|
||||
self.file_value = None # current token value in file
|
||||
self.file_lines = [] # all lines in the file
|
||||
self.file_values = {} # dict of token values
|
||||
|
||||
def write_sysctl(module, lines, **sysctl_args):
|
||||
# open a tmp file
|
||||
fd, tmp_path = tempfile.mkstemp('.conf', '.ansible_m_sysctl_', os.path.dirname(sysctl_args['sysctl_file']))
|
||||
f = open(tmp_path,"w")
|
||||
try:
|
||||
for l in lines:
|
||||
f.write(l)
|
||||
except IOError, e:
|
||||
module.fail_json(msg="Failed to write to file %s: %s" % (tmp_path, str(e)))
|
||||
f.flush()
|
||||
f.close()
|
||||
self.changed = False # will change occur
|
||||
self.set_proc = False # does sysctl need to set value
|
||||
self.write_file = False # does the sysctl file need to be reloaded
|
||||
|
||||
# replace the real one
|
||||
module.atomic_move(tmp_path, sysctl_args['sysctl_file'])
|
||||
self.process()
|
||||
|
||||
# end
|
||||
return sysctl_args
|
||||
# ==============================================================
|
||||
# LOGIC
|
||||
# ==============================================================
|
||||
|
||||
# ==============================================================
|
||||
def process(self):
|
||||
|
||||
def sysctl_args_expand(**sysctl_args):
|
||||
if get_platform().lower() == 'freebsd':
|
||||
# FreeBSD does not use the /proc file system, and instead
|
||||
# just uses the sysctl command to set the values
|
||||
sysctl_args['key_path'] = None
|
||||
else:
|
||||
sysctl_args['key_path'] = sysctl_args['name'].replace('.' ,'/')
|
||||
sysctl_args['key_path'] = '/proc/sys/' + sysctl_args['key_path']
|
||||
return sysctl_args
|
||||
|
||||
# ==============================================================
|
||||
|
||||
def sysctl_args_collapse(**sysctl_args):
|
||||
# go ahead
|
||||
if sysctl_args.get('key_path') is not None:
|
||||
del sysctl_args['key_path']
|
||||
if sysctl_args['state'] == 'absent' and 'value' in sysctl_args:
|
||||
del sysctl_args['value']
|
||||
|
||||
# end
|
||||
return sysctl_args
|
||||
|
||||
# ==============================================================
|
||||
|
||||
def sysctl_check(module, current_step, **sysctl_args):
|
||||
|
||||
# no smart checks at this step ?
|
||||
if sysctl_args['checks'] == 'none':
|
||||
return 0, ''
|
||||
if current_step == 'before' and sysctl_args['checks'] not in ['before', 'both']:
|
||||
return 0, ''
|
||||
if current_step == 'after' and sysctl_args['checks'] not in ['after', 'both']:
|
||||
return 0, ''
|
||||
|
||||
# checking coherence
|
||||
if sysctl_args['state'] == 'absent' and sysctl_args['value'] is not None:
|
||||
return 1, 'value=x must not be supplied when state=absent'
|
||||
|
||||
if sysctl_args['state'] == 'present' and sysctl_args['value'] is None:
|
||||
return 1, 'value=x must be supplied when state=present'
|
||||
|
||||
if not sysctl_args['reload'] and sysctl_args['checks'] in ['after', 'both']:
|
||||
return 1, 'checks cannot be set to after or both if reload=no'
|
||||
|
||||
if sysctl_args['key_path'] is not None:
|
||||
# getting file stat
|
||||
if not os.access(sysctl_args['key_path'], os.F_OK):
|
||||
return 1, 'key_path is not an existing file, key %s seems invalid' % sysctl_args['key_path']
|
||||
if not os.access(sysctl_args['key_path'], os.R_OK):
|
||||
return 1, 'key_path is not a readable file, key seems to be uncheckable'
|
||||
|
||||
# checks before
|
||||
if current_step == 'before' and sysctl_args['checks'] in ['before', 'both']:
|
||||
if sysctl_args['key_path'] is not None and not os.access(sysctl_args['key_path'], os.W_OK):
|
||||
return 1, 'key_path is not a writable file, key seems to be read only'
|
||||
return 0, ''
|
||||
|
||||
# checks after
|
||||
if current_step == 'after' and sysctl_args['checks'] in ['after', 'both']:
|
||||
if sysctl_args['value'] is not None:
|
||||
if sysctl_args['key_path'] is not None:
|
||||
# reading the virtual file
|
||||
f = open(sysctl_args['key_path'],'r')
|
||||
output = f.read()
|
||||
f.close()
|
||||
else:
|
||||
# we're on a system without /proc (ie. freebsd), so just
|
||||
# use the sysctl command to get the currently set value
|
||||
sysctl_cmd = module.get_bin_path('sysctl', required=True)
|
||||
rc,output,stderr = module.run_command("%s -n %s" % (sysctl_cmd, sysctl_args['name']))
|
||||
if rc != 0:
|
||||
return 1, 'failed to lookup the value via the sysctl command'
|
||||
|
||||
output = output.strip(' \t\n\r')
|
||||
output = re.sub(r'\s+', ' ', output)
|
||||
|
||||
# normal case, found value must be equal to the submitted value, and
|
||||
# we compare the exploded values to handle any whitepsace differences
|
||||
if output.split() != sysctl_args['value'].split():
|
||||
return 1, 'key seems not set to value even after update/sysctl, founded : <%s>, wanted : <%s>' % (output, sysctl_args['value'])
|
||||
|
||||
return 0, ''
|
||||
# Whitespace is bad
|
||||
self.args['name'] = self.args['name'].strip()
|
||||
if self.args['value'] is not None:
|
||||
self.args['value'] = self.args['value'].strip()
|
||||
else:
|
||||
# no value was supplied, so we're checking to make sure
|
||||
# the associated name is absent. We just fudge this since
|
||||
# the sysctl isn't really gone, just removed from the conf
|
||||
# file meaning it will be whatever the system default is
|
||||
return 0, ''
|
||||
self.args['value'] = ""
|
||||
|
||||
thisname = self.args['name']
|
||||
|
||||
# get the current proc fs value
|
||||
self.proc_value = self.get_token_curr_value(thisname)
|
||||
|
||||
# get the currect sysctl file value
|
||||
self.read_sysctl_file()
|
||||
if thisname not in self.file_values:
|
||||
self.file_values[thisname] = None
|
||||
|
||||
# update file contents with desired token/value
|
||||
self.fix_lines()
|
||||
|
||||
# what do we need to do now?
|
||||
if self.file_values[thisname] is None and self.args['state'] == "present":
|
||||
self.changed = True
|
||||
self.write_file = True
|
||||
elif self.file_values[thisname] != self.args['value']:
|
||||
self.changed = True
|
||||
self.write_file = True
|
||||
if self.args['sysctl_set']:
|
||||
if self.proc_value is None:
|
||||
self.changed = True
|
||||
elif self.proc_value != self.args['value']:
|
||||
self.changed = True
|
||||
self.set_proc = True
|
||||
|
||||
# Do the work
|
||||
if not self.module.check_mode:
|
||||
if self.write_file:
|
||||
self.write_sysctl()
|
||||
if self.write_file and self.args['reload']:
|
||||
self.reload_sysctl()
|
||||
if self.set_proc:
|
||||
self.set_token_value(self.args['name'], self.args['value'])
|
||||
|
||||
# ==============================================================
|
||||
# SYSCTL COMMAND MANAGEMENT
|
||||
# ==============================================================
|
||||
|
||||
# Use the sysctl command to find the current value
|
||||
def get_token_curr_value(self, token):
|
||||
thiscmd = "%s -e -n %s" % (self.sysctl_cmd, token)
|
||||
rc,out,err = self.module.run_command(thiscmd)
|
||||
if rc != 0:
|
||||
return None
|
||||
else:
|
||||
return out
|
||||
|
||||
# Use the sysctl command to set the current value
|
||||
def set_token_value(self, token, value):
|
||||
if len(value.split()) > 0:
|
||||
value = '"' + value + '"'
|
||||
thiscmd = "%s -w %s=%s" % (self.sysctl_cmd, token, value)
|
||||
rc,out,err = self.module.run_command(thiscmd)
|
||||
if rc != 0:
|
||||
self.module.fail_json(msg='setting %s failed: %s' % (token, out + err))
|
||||
else:
|
||||
return rc
|
||||
|
||||
# Run sysctl -p
|
||||
def reload_sysctl(self):
|
||||
# do it
|
||||
if get_platform().lower() == 'freebsd':
|
||||
# freebsd doesn't support -p, so reload the sysctl service
|
||||
rc,out,err = self.module.run_command('/etc/rc.d/sysctl reload')
|
||||
else:
|
||||
# system supports reloading via the -p flag to sysctl, so we'll use that
|
||||
rc,out,err = self.module.run_command([self.sysctl_cmd, '-p', self.sysctl_file])
|
||||
|
||||
if rc != 0:
|
||||
self.module.fail_json(msg="Failed to reload sysctl: %s" % str(out) + str(err))
|
||||
|
||||
# ==============================================================
|
||||
# SYSCTL FILE MANAGEMENT
|
||||
# ==============================================================
|
||||
|
||||
# Get the token value from the sysctl file
|
||||
def read_sysctl_file(self):
|
||||
lines = open(self.sysctl_file, "r").readlines()
|
||||
for line in lines:
|
||||
line = line.strip()
|
||||
self.file_lines.append(line)
|
||||
|
||||
# don't split empty lines or comments
|
||||
if not line or line.startswith("#"):
|
||||
continue
|
||||
|
||||
k, v = line.split('=',1)
|
||||
k = k.strip()
|
||||
v = v.strip()
|
||||
self.file_values[k] = v.strip()
|
||||
|
||||
# Fix the value in the sysctl file content
|
||||
def fix_lines(self):
|
||||
checked = []
|
||||
self.fixed_lines = []
|
||||
for line in self.file_lines:
|
||||
if not line.strip() or line.strip().startswith("#"):
|
||||
self.fixed_lines.append(line)
|
||||
continue
|
||||
tmpline = line.strip()
|
||||
k, v = line.split('=',1)
|
||||
k = k.strip()
|
||||
v = v.strip()
|
||||
if k not in checked:
|
||||
checked.append(k)
|
||||
if k == self.args['name']:
|
||||
if self.args['state'] == "present":
|
||||
new_line = "%s = %s\n" % (k, self.args['value'])
|
||||
self.fixed_lines.append(new_line)
|
||||
else:
|
||||
new_line = "%s = %s\n" % (k, v)
|
||||
self.fixed_lines.append(new_line)
|
||||
|
||||
if self.args['name'] not in checked and self.args['state'] == "present":
|
||||
new_line = "%s = %s\n" % (self.args['name'], self.args['value'])
|
||||
self.fixed_lines.append(new_line)
|
||||
|
||||
# Completely rewrite the sysctl file
|
||||
def write_sysctl(self):
|
||||
# open a tmp file
|
||||
fd, tmp_path = tempfile.mkstemp('.conf', '.ansible_m_sysctl_', os.path.dirname(self.sysctl_file))
|
||||
f = open(tmp_path,"w")
|
||||
try:
|
||||
for l in self.fixed_lines:
|
||||
f.write(l.strip() + "\n")
|
||||
except IOError, e:
|
||||
self.module.fail_json(msg="Failed to write to file %s: %s" % (tmp_path, str(e)))
|
||||
f.flush()
|
||||
f.close()
|
||||
|
||||
# replace the real one
|
||||
self.module.atomic_move(tmp_path, self.sysctl_file)
|
||||
|
||||
# weird end
|
||||
return 1, 'unexpected position reached'
|
||||
|
||||
# ==============================================================
|
||||
# main
|
||||
@@ -233,110 +272,16 @@ def main():
|
||||
name = dict(aliases=['key'], required=True),
|
||||
value = dict(aliases=['val'], required=False),
|
||||
state = dict(default='present', choices=['present', 'absent']),
|
||||
checks = dict(default='both', choices=['none', 'before', 'after', 'both']),
|
||||
reload = dict(default=True, type='bool'),
|
||||
sysctl_set = dict(default=False, type='bool'),
|
||||
sysctl_file = dict(default='/etc/sysctl.conf')
|
||||
)
|
||||
),
|
||||
supports_check_mode=True
|
||||
)
|
||||
|
||||
# defaults
|
||||
sysctl_args = {
|
||||
'changed': False,
|
||||
'name': module.params['name'],
|
||||
'state': module.params['state'],
|
||||
'checks': module.params['checks'],
|
||||
'reload': module.params['reload'],
|
||||
'value': module.params.get('value'),
|
||||
'sysctl_file': module.params['sysctl_file']
|
||||
}
|
||||
|
||||
# prepare vars
|
||||
sysctl_args = sysctl_args_expand(**sysctl_args)
|
||||
if get_platform().lower() == 'freebsd':
|
||||
# freebsd does not like spaces around the equal sign
|
||||
pattern = "%s=%s\n"
|
||||
else:
|
||||
pattern = "%s = %s\n"
|
||||
new_line = pattern % (sysctl_args['name'], sysctl_args['value'])
|
||||
to_write = []
|
||||
founded = False
|
||||
|
||||
# make checks before act
|
||||
res,msg = sysctl_check(module, 'before', **sysctl_args)
|
||||
if res != 0:
|
||||
module.fail_json(msg='checks_before failed with: ' + msg)
|
||||
result = SysctlModule(module)
|
||||
|
||||
if not os.access(sysctl_args['sysctl_file'], os.W_OK):
|
||||
try:
|
||||
f = open(sysctl_args['sysctl_file'],'w')
|
||||
f.close()
|
||||
except IOError, e:
|
||||
module.fail_json(msg='unable to create supplied sysctl file (destination directory probably missing)')
|
||||
|
||||
# reading the file
|
||||
for line in open(sysctl_args['sysctl_file'], 'r').readlines():
|
||||
if not line.strip():
|
||||
to_write.append(line)
|
||||
continue
|
||||
if line.strip().startswith('#'):
|
||||
to_write.append(line)
|
||||
continue
|
||||
|
||||
# write line if not the one searched
|
||||
ld = {}
|
||||
ld['name'], ld['val'] = line.split('=',1)
|
||||
ld['name'] = ld['name'].strip()
|
||||
|
||||
if ld['name'] != sysctl_args['name']:
|
||||
to_write.append(line)
|
||||
continue
|
||||
|
||||
# should be absent ?
|
||||
if sysctl_args['state'] == 'absent':
|
||||
# not writing the founded line
|
||||
# mark as changed
|
||||
sysctl_args['changed'] = True
|
||||
|
||||
# should be present
|
||||
if sysctl_args['state'] == 'present':
|
||||
# is the founded line equal to the wanted one ?
|
||||
ld['val'] = ld['val'].strip()
|
||||
if ld['val'] == sysctl_args['value']:
|
||||
# line is equal, writing it without update (but cancel repeats)
|
||||
if sysctl_args['changed'] == False and founded == False:
|
||||
to_write.append(line)
|
||||
founded = True
|
||||
else:
|
||||
# update the line (but cancel repeats)
|
||||
if sysctl_args['changed'] == False and founded == False:
|
||||
to_write.append(new_line)
|
||||
sysctl_args['changed'] = True
|
||||
continue
|
||||
|
||||
# if not changed, but should be present, so we have to add it
|
||||
if sysctl_args['state'] == 'present' and sysctl_args['changed'] == False and founded == False:
|
||||
to_write.append(new_line)
|
||||
sysctl_args['changed'] = True
|
||||
|
||||
# has changed ?
|
||||
res = 0
|
||||
if sysctl_args['changed'] == True:
|
||||
sysctl_args = write_sysctl(module, to_write, **sysctl_args)
|
||||
res,msg = reload_sysctl(module, **sysctl_args)
|
||||
|
||||
# make checks after act
|
||||
res,msg = sysctl_check(module, 'after', **sysctl_args)
|
||||
if res != 0:
|
||||
module.fail_json(msg='checks_after failed with: ' + msg)
|
||||
|
||||
# look at the next link to avoid this workaround
|
||||
# https://groups.google.com/forum/?fromgroups=#!topic/ansible-project/LMY-dwF6SQk
|
||||
changed = sysctl_args['changed']
|
||||
del sysctl_args['changed']
|
||||
|
||||
# end
|
||||
sysctl_args = sysctl_args_collapse(**sysctl_args)
|
||||
module.exit_json(changed=changed, **sysctl_args)
|
||||
module.exit_json(changed=result.changed)
|
||||
sys.exit(0)
|
||||
|
||||
# import module snippets
|
||||
|
||||
@@ -77,8 +77,8 @@ options:
|
||||
description:
|
||||
- Optionally set the user's password to this crypted value. See
|
||||
the user example in the github examples directory for what this looks
|
||||
like in a playbook.
|
||||
- Passwords values can be generated with "openssl passwd -salt <salt> -1 <plaintext>"
|
||||
like in a playbook. The `FAQ <http://docs.ansible.com/faq.html#how-do-i-generate-crypted-passwords-for-the-user-module>`_
|
||||
contains details on various ways to generate these password values.
|
||||
state:
|
||||
required: false
|
||||
default: "present"
|
||||
@@ -901,8 +901,21 @@ class OpenBSDUser(User):
|
||||
cmd.append(self.shell)
|
||||
|
||||
if self.login_class is not None:
|
||||
cmd.append('-L')
|
||||
cmd.append(self.login_class)
|
||||
# find current login class
|
||||
user_login_class = None
|
||||
userinfo_cmd = [self.module.get_bin_path('userinfo', True), self.name]
|
||||
(rc, out, err) = self.execute_command(userinfo_cmd)
|
||||
|
||||
for line in out.splitlines():
|
||||
tokens = line.split()
|
||||
|
||||
if tokens[0] == 'class' and len(tokens) == 2:
|
||||
user_login_class = tokens[1]
|
||||
|
||||
# act only if login_class change
|
||||
if self.login_class != user_login_class:
|
||||
cmd.append('-L')
|
||||
cmd.append(self.login_class)
|
||||
|
||||
if self.update_password == 'always' and self.password is not None and info[1] != self.password:
|
||||
cmd.append('-p')
|
||||
|
||||
@@ -40,5 +40,5 @@ author: Dag Wieers
|
||||
EXAMPLES = '''
|
||||
# Example playbook using fail and when together
|
||||
- fail: msg="The system may not be provisioned according to the CMDB status."
|
||||
when: "{{ cmdb_status }} != 'to-be-staged'"
|
||||
when: cmdb_status != "to-be-staged"
|
||||
'''
|
||||
|
||||
@@ -129,12 +129,11 @@ def _ensure_virtualenv(module):
|
||||
if venv_param is None:
|
||||
return
|
||||
|
||||
virtualenv = module.get_bin_path('virtualenv', True)
|
||||
|
||||
vbin = os.path.join(os.path.expanduser(venv_param), 'bin')
|
||||
activate = os.path.join(vbin, 'activate')
|
||||
|
||||
if not os.path.exists(activate):
|
||||
virtualenv = module.get_bin_path('virtualenv', True)
|
||||
vcmd = '%s %s' % (virtualenv, venv_param)
|
||||
vcmd = [virtualenv, venv_param]
|
||||
rc, out_venv, err_venv = module.run_command(vcmd)
|
||||
|
||||
Reference in New Issue
Block a user