UniqueConstraint for Port address doesn't work for updates with sqlite

Bug #1252343 reported by Lucas Alvares Gomes
6
This bug affects 1 person
Affects Status Importance Assigned to Milestone
Ironic
Fix Released
Medium
Yuriy Zveryanskyy

Bug Description

The address column on Port is a UniqueConstraint:

ironic/db/sqlalchemy/models.py:135: schema.UniqueConstraint('address', name='iface_address_ux'),

So, I created the following unittest on test_ports.py

    def test_replace_address_already_exist(self):
        pdict1 = api_get_test_port(address='AA:AA:AA:AA:AA:AA',
                                  uuid=uuidutils.generate_uuid())
        self.post_json('/ports', pdict1)

        pdict2 = api_get_test_port(address='BB:BB:BB:BB:BB:BB',
                                  uuid=uuidutils.generate_uuid())
        self.post_json('/ports', pdict2)

        response = self.patch_json('/ports/%s' % pdict1['uuid'],
                                   [{'path': '/address',
                                     'value': pdict2['address'],
                                     'op': 'replace'}],
                                     expect_errors=True)
        self.assertEqual(response.content_type, 'application/json')
        self.assertEqual(response.status_code, 400)
        self.assertTrue(response.json['error_message'])

It creates two Ports with different addresses and then it updates the first port with the same address of the second one, it suppose to fail with an IntegrityError, but it doesn't.

I changed the configuration to not create the database in memory and took a look at the 'ports' table and the address is inddeed wrong there.

(venv)[lucasagomes@lucasagomes ironic]$ sqlite3 /tmp/uhul.db
SQLite version 3.7.13 2012-06-11 02:05:22
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> select * from ports;
1|52:54:00:cf:2d:31|123|"{}"|2013-11-18 16:32:36.834728||1be26c0b-03f2-4d2e-ae87-c02d7f33c781
2|BB:BB:BB:BB:BB:BB|123|"{}"|2013-11-18 16:32:36.841126|2013-11-18 16:32:36.856734|5fd84198-5166-4e97-9981-cd52a6614641
3|BB:BB:BB:BB:BB:BB|123|"{}"|2013-11-18 16:32:36.847129||d8719b7e-b1ed-49c3-aefe-d37252d98bb2
sqlite> .quit

####################

I tested against my devstack deployment running with MySQL and it fails there, so it only affects the tests.

stack@stack-virtual-machine:~/devstack$ curl -X PATCH -H 'Content-Type: application/json' -H 'Accept: application/json' -v -d '[{ "path": "/address", "value": "AA:AA:AA:AA:AA:AB", "op": "replace" }]' http://0.0.0.0:6385/v1/ports/cff3477e-285c-452b-a8e2-f1d6d9099da7
* About to connect() to 0.0.0.0 port 6385 (#0)
* Trying 0.0.0.0...
* Connected to 0.0.0.0 (0.0.0.0) port 6385 (#0)
> PATCH /v1/ports/cff3477e-285c-452b-a8e2-f1d6d9099da7 HTTP/1.1
> User-Agent: curl/7.29.0
> Host: 0.0.0.0:6385
> Content-Type: application/json
> Accept: application/json
> Content-Length: 71
>
* upload completely sent off: 71 out of 71 bytes
* HTTP 1.0, assume close after body
< HTTP/1.0 500 Internal Server Error
< Date: Mon, 18 Nov 2013 16:45:52 GMT
< Server: WSGIServer/0.1 Python/2.7.4
< Content-Type: application/json
< Content-Length: 331
<
* Closing connection 0
{"error_message": "{\"debuginfo\": null, \"faultcode\": \"Server\", \"faultstring\": \"(IntegrityError) (1062, \\\"Duplicate entry 'AA:AA:AA:AA:AA:AB' for key 'iface_address_ux'\\\") 'UPDATE ports SET updated_at=%s, address=%s WHERE ports.id = %s' (datetime.datetime(2013, 11, 18, 16, 45, 52, 517416), 'AA:AA:AA:AA:AA:AB', 1L)\"}"}

####################

Also, in our code the objects save() method should deal with the IntegrityError and convert it to an IronicException.

summary: - Unique Constraint for Port address doesn't work for Updates on tests
+ Unique Constraint for Port address doesn't work for updates on tests
(sqlite)
summary: - Unique Constraint for Port address doesn't work for updates on tests
- (sqlite)
+ Unique Constraint for Port address doesn't work for updates with sqlite
summary: - Unique Constraint for Port address doesn't work for updates with sqlite
+ UniqueConstraint for Port address doesn't work for updates with sqlite
Changed in ironic:
assignee: nobody → Yuriy Zveryanskyy (yzveryanskyy)
Revision history for this message
OpenStack Infra (hudson-openstack) wrote : Fix proposed to ironic (master)

Fix proposed to branch: master
Review: https://review.openstack.org/57722

Changed in ironic:
status: New → In Progress
aeva black (tenbrae)
Changed in ironic:
importance: Undecided → Medium
Revision history for this message
OpenStack Infra (hudson-openstack) wrote : Fix merged to ironic (master)

Reviewed: https://review.openstack.org/57722
Committed: http://github.com/openstack/ironic/commit/83dba5c1fba33826cd6f0d854c1146329ce2eb66
Submitter: Jenkins
Branch: master

commit 83dba5c1fba33826cd6f0d854c1146329ce2eb66
Author: Yuriy Zveryanskyy <email address hidden>
Date: Thu Nov 21 19:02:26 2013 +0200

    Add port address unique constraint for sqlite

    SQLite backend used in unit tests, but unique constraint for 'address'
    column in 'ports' table not working for this backend. Patch fix this
    and also unit tests which violates 'address' UC.

    Closes-Bug: #1252343
    Change-Id: I761e480c99f1687531cf4c64a64c02faa7e4fb73

Changed in ironic:
status: In Progress → Fix Committed
Thierry Carrez (ttx)
Changed in ironic:
milestone: none → icehouse-1
status: Fix Committed → Fix Released
Thierry Carrez (ttx)
Changed in ironic:
milestone: icehouse-1 → 2014.1
To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.