quantum_subnet 9.69 KB
Newer Older
bennojoy committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
#!/usr/bin/python
#coding: utf-8 -*-

# (c) 2013, Benno Joy <benno@ansibleworks.com>
#
# This module is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This software is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this software.  If not, see <http://www.gnu.org/licenses/>.

try:
    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'")

DOCUMENTATION = '''
---
27
module: quantum_subnet
28
short_description: Add/Remove floating IP from an instance
bennojoy committed
29
description:
30
   - Add or Remove a floating IP to an instance
bennojoy committed
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
options:
   login_username:
     description:
        - login username to authenticate to keystone
     required: true
     default: admin
   login_password:
     description:
        - Password of login user
     required: true
     default: True
   login_tenant_name:
     description:
        - The tenant name of the login user
     required: true
     default: True
   auth_url:
     description:
49
        - The keystone URL for authentication
bennojoy committed
50 51 52 53 54 55 56 57 58 59 60 61 62 63
     required: false
     default: 'http://127.0.0.1:35357/v2.0/'
   region_name:
     description:
        - Name of the region
     required: false
     default: None
   state:
     description:
        - Indicate desired state of the resource
     choices: ['present', 'absent']
     default: present
   network_name:
     description:
64
        - Name of the network to which the subnet should be attached
bennojoy committed
65 66 67 68
     required: true
     default: None
   cidr:
     description:
69
        - The CIDR representation of the subnet that should be assigned to the subnet
bennojoy committed
70 71 72 73 74 75 76 77 78 79 80 81 82 83
     required: true
     default: None
   tenant_name:
     description:
        - The name of the tenant for whom the subnet should be created
     required: false
     default: None
   ip_version:
     description:
        - The IP version of the subnet 4 or 6 
     required: false
     default: 4
   enable_dhcp:
     description:
Michael DeHaan committed
84
        - Whether DHCP should be enabled for this subnet.
bennojoy committed
85 86 87 88 89 90 91
     required: false
     default: true
   gateway_ip:
     description:
        - The ip that would be assigned to the gateway for this subnet
     required: false
     default: None
92 93 94 95 96
   dns_nameservers:
     description:
        - DNS nameservers for this subnet, comma-separated
     required: false
     default: None
bennojoy committed
97 98
   allocation_pool_start:
     description:
99
        - From the subnet pool the starting address from which the IP should be allocated
bennojoy committed
100 101 102 103
     required: false
     default: None
   allocation_pool_end:
     description:
104
        - From the subnet pool the last IP that should be assigned to the virtual machines
bennojoy committed
105 106 107 108 109
     required: false
     default: None
requirements: ["quantum", "keystoneclient"]
'''

110 111 112 113 114 115 116
EXAMPLES = '''
# Create a subnet for a tenant with the specified subnet
- quantum_subnet: state=present login_username=admin login_password=admin
                  login_tenant_name=admin tenant_name=tenant1
                  network_name=network1 name=net1subnet cidr=192.168.0.0/24"
'''

bennojoy committed
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
_os_keystone   = None
_os_tenant_id  = None
_os_network_id = None

def _get_ksclient(module, kwargs):
    try:
        kclient = ksclient.Client(username=kwargs.get('login_username'),
                                 password=kwargs.get('login_password'),
                                 tenant_name=kwargs.get('login_tenant_name'),
                                 auth_url=kwargs.get('auth_url'))
    except Exception as e:   
        module.fail_json(msg = "Error authenticating to the keystone: %s" %e.message)
    global _os_keystone 
    _os_keystone = 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)
    return endpoint

def _get_quantum_client(module, kwargs):
    _ksclient = _get_ksclient(module, kwargs)
    token     = _ksclient.auth_token
    endpoint  = _get_endpoint(module, _ksclient)
    kwargs = {
            'token':        token,
147
            'endpoint_url': endpoint
bennojoy committed
148 149
    }
    try:
150
        quantum = client.Client('2.0', **kwargs)
bennojoy committed
151 152 153 154 155 156 157 158 159 160 161 162 163 164
    except Exception as e:
        module.fail_json(msg = " Error in connecting to quantum: %s" % e.message)
    return quantum

def _set_tenant_id(module):
    global _os_tenant_id
    if not module.params['tenant_name']:
        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
165
            break
