Statistics
| Branch: | Tag: | Revision:

root / kamaki / clients / network / __init__.py @ 5c433331

History | View | Annotate | Download (12 kB)

1 25d2ff8e Stavros Sachtouris
# Copyright 2013 GRNET S.A. All rights reserved.
2 25d2ff8e Stavros Sachtouris
#
3 25d2ff8e Stavros Sachtouris
# Redistribution and use in source and binary forms, with or
4 25d2ff8e Stavros Sachtouris
# without modification, are permitted provided that the following
5 25d2ff8e Stavros Sachtouris
# conditions are met:
6 25d2ff8e Stavros Sachtouris
#
7 25d2ff8e Stavros Sachtouris
#   1. Redistributions of source code must retain the above
8 25d2ff8e Stavros Sachtouris
#      copyright notice, this list of conditions and the following
9 25d2ff8e Stavros Sachtouris
#      disclaimer.
10 25d2ff8e Stavros Sachtouris
#
11 25d2ff8e Stavros Sachtouris
#   2. Redistributions in binary form must reproduce the above
12 25d2ff8e Stavros Sachtouris
#      copyright notice, this list of conditions and the following
13 25d2ff8e Stavros Sachtouris
#      disclaimer in the documentation and/or other materials
14 25d2ff8e Stavros Sachtouris
#      provided with the distribution.
15 25d2ff8e Stavros Sachtouris
#
16 25d2ff8e Stavros Sachtouris
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 25d2ff8e Stavros Sachtouris
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 25d2ff8e Stavros Sachtouris
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 25d2ff8e Stavros Sachtouris
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 25d2ff8e Stavros Sachtouris
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 25d2ff8e Stavros Sachtouris
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 25d2ff8e Stavros Sachtouris
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 25d2ff8e Stavros Sachtouris
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 25d2ff8e Stavros Sachtouris
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 25d2ff8e Stavros Sachtouris
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 25d2ff8e Stavros Sachtouris
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 25d2ff8e Stavros Sachtouris
# POSSIBILITY OF SUCH DAMAGE.
28 25d2ff8e Stavros Sachtouris
#
29 25d2ff8e Stavros Sachtouris
# The views and conclusions contained in the software and
30 25d2ff8e Stavros Sachtouris
# documentation are those of the authors and should not be
31 25d2ff8e Stavros Sachtouris
# interpreted as representing official policies, either expressed
32 25d2ff8e Stavros Sachtouris
# or implied, of GRNET S.A.
33 c6ebe715 Stavros Sachtouris
34 c6ebe715 Stavros Sachtouris
from kamaki.clients import ClientError
35 5c433331 Stavros Sachtouris
from kamaki.clients.network.rest_api import NetworkRestClient
36 c6ebe715 Stavros Sachtouris
37 c6ebe715 Stavros Sachtouris
38 5c433331 Stavros Sachtouris
class NetworkClient(NetworkRestClient):
39 c6ebe715 Stavros Sachtouris
    """OpenStack Network API 2.0 client"""
40 058ee9a8 Stavros Sachtouris
41 058ee9a8 Stavros Sachtouris
    def list_networks(self):
42 058ee9a8 Stavros Sachtouris
        r = self.networks_get(success=200)
43 058ee9a8 Stavros Sachtouris
        return r.json['networks']
44 058ee9a8 Stavros Sachtouris
45 afba96a7 Stavros Sachtouris
    def create_network(self, name, admin_state_up=None, shared=None):
46 058ee9a8 Stavros Sachtouris
        req = dict(network=dict(
47 ba1ab65d Stavros Sachtouris
            name=name, admin_state_up=bool(admin_state_up)))
48 ba1ab65d Stavros Sachtouris
        if shared not in (None, ):
49 ba1ab65d Stavros Sachtouris
            req['network']['shared'] = bool(shared)
50 ba1ab65d Stavros Sachtouris
        r = self.networks_post(json_data=req, success=201)
51 058ee9a8 Stavros Sachtouris
        return r.json['network']
52 afba96a7 Stavros Sachtouris
53 ba1ab65d Stavros Sachtouris
    def create_networks(self, networks):
