Allow to deprecate policy
if a policy is marked as 'deprecate = yes' in swift.conf: * it will not appear in /info of the cluster * upload/download/delete/post are allowed on the existing containers with this policy. * clients will get error when trying to create container with this policy * clients can get the policy info via HEAD on the existing containers created with this policy * clients also can set new metadata via POST to the containers with this policy corner cases: * deprecated policy will ignore the default option * deprecating a default policy make the policy with the lowest index default Change-Id: Ia72d39dca0c993e461e0e8cadef1dc91be98f3f4
This commit is contained in:
parent
42fab1c763
commit
b9d25a5731
|
@ -64,7 +64,7 @@ class StoragePolicy(object):
|
|||
is known via the Collection's get_object_ring method, but it may be
|
||||
over-ridden via object_ring kwarg at create time for testing.
|
||||
"""
|
||||
def __init__(self, idx, name='', is_default=False,
|
||||
def __init__(self, idx, name='', is_default=False, is_deprecated=False,
|
||||
policy_type=DEFAULT_TYPE, object_ring=None):
|
||||
try:
|
||||
self.idx = int(idx)
|
||||
|
@ -75,7 +75,10 @@ class StoragePolicy(object):
|
|||
if not name:
|
||||
raise PolicyError('Invalid name', idx)
|
||||
self.name = name
|
||||
self.is_default = config_true_value(is_default)
|
||||
self.is_deprecated = config_true_value(is_deprecated)
|
||||
# deprecation takes precedence over default
|
||||
self.is_default = config_true_value(is_default) and \
|
||||
not self.is_deprecated
|
||||
if policy_type not in VALID_TYPES:
|
||||
raise PolicyError('Invalid type', idx)
|
||||
self.policy_type = policy_type
|
||||
|
@ -91,8 +94,10 @@ class StoragePolicy(object):
|
|||
return cmp(self.idx, int(other))
|
||||
|
||||
def __repr__(self):
|
||||
return "StoragePolicy(%d, %r, is_default=%s, policy_type=%r)" % (
|
||||
self.idx, self.name, self.is_default, self.policy_type)
|
||||
return ("StoragePolicy(%d, %r, is_default=%s, "
|
||||
"is_deprecated=%s, policy_type=%r)") % (
|
||||
self.idx, self.name, self.is_default, self.is_deprecated,
|
||||
self.policy_type)
|
||||
|
||||
def load_ring(self, swift_dir):
|
||||
if self.object_ring:
|
||||
|
@ -165,9 +170,14 @@ class StoragePolicyCollection(object):
|
|||
if 0 not in self.by_index:
|
||||
self.add_policy(StoragePolicy(0, 'Policy_0', False))
|
||||
|
||||
# if needed, specify default of policy 0
|
||||
# at least one policy must be enabled
|
||||
enabled_policies = [p for p in self if not p.is_deprecated]
|
||||
if not enabled_policies:
|
||||
raise PolicyError("Unable to find policy that's not deprecated!")
|
||||
|
||||
# if needed, specify default
|
||||
if not self.default:
|
||||
self.default = self[0]
|
||||
self.default = sorted(enabled_policies)[0]
|
||||
self.default.is_default = True
|
||||
|
||||
def get_by_name(self, name):
|
||||
|
@ -220,6 +230,9 @@ class StoragePolicyCollection(object):
|
|||
"""
|
||||
policy_info = []
|
||||
for pol in self:
|
||||
# delete from /info if deprecated
|
||||
if pol.is_deprecated:
|
||||
continue
|
||||
policy_entry = {}
|
||||
policy_entry['name'] = pol.name
|
||||
policy_entry['type'] = pol.policy_type
|
||||
|
@ -263,6 +276,7 @@ def parse_storage_policies(conf):
|
|||
config_to_policy_option_map = {
|
||||
'name': 'name',
|
||||
'default': 'is_default',
|
||||
'deprecated': 'is_deprecated',
|
||||
'type': 'policy_type',
|
||||
}
|
||||
policy_options = {}
|
||||
|
|
|
@ -124,6 +124,12 @@ class ContainerController(Controller):
|
|||
if policy_index is None:
|
||||
# make sure all backend servers get the same default policy
|
||||
policy_index = POLICIES.default.idx
|
||||
policy = POLICIES[policy_index]
|
||||
if policy.is_deprecated:
|
||||
resp = HTTPBadRequest(request=req)
|
||||
resp.body = 'Storage Policy %r is deprecated' % \
|
||||
(policy.name)
|
||||
return resp
|
||||
if not req.environ.get('swift_owner'):
|
||||
for key in self.app.swift_owner_headers:
|
||||
req.headers.pop(key, None)
|
||||
|
|
|
@ -35,8 +35,10 @@ class TestStoragePolicies(unittest.TestCase):
|
|||
|
||||
@patch_policies([StoragePolicy(0, 'zero', True),
|
||||
StoragePolicy(1, 'one', False),
|
||||
StoragePolicy(2, 'two', False)])
|
||||
StoragePolicy(2, 'two', False),
|
||||
StoragePolicy(3, 'three', False, is_deprecated=True)])
|
||||
def test_swift_info(self):
|
||||
# the deprecated 'three' should not exist in expect
|
||||
expect = [{'default': True, 'type': 'replication', 'name': 'zero'},
|
||||
{'type': 'replication', 'name': 'two'},
|
||||
{'type': 'replication', 'name': 'one'}]
|
||||
|
@ -101,6 +103,25 @@ class TestStoragePolicies(unittest.TestCase):
|
|||
self.assertEquals(policies.default, policies[0])
|
||||
self.assertEquals(policies.default.name, 'Policy_0')
|
||||
|
||||
def test_deprecate_policies(self):
|
||||
# deprecation specified
|
||||
test_policies = [StoragePolicy(0, 'zero', True),
|
||||
StoragePolicy(1, 'one', False),
|
||||
StoragePolicy(2, 'two', False, is_deprecated=True)]
|
||||
policies = StoragePolicyCollection(test_policies)
|
||||
self.assertEquals(policies.default, test_policies[0])
|
||||
self.assertEquals(policies.default.name, 'zero')
|
||||
self.assertEquals(len(policies), 3)
|
||||
|
||||
# deprecating old default makes policy 0 the default
|
||||
test_policies = [StoragePolicy(0, 'zero', False),
|
||||
StoragePolicy(1, 'one', True, is_deprecated=True),
|
||||
StoragePolicy(2, 'two', False)]
|
||||
policies = StoragePolicyCollection(test_policies)
|
||||
self.assertEquals(policies.default, test_policies[0])
|
||||
self.assertEquals(policies.default.name, 'zero')
|
||||
self.assertEquals(len(policies), 3)
|
||||
|
||||
def test_validate_policies_indexes(self):
|
||||
# duplicate indexes
|
||||
test_policies = [StoragePolicy(0, 'zero', True),
|
||||
|
@ -149,7 +170,39 @@ class TestStoragePolicies(unittest.TestCase):
|
|||
else:
|
||||
self.fail('%r did not raise %s' % (message, exc_class.__name__))
|
||||
|
||||
def test_deprecated_default(self):
|
||||
bad_conf = self._conf("""
|
||||
[storage-policy:1]
|
||||
name = one
|
||||
deprecated = yes
|
||||
default = yes
|
||||
""")
|
||||
|
||||
policies = parse_storage_policies(bad_conf)
|
||||
self.assertEqual(len(policies), 2)
|
||||
self.assertTrue(policies[1].is_deprecated)
|
||||
self.assertFalse(policies[1].is_default)
|
||||
self.assertEqual(policies.default.idx, 0)
|
||||
self.assertTrue(policies[0].is_default)
|
||||
self.assertFalse(policies[0].is_deprecated)
|
||||
|
||||
def test_parse_storage_policies(self):
|
||||
# ValueError when deprecating policy 0
|
||||
bad_conf = self._conf("""
|
||||
[storage-policy:0]
|
||||
name = zero
|
||||
deprecated = yes
|
||||
default = yes
|
||||
|
||||
[storage-policy:1]
|
||||
name = one
|
||||
deprecated = yes
|
||||
""")
|
||||
|
||||
self.assertRaisesWithMessage(
|
||||
ValueError, "Unable to find policy that's not deprecated",
|
||||
parse_storage_policies, bad_conf)
|
||||
|
||||
bad_conf = self._conf("""
|
||||
[storage-policy:x]
|
||||
name = zero
|
||||
|
|
|
@ -4486,7 +4486,8 @@ class TestObjectController(unittest.TestCase):
|
|||
|
||||
@patch_policies([
|
||||
StoragePolicy(0, 'zero', True, object_ring=FakeRing()),
|
||||
StoragePolicy(1, 'one', False, object_ring=FakeRing())
|
||||
StoragePolicy(1, 'one', False, object_ring=FakeRing()),
|
||||
StoragePolicy(2, 'two', False, True, object_ring=FakeRing())
|
||||
])
|
||||
class TestContainerController(unittest.TestCase):
|
||||
"Test swift.proxy_server.ContainerController"
|
||||
|
@ -4506,6 +4507,9 @@ class TestContainerController(unittest.TestCase):
|
|||
req = Request.blank('/a/c', headers={'Content-Length': '0',
|
||||
'Content-Type': 'text/plain', POLICY: 'one'})
|
||||
self.assertEqual(controller._convert_policy_to_index(req), 1)
|
||||
req = Request.blank('/a/c', headers={'Content-Length': '0',
|
||||
'Content-Type': 'text/plain', POLICY: 'two'})
|
||||
self.assertEqual(controller._convert_policy_to_index(req), 2)
|
||||
req = Request.blank('/a/c', headers={'Content-Length': '0',
|
||||
'Content-Type': 'text/plain', POLICY: 'nada'})
|
||||
self.assertRaises(HTTPException, controller._convert_policy_to_index,
|
||||
|
@ -4640,6 +4644,14 @@ class TestContainerController(unittest.TestCase):
|
|||
else:
|
||||
policy = POLICIES.default
|
||||
res = req.get_response(self.app)
|
||||
if policy.is_deprecated:
|
||||
self.assertEquals(res.status_int, 400)
|
||||
self.assertEqual(0, len(backend_requests))
|
||||
expected = 'is deprecated'
|
||||
self.assertTrue(expected in res.body,
|
||||
'%r did not include %r' % (
|
||||
res.body, expected))
|
||||
return
|
||||
self.assertEquals(res.status_int, 201)
|
||||
self.assertEqual(
|
||||
policy.object_ring.replicas,
|
||||
|
@ -6297,6 +6309,7 @@ class TestProxyObjectPerformance(unittest.TestCase):
|
|||
|
||||
@patch_policies([StoragePolicy(0, 'migrated'),
|
||||
StoragePolicy(1, 'ernie', True),
|
||||
StoragePolicy(2, 'deprecated', is_deprecated=True),
|
||||
StoragePolicy(3, 'bert')])
|
||||
class TestSwiftInfo(unittest.TestCase):
|
||||
def setUp(self):
|
||||
|
@ -6338,6 +6351,8 @@ class TestSwiftInfo(unittest.TestCase):
|
|||
self.assertTrue('policies' in si)
|
||||
sorted_pols = sorted(si['policies'], key=operator.itemgetter('name'))
|
||||
self.assertEqual(len(sorted_pols), 3)
|
||||
for policy in sorted_pols:
|
||||
self.assertNotEquals(policy['name'], 'deprecated')
|
||||
self.assertEqual(sorted_pols[0]['name'], 'bert')
|
||||
self.assertEqual(sorted_pols[1]['name'], 'ernie')
|
||||
self.assertEqual(sorted_pols[2]['name'], 'migrated')
|
||||
|
|
Loading…
Reference in New Issue