Statistics
| Branch: | Tag: | Revision:

root / kamaki / clients / network / __init__.py @ 74b7c6dc

History | View | Annotate | Download (14.6 kB)

1
# Copyright 2013 GRNET S.A. All rights reserved.
2
#
3
# Redistribution and use in source and binary forms, with or
4
# without modification, are permitted provided that the following
5
# conditions are met:
6
#
7
#   1. Redistributions of source code must retain the above
8
#      copyright notice, this list of conditions and the following
9
#      disclaimer.
10
#
11
#   2. Redistributions in binary form must reproduce the above
12
#      copyright notice, this list of conditions and the following
13
#      disclaimer in the documentation and/or other materials
14
#      provided with the distribution.
15
#
16
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
# POSSIBILITY OF SUCH DAMAGE.
28
#
29
# The views and conclusions contained in the software and
30
# documentation are those of the authors and should not be
31
# interpreted as representing official policies, either expressed
32
# or implied, of GRNET S.A.
33

    
34
from kamaki.clients import ClientError
35
from kamaki.clients.network.rest_api import NetworkRestClient
36

    
37

    
38
class NetworkClient(NetworkRestClient):
39
    """OpenStack Network API 2.0 client"""
40

    
41
    def list_networks(self):
42
        r = self.networks_get(success=200)
43
        return r.json['networks']
44

    
45
    def create_network(self, name, admin_state_up=None, shared=None):
46
        req = dict(network=dict(
47
            name=name, admin_state_up=bool(admin_state_up)))
48
        if shared not in (None, ):
49
            req['network']['shared'] = bool(shared)
50
        r = self.networks_post(json_data=req, success=201)
51
        return r.json['network']
52

    
53
    def create_networks(self, networks):
54
        """Atomic operation for batch network creation (all or nothing)
55
        :param networks: (list) [
56
            {name: ..(str).., admin_state_up: ..(bool).., shared: ..(bool)..},
57
            {name: ..(str).., admin_state_up: ..(bool).., shared: ..(bool)..}]
58
            name is mandatory, the rest is optional
59
            e.g., create_networks([
60
                {name: 'net1', admin_state_up: True},
61
                {name: 'net2'}])
62
        :returns: (list of dicts) created networks details
63
        :raises ValueError: if networks is misformated
64
        :raises ClientError: if the request failed or didn't return 201
65
        """
66
        try:
67
            msg = 'The networks parameter must be list or tuple'
68
            assert (
69
                isinstance(networks, list) or isinstance(networks, tuple)), msg
70
            for network in networks:
71
                msg = 'Network specification %s is not a dict' % network
72
                assert isinstance(network, dict), msg
73
                err = set(network).difference(
74
                    ('name', 'admin_state_up', 'shared'))
75
                if err:
76
                    raise ValueError(
77
                        'Invalid key(s): %s in network specification %s' % (
78
                            err, network))
79
                msg = 'Name is missing in network specification: %s' % network
80
                assert network.get('name', None), msg
81
                network.setdefault('admin_state_up', False)
82
        except AssertionError as ae:
83
            raise ValueError('%s' % ae)
84

    
85
        req = dict(networks=list(networks))
86
        r = self.networks_post(json_data=req, success=201)
87
        return r.json['networks']
88

    
89
    def get_network_details(self, network_id):
90
        r = self.networks_get(network_id, success=200)
91
        return r.json['network']
92

    
93
    def update_network(
94
            self, network_id, name=None, admin_state_up=None, shared=None):
95
        network = dict()
96
        if name:
97
            network['name'] = name
98
        if admin_state_up not in (None, ):
99
            network['admin_state_up'] = admin_state_up
100
        if shared not in (None, ):
101
            network['shared'] = shared
102
        network = dict(network=network)
103
        r = self.networks_put(network_id, json_data=network, success=200)
104
        return r.json['network']
105

    
106
    def delete_network(self, network_id):
107
        r = self.networks_delete(network_id, success=204)
108
        return r.headers
109

    
110
    def list_subnets(self):
111
        r = self.subnets_get(success=200)
112
        return r.json['subnets']
113

    
114
    def create_subnet(
115
            self, network_id, cidr,
116
            name=None, allocation_pools=None, gateway_ip=None, subnet_id=None,
117
            ipv6=None, enable_dhcp=None):
118
        """
119
        :param network_id: (str)
120
        :param cidr: (str)
121

122
        :param name: (str) The subnet name
123
        :param allocation_pools: (list of dicts) start/end addresses of
124
            allocation pools: [{'start': ..., 'end': ...}, ...]
125
        :param gateway_ip: (str)
126
        :param subnet_id: (str)
127
        :param ipv6: (bool) ip_version == 6 if true else 4 (default)
128
        :param enable_dhcp: (bool)
129
        """
130
        subnet = dict(
131
            network_id=network_id, cidr=cidr, ip_version=6 if ipv6 else 4)