54 ba1ab65d Stavros Sachtouris
        """Atomic operation for batch network creation (all or nothing)
55 ba1ab65d Stavros Sachtouris
        :param networks: (list) [
56 ba1ab65d Stavros Sachtouris
            {name: ..(str).., admin_state_up: ..(bool).., shared: ..(bool)..},
57 ba1ab65d Stavros Sachtouris
            {name: ..(str).., admin_state_up: ..(bool).., shared: ..(bool)..}]
58 afba96a7 Stavros Sachtouris
            name is mandatory, the rest is optional
59 ba1ab65d Stavros Sachtouris
            e.g., create_networks([
60 ba1ab65d Stavros Sachtouris
                {name: 'net1', admin_state_up: True},
61 ba1ab65d Stavros Sachtouris
                {name: 'net2'}])
62 ba1ab65d Stavros Sachtouris
        :returns: (list of dicts) created networks details
63 afba96a7 Stavros Sachtouris
        :raises ValueError: if networks is misformated
64 afba96a7 Stavros Sachtouris
        :raises ClientError: if the request failed or didn't return 201
65 afba96a7 Stavros Sachtouris
        """
66 afba96a7 Stavros Sachtouris
        try:
67 afba96a7 Stavros Sachtouris
            msg = 'The networks parameter must be list or tuple'
68 afba96a7 Stavros Sachtouris
            assert (
69 afba96a7 Stavros Sachtouris
                isinstance(networks, list) or isinstance(networks, tuple)), msg
70 afba96a7 Stavros Sachtouris
            for network in networks:
71 afba96a7 Stavros Sachtouris
                msg = 'Network specification %s is not a dict' % network
72 afba96a7 Stavros Sachtouris
                assert isinstance(network, dict), msg
73 ba1ab65d Stavros Sachtouris
                err = set(network).difference(
74 ba1ab65d Stavros Sachtouris
                    ('name', 'admin_state_up', 'shared'))
75 afba96a7 Stavros Sachtouris
                if err:
76 afba96a7 Stavros Sachtouris
                    raise ValueError(
77 afba96a7 Stavros Sachtouris
                        'Invalid key(s): %s in network specification %s' % (
78 afba96a7 Stavros Sachtouris
                            err, network))
79 afba96a7 Stavros Sachtouris
                msg = 'Name is missing in network specification: %s' % network
80 afba96a7 Stavros Sachtouris
                assert network.get('name', None), msg
81 afba96a7 Stavros Sachtouris
                network.setdefault('admin_state_up', False)
82 afba96a7 Stavros Sachtouris
        except AssertionError as ae:
83 afba96a7 Stavros Sachtouris
            raise ValueError('%s' % ae)
84 afba96a7 Stavros Sachtouris
85 afba96a7 Stavros Sachtouris
        req = dict(networks=list(networks))
86 ba1ab65d Stavros Sachtouris
        r = self.networks_post(json_data=req, success=201)
87 afba96a7 Stavros Sachtouris
        return r.json['networks']
88 afba96a7 Stavros Sachtouris
89 afba96a7 Stavros Sachtouris
    def get_network_details(self, network_id):
90 afba96a7 Stavros Sachtouris
        r = self.networks_get(network_id, success=200)
91 afba96a7 Stavros Sachtouris
        return r.json['network']
92 afba96a7 Stavros Sachtouris
93 afba96a7 Stavros Sachtouris
    def update_network(
94 afba96a7 Stavros Sachtouris
            self, network_id, name=None, admin_state_up=None, shared=None):
95 afba96a7 Stavros Sachtouris
        network = dict()
96 afba96a7 Stavros Sachtouris
        if name:
97 afba96a7 Stavros Sachtouris
            network['name'] = name
98 afba96a7 Stavros Sachtouris
        if admin_state_up not in (None, ):
99 afba96a7 Stavros Sachtouris
            network['admin_state_up'] = admin_state_up
100 ba1ab65d Stavros Sachtouris
        if shared not in (None, ):
101 ba1ab65d Stavros Sachtouris
            network['shared'] = shared
102 afba96a7 Stavros Sachtouris
        network = dict(network=network)