bennojoy committed
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
    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):
    kwargs = {
        'tenant_id': _os_tenant_id,
        'name': module.params['network_name'],
    }
    try:
        networks = quantum.list_networks(**kwargs)
    except Exception as e:
        module.fail_json("Error in listing quantum networks: %s" % e.message)
    if not networks['networks']:
            return None
    return networks['networks'][0]['id']


def _get_subnet_id(module, quantum):
    global _os_network_id
    subnet_id = None
    _os_network_id = _get_net_id(quantum, module)
    if not _os_network_id:
188
        module.fail_json(msg = "network id of network not found.")
bennojoy committed
189
    else:
190
        kwargs = {
bennojoy committed
191 192 193
            'tenant_id': _os_tenant_id,
            'name': module.params['name'],
        }
194 195 196 197 198 199 200
        try:
            subnets = quantum.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']
bennojoy committed
201 202 203 204

def _create_subnet(module, quantum):
    quantum.format = 'json'
    subnet = {
205 206 207 208 209 210 211 212
            'name':            module.params['name'],
            'ip_version':      module.params['ip_version'],
            'enable_dhcp':     module.params['enable_dhcp'],
            'tenant_id':       _os_tenant_id,
            'gateway_ip':      module.params['gateway_ip'],
            'dns_nameservers': module.params['dns_nameservers'],
            'network_id':      _os_network_id,
            'cidr':            module.params['cidr'],
bennojoy committed
213 214
    }
    if module.params['allocation_pool_start'] and module.params['allocation_pool_end']:
215 216 217 218 219 220 221
        allocation_pools = [
            { 
                'start' : module.params['allocation_pool_start'],
                'end'   :  module.params['allocation_pool_end']
            }
        ]
        subnet.update({'allocation_pools': allocation_pools})
bennojoy committed
222
    if not module.params['gateway_ip']:
223
        subnet.pop('gateway_ip')
224 225 226 227
    if module.params['dns_nameservers']:
        subnet['dns_nameservers'] = module.params['dns_nameservers'].split(',')
    else:
        subnet.pop('dns_nameservers')
bennojoy committed
228
    try:
229 230 231
        new_subnet = quantum.create_subnet(dict(subnet=subnet))
    except Exception, e:
        module.fail_json(msg = "Failure in creating subnet: %s" % e.message) 
bennojoy committed
232
    return new_subnet['subnet']['id']
233 234
        
                
bennojoy committed
235 236
def _delete_subnet(module, quantum, subnet_id):
    try:
237
        quantum.delete_subnet(subnet_id)
bennojoy committed
238
    except Exception as e:
239
        module.fail_json( msg = "Error in deleting subnet: %s" % e.message)
bennojoy committed
240
    return True
241 242
        
                
bennojoy committed
243 244 245
def main():
    
    module = AnsibleModule(
246 247 248 249 250 251 252 253 254 255 256 257 258 259
        argument_spec = dict(
            login_username          = dict(default='admin'),
            login_password          = dict(required=True),
            login_tenant_name       = dict(required='True'),
            auth_url                = dict(default='http://127.0.0.1:35357/v2.0/'),
            region_name             = dict(default=None),
            name                    = dict(required=True),
            network_name            = dict(required=True),
            cidr                    = dict(required=True),
            tenant_name             = dict(default=None),
            state                   = dict(default='present', choices=['absent', 'present']),
            ip_version              = dict(default='4', choices=['4', '6']),
            enable_dhcp             = dict(default='true', choices=BOOLEANS),
            gateway_ip              = dict(default=None),
260
            dns_nameservers         = dict(default=None),
261 262
            allocation_pool_start   = dict(default=None),
            allocation_pool_end     = dict(default=None),
bennojoy committed
263 264 265 266 267
        ),
    )
    quantum = _get_quantum_client(module, module.params)
    _set_tenant_id(module)
    if module.params['state'] == 'present':
268 269 270 271 272 273
        subnet_id = _get_subnet_id(module, quantum)
        if not subnet_id:
            subnet_id = _create_subnet(module, quantum)
            module.exit_json(changed = True, result = "Created" , id = subnet_id)
        else:
            module.exit_json(changed = False, result = "success" , id = subnet_id)
bennojoy committed
274
    else:
275 276
        subnet_id = _get_subnet_id(module, quantum)
        if not subnet_id:
277
            module.exit_json(changed = False, result = "success")
278
        else:
279 280
            _delete_subnet(module, quantum, subnet_id)
            module.exit_json(changed = True, result = "deleted")
281
                
bennojoy committed
282 283 284 285
# this is magic, see lib/ansible/module.params['common.py
#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
main()