132
        if name:
133
            subnet['name'] = name
134
        if allocation_pools:
135
            subnet['allocation_pools'] = allocation_pools
136
        if gateway_ip:
137
            subnet['gateway_ip'] = gateway_ip
138
        if subnet_id:
139
            subnet['id'] = subnet_id
140
        if enable_dhcp not in (None, ):
141
            subnet['enable_dhcp'] = bool(enable_dhcp)
142
        r = self.subnets_post(json_data=dict(subnet=subnet), success=201)
143
        return r.json['subnet']
144

    
145
    def create_subnets(self, subnets):
146
        """Atomic operation for batch subnet creation (all or nothing)
147
        :param subnets: (list of dicts) {key: ...} with all parameters in the
148
            method create_subnet, where method mandatory / optional paramteres
149
            respond to mandatory / optional paramters in subnets items
150
        :returns: (list of dicts) created subnetss details
151
        :raises ValueError: if subnets parameter is incorrectly formated
152
        :raises ClientError: if the request failed or didn't return 201
153
        """
154
        try:
155
            msg = 'The subnets parameter must be list or tuple'
156
            assert (
157
                isinstance(subnets, list) or isinstance(subnets, tuple)), msg
158
            for subnet in subnets:
159
                msg = 'Subnet specification %s is not a dict' % subnet
160
                assert isinstance(subnet, dict), msg
161
                err = set(subnet).difference((
162
                    'network_id', 'cidr', 'name', 'allocation_pools',
163
                    'gateway_ip', 'subnet_id', 'ipv6', 'enable_dhcp'))
164
                if err:
165
                    raise ValueError(
166
                        'Invalid key(s): %s in subnet specification %s' % (
167
                            err, subnet))
168
                msg = 'network_id is missing in subnet spec: %s' % subnet
169
                assert subnet.get('network_id', None), msg
170
                msg = 'cidr is missing in subnet spec: %s' % subnet
171
                assert subnet.get('cidr', None), msg
172
                subnet['ip_version'] = 6 if subnet.pop('ipv6', None) else 4
173
                if 'subnet_id' in subnet:
174
                    subnet['id'] = subnet.pop('subnet_id')
175
        except AssertionError as ae:
176
            raise ValueError('%s' % ae)
177

    
178
        r = self.subnets_post(
179
            json_data=dict(subnets=list(subnets)), success=201)
180
        return r.json['subnets']
181

    
182
    def get_subnet_details(self, subnet_id):
183
        r = self.subnets_get(subnet_id, success=201)
184
        return r.json
185

    
186
    def update_subnet(
187
            self, network_id, cidr,
188
            name=None, allocation_pools=None, gateway_ip=None, subnet_id=None,
189
            ipv6=None, enable_dhcp=None):
190
        """
191
        :param network_id: (str) used as filter
192
        :param cidr: (str) used as filter
193

194
        :param name: (str) The subnet name
195
        :param allocation_pools: (list of dicts) start/end addresses of
196
            allocation pools: [{'start': ..., 'end': ...}, ...]
197
        :param gateway_ip: (str)
198
        :param subnet_id: (str)
199
        :param ipv6: (bool) ip_version == 6 if true, 4 if false, used as filter
200
        :param enable_dhcp: (bool)
201
        """
202
        subnet = dict(network_id=network_id, cidr=cidr)
203
        if name not in (None, ):
204
            subnet['name'] = name
205
        if allocation_pools not in (None, ):
206
            subnet['allocation_pools'] = allocation_pools
207
        if gateway_ip not in (None, ):
208
            subnet['gateway_ip'] = gateway_ip
209
        if subnet_id not in (None, ):
210
            subnet['id'] = subnet_id
211
        if ipv6 not in (None, ):
212
            subnet['ip_version'] = 6 if ipv6 else 4
213
        if enable_dhcp not in (None, ):
214
            subnet['enable_dhcp'] = enable_dhcp
215
        r = self.subnets_put(json_data=dict(subnet=subnet), success=201)
216
        return r.json['subnet']
217

    
218
    def delete_subnet(self, subnet_id):
219
        r = self.subnets_delete(subnet_id, success=204)
220
        return r.headers
221

    
222
    def list_ports(self):
223
        r = self.ports_get(success=200)
224
        return r.json['ports']
225

    
226
    def create_port(
227
            self, network_id,
228
            name=None, status=None, admin_state_up=None, mac_address=None,
229
            fixed_ips=None, security_groups=None):
230
        """
231
        :param network_id: (str)
232

233
        :param name: (str)
234
        :param status: (str)
235
        :param admin_state_up: (bool) Router administrative status (UP / DOWN)
236
        :param mac_address: (str)
237
        :param fixed_ips: (str)
238
        :param security_groups: (list)
239
        """
240
        port = dict(network_id=network_id)
241
        if name:
242
            port['name'] = name
243
        if status:
