Add inactive value to floating ip status

This patch adds a new status value for floating ips called
inactive that is used to indicate if there is not a dns record
assosciated with a floating ip.

Partial-Bug: #1932026

Change-Id: Ieca3cb06b99ba4556f4e6e770f82ec594d1ab1b6
This commit is contained in:
Erik Olof Gunnar Andersson 2022-02-22 20:37:35 -08:00
parent 8ce022a7b9
commit 93ebb1af53
6 changed files with 168 additions and 34 deletions

View File

@ -1993,31 +1993,55 @@ class Service(service.RPCService):
'ptrdname': None,
'ttl': None,
'description': None,
'action': None,
'status': 'ACTIVE'
'action': constants.NONE,
'status': constants.INACTIVE
})
# TTL population requires a present record in order to find the
# RS or Zone.
if record and record.action != 'DELETE':
if not recordset:
recordset = self.storage.get_recordset(
elevated_context, record.recordset_id)
fip_ptr['action'] = recordset.action
fip_ptr['status'] = recordset.status
if recordset.ttl is not None:
fip_ptr['ttl'] = recordset.ttl
else:
if not zone:
zone = self.get_zone(elevated_context,
record.zone_id)
fip_ptr['ttl'] = zone.ttl
fip_ptr['ptrdname'] = record.data
fip_ptr['description'] = record.description
else:
# Recordset or Zone.
if not record:
LOG.debug('No record information found for %s', fip['id'])
return fip_ptr
if not recordset:
try:
recordset = self.storage.get_recordset(
elevated_context, record.recordset_id
)
except exceptions.RecordSetNotFound:
LOG.debug('No recordset found for %s', fip['id'])
return fip_ptr
if recordset.ttl is not None:
fip_ptr['ttl'] = recordset.ttl
else:
if not zone:
try:
zone = self.get_zone(
elevated_context, record.zone_id
)
except exceptions.ZoneNotFound:
LOG.debug('No zone found for %s', fip['id'])
return fip_ptr
fip_ptr['ttl'] = zone.ttl
if recordset.action in constants.FLOATING_IP_ACTIONS:
fip_ptr['action'] = recordset.action
else:
LOG.debug(
'Action %s not valid for floating ip action', recordset.action
)
if recordset.status in constants.FLOATING_IP_STATUSES:
fip_ptr['status'] = recordset.status
else:
LOG.debug(
'Status %s not valid for floating ip status', recordset.status
)
fip_ptr['ptrdname'] = record.data
fip_ptr['description'] = record.description
return fip_ptr

View File

@ -15,3 +15,19 @@
# RBAC related constants
RBAC_PROJECT_ID = 'project_id'
RBAC_TARGET_PROJECT_ID = 'target_project_id'
# Statuses
ACTIVE = 'ACTIVE'
ERROR = 'ERROR'
INACTIVE = 'INACTIVE'
PENDING = 'PENDING'
# Actions
CREATE = 'CREATE'
DELETE = 'DELETE'
NONE = 'NONE'
UPDATE = 'UPDATE'
# Floating IP constants
FLOATING_IP_ACTIONS = [CREATE, DELETE, UPDATE, NONE]
FLOATING_IP_STATUSES = [ACTIVE, ERROR, INACTIVE, PENDING]

View File