103 ba1ab65d Stavros Sachtouris
        r = self.networks_put(network_id, json_data=network, success=200)
104 afba96a7 Stavros Sachtouris
        return r.json['network']
105 afba96a7 Stavros Sachtouris
106 afba96a7 Stavros Sachtouris
    def delete_network(self, network_id):
107 afba96a7 Stavros Sachtouris
        r = self.networks_delete(network_id, success=204)
108 afba96a7 Stavros Sachtouris
        return r.headers
109 ba1ab65d Stavros Sachtouris
110 ba1ab65d Stavros Sachtouris
    def list_subnets(self):
111 ba1ab65d Stavros Sachtouris
        r = self.subnets_get(success=200)
112 ba1ab65d Stavros Sachtouris
        return r.json['subnets']
113 ba1ab65d Stavros Sachtouris
114 ba1ab65d Stavros Sachtouris
    def create_subnet(
115 ba1ab65d Stavros Sachtouris
            self, network_id, cidr,
116 25d2ff8e Stavros Sachtouris
            name=None, allocation_pools=None, gateway_ip=None, subnet_id=None,
117 25d2ff8e Stavros Sachtouris
            ipv6=None, enable_dhcp=None):
118 ba1ab65d Stavros Sachtouris
        """
119 ba1ab65d Stavros Sachtouris
        :param network_id: (str)
120 ba1ab65d Stavros Sachtouris
        :param cidr: (str)
121 ba1ab65d Stavros Sachtouris

122 ba1ab65d Stavros Sachtouris
        :param name: (str) The subnet name
123 ba1ab65d Stavros Sachtouris
        :param allocation_pools: (list of dicts) start/end addresses of
124 ba1ab65d Stavros Sachtouris
            allocation pools: [{'start': ..., 'end': ...}, ...]
125 ba1ab65d Stavros Sachtouris
        :param gateway_ip: (str)
126 ba1ab65d Stavros Sachtouris
        :param subnet_id: (str)
127 ba1ab65d Stavros Sachtouris
        :param ipv6: (bool) ip_version == 6 if true else 4 (default)
128 ba1ab65d Stavros Sachtouris
        :param enable_dhcp: (bool)
129 ba1ab65d Stavros Sachtouris
        """
130 ba1ab65d Stavros Sachtouris
        subnet = dict(
131 ba1ab65d Stavros Sachtouris
            network_id=network_id, cidr=cidr, ip_version=6 if ipv6 else 4)
132 ba1ab65d Stavros Sachtouris
        if name:
133 ba1ab65d Stavros Sachtouris
            subnet['name'] = name
134 ba1ab65d Stavros Sachtouris
        if allocation_pools:
135 ba1ab65d Stavros Sachtouris
            subnet['allocation_pools'] = allocation_pools
136 ba1ab65d Stavros Sachtouris
        if gateway_ip:
137 ba1ab65d Stavros Sachtouris
            subnet['gateway_ip'] = gateway_ip
138 ba1ab65d Stavros Sachtouris
        if subnet_id:
139 ba1ab65d Stavros Sachtouris
            subnet['id'] = subnet_id
140 ba1ab65d Stavros Sachtouris
        if enable_dhcp not in (None, ):
141 ba1ab65d Stavros Sachtouris
            subnet['enable_dhcp'] = bool(enable_dhcp)
142 ba1ab65d Stavros Sachtouris
        r = self.subnets_post(json_data=dict(subnet=subnet), success=201)
143 ba1ab65d Stavros Sachtouris
        return r.json['subnet']
144 ba1ab65d Stavros Sachtouris
145 ba1ab65d Stavros Sachtouris
    def create_subnets(self, subnets):
146 ba1ab65d Stavros Sachtouris
        """Atomic operation for batch subnet creation (all or nothing)
147 ba1ab65d Stavros Sachtouris
        :param subnets: (list of dicts) {key: ...} with all parameters in the
148 ba1ab65d Stavros Sachtouris
            method create_subnet, where method mandatory / optional paramteres
149 ba1ab65d Stavros Sachtouris
            respond to mandatory / optional paramters in subnets items
150 ba1ab65d Stavros Sachtouris
        :returns: (list of dicts) created subnetss details
151 ba1ab65d Stavros Sachtouris
        :raises ValueError: if subnets parameter is incorrectly formated
152 ba1ab65d Stavros Sachtouris
        :raises ClientError: if the request failed or didn't return 201
153 ba1ab65d Stavros Sachtouris
        """
