Revision 5cf968ab

b/snf-cyclades-app/synnefo/neutron/models.py
169 169
    )
170 170

  
171 171
    name = models.CharField('nic name', max_length=128)
172
    machine = models.ForeignKey(VirtualMachine, related_name='neutron_nics')
172
    machine = models.ForeignKey(VirtualMachine, null=True,
173
                                related_name='neutron_nics')
173 174
    network = models.ForeignKey(Network, related_name='neutron_nics')
174
    subnet = models.ForeignKey(Subnet, related_names='neutron_nics')
175
    subnet = models.ForeignKey(Subnet, related_name='neutron_nics', null=True)
175 176
    created = models.DateTimeField(auto_now_add=True)
176 177
    updated = models.DateTimeField(auto_now=True)
177 178
    index = models.IntegerField(null=True)
......
197 198
            return network.floating_ips.filter(machine=self.machine,
198 199
                                               ipv4=self.ipv4,
199 200
                                               deleted=False).exists()
200

  
201

  
202

  
b/snf-cyclades-app/synnefo/neutron/network_views.py
237 237
        d['status'] = network.state
238 238
        d['public'] = network.public
239 239
        d['admin_state_up'] = "true"
240
        subnet_cidr = [s.subnet_id for s in network.subnet_set.all()]
240
        subnet_cidr = [s.id for s in network.subnet_set.all()]
241 241
        d['subnets'] = subnet_cidr
242 242
    return d
243 243

  
b/snf-cyclades-app/synnefo/neutron/router_views.py
13 13

  
14 14
from synnefo.db.models import VirtualMachine
15 15
import models
16
import subnet_views
16 17
from logging import getLogger
17 18

  
18 19
import network_views as nv
......
26 27
        #return HttpResponse("list routers")
27 28
        return list_routers(request)
28 29
    elif request.method == 'POST':
29
        #return create_router(request)
30
        return HttpResponse("create router")
30
        return create_router(request)
31
        #return HttpResponse("create router")
31 32
    else:
32 33
        return api.api_method_not_allowed(request)
33 34

  
......
41 42
        return delete_router(request, offset)
42 43
    elif request.method == 'PUT':
43 44
        #return HttpResponse("put router")
44
        return update_router(request,offset)
45
        return update_router(request, offset)
45 46
    else:
46 47
        return api.api_method_not_allowed(request)
47 48

  
......
50 51
    if request.method == 'PUT':
51 52
        if offset2 == "add_router_interface":
52 53
            #return HttpResponse("add interface")
53
            return add_interface(request, offset2)
54
            return add_interface(request, offset1)
54 55
        elif offset2 == "remove_router_interface":
55 56
            #return HttpResponse("remove interface")
56
            return remove_interface(request, offset22)
57
            return remove_interface(request, offset1)
57 58
    else:
58 59
        return api.api_method_not_allowed(request)
59 60

  
......
62 63
def list_routers(request):
63 64
    log.debug('list_routers')
64 65

  
65
    user_routers = VirtualMachine.objects.filter(userid=request.user_uniq, router=True)
66
    user_routers = VirtualMachine.objects.filter(userid=request.user_uniq,
67
                                                 router=True)
66 68

  
67 69
    user_routers = utils.filter_modified_since(request, objects=user_routers)
68 70

  
......
77 79

  
78 80
    return HttpResponse(data, status=200)
79 81

  
80
'''
82

  
81 83
@api.api_method(http_method='POST', user_required=True, logger=log)
82 84
@transaction.commit_manually
83 85
def create_router(request):
......
89 91
        name = server['name']
90 92
    except (KeyError, AssertionError):
91 93
        raise api.faults.BadRequest("Malformed request")
92
    metadata = server.get('metadata', {})
93
    assert isinstance(metadata, dict)
94
    image_id = server['imageRef']
95
    flavor_id = server['flavorRef']
96
    personality = server.get('personality', [])
97
    assert isinstance(personality, list)
98
    private_networks = server.get("networks", [])
99
    assert isinstance(private_networks, list)
100
    floating_ips = server.get("floating_ips", [])
101
    assert isinstance(floating_ips, list)
102
    # Verify that personalities are well-formed
103
    util.verify_personality(personality)
104
    # Get image information
105
    image = util.get_image_dict(image_id, user_id)
106
    # Get flavor (ensure it is active)
107
    flavor = util.get_flavor(flavor_id, include_deleted=False)
108
    # Generate password
109
    password = util.random_password()
94

  
95
    try:
96
        netid = server[external_gateway_info]["network_id"]
97
        net = nv.get_network_fromdb(netid, request.user_uniq)
98
    except (KeyError, AssertionError):
99
        pass
100

  
101
    '''
