Merge "Add CIDR format validation"

This commit is contained in:
Jenkins 2015-05-15 17:40:44 +00:00 committed by Gerrit Code Review
commit f81cb5dbd1
9 changed files with 80 additions and 15 deletions

View File

@ -11,10 +11,8 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import netaddr
from oslo_log import log as logging from oslo_log import log as logging
from heat.common import exception
from heat.common.i18n import _ from heat.common.i18n import _
from heat.common.i18n import _LW from heat.common.i18n import _LW
from heat.engine import attributes from heat.engine import attributes
@ -79,7 +77,10 @@ class CloudNetwork(resource.Resource):
properties.Schema.STRING, properties.Schema.STRING,
_("The IP block from which to allocate the network. For example, " _("The IP block from which to allocate the network. For example, "
"172.16.0.0/24 or 2001:DB8::/64."), "172.16.0.0/24 or 2001:DB8::/64."),
required=True required=True,
constraints=[
constraints.CustomConstraint('net_cidr')
]
) )
} }
@ -154,10 +155,6 @@ class CloudNetwork(resource.Resource):
def validate(self): def validate(self):
super(CloudNetwork, self).validate() super(CloudNetwork, self).validate()
try:
netaddr.IPNetwork(self.properties[self.CIDR])
except netaddr.core.AddrFormatError:
raise exception.StackValidationFailed(message=_("Invalid cidr"))
def _resolve_attribute(self, name): def _resolve_attribute(self, name):
net = self.network() net = self.network()

View File

@ -116,12 +116,15 @@ class CloudNetworkTest(common.HeatTestCase):
self.assertEqual(expect_label, res.FnGetAtt('label')) self.assertEqual(expect_label, res.FnGetAtt('label'))
self.assertEqual(expect_cidr, res.FnGetAtt('cidr')) self.assertEqual(expect_cidr, res.FnGetAtt('cidr'))
def test_create_bad_cider(self, mock_client): def test_create_bad_cidr(self, mock_client):
self._template['resources']['cnw']['properties']['cidr'] = "bad cidr" prop = self._template['resources']['cnw']['properties']
prop['cidr'] = "bad cidr"
self._parse_stack() self._parse_stack()
exc = self.assertRaises(exception.StackValidationFailed, exc = self.assertRaises(exception.StackValidationFailed,
self.stack.validate) self.stack.validate)
self.assertIn("Invalid cidr", six.text_type(exc)) self.assertIn("Invalid net cidr", six.text_type(exc))
# reset property
prop['cidr'] = "172.16.0.0/24"
def test_check(self, mock_client): def test_check(self, mock_client):
self._setup_stack(mock_client) self._setup_stack(mock_client)

View File

@ -12,6 +12,7 @@
# under the License. # under the License.
import netaddr import netaddr
import six
from neutronclient.common import exceptions from neutronclient.common import exceptions
from neutronclient.neutron import v2_0 as neutronV20 from neutronclient.neutron import v2_0 as neutronV20
@ -189,3 +190,21 @@ class MACConstraint(constraints.BaseCustomConstraint):
def validate(self, value, context): def validate(self, value, context):
self._error_message = 'Invalid MAC address.' self._error_message = 'Invalid MAC address.'
return netaddr.valid_mac(value) return netaddr.valid_mac(value)
class CIDRConstraint(constraints.BaseCustomConstraint):
def _validate_whitespace(self, data):
self._error_message = ("Invalid net cidr '%s' contains "
"whitespace" % data)
if len(data.split()) > 1:
return False
return True
def validate(self, value, context):
try:
netaddr.IPNetwork(value)
return self._validate_whitespace(value)
except Exception as ex:
self._error_message = 'Invalid net cidr %s ' % six.text_type(ex)
return False

View File