154 ba1ab65d Stavros Sachtouris
        try:
155 ba1ab65d Stavros Sachtouris
            msg = 'The subnets parameter must be list or tuple'
156 ba1ab65d Stavros Sachtouris
            assert (
157 ba1ab65d Stavros Sachtouris
                isinstance(subnets, list) or isinstance(subnets, tuple)), msg
158 ba1ab65d Stavros Sachtouris
            for subnet in subnets:
159 ba1ab65d Stavros Sachtouris
                msg = 'Subnet specification %s is not a dict' % subnet
160 ba1ab65d Stavros Sachtouris
                assert isinstance(subnet, dict), msg
161 ba1ab65d Stavros Sachtouris
                err = set(subnet).difference((
162 ba1ab65d Stavros Sachtouris
                    'network_id', 'cidr', 'name', 'allocation_pools',
163 25d2ff8e Stavros Sachtouris
                    'gateway_ip', 'subnet_id', 'ipv6', 'enable_dhcp'))
164 ba1ab65d Stavros Sachtouris
                if err:
165 ba1ab65d Stavros Sachtouris
                    raise ValueError(
166 ba1ab65d Stavros Sachtouris
                        'Invalid key(s): %s in subnet specification %s' % (
167 ba1ab65d Stavros Sachtouris
                            err, subnet))
168 ba1ab65d Stavros Sachtouris
                msg = 'network_id is missing in subnet spec: %s' % subnet
169 ba1ab65d Stavros Sachtouris
                assert subnet.get('network_id', None), msg
170 ba1ab65d Stavros Sachtouris
                msg = 'cidr is missing in subnet spec: %s' % subnet
171 ba1ab65d Stavros Sachtouris
                assert subnet.get('cidr', None), msg
172 ba1ab65d Stavros Sachtouris
                subnet['ip_version'] = 6 if subnet.pop('ipv6', None) else 4
173 25d2ff8e Stavros Sachtouris
                if 'subnet_id' in subnet:
174 25d2ff8e Stavros Sachtouris
                    subnet['id'] = subnet.pop('subnet_id')
175 ba1ab65d Stavros Sachtouris
        except AssertionError as ae:
176 ba1ab65d Stavros Sachtouris
            raise ValueError('%s' % ae)
177 ba1ab65d Stavros Sachtouris
178 25d2ff8e Stavros Sachtouris
        r = self.subnets_post(
179 25d2ff8e Stavros Sachtouris
            json_data=dict(subnets=list(subnets)), success=201)
180 ba1ab65d Stavros Sachtouris
        return r.json['subnets']
181 25d2ff8e Stavros Sachtouris
182 25d2ff8e Stavros Sachtouris
    def get_subnet_details(self, subnet_id):
183 25d2ff8e Stavros Sachtouris
        r = self.subnets_get(subnet_id, success=201)
184 25d2ff8e Stavros Sachtouris
        return r.json
185 25d2ff8e Stavros Sachtouris
186 25d2ff8e Stavros Sachtouris
    def update_subnet(
187 25d2ff8e Stavros Sachtouris
            self, network_id, cidr,
188 25d2ff8e Stavros Sachtouris
            name=None, allocation_pools=None, gateway_ip=None, subnet_id=None,
189 25d2ff8e Stavros Sachtouris
            ipv6=None, enable_dhcp=None):
190 25d2ff8e Stavros Sachtouris
        """
191 25d2ff8e Stavros Sachtouris
        :param network_id: (str) used as filter
192 25d2ff8e Stavros Sachtouris
        :param cidr: (str) used as filter
193 25d2ff8e Stavros Sachtouris

194 25d2ff8e Stavros Sachtouris
        :param name: (str) The subnet name
195 25d2ff8e Stavros Sachtouris
        :param allocation_pools: (list of dicts) start/end addresses of
196 25d2ff8e Stavros Sachtouris
            allocation pools: [{'start': ..., 'end': ...}, ...]
197 25d2ff8e Stavros Sachtouris
        :param gateway_ip: (str)
198 25d2ff8e Stavros Sachtouris
        :param subnet_id: (str)
199 25d2ff8e Stavros Sachtouris
        :param ipv6: (bool) ip_version == 6 if true, 4 if false, used as filter
200 25d2ff8e Stavros Sachtouris
        :param enable_dhcp: (bool)
201 25d2ff8e Stavros Sachtouris
        """