110 102
    vm = servers.create(user_id,
111 103
                        name,
112 104
                        #password,
......
117 109
                        #private_networks=private_networks,
118 110
                        #floating_ips=floating_ips
119 111
                        )
112
    '''
113

  
114
    try:
115
        net
116
        mock_connect(vm, net)
117
    except NameError:
118
        pass
119
        #mock_connect(vm, random_public_net)
120 120

  
121 121
    server = router_to_dict(vm, detail=True)
122
    server['status'] = 'BUILD'
123
    server['adminPass'] = password
124 122

  
125 123
    response = render_router(request, server, status=202)
126 124

  
127 125
    return response
128 126

  
129 127

  
130
'''
131 128
@api.api_method(http_method='GET', user_required=True, logger=log)
132 129
def get_router(request, router_id):
133 130
    log.debug('get_router_details %s', router_id)
......
144 141
    router = util.get_vm(router_id, request.user_uniq)
145 142

  
146 143
    if router.neutron_networks.filter(public=False):
147
        return HttpResponse("There are internal interfaces on the router", status=409)
144
        return HttpResponse("There are internal interfaces on the router",
145
                            status=409)
148 146

  
149 147
    #servers.destroy(router)
150 148

  
......
196 194
@api.api_method(http_method='PUT', user_required=True, logger=log)
197 195
def add_interface(request, router_id):
198 196
    log.debug('add interface to router %s', router_id)
197
    info = utils.get_request_dict(request)
199 198
    router = util.get_vm(router_id, request.user_uniq)
200 199

  
201
    router_info = utils.get_request_dict(request)
202

  
203 200
    subnet = False
204 201
    try:
205
        subnet_id = router_info["subnet_id"]
202
        subnet_id = info["subnet_id"]
206 203
        subnet = True
207 204
        subnet_obj = subnet_views.get_subnet_fromdb(subnet_id,
208
                                        request.user_unique)
205
                                                    request.user_uniq)
209 206
    except KeyError:
210 207
        pass
211 208

  
212 209
    try:
213
        port_id = router_info['port_id']
210
        port_id = info['port_id']
214 211
        if subnet:
215 212
            raise api.faults.BadRequest("Both subnet and port provided")
216 213
        try:
217
            nic_obj = models.NetworkInteface.objects.get(id=port_id)
218
        except (ValueError, models.NetworkInteraface.DoesNotExist):
214
            nic_obj = models.NetworkInterface.objects.get(id=port_id)
215
        except (ValueError, models.NetworkInterface.DoesNotExist):
219 216
            raise api.faults.ItemNotFound('Port not found')
220 217
        if not nic_obj.ipv4:
221 218
            raise api.faults.BadRequest("No ip-address")
......
227 224

  
228 225
    if subnet:
229 226
        #create nic with the subnet and add to the vm
230
        nic = models.NetworkInteface(machine=router,
231
                                    subnet=subnet_obj,
232
                                    network=subnet_obj.network
233
                                    ipv4=subnet.gateway
234
                                    )
235
        nic.save()
236
        port_id = nic.id
227
        nic_obj = models.NetworkInterface(machine=router,
228
                                          subnet=subnet_obj,
229
                                          network=subnet_obj.network,
230
                                          ipv4=subnet_obj.gateway)
231
        nic_obj.save()
232

  
237 233
    else:
238 234
        #connect the nic
239 235
        nic_obj.machine = router
240 236
        nic_obj.save()
241
        subnet_id = nic.subnet.id
237
    #FIX ME : do backend connection
242 238

  
243
    res = {"port_id":port_db.id,
244
            "subnet_id":subnet_db.id
245
          }
239
    res = {"port_id": nic_obj.id,
240
           "subnet_id": nic_obj.subnet.id}
246 241

  
247 242
    data = json.dumps(res)
248 243
    return HttpResponse(data, status=200)
249 244

  
245

  
250 246
@api.api_method(http_method='PUT', user_required=True, logger=log)
251 247
def remove_interface(request, router_id):
252 248

  
253 249
    log.debug('remove interface from router %s', router_id)
254
    router = util.get_vm(router_id, request.user_uniq)