244
            port['status'] = status
245
        if admin_state_up not in (None, ):
246
            port['admin_state_up'] = bool(admin_state_up)
247
        if mac_address:
248
            port['mac_address'] = mac_address
249
        if fixed_ips:
250
            port['fixed_ips'] = fixed_ips
251
        if security_groups:
252
            port['security_groups'] = security_groups
253
        r = self.ports_post(json_data=dict(port=port), success=201)
254
        return r.json['port']
255

    
256
    def create_ports(self, ports):
257
        """Atomic operation for batch port creation (all or nothing)
258
        :param ports: (list of dicts) {key: ...} with all parameters in the
259
            method create_port, where method mandatory / optional paramteres
260
            respond to mandatory / optional paramters in ports items
261
        :returns: (list of dicts) created portss details
262
        :raises ValueError: if ports parameter is incorrectly formated
263
        :raises ClientError: if the request failed or didn't return 201
264
        """
265
        try:
266
            msg = 'The ports parameter must be list or tuple'
267
            assert (
268
                isinstance(ports, list) or isinstance(ports, tuple)), msg
269
            for port in ports:
270
                msg = 'Subnet specification %s is not a dict' % port
271
                assert isinstance(port, dict), msg
272
                err = set(port).difference((
273
                    'network_id', 'status', 'name', 'admin_state_up',
274
                    'mac_address', 'fixed_ips', 'security_groups'))
275
                if err:
276
                    raise ValueError(
277
                        'Invalid key(s): %s in port specification %s' % (
278
                            err, port))
279
                msg = 'network_id is missing in port spec: %s' % port
280
                assert port.get('network_id', None), msg
281
        except AssertionError as ae:
282
            raise ValueError('%s' % ae)
283
        r = self.ports_post(json_data=dict(ports=list(ports)), success=201)
284
        return r.json['ports']
285

    
286
    def get_port_details(self, port_id):
287
        r = self.ports_get(port_id, success=201)
288
        return r.json['port']
289

    
290
    def delete_port(self, port_id):
291
        r = self.ports_delete(port_id, success=204)
292
        return r.headers
293

    
294
    def update_port(
295
            self, port_id, network_id,
296
            name=None, status=None, admin_state_up=None, mac_address=None,
297
            fixed_ips=None, security_groups=None):
298
        """
299
        :param network_id: (str)
300

301
        :param name: (str)
302
        :param status: (str)
303
        :param admin_state_up: (bool) Router administrative status (UP / DOWN)
304
        :param mac_address: (str)
305
        :param fixed_ips: (str)
306
        :param security_groups: (list)
307
        """
308
        port = dict(network_id=network_id)
309
        if name:
310
            port['name'] = name
311
        if status:
312
            port['status'] = status
313
        if admin_state_up not in (None, ):
314
            port['admin_state_up'] = bool(admin_state_up)
315
        if mac_address:
316
            port['mac_address'] = mac_address
317
        if fixed_ips:
318
            port['fixed_ips'] = fixed_ips
319
        if security_groups:
320
            port['security_groups'] = security_groups
321
        r = self.ports_put(port_id, json_data=dict(port=port), success=201)
322
        return r.json['port']
323

    
324
    def list_floatingips(self):
325
        r = self.floatingips_get(success=200)
326
        return r.json['floatingips']
327

    
328
    def get_floatingip_details(self, floatingip_id):
329
        r = self.floatingips_get(floatingip_id, success=200)
330
        return r.json['floatingip']
331

    
332
    def create_floatingip(
333
            self, floating_network_id,
334
            floating_ip_address='', port_id='', fixed_ip_address=''):
335
        floatingip = dict(floating_network_id=floating_network_id)
336
        if floating_ip_address:
337
            floatingip['floating_ip_address'] = floating_ip_address
338
        if port_id:
339
            floatingip['port_id'] = port_id
340
        if fixed_ip_address:
341
            floatingip['fixed_ip_address'] = fixed_ip_address
342
        r = self.floatingips_post(
343
            json_data=dict(floatingip=floatingip), success=200)
344
        return r.json['floatingip']
345

    
346
    def update_floatingip(
347
            self, floatingip_id,
348
            floating_ip_address='', port_id='', fixed_ip_address=''):
349
        """To nullify something optional, use None"""
350
        floatingip = dict()
351
        if floating_ip_address != '':
352
            floatingip['floating_ip_address'] = floating_ip_address
353
        if port_id != '':
354
            floatingip['port_id'] = port_id
355
        if fixed_ip_address != '':
356
            floatingip['fixed_ip_address'] = fixed_ip_address
357
        r = self.floatingips_put(
358
            floatingip_id, json_data=dict(floatingip=floatingip), success=200)
359
        return r['floatingip']
360

    
361
    def delete_floatingip(self, floatingip_id):
362
        r = self.floatingips_delete(floatingip_id, success=204)
363
        return r.headers