@ -298,12 +298,18 @@ class FirewallRule(neutron.NeutronResource):
SOURCE_IP_ADDRESS: properties.Schema( SOURCE_IP_ADDRESS: properties.Schema(
properties.Schema.STRING, properties.Schema.STRING,
_('Source IP address or CIDR.'), _('Source IP address or CIDR.'),
update_allowed=True update_allowed=True,
constraints=[
constraints.CustomConstraint('net_cidr')
]
), ),
DESTINATION_IP_ADDRESS: properties.Schema( DESTINATION_IP_ADDRESS: properties.Schema(
properties.Schema.STRING, properties.Schema.STRING,
_('Destination IP address or CIDR.'), _('Destination IP address or CIDR.'),
update_allowed=True update_allowed=True,
constraints=[
constraints.CustomConstraint('net_cidr')
]
), ),
SOURCE_PORT: properties.Schema( SOURCE_PORT: properties.Schema(
properties.Schema.STRING, properties.Schema.STRING,

View File

@ -105,7 +105,10 @@ class SecurityGroup(neutron.NeutronResource):
RULE_REMOTE_IP_PREFIX: properties.Schema( RULE_REMOTE_IP_PREFIX: properties.Schema(
properties.Schema.STRING, properties.Schema.STRING,
_('The remote IP prefix (CIDR) to be associated with this ' _('The remote IP prefix (CIDR) to be associated with this '
'security group rule.') 'security group rule.'),
constraints=[
constraints.CustomConstraint('net_cidr')
]
), ),
} }

View File

@ -84,7 +84,10 @@ class Subnet(neutron.NeutronResource):
CIDR: properties.Schema( CIDR: properties.Schema(
properties.Schema.STRING, properties.Schema.STRING,
_('The CIDR.'), _('The CIDR.'),
required=True required=True,
constraints=[
constraints.CustomConstraint('net_cidr')
]
), ),
VALUE_SPECS: properties.Schema( VALUE_SPECS: properties.Schema(
properties.Schema.MAP, properties.Schema.MAP,

View File

@ -219,7 +219,13 @@ class IPsecSiteConnection(neutron.NeutronResource):
PEER_CIDRS: properties.Schema( PEER_CIDRS: properties.Schema(
properties.Schema.LIST, properties.Schema.LIST,
_('Remote subnet(s) in CIDR format.'), _('Remote subnet(s) in CIDR format.'),
required=True required=True,
schema=properties.Schema(
properties.Schema.STRING,
constraints=[
constraints.CustomConstraint('net_cidr')
]
)
), ),
MTU: properties.Schema( MTU: properties.Schema(
properties.Schema.INTEGER, properties.Schema.INTEGER,

View File

@ -254,3 +254,30 @@ class TestMACConstraint(common.HeatTestCase):
] ]
for mac in invalidate_format: for mac in invalidate_format:
self.assertFalse(self.constraint.validate(mac, None)) self.assertFalse(self.constraint.validate(mac, None))
class TestCIDRConstraint(common.HeatTestCase):
def setUp(self):
super(TestCIDRConstraint, self).setUp()
self.constraint = neutron.CIDRConstraint()
def test_valid_cidr_format(self):
validate_format = [
'10.0.0.0/24',
'6000::/64',
'8.8.8.8'
]
for cidr in validate_format:
self.assertTrue(self.constraint.validate(cidr, None))
def test_invalid_cidr_format(self):
invalidate_format = [
'::/129',
'Invalid cidr',
'300.0.0.0/24',
'10.0.0.0/33',
'8.8.8.0/ 24'
]
for cidr in invalidate_format:
self.assertFalse(self.constraint.validate(cidr, None))

View File

@ -75,6 +75,7 @@ heat.constraints =
trove.flavor = heat.engine.clients.os.trove:FlavorConstraint trove.flavor = heat.engine.clients.os.trove:FlavorConstraint
ip_addr = heat.engine.clients.os.neutron:IPConstraint ip_addr = heat.engine.clients.os.neutron:IPConstraint
mac_addr = heat.engine.clients.os.neutron:MACConstraint mac_addr = heat.engine.clients.os.neutron:MACConstraint
net_cidr = heat.engine.clients.os.neutron:CIDRConstraint
heat.stack_lifecycle_plugins = heat.stack_lifecycle_plugins =