255 250

  
256 251
    info = utils.get_request_dict(request)
257 252

  
253
    router = util.get_vm(router_id, request.user_uniq)
258 254
    subnet = False
259 255
    try:
260 256
        subnet_id = info["subnet_id"]
261 257
        subnet = True
262 258
        subnet_db = subnet_views.get_subnet_fromdb(subnet_id,
263
                                request.user_unique)
259
                                                   request.user_uniq)
264 260
    except KeyError:
265 261
        pass
266 262

  
......
269 265
        port_id = info['port_id']
270 266
        port = True
271 267
        try:
272
            nic_obj = models.NetworkInteface.objects.get(id=port_id)
273
        except (ValueError, models.NetworkInteraface.DoesNotExist):
268
            port_db = models.NetworkInterface.objects.get(id=port_id)
269
        except (ValueError, models.NetworkInterface.DoesNotExist):
274 270
            raise api.faults.ItemNotFound('Port not found')
275 271
    except KeyError:
276 272
        pass
277 273

  
278
    if port and subnet:
274
    if (port and subnet):
279 275
        #validate port-subnet combination else return 409
280 276
        #subnet must be the first of the port
281
        if not port_db is subnet_db:
277
        if not (port_db.subnet.id == subnet_db.id):
282 278
            return HttpResponse(status=409)
283 279

  
284 280
    if subnet:
285 281
        #get the port
286
        if not port_db:
287
            port_db = subnet_db.neutron_nics.get(machine=router)
282
        try:
283
            port_db
284
        except NameError:
285
            try:
286
                port_db = subnet_db.neutron_nics.get(machine=router)
287
            except (ValueError, models.NetworkInterface.DoesNotExist):
288
                raise api.faults.ItemNotFound('Port not found')
288 289
    elif port:
289 290
        #get the subnet
290
        if not subnet_db:
291
        try:
292
            subnet_db
293
        except NameError:
291 294
            subnet_db = port_db.subnet
292 295
    else:
293 296
        raise api.faults.BadRequest("Malformed request")
294 297

  
295
    res = {"id":str(router.id),
296
            "tenant_id":request.user_uniq,
297
            "port_id":port_db.id,
298
            "subnet_id":subnet_db.id
299
          }
298
    res = {"id": str(router.id),
299
           "tenant_id": request.user_uniq,
300
           "port_id": port_db.id,
301
           "subnet_id": subnet_db.id}
300 302

  
301 303
    port_db.delete()  # need to add backend stuff
302 304
    data = json.dumps(res)
......
334 336
    nic = models.NetworkInterface.objects.get(network=net, machine=router)
335 337
    nic.delete()
336 338

  
339

  
337 340
def mock_connect(router, net):
338 341
    nic = models.NetworkInterface(network=net, machine=router)
339 342
    nic.save()
b/snf-cyclades-app/synnefo/neutron/subnet_views.py
162 162
    raise api.faults.BadRequest("Deletion of a subnet is not supported")
163 163

  
164 164

  
165

  
166 165
@api.api_method(http_method='PUT', user_required=True, logger=log)
167 166
def update_subnet(request, sub_id):
168 167
    '''Update info of a subnet'''
......
189 188
        raise api.faults.BadRequest("Only one subnet of IPv4/IPv6 per "
190 189
                                    "network is allowed")
