One-byte typo
[kamaki] / kamaki / clients / network / __init__.py
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['port']
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']