diff --git a/heat/engine/constraint/common/__init__.py b/heat/engine/constraint/common/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/heat/engine/constraint/common/cron_expression.py b/heat/engine/constraint/common/cron_expression.py deleted file mode 100644 index f46a81cf58..0000000000 --- a/heat/engine/constraint/common/cron_expression.py +++ /dev/null @@ -1,32 +0,0 @@ -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import croniter -import six - -from heat.common.i18n import _ -from heat.engine import constraints - - -class CRONExpressionConstraint(constraints.BaseCustomConstraint): - - def validate(self, value, context): - if not value: - return True - try: - croniter.croniter(value) - return True - except Exception as ex: - self._error_message = _( - 'Invalid CRON expression: %s') % six.text_type(ex) - return False diff --git a/heat/engine/constraint/common/timezone.py b/heat/engine/constraint/common/timezone.py deleted file mode 100644 index c43a5406a8..0000000000 --- a/heat/engine/constraint/common/timezone.py +++ /dev/null @@ -1,32 +0,0 @@ -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import pytz -import six - -from heat.common.i18n import _ -from heat.engine import constraints - - -class TimezoneConstraint(constraints.BaseCustomConstraint): - - def validate(self, value, context): - if not value: - return True - try: - pytz.timezone(value) - return True - except Exception as ex: - self._error_message = _( - 'Invalid timezone: %s') % six.text_type(ex) - return False diff --git a/heat/engine/constraint/common_constraints.py b/heat/engine/constraint/common_constraints.py index 3629c8bb9a..9cdb9ffe09 100644 --- a/heat/engine/constraint/common_constraints.py +++ b/heat/engine/constraint/common_constraints.py @@ -11,12 +11,15 @@ # License for the specific language governing permissions and limitations # under the License. +import croniter import iso8601 import netaddr +import pytz import six from oslo_utils import netutils +from heat.common.i18n import _ from heat.engine import constraints @@ -61,3 +64,31 @@ class ISO8601Constraint(object): return False else: return True + + +class CRONExpressionConstraint(constraints.BaseCustomConstraint): + + def validate(self, value, context): + if not value: + return True + try: + croniter.croniter(value) + return True + except Exception as ex: + self._error_message = _( + 'Invalid CRON expression: %s') % six.text_type(ex) + return False + + +class TimezoneConstraint(constraints.BaseCustomConstraint): + + def validate(self, value, context): + if not value: + return True + try: + pytz.timezone(value) + return True + except Exception as ex: + self._error_message = _( + 'Invalid timezone: %s') % six.text_type(ex) + return False diff --git a/heat/tests/constraints/test_common_constraints.py b/heat/tests/constraints/test_common_constraints.py index 91f33b2ed9..12e321b5af 100644 --- a/heat/tests/constraints/test_common_constraints.py +++ b/heat/tests/constraints/test_common_constraints.py @@ -11,8 +11,11 @@ # License for the specific language governing permissions and limitations # under the License. +import six + from heat.engine.constraint import common_constraints as cc from heat.tests import common +from heat.tests import utils class TestIPConstraint(common.HeatTestCase): @@ -137,3 +140,58 @@ class TestISO8601Constraint(common.HeatTestCase): def test_validate_refuses_other_formats(self): self.assertFalse(self.constraint.validate('Fri 13th, 2050', None)) + + +class CRONExpressionConstraint(common.HeatTestCase): + + def setUp(self): + super(CRONExpressionConstraint, self).setUp() + self.ctx = utils.dummy_context() + self.constraint = cc.CRONExpressionConstraint() + + def test_validation(self): + self.assertTrue(self.constraint.validate("0 23 * * *", self.ctx)) + + def test_validation_none(self): + self.assertTrue(self.constraint.validate(None, self.ctx)) + + def test_validation_out_of_range_error(self): + cron_expression = "* * * * * 100" + expect = ("Invalid CRON expression: [%s] " + "is not acceptable, out of range") % cron_expression + self.assertFalse(self.constraint.validate(cron_expression, self.ctx)) + self.assertEqual(expect, + six.text_type(self.constraint._error_message)) + + def test_validation_columns_length_error(self): + cron_expression = "* *" + expect = ("Invalid CRON expression: Exactly 5 " + "or 6 columns has to be specified for " + "iteratorexpression.") + self.assertFalse(self.constraint.validate(cron_expression, self.ctx)) + self.assertEqual(expect, + six.text_type(self.constraint._error_message)) + + +class TimezoneConstraintTest(common.HeatTestCase): + + def setUp(self): + super(TimezoneConstraintTest, self).setUp() + self.ctx = utils.dummy_context() + self.constraint = cc.TimezoneConstraint() + + def test_validation(self): + self.assertTrue(self.constraint.validate("Asia/Taipei", self.ctx)) + + def test_validation_error(self): + timezone = "wrong_timezone" + expected = "Invalid timezone: '%s'" % timezone + + self.assertFalse(self.constraint.validate(timezone, self.ctx)) + self.assertEqual( + expected, + six.text_type(self.constraint._error_message) + ) + + def test_validation_none(self): + self.assertTrue(self.constraint.validate(None, self.ctx)) diff --git a/heat/tests/test_cron_expression.py b/heat/tests/test_cron_expression.py deleted file mode 100644 index 3d5691e492..0000000000 --- a/heat/tests/test_cron_expression.py +++ /dev/null @@ -1,49 +0,0 @@ -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import six - -from heat.engine.constraint.common import cron_expression as ce -from heat.tests import common -from heat.tests import utils - - -class CRONExpressionConstraint(common.HeatTestCase): - - def setUp(self): - super(CRONExpressionConstraint, self).setUp() - self.ctx = utils.dummy_context() - self.constraint = ce.CRONExpressionConstraint() - - def test_validation(self): - self.assertTrue(self.constraint.validate("0 23 * * *", self.ctx)) - - def test_validation_none(self): - self.assertTrue(self.constraint.validate(None, self.ctx)) - - def test_validation_out_of_range_error(self): - cron_expression = "* * * * * 100" - expect = ("Invalid CRON expression: [%s] " - "is not acceptable, out of range") % cron_expression - self.assertFalse(self.constraint.validate(cron_expression, self.ctx)) - self.assertEqual(expect, - six.text_type(self.constraint._error_message)) - - def test_validation_columns_length_error(self): - cron_expression = "* *" - expect = ("Invalid CRON expression: Exactly 5 " - "or 6 columns has to be specified for " - "iteratorexpression.") - self.assertFalse(self.constraint.validate(cron_expression, self.ctx)) - self.assertEqual(expect, - six.text_type(self.constraint._error_message)) diff --git a/heat/tests/test_timezone.py b/heat/tests/test_timezone.py deleted file mode 100644 index f12be5b4ab..0000000000 --- a/heat/tests/test_timezone.py +++ /dev/null @@ -1,42 +0,0 @@ -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import six - -from heat.engine.constraint.common import timezone as tz -from heat.tests import common -from heat.tests import utils - - -class TimezoneConstraintTest(common.HeatTestCase): - - def setUp(self): - super(TimezoneConstraintTest, self).setUp() - self.ctx = utils.dummy_context() - self.constraint = tz.TimezoneConstraint() - - def test_validation(self): - self.assertTrue(self.constraint.validate("Asia/Taipei", self.ctx)) - - def test_validation_error(self): - timezone = "wrong_timezone" - expected = "Invalid timezone: '%s'" % timezone - - self.assertFalse(self.constraint.validate(timezone, self.ctx)) - self.assertEqual( - expected, - six.text_type(self.constraint._error_message) - ) - - def test_validation_none(self): - self.assertTrue(self.constraint.validate(None, self.ctx)) diff --git a/setup.cfg b/setup.cfg index 47ea253cca..0ae0687501 100644 --- a/setup.cfg +++ b/setup.cfg @@ -92,8 +92,8 @@ heat.constraints = manila.share_network = heat.engine.clients.os.manila:ManilaShareNetworkConstraint manila.share_type = heat.engine.clients.os.manila:ManilaShareTypeConstraint designate.domain = heat.engine.clients.os.designate:DesignateDomainConstraint - timezone = heat.engine.constraint.common.timezone:TimezoneConstraint - cron_expression = heat.engine.constraint.common.cron_expression:CRONExpressionConstraint + timezone = heat.engine.constraint.common_constraints:TimezoneConstraint + cron_expression = heat.engine.constraint.common_constraints:CRONExpressionConstraint heat.stack_lifecycle_plugins =