191 190

  
191

  
192 192
def get_subnet_fromdb(subnet_id, user_id, for_update=False):
193 193
    """
194 194
    Return a Subnet instance or raise ItemNotFound.
......
199 199
        objects = Subnet.objects
200 200
        if for_update:
201 201
            objects = objects.select_for_update()
202
        return objects.get(userid=user_id, id=subnet_id)
202
        return objects.get(id=subnet_id, network__userid=user_id)
203 203
    except (ValueError, Subnet.DoesNotExist):
204
        raise api.faults.ItemNotFound('Network not found.')
205

  
204
        raise api.faults.ItemNotFound('Subnet not found.')
b/snf-cyclades-app/synnefo/neutron/tests/api.py
12 12
SUBNETS_URL = join_urls(NEUTRON_URL, "subnets/")
13 13
ROUTERS_URL = join_urls(NEUTRON_URL, "routers/")
14 14

  
15

  
15 16
class NetworkTest(BaseAPITest):
16 17

  
17 18
    def test_list_networks(self):
......
133 134
        router = dbmf.VirtualMachineFactory.create(router=True)
134 135
        url = join_urls(ROUTERS_URL, str(router.id))
135 136
        response = self.delete(url, user=router.userid)
136
        print response.content
137 137
        self.assertEqual(response.status_code, 204)
138 138

  
139 139
    def test_delete_router_with_private_net(self):
......
142 142
        nic = mf.NetworkInterfaceFactory.create(network=net, machine=router)
143 143
        url = join_urls(ROUTERS_URL, str(router.id))
144 144
        response = self.delete(url, user=router.userid)
145
        print response.content
146 145
        self.assertEqual(response.status_code, 409)
147 146

  
148 147
    def test_update_router(self):
......
150 149
        net1 = mf.NetworkFactory.create(public=True)
151 150
        net2 = mf.NetworkFactory.create(public=True)
152 151
        nic = mf.NetworkInterfaceFactory.create(network=net1, machine=router)
153
        request = {"router":{
154
                        "name": "new_name",
155
                        "external_gateway_info":{
156
                           "network_id": net2.id
157
                           }
158
                    }
152
        request = {
153
            "router": {
154
                "name": "new_name",
155
                "external_gateway_info": {"network_id": net2.id}
156
                }
159 157
            }
160 158
        url = join_urls(ROUTERS_URL, str(router.id))
161
        response = self.put(url, params=json.dumps(request), user=router.userid)
159
        response = self.put(url, params=json.dumps(request),
160
                            user=router.userid)
162 161
        info = json.loads(response.content)
163
        self.assertEqual(info['router']['external_gateway_info']['network_id'], net2.id)
162
        self.assertEqual(info['router']['external_gateway_info']['network_id'],
163
                         net2.id)
164 164
        self.assertEqual(info['router']['name'], "new_name")
165 165

  
166
    def test_remove_interface(self):
167
        url = join_urls(join_urls(ROUTERS_URL,"123"), "remove_router_interface")
166
    def test_remove_interface_no_body(self):
167
        url = join_urls(join_urls(ROUTERS_URL, "123"),
168
                        "remove_router_interface")
169

  
168 170
        response = self.put(url, params="")
169
        print response.content
171
        self.assertEqual(response.status_code, 400)
172

  
173
    def test_remove_interface_unfound_port(self):
174
        router = dbmf.VirtualMachineFactory.create(router=True)
175
        request = {"port_id": "123"}
176
        url = join_urls(join_urls(ROUTERS_URL, str(router.id)),
177
                        "remove_router_interface")
178
        response = self.put(url, params=json.dumps(request),
179
                            user=router.userid)
180
        self.assertEqual(response.status_code, 404)
181

  
182
    def test_remove_interface_unfound_subnet(self):
183
        router = dbmf.VirtualMachineFactory.create(router=True)
184
        request = {"subnet_id": "123"}
185
        url = join_urls(join_urls(ROUTERS_URL, str(router.id)),
186
                        "remove_router_interface")
187
        response = self.put(url, params=json.dumps(request),
188
                            user=router.userid)
189
        self.assertEqual(response.status_code, 404)
190

  
191
    def test_remove_interface_no_info(self):
192
        router = dbmf.VirtualMachineFactory.create(router=True)
193
        request = {"wrong": "123"}
194
        url = join_urls(join_urls(ROUTERS_URL, str(router.id)),
195
                        "remove_router_interface")
196
        response = self.put(url, params=json.dumps(request),
197
                            user=router.userid)
198
        self.assertEqual(response.status_code, 400)
199

  
200
    def test_remove_interface_both_info_wrong(self):
201
        router = dbmf.VirtualMachineFactory.create(router=True)
202
        net1 = mf.NetworkFactory.create(public=True, userid=router.userid)
203
        subnet = mf.SubnetFactory.create(network=net1)
204
        subnet2 = mf.SubnetFactory.create(network=net1)
205
        nic = mf.NetworkInterfaceFactory.create(network=net1, machine=router,
206
                                                subnet=subnet2)
207
        request = {"subnet_id": subnet.id, "port_id": nic.id}
208
        url = join_urls(join_urls(ROUTERS_URL, str(router.id)),
209
                        "remove_router_interface")
210
        response = self.put(url, params=json.dumps(request),
211
                            user=router.userid)
212
        self.assertEqual(response.status_code, 409)
213

  
214
    def test_remove_interface_subnet(self):
215
        router = dbmf.VirtualMachineFactory.create(router=True)
216
        net1 = mf.NetworkFactory.create(public=True, userid=router.userid)
217
        subnet = mf.SubnetFactory.create(network=net1)
218
        nic = mf.NetworkInterfaceFactory.create(network=net1, machine=router,
219
                                                subnet=subnet)
220
        request = {"subnet_id": subnet.id}
221
        url = join_urls(join_urls(ROUTERS_URL, str(router.id)),
222
                        "remove_router_interface")
223
        response = self.put(url, params=json.dumps(request),
224
                            user=router.userid)
225
        self.assertEqual(response.status_code, 200)
226

  
227
    def test_remove_interface_port(self):
228
        router = dbmf.VirtualMachineFactory.create(router=True)
229
        net1 = mf.NetworkFactory.create(public=True, userid=router.userid)
230
        subnet = mf.SubnetFactory.create(network=net1)
231
        nic = mf.NetworkInterfaceFactory.create(network=net1, machine=router,
232
                                                subnet=subnet)
233
        request = {"port_id": nic.id}
234
        url = join_urls(join_urls(ROUTERS_URL, str(router.id)),
235
                        "remove_router_interface")
236
        response = self.put(url, params=json.dumps(request),
237
                            user=router.userid)
238
        self.assertEqual(response.status_code, 200)
239

  
240
    def test_remove_interface_both_info(self):
241
        router = dbmf.VirtualMachineFactory.create(router=True)
242
        net1 = mf.NetworkFactory.create(public=True, userid=router.userid)
243
        subnet = mf.SubnetFactory.create(network=net1)
244
        nic = mf.NetworkInterfaceFactory.create(network=net1, machine=router,
245
                                                subnet=subnet)
246
        request = {"subnet_id": subnet.id, "port_id": nic.id}
247
        url = join_urls(join_urls(ROUTERS_URL, str(router.id)),
248
                        "remove_router_interface")
249
        response = self.put(url, params=json.dumps(request),
250
                            user=router.userid)
251
        self.assertEqual(response.status_code, 200)
252

  
253
    def test_add_interface_no_info(self):
254
        url = join_urls(join_urls(ROUTERS_URL, "123"), "add_router_interface")
255
        response = self.put(url, params="")
256
        self.assertEqual(response.status_code, 400)
257

  
258
    def test_add_interface_wrong_info(self):
259
        router = dbmf.VirtualMachineFactory.create(router=True)
260
        url = join_urls(join_urls(ROUTERS_URL, str(router.id)),
261
                        "add_router_interface")
262
        request = {}
263
        response = self.put(url, params=json.dumps(request),
264
                            user=router.userid)
265
        self.assertEqual(response.status_code, 400)
266

  
267
    def test_add_interface_unfound_port(self):
268
        router = dbmf.VirtualMachineFactory.create(router=True)
269
        url = join_urls(join_urls(ROUTERS_URL, str(router.id)),
270
                        "add_router_interface")
271
        request = {"port_id": "123"}
272
        response = self.put(url, params=json.dumps(request),
273
                            user=router.userid)
274
        self.assertEqual(response.status_code, 404)
275

  
276
    def test_add_interface_unfound_subnet(self):
277
        router = dbmf.VirtualMachineFactory.create(router=True)
278
        url = join_urls(join_urls(ROUTERS_URL, str(router.id)),
279
                        "add_router_interface")
280
        request = {"subnet_id": "123"}
281
        response = self.put(url, params=json.dumps(request),
282
                            user=router.userid)
283
        self.assertEqual(response.status_code, 404)
284

  
285
    def test_add_interface_both(self):
286
        router = dbmf.VirtualMachineFactory.create(router=True)
287
        net1 = mf.NetworkFactory.create(public=True, userid=router.userid)
288
        subnet = mf.SubnetFactory.create(network=net1)
289
        url = join_urls(join_urls(ROUTERS_URL, str(router.id)),
290
                        "add_router_interface")
291
        request = {"subnet_id": subnet.id, "port_id": "123"}
292
        response = self.put(url, params=json.dumps(request),
293
                            user=router.userid)
294
        self.assertEqual(response.status_code, 400)
295

  
296
    def test_add_interface_subnet(self):
297
        router = dbmf.VirtualMachineFactory.create(router=True)
298
        net1 = mf.NetworkFactory.create(public=True, userid=router.userid)
299
        subnet = mf.SubnetFactory.create(network=net1)
300
        url = join_urls(join_urls(ROUTERS_URL, str(router.id)),
301
                        "add_router_interface")
302
        request = {"subnet_id": subnet.id}
303
        response = self.put(url, params=json.dumps(request),
304
                            user=router.userid)
305
        self.assertEqual(response.status_code, 200)
306

  
307
    def test_add_interface_port_no_ip(self):
308
        router = dbmf.VirtualMachineFactory.create(router=True)
309
        net1 = mf.NetworkFactory.create(public=True, userid=router.userid)
310
        subnet = mf.SubnetFactory.create(network=net1)
311
        nic = mf.NetworkInterfaceFactory.create(network=net1, machine=router,
312
                                                subnet=subnet)
313
        url = join_urls(join_urls(ROUTERS_URL, str(router.id)),
314
                        "add_router_interface")
315
        request = {"port_id": nic.id}
316
        response = self.put(url, params=json.dumps(request),
317
                            user=router.userid)
318
        self.assertEqual(response.status_code, 400)
319

  
320
    def test_add_interface_port_connected(self):
321
        router = dbmf.VirtualMachineFactory.create(router=True)
322
        vm = dbmf.VirtualMachineFactory.create()
323
        net1 = mf.NetworkFactory.create(public=True, userid=router.userid)
324
        subnet = mf.SubnetFactory.create(network=net1)
325
        nic = mf.NetworkInterfaceFactory.create(network=net1, machine=vm,
326
                                                subnet=subnet,
327
                                                ipv4="192.168.0.1")
328
        url = join_urls(join_urls(ROUTERS_URL, str(router.id)),
329
                        "add_router_interface")
330
        request = {"port_id": nic.id}
331
        response = self.put(url, params=json.dumps(request),
332
                            user=router.userid)
333
        self.assertEqual(response.status_code, 409)
334

  
335
    def test_add_interface_port(self):
336
        router = dbmf.VirtualMachineFactory.create(router=True)
337
        net1 = mf.NetworkFactory.create(public=True, userid=router.userid)
338
        subnet = mf.SubnetFactory.create(network=net1)
339
        nic = mf.NetworkInterfaceFactory.create(network=net1,
340
                                                machine=None,
341
                                                subnet=subnet,
342
                                                ipv4="192.168.0.1")
343
        url = join_urls(join_urls(ROUTERS_URL, str(router.id)),
344
                        "add_router_interface")
345
        request = {"port_id": nic.id}
346
        response = self.put(url, params=json.dumps(request),
347
                            user=router.userid)
348
        self.assertEqual(response.status_code, 200)
170 349

  
171
    def test_add_interface(self):
172
        url = join_urls(join_urls(ROUTERS_URL,"123"), "add_router_interface")
173
        request =  {"port_id": "a2f1f29d-571b-4533-907f-5803ab96ead1","subnet_id": "a2f1f29d-571b-4533-907f-5803ab96ead1"}
174
        print json.dumps(request)
175
        response = self.put(url, params=json.dumps(request))
176
        print response.content
177 350

  
178 351
class SubnetTest(BaseAPITest):
179 352
    def test_list_subnets(self):
......
188 361
        test_net = mf.NetworkFactory()
189 362
        test_subnet_ipv4 = mf.SubnetFactory(network=test_net)
190 363
        test_subnet_ipv6 = mf.SubnetFactory(network=test_net, ipversion=6,
191
                                            cidr='2620:0:2d0:200::7/32')
364
                                            cidr='2620: 0:2d0:200::7/32')
192 365
        response = self.get(SUBNETS_URL, user=test_net.userid)
193 366
        self.assertSuccess(response)
194 367

  
b/snf-cyclades-app/synnefo/neutron/urls.py
48 48
    (r'^ports/(\w+)(?:/|.json|.xml)?$', 'port_views.port_demux'),
49 49
    (r'^routers(?:/|.json|.xml)?$', 'router_views.demux'),
50 50
    (r'^routers/(\w+)(?:/|.json|.xml)?$', 'router_views.router_demux'),
51
    (r'^routers/(\w+)/(remove_router_interface|add_router_interface)$', 'router_views.rinterface_demux'))
51
    (r'^routers/(\w+)/(remove_router_interface|add_router_interface)$',
52
        'router_views.rinterface_demux'))
52 53

  
53 54
urlpatterns = patterns(
54 55
    '',

Also available in: Unified diff