202 25d2ff8e Stavros Sachtouris
        subnet = dict(network_id=network_id, cidr=cidr)
203 25d2ff8e Stavros Sachtouris
        if name not in (None, ):
204 25d2ff8e Stavros Sachtouris
            subnet['name'] = name
205 25d2ff8e Stavros Sachtouris
        if allocation_pools not in (None, ):
206 25d2ff8e Stavros Sachtouris
            subnet['allocation_pools'] = allocation_pools
207 25d2ff8e Stavros Sachtouris
        if gateway_ip not in (None, ):
208 25d2ff8e Stavros Sachtouris
            subnet['gateway_ip'] = gateway_ip
209 25d2ff8e Stavros Sachtouris
        if subnet_id not in (None, ):
210 25d2ff8e Stavros Sachtouris
            subnet['id'] = subnet_id
211 25d2ff8e Stavros Sachtouris
        if ipv6 not in (None, ):
212 25d2ff8e Stavros Sachtouris
            subnet['ip_version'] = 6 if ipv6 else 4
213 25d2ff8e Stavros Sachtouris
        if enable_dhcp not in (None, ):
214 25d2ff8e Stavros Sachtouris
            subnet['enable_dhcp'] = enable_dhcp
215 25d2ff8e Stavros Sachtouris
        r = self.subnets_put(json_data=dict(subnet=subnet), success=201)
216 25d2ff8e Stavros Sachtouris
        return r.json['subnet']
217 25d2ff8e Stavros Sachtouris
218 25d2ff8e Stavros Sachtouris
    def delete_subnet(self, subnet_id):
219 25d2ff8e Stavros Sachtouris
        r = self.subnets_delete(subnet_id, success=204)
220 25d2ff8e Stavros Sachtouris
        return r.headers
221 bac9c8ac Stavros Sachtouris
222 bac9c8ac Stavros Sachtouris
    def list_ports(self):
223 bac9c8ac Stavros Sachtouris
        r = self.ports_get(success=200)
224 bac9c8ac Stavros Sachtouris
        return r.json['ports']
225 bac9c8ac Stavros Sachtouris
226 bac9c8ac Stavros Sachtouris
    def create_port(
227 bac9c8ac Stavros Sachtouris
            self, network_id,
228 bac9c8ac Stavros Sachtouris
            name=None, status=None, admin_state_up=None, mac_address=None,
229 bac9c8ac Stavros Sachtouris
            fixed_ips=None, security_groups=None):
230 bac9c8ac Stavros Sachtouris
        """
231 bac9c8ac Stavros Sachtouris
        :param network_id: (str)
232 bac9c8ac Stavros Sachtouris

233 bac9c8ac Stavros Sachtouris
        :param name: (str)
234 bac9c8ac Stavros Sachtouris
        :param status: (str)
235 bac9c8ac Stavros Sachtouris
        :param admin_state_up: (bool) Router administrative status (UP / DOWN)
236 bac9c8ac Stavros Sachtouris
        :param mac_address: (str)
237 bac9c8ac Stavros Sachtouris
        :param fixed_ips: (str)
238 bac9c8ac Stavros Sachtouris
        :param security_groups: (list)
239 bac9c8ac Stavros Sachtouris
        """
240 bac9c8ac Stavros Sachtouris
        port = dict(network_id=network_id)
241 bac9c8ac Stavros Sachtouris
        if name:
242 bac9c8ac Stavros Sachtouris
            port['name'] = name
243 bac9c8ac Stavros Sachtouris
        if status:
244 bac9c8ac Stavros Sachtouris
            port['status'] = status
245 bac9c8ac Stavros Sachtouris
        if admin_state_up not in (None, ):
