Shared IP API

Squashed work from John Perkins <john.perkins@rackspace.com> and Thomas Maddox <thomas.maddox@rackspace.com>

- An API to allow an already shared IP address to be added to or removed from another port.
- An API to allow an IP address to be "shared" instead of "configured" or "owned"
- Filters on db.api.ip_address_find should be updated to allow searching by other attributes, like the port_id. Currently it only supports "ip_shared" (changed ip_shared to address_type=shared') and "device_id"
- Any time we show ports to the caller, we must set the "enabled" flag if the port is the one the IP is currently assigned to. A change already exists in Nova anticipating this change.
- Only New IPs can be marked as "shared" at the time of their creation
- IPs cannot change from shared to not shared, or vice versa, at any time after creation until deallocated.
- Remove device_ids attribute from /ip_addresses
- Change from 'shared' boolean attribute to 'type' string attribute with the following valid values: 'shared', 'fixed', and 'floating'.
- Move address types to constants for consistency
After some digging, time testing, explains, it looks like adding lazy='joined' on that relationship in the IPAddress model will cause it to eager load in a single query, with a pretty simple plan compared to the alternatives.

By default this is lazy='select', which just causes it to lazily do a SELECT for the relationship when that attribute is called. There are two other options, 'joined' and 'subquery'.

The 'joined' option emitted a single query on session.query(models.IPAddress).all():
```sql
SELECT quark_ip_addresses.id                              AS 
       quark_ip_addresses_id, 
       quark_ip_addresses.created_at                      AS 
       quark_ip_addresses_created_at, 
       quark_ip_addresses.address_readable                AS 
       quark_ip_addresses_address_readable, 
       quark_ip_addresses.address                         AS 
       quark_ip_addresses_address, 
       quark_ip_addresses.subnet_id                       AS 
       quark_ip_addresses_subnet_id, 
       quark_ip_addresses.network_id                      AS 
       quark_ip_addresses_network_id, 
       quark_ip_addresses.version                         AS 
       quark_ip_addresses_version, 
       quark_ip_addresses.allocated_at                    AS 
       quark_ip_addresses_allocated_at, 
       quark_ip_addresses._deallocated                    AS 
       quark_ip_addresses__deallocated, 
       quark_ip_addresses.used_by_tenant_id               AS 
       quark_ip_addresses_used_by_tenant_id, 
       quark_ip_addresses.address_type                    AS 
       quark_ip_addresses_address_type, 
       quark_ip_addresses.deallocated_at                  AS 
       quark_ip_addresses_deallocated_at, 
       quark_port_ip_address_associations_1.port_id       AS 
       quark_port_ip_address_associations_1_port_id, 
       quark_port_ip_address_associations_1.ip_address_id AS 
       quark_port_ip_address_associations_1_ip_address_id, 
       quark_port_ip_address_associations_1.enabled       AS 
       quark_port_ip_address_associations_1_enabled 
FROM   quark_ip_addresses 
       LEFT OUTER JOIN quark_port_ip_address_associations AS 
                       quark_port_ip_address_associations_1 
                    ON quark_ip_addresses.id = 
       quark_port_ip_address_associations_1.ip_address_id 
```

EXPLAIN on this query:
```
+----+-------------+--------------------------------------+------+---------------+---------------+---------+-------------------------------+------+-------+
| id | select_type | table                                | type | possible_keys | key           | key_len | ref                           | rows | Extra |
+----+-------------+--------------------------------------+------+---------------+---------------+---------+-------------------------------+------+-------+
|  1 | SIMPLE      | quark_ip_addresses                   | ALL  | NULL          | NULL          | NULL    | NULL                          |   39 |       |
|  1 | SIMPLE      | quark_port_ip_address_associations_1 | ref  | ip_address_id | ip_address_id | 38      | neutron.quark_ip_addresses.id |    1 |       |
+----+-------------+--------------------------------------+------+---------------+---------------+---------+-------------------------------+------+-------+
2 rows in set (0.03 sec)
```

The 'subquery' option emitted the following *two* separate DB queries:
```sql
SELECT quark_ip_addresses.id                AS quark_ip_addresses_id, 
       quark_ip_addresses.created_at        AS quark_ip_addresses_created_at, 
       quark_ip_addresses.address_readable  AS 
       quark_ip_addresses_address_readable, 
       quark_ip_addresses.address           AS quark_ip_addresses_address, 
       quark_ip_addresses.subnet_id         AS quark_ip_addresses_subnet_id, 
       quark_ip_addresses.network_id        AS quark_ip_addresses_network_id, 
       quark_ip_addresses.version           AS quark_ip_addresses_version, 
       quark_ip_addresses.allocated_at      AS quark_ip_addresses_allocated_at, 
       quark_ip_addresses._deallocated      AS quark_ip_addresses__deallocated, 
       quark_ip_addresses.used_by_tenant_id AS 
       quark_ip_addresses_used_by_tenant_id, 
       quark_ip_addresses.address_type      AS quark_ip_addresses_address_type, 
       quark_ip_addresses.deallocated_at    AS quark_ip_addresses_deallocated_at 
FROM   quark_ip_addresses 
```

EXPLAIN on this query:
```
+----+-------------+--------------------+------+---------------+------+---------+------+------+-------+
| id | select_type | table              | type | possible_keys | key  | key_len | ref  | rows | Extra |
+----+-------------+--------------------+------+---------------+------+---------+------+------+-------+
|  1 | SIMPLE      | quark_ip_addresses | ALL  | NULL          | NULL | NULL    | NULL |   39 |       |
+----+-------------+--------------------+------+---------------+------+---------+------+------+-------+
1 row in set (0.00 sec)
```

and
```sql
SELECT quark_port_ip_address_associations.port_id       AS 
       quark_port_ip_address_associations_port_id, 
       quark_port_ip_address_associations.ip_address_id AS 
       quark_port_ip_address_associations_ip_address_id, 
       quark_port_ip_address_associations.enabled       AS 
       quark_port_ip_address_associations_enabled, 
       anon_1.quark_ip_addresses_id                     AS 
       anon_1_quark_ip_addresses_id 
FROM   (SELECT quark_ip_addresses.id AS quark_ip_addresses_id 
        FROM   quark_ip_addresses) AS anon_1 
       INNER JOIN quark_port_ip_address_associations 
               ON anon_1.quark_ip_addresses_id = 
                  quark_port_ip_address_associations.ip_address_id 
ORDER  BY anon_1.quark_ip_addresses_id 
```
EXPLAIN on this query:
```
+----+-------------+------------------------------------+-------+---------------+-------------------------------+---------+------------------------------+------+----------------+
| id | select_type | table                              | type  | possible_keys | key                           | key_len | ref                          | rows | Extra          |+----+-------------+------------------------------------+-------+---------------+-------------------------------+---------+------------------------------+------+----------------+|  1 | PRIMARY     | <derived2>                         | ALL   | NULL          | NULL                          | NULL    | NULL                         |   39 | Using filesort |
|  1 | PRIMARY     | quark_port_ip_address_associations | ref   | ip_address_id | ip_address_id                 | 38      | anon_1.quark_ip_addresses_id |    1 |                |
|  2 | DERIVED     | quark_ip_addresses                 | index | NULL          | ix_quark_ip_addresses_version | 5       | NULL                         |   39 | Using index    |+----+-------------+------------------------------------+-------+---------------+-------------------------------+---------+------------------------------+------+----------------+
3 rows in set (0.00 sec)
```

Okay, the first one in the 'subquery' scenario is pretty darn simple. The second, however, is basically as complex, if not more-so, than the one in the 'joined' scenario.

So, I think I shall go with lazy='joined' on the 'associations' relationship and that should eager-load for us. I'd be interested to see if we have any performance tests around these calls?