Warn about using EC with isa_l_rs_vand and nparity >= 5

We *know* there are combinations that will prevent decoding, and we're
going to be increasingly aggressive about getting it out of clusters.

Partial-Bug: 1639691
Change-Id: I50159c9d19f2385d5f60112e9aaefa1a68098313
This commit is contained in:
Tim Burke 2017-01-26 02:03:28 +00:00 committed by Ondřej Nový
parent 3129a55d44
commit bd75a97ad4
2 changed files with 130 additions and 0 deletions

View File

@ -12,8 +12,10 @@
# limitations under the License. # limitations under the License.
import logging
import os import os
import string import string
import sys
import textwrap import textwrap
import six import six
from six.moves.configparser import ConfigParser from six.moves.configparser import ConfigParser
@ -453,6 +455,26 @@ class ECStoragePolicy(BaseStoragePolicy):
raise PolicyError('Invalid ec_object_segment_size %r' % raise PolicyError('Invalid ec_object_segment_size %r' %
ec_segment_size, index=self.idx) ec_segment_size, index=self.idx)
if self._ec_type == 'isa_l_rs_vand' and self._ec_nparity >= 5:
logger = logging.getLogger("swift.common.storage_policy")
if not logger.handlers:
# If nothing else, log to stderr
logger.addHandler(logging.StreamHandler(sys.__stderr__))
logger.warning(
'Storage policy %s uses an EC configuration known to harm '
'data durability. Any data in this policy should be migrated. '
'See https://bugs.launchpad.net/swift/+bug/1639691 for '
'more information.' % self.name)
if not is_deprecated:
# TODO: To fully close bug 1639691, uncomment the raise and
# removing the warning below. This will be in the Pike release
# at the earliest.
logger.warning(
'In a future release, this will prevent services from '
'starting unless the policy is marked as deprecated.')
# raise PolicyError('Storage policy %s MUST be deprecated' %
# self.name)
# Initialize PyECLib EC backend # Initialize PyECLib EC backend
try: try:
self.pyeclib_driver = \ self.pyeclib_driver = \

View File

@ -12,7 +12,9 @@
# limitations under the License. # limitations under the License.
""" Tests for swift.common.storage_policies """ """ Tests for swift.common.storage_policies """
import contextlib
import six import six
import logging
import unittest import unittest
import os import os
import mock import mock
@ -20,6 +22,7 @@ from functools import partial
from six.moves.configparser import ConfigParser from six.moves.configparser import ConfigParser
from tempfile import NamedTemporaryFile from tempfile import NamedTemporaryFile
from test.unit import patch_policies, FakeRing, temptree, DEFAULT_TEST_EC_TYPE from test.unit import patch_policies, FakeRing, temptree, DEFAULT_TEST_EC_TYPE
import swift.common.storage_policy
from swift.common.storage_policy import ( from swift.common.storage_policy import (
StoragePolicyCollection, POLICIES, PolicyError, parse_storage_policies, StoragePolicyCollection, POLICIES, PolicyError, parse_storage_policies,
reload_storage_policies, get_policy_string, split_policy_string, reload_storage_policies, get_policy_string, split_policy_string,
@ -30,6 +33,26 @@ from swift.common.exceptions import RingLoadError
from pyeclib.ec_iface import ECDriver from pyeclib.ec_iface import ECDriver
class CapturingHandler(logging.Handler):
def __init__(self):
super(CapturingHandler, self).__init__()
self._records = []
def emit(self, record):
self._records.append(record)
@contextlib.contextmanager
def capture_logging(log_name):
captured = CapturingHandler()
logger = logging.getLogger(log_name)
logger.addHandler(captured)
try:
yield captured._records
finally:
logger.removeHandler(captured)
@BaseStoragePolicy.register('fake') @BaseStoragePolicy.register('fake')
class FakeStoragePolicy(BaseStoragePolicy): class FakeStoragePolicy(BaseStoragePolicy):
""" """
@ -582,6 +605,91 @@ class TestStoragePolicies(unittest.TestCase):
PolicyError, "must specify a storage policy section " PolicyError, "must specify a storage policy section "
"for policy index 0", parse_storage_policies, bad_conf) "for policy index 0", parse_storage_policies, bad_conf)
@mock.patch.object(swift.common.storage_policy, 'VALID_EC_TYPES',
['isa_l_rs_vand', 'isa_l_rs_cauchy'])
@mock.patch('swift.common.storage_policy.ECDriver')
def test_known_bad_ec_config(self, mock_driver):
good_conf = self._conf("""
[storage-policy:0]
name = bad-policy
policy_type = erasure_coding
ec_type = isa_l_rs_cauchy
ec_num_data_fragments = 10
ec_num_parity_fragments = 5
""")
with capture_logging('swift.common.storage_policy') as records:
parse_storage_policies(good_conf)
mock_driver.assert_called_once()
mock_driver.reset_mock()
self.assertFalse([(r.levelname, r.message) for r in records])
good_conf = self._conf("""
[storage-policy:0]
name = bad-policy
policy_type = erasure_coding
ec_type = isa_l_rs_vand
ec_num_data_fragments = 10
ec_num_parity_fragments = 4
""")
with capture_logging('swift.common.storage_policy') as records:
parse_storage_policies(good_conf)
mock_driver.assert_called_once()
mock_driver.reset_mock()
self.assertFalse([(r.levelname, r.message) for r in records])
bad_conf = self._conf("""
[storage-policy:0]
name = bad-policy
policy_type = erasure_coding
ec_type = isa_l_rs_vand
ec_num_data_fragments = 10
ec_num_parity_fragments = 5
""")
with capture_logging('swift.common.storage_policy') as records:
parse_storage_policies(bad_conf)
mock_driver.assert_called_once()
mock_driver.reset_mock()
self.assertEqual([r.levelname for r in records],
['WARNING', 'WARNING'])
for msg in ('known to harm data durability',
'Any data in this policy should be migrated',
'https://bugs.launchpad.net/swift/+bug/1639691'):
self.assertIn(msg, records[0].message)
self.assertIn('In a future release, this will prevent services from '
'starting', records[1].message)
slightly_less_bad_conf = self._conf("""
[storage-policy:0]
name = bad-policy
policy_type = erasure_coding
ec_type = isa_l_rs_vand
ec_num_data_fragments = 10
ec_num_parity_fragments = 5
deprecated = true
[storage-policy:1]
name = good-policy
policy_type = erasure_coding
ec_type = isa_l_rs_cauchy
ec_num_data_fragments = 10
ec_num_parity_fragments = 5
default = true
""")
with capture_logging('swift.common.storage_policy') as records:
parse_storage_policies(slightly_less_bad_conf)
self.assertEqual(2, mock_driver.call_count)
mock_driver.reset_mock()
self.assertEqual([r.levelname for r in records],
['WARNING'])
for msg in ('known to harm data durability',
'Any data in this policy should be migrated',
'https://bugs.launchpad.net/swift/+bug/1639691'):
self.assertIn(msg, records[0].message)
def test_no_default(self): def test_no_default(self):
orig_conf = self._conf(""" orig_conf = self._conf("""
[storage-policy:0] [storage-policy:0]