246 bac9c8ac Stavros Sachtouris
            port['admin_state_up'] = bool(admin_state_up)
247 bac9c8ac Stavros Sachtouris
        if mac_address:
248 bac9c8ac Stavros Sachtouris
            port['mac_address'] = mac_address
249 bac9c8ac Stavros Sachtouris
        if fixed_ips:
250 bac9c8ac Stavros Sachtouris
            port['fixed_ips'] = fixed_ips
251 bac9c8ac Stavros Sachtouris
        if security_groups:
252 bac9c8ac Stavros Sachtouris
            port['security_groups'] = security_groups
253 bac9c8ac Stavros Sachtouris
        r = self.ports_post(json_data=dict(port=port), success=201)
254 bac9c8ac Stavros Sachtouris
        return r.json['port']
255 bac9c8ac Stavros Sachtouris
256 bac9c8ac Stavros Sachtouris
    def create_ports(self, ports):
257 bac9c8ac Stavros Sachtouris
        """Atomic operation for batch port creation (all or nothing)
258 bac9c8ac Stavros Sachtouris
        :param ports: (list of dicts) {key: ...} with all parameters in the
259 bac9c8ac Stavros Sachtouris
            method create_port, where method mandatory / optional paramteres
260 bac9c8ac Stavros Sachtouris
            respond to mandatory / optional paramters in ports items
261 bac9c8ac Stavros Sachtouris
        :returns: (list of dicts) created portss details
262 bac9c8ac Stavros Sachtouris
        :raises ValueError: if ports parameter is incorrectly formated
263 bac9c8ac Stavros Sachtouris
        :raises ClientError: if the request failed or didn't return 201
264 bac9c8ac Stavros Sachtouris
        """
265 bac9c8ac Stavros Sachtouris
        try:
266 bac9c8ac Stavros Sachtouris
            msg = 'The ports parameter must be list or tuple'
267 bac9c8ac Stavros Sachtouris
            assert (
268 bac9c8ac Stavros Sachtouris
                isinstance(ports, list) or isinstance(ports, tuple)), msg
269 bac9c8ac Stavros Sachtouris
            for port in ports:
270 bac9c8ac Stavros Sachtouris
                msg = 'Subnet specification %s is not a dict' % port
271 bac9c8ac Stavros Sachtouris
                assert isinstance(port, dict), msg
272 bac9c8ac Stavros Sachtouris
                err = set(port).difference((
273 bac9c8ac Stavros Sachtouris
                    'network_id', 'status', 'name', 'admin_state_up',
274 bac9c8ac Stavros Sachtouris
                    'mac_address', 'fixed_ips', 'security_groups'))
275 bac9c8ac Stavros Sachtouris
                if err:
276 bac9c8ac Stavros Sachtouris
                    raise ValueError(
277 bac9c8ac Stavros Sachtouris
                        'Invalid key(s): %s in port specification %s' % (
278 bac9c8ac Stavros Sachtouris
                            err, port))
279 bac9c8ac Stavros Sachtouris
                msg = 'network_id is missing in port spec: %s' % port
280 bac9c8ac Stavros Sachtouris
                assert port.get('network_id', None), msg
281 bac9c8ac Stavros Sachtouris
        except AssertionError as ae:
282 bac9c8ac Stavros Sachtouris
            raise ValueError('%s' % ae)
283 bac9c8ac Stavros Sachtouris
        r = self.ports_post(json_data=dict(ports=list(ports)), success=201)
284 bac9c8ac Stavros Sachtouris
        return r.json['ports']
285 bac9c8ac Stavros Sachtouris
286 bac9c8ac Stavros Sachtouris
    def get_port_details(self, port_id):
287 bac9c8ac Stavros Sachtouris
        r = self.ports_get(port_id, success=201)
288 bac9c8ac Stavros Sachtouris
        return r.json['ports']
289 bac9c8ac Stavros Sachtouris
290 bac9c8ac Stavros Sachtouris
    def delete_port(self, port_id):
291 bac9c8ac Stavros Sachtouris
        r = self.ports_delete(port_id, success=204)
292 bac9c8ac Stavros Sachtouris
        return r.headers