Guard against concurrent port removal in DVR
The delete_csnat_router_interface_ports method constructs
a generator expression to retrieve the ports attached
to a router. If a concurrent process manages to delete
one of the ports referenced in the generator from the DB
after it is constructed (but before iteration), some of the
ports will be None objects on iteration.
This patch verifies that the port db object is there
before trying to extract the ID from it.
More details:
This is because the query expression[1] is evaluated immediately
at the time the generator is defined. If there are ports in the
DB at the time of this evaluation, RouterPort objects will be
prepared to be iterated over. However, before the iteration over the
generator happens, something else may delete the port from the DB.
If that happens, when the iteration starts and the 'port' attribute
is accessed on the router port, a SELECT statement will be issued to
the DB to get that port[2] and it will return None.
1. router.attached_ports.filter_by(port_type=DEVICE_OWNER_DVR_SNAT)
2. The RouterPorts table's relationship to the Ports table is using
the default 'select' lazy loading.
Closes-Bug: #
1381263
Change-Id: Ia371545d641aaa1cbaa0fd10cd233250ec5769e5