@ -13,6 +13,7 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from designate.common import constants
from designate.objects import base
from designate.objects import fields
@ -27,10 +28,10 @@ class FloatingIP(base.DictObjectMixin, base.PersistentObjectMixin,
"ttl": fields.IntegerFields(nullable=True,
minimum=1, maximum=2147483647),
"region": fields.StringFields(nullable=True),
"action": fields.EnumField(['CREATE', 'DELETE',
'UPDATE', 'NONE'], nullable=True),
"status": fields.EnumField(['ACTIVE',
'PENDING', 'ERROR'], nullable=True)
"action": fields.EnumField(constants.FLOATING_IP_ACTIONS,
nullable=True),
"status": fields.EnumField(constants.FLOATING_IP_STATUSES,
nullable=True)
}
STRING_KEYS = [

View File

@ -41,8 +41,8 @@ class ApiV2ReverseFloatingIPTest(ApiV2TestCase):
self.assertEqual(fip['address'], fip_record['address'])
self.assertIsNone(fip_record['description'])
self.assertIsNone(fip_record['ptrdname'])
self.assertIsNone(fip_record['action'])
self.assertEqual('ACTIVE', fip_record['status'])
self.assertEqual('NONE', fip_record['action'])
self.assertEqual('INACTIVE', fip_record['status'])
def test_get_floatingip_with_record(self):
fixture = self.get_ptr_fixture()
@ -72,6 +72,61 @@ class ApiV2ReverseFloatingIPTest(ApiV2TestCase):
self.assertEqual('CREATE', fip_record['action'])
self.assertEqual('PENDING', fip_record['status'])
def test_get_floatingip_after_unset(self):
fixture = self.get_ptr_fixture()
context = self.get_context(project_id='a')
elevated_context = context.elevated()
elevated_context.all_tenants = True
fip = self.network_api.fake.allocate_floatingip(context.project_id)
# Unsetting via "None"
self.central_service.update_floatingip(
context, fip['region'], fip['id'], fixture)
criterion = {
'managed_resource_id': fip['id'],
'managed_tenant_id': context.project_id
}
zone_id = self.central_service.find_record(
elevated_context, criterion=criterion).zone_id
# Simulate the unset on the backend
zone_serial = self.central_service.get_zone(
elevated_context, zone_id).serial
self.central_service.update_status(
elevated_context, zone_id, 'SUCCESS', zone_serial, 'UPDATE')
# Unset PTR ('ptrdname' is None aka null in JSON)
response = self.client.patch_json(
'/reverse/floatingips/%s' % ":".join([fip['region'], fip['id']]),
{'ptrdname': None},
headers={'X-Test-Tenant-Id': context.project_id})
self.assertIsNone(response.json)
self.assertEqual(202, response.status_int)
# Simulate the unset on the backend
zone_serial = self.central_service.get_zone(
elevated_context, zone_id).serial
self.central_service.update_status(
elevated_context, zone_id, 'SUCCESS', zone_serial, 'UPDATE')
response = self.client.get(
'/reverse/floatingips/%s' % ":".join([fip['region'], fip['id']]),
headers={'X-Test-Tenant-Id': context.project_id})
self.assertEqual(200, response.status_int)
self.assertEqual('application/json', response.content_type)
fip_record = response.json
self.assertEqual(":".join([fip['region'], fip['id']]),
fip_record['id'])
self.assertEqual(fip['address'], fip_record['address'])
self.assertIsNone(fip_record['description'])
self.assertIsNone(fip_record['ptrdname'])
self.assertEqual('NONE', fip_record['action'])
self.assertEqual('INACTIVE', fip_record['status'])
def test_get_floatingip_not_allocated(self):
url = '/reverse/floatingips/foo:04580c52-b253-4eb7-8791-fbb9de9f856f'
@ -108,8 +163,8 @@ class ApiV2ReverseFloatingIPTest(ApiV2TestCase):
fip_record['id'])
self.assertEqual(fip['address'], fip_record['address'])
self.assertIsNone(fip_record['description'])
self.assertIsNone(fip_record['action'])
self.assertEqual('ACTIVE', fip_record['status'])
self.assertEqual('NONE', fip_record['action'])
self.assertEqual('INACTIVE', fip_record['status'])
def test_list_floatingip_with_record(self):
fixture = self.get_ptr_fixture()
@ -197,6 +252,19 @@ class ApiV2ReverseFloatingIPTest(ApiV2TestCase):
self.central_service.update_floatingip(
context, fip['region'], fip['id'], fixture)
criterion = {
'managed_resource_id': fip['id'],
'managed_tenant_id': context.project_id
}
zone_id = self.central_service.find_record(
elevated_context, criterion=criterion).zone_id
# Simulate the unset on the backend
zone_serial = self.central_service.get_zone(
elevated_context, zone_id).serial
self.central_service.update_status(
elevated_context, zone_id, 'SUCCESS', zone_serial, 'UPDATE')
# Unset PTR ('ptrdname' is None aka null in JSON)
response = self.client.patch_json(
'/reverse/floatingips/%s' % ":".join([fip['region'], fip['id']]),
@ -205,6 +273,12 @@ class ApiV2ReverseFloatingIPTest(ApiV2TestCase):
self.assertIsNone(response.json)
self.assertEqual(202, response.status_int)
# Simulate the unset on the backend
zone_serial = self.central_service.get_zone(
elevated_context, zone_id).serial
self.central_service.update_status(
elevated_context, zone_id, 'SUCCESS', zone_serial, 'UPDATE')
fip = self.central_service.get_floatingip(
context, fip['region'], fip['id'])
self.assertIsNone(fip['ptrdname'])

View File

@ -2222,6 +2222,8 @@ class CentralServiceTest(CentralTestCase):
criterion = {
'managed_resource_id': fip['id'],
'managed_tenant_id': context_a.project_id}
zone_id = self.central_service.find_record(
elevated_a, criterion).zone_id
self.network_api.fake.deallocate_floatingip(fip['id'])
@ -2243,9 +2245,15 @@ class CentralServiceTest(CentralTestCase):
context_b, fip['region'], fip['id'])
self.assertIsNone(fip_ptr['ptrdname'])
# Simulate the invalidation on the backend
zone_serial = self.central_service.get_zone(
elevated_a, zone_id).serial
self.central_service.update_status(
elevated_a, zone_id, 'SUCCESS', zone_serial, 'UPDATE')
record = self.central_service.find_record(elevated_a, criterion)
self.assertEqual('DELETE', record.action)
self.assertEqual('PENDING', record.status)
self.assertEqual('NONE', record.action)
self.assertEqual('DELETED', record.status)
def test_list_floatingips_no_allocations(self):
context = self.get_context(project_id='a')
@ -2331,9 +2339,15 @@ class CentralServiceTest(CentralTestCase):
self.assertEqual(1, len(fips))
self.assertIsNone(fips[0]['ptrdname'])
# Simulate the invalidation on the backend
zone_serial = self.central_service.get_zone(
elevated_a, zone_id).serial
self.central_service.update_status(
elevated_a, zone_id, 'SUCCESS', zone_serial, 'UPDATE')
record = self.central_service.find_record(elevated_a, criterion)
self.assertEqual('DELETE', record.action)
self.assertEqual('PENDING', record.status)
self.assertEqual('NONE', record.action)
self.assertEqual('DELETED', record.status)
def test_set_floatingip(self):
context = self.get_context(project_id='a')

View File

@ -0,0 +1,5 @@
---
upgrade:
- |
Added new state ``INACTIVE`` to the Floating IP status to indicate that
it is not currently associated to a DNS record.