Merge "Add address format check for property"
This commit is contained in:
commit
e27831cc95
@ -14,6 +14,7 @@
|
|||||||
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
|
||||||
from neutronclient.v2_0 import client as nc
|
from neutronclient.v2_0 import client as nc
|
||||||
|
from oslo_utils import netutils
|
||||||
from oslo_utils import uuidutils
|
from oslo_utils import uuidutils
|
||||||
|
|
||||||
from heat.common import exception
|
from heat.common import exception
|
||||||
@ -172,3 +173,10 @@ class SubnetConstraint(constraints.BaseCustomConstraint):
|
|||||||
neutron_client = client.client('neutron')
|
neutron_client = client.client('neutron')
|
||||||
neutronV20.find_resourceid_by_name_or_id(
|
neutronV20.find_resourceid_by_name_or_id(
|
||||||
neutron_client, 'subnet', value)
|
neutron_client, 'subnet', value)
|
||||||
|
|
||||||
|
|
||||||
|
class IPConstraint(constraints.BaseCustomConstraint):
|
||||||
|
|
||||||
|
def validate(self, value, context):
|
||||||
|
self._error_message = 'Invalid IP address'
|
||||||
|
return netutils.is_valid_ip(value)
|
||||||
|
@ -201,7 +201,10 @@ class ElasticIpAssociation(resource.Resource):
|
|||||||
EIP: properties.Schema(
|
EIP: properties.Schema(
|
||||||
properties.Schema.STRING,
|
properties.Schema.STRING,
|
||||||
_('EIP address to associate with instance.'),
|
_('EIP address to associate with instance.'),
|
||||||
update_allowed=True
|
update_allowed=True,
|
||||||
|
constraints=[
|
||||||
|
constraints.CustomConstraint('ip_addr')
|
||||||
|
]
|
||||||
),
|
),
|
||||||
ALLOCATION_ID: properties.Schema(
|
ALLOCATION_ID: properties.Schema(
|
||||||
properties.Schema.STRING,
|
properties.Schema.STRING,
|
||||||
|
@ -78,13 +78,19 @@ class FloatingIP(neutron.NeutronResource):
|
|||||||
FIXED_IP_ADDRESS: properties.Schema(
|
FIXED_IP_ADDRESS: properties.Schema(
|
||||||
properties.Schema.STRING,
|
properties.Schema.STRING,
|
||||||
_('IP address to use if the port has multiple addresses.'),
|
_('IP address to use if the port has multiple addresses.'),
|
||||||
update_allowed=True
|
update_allowed=True,
|
||||||
|
constraints=[
|
||||||
|
constraints.CustomConstraint('ip_addr')
|
||||||
|
]
|
||||||
),
|
),
|
||||||
FLOATING_IP_ADDRESS: properties.Schema(
|
FLOATING_IP_ADDRESS: properties.Schema(
|
||||||
properties.Schema.STRING,
|
properties.Schema.STRING,
|
||||||
_('IP address of the floating IP. NOTE: The default policy '
|
_('IP address of the floating IP. NOTE: The default policy '
|
||||||
'setting in Neutron restricts usage of this property to '
|
'setting in Neutron restricts usage of this property to '
|
||||||
'administrative users only.'),
|
'administrative users only.'),
|
||||||
|
constraints=[
|
||||||
|
constraints.CustomConstraint('ip_addr')
|
||||||
|
],
|
||||||
support_status=support.SupportStatus(version='2015.2'),
|
support_status=support.SupportStatus(version='2015.2'),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
@ -257,7 +263,10 @@ class FloatingIPAssociation(neutron.NeutronResource):
|
|||||||
FIXED_IP_ADDRESS: properties.Schema(
|
FIXED_IP_ADDRESS: properties.Schema(
|
||||||
properties.Schema.STRING,
|
properties.Schema.STRING,
|
||||||
_('IP address to use if the port has multiple addresses.'),
|
_('IP address to use if the port has multiple addresses.'),
|
||||||
update_allowed=True
|
update_allowed=True,
|
||||||
|
constraints=[
|
||||||
|
constraints.CustomConstraint('ip_addr')
|
||||||
|
]
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,7 +278,10 @@ class Pool(neutron.NeutronResource):
|
|||||||
),
|
),
|
||||||
VIP_ADDRESS: properties.Schema(
|
VIP_ADDRESS: properties.Schema(
|
||||||
properties.Schema.STRING,
|
properties.Schema.STRING,
|
||||||
_('IP address of the vip.')
|
_('IP address of the vip.'),
|
||||||
|
constraints=[
|
||||||
|
constraints.CustomConstraint('ip_addr')
|
||||||
|
]
|
||||||
),
|
),
|
||||||
VIP_CONNECTION_LIMIT: properties.Schema(
|
VIP_CONNECTION_LIMIT: properties.Schema(
|
||||||
properties.Schema.INTEGER,
|
properties.Schema.INTEGER,
|
||||||
@ -547,7 +550,10 @@ class PoolMember(neutron.NeutronResource):
|
|||||||
ADDRESS: properties.Schema(
|
ADDRESS: properties.Schema(
|
||||||
properties.Schema.STRING,
|
properties.Schema.STRING,
|
||||||
_('IP address of the pool member on the pool network.'),
|
_('IP address of the pool member on the pool network.'),
|
||||||
required=True
|
required=True,
|
||||||
|
constraints=[
|
||||||
|
constraints.CustomConstraint('ip_addr')
|
||||||
|
]
|
||||||
),
|
),
|
||||||
PROTOCOL_PORT: properties.Schema(
|
PROTOCOL_PORT: properties.Schema(
|
||||||
properties.Schema.INTEGER,
|
properties.Schema.INTEGER,
|
||||||
|
@ -132,7 +132,10 @@ class Port(neutron.NeutronResource):
|
|||||||
),
|
),
|
||||||
FIXED_IP_IP_ADDRESS: properties.Schema(
|
FIXED_IP_IP_ADDRESS: properties.Schema(
|
||||||
properties.Schema.STRING,
|
properties.Schema.STRING,
|
||||||
_('IP address desired in the subnet for this port.')
|
_('IP address desired in the subnet for this port.'),
|
||||||
|
constraints=[
|
||||||
|
constraints.CustomConstraint('ip_addr')
|
||||||
|
]
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -166,7 +169,10 @@ class Port(neutron.NeutronResource):
|
|||||||
ALLOWED_ADDRESS_PAIR_IP_ADDRESS: properties.Schema(
|
ALLOWED_ADDRESS_PAIR_IP_ADDRESS: properties.Schema(
|
||||||
properties.Schema.STRING,
|
properties.Schema.STRING,
|
||||||
_('IP address to allow through this port.'),
|
_('IP address to allow through this port.'),
|
||||||
required=True
|
required=True,
|
||||||
|
constraints=[
|
||||||
|
constraints.CustomConstraint('ip_addr')
|
||||||
|
]
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
@ -11,6 +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.
|
||||||
|
|
||||||
|
from oslo_utils import netutils
|
||||||
|
|
||||||
from heat.common import exception
|
from heat.common import exception
|
||||||
from heat.common.i18n import _
|
from heat.common.i18n import _
|
||||||
from heat.engine import attributes
|
from heat.engine import attributes
|
||||||
@ -130,11 +132,17 @@ class Subnet(neutron.NeutronResource):
|
|||||||
schema={
|
schema={
|
||||||
ALLOCATION_POOL_START: properties.Schema(
|
ALLOCATION_POOL_START: properties.Schema(
|
||||||
properties.Schema.STRING,
|
properties.Schema.STRING,
|
||||||
required=True
|
required=True,
|
||||||
|
constraints=[
|
||||||
|
constraints.CustomConstraint('ip_addr')
|
||||||
|
]
|
||||||
),
|
),
|
||||||
ALLOCATION_POOL_END: properties.Schema(
|
ALLOCATION_POOL_END: properties.Schema(
|
||||||
properties.Schema.STRING,
|
properties.Schema.STRING,
|
||||||
required=True
|
required=True,
|
||||||
|
constraints=[
|
||||||
|
constraints.CustomConstraint('ip_addr')
|
||||||
|
]
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@ -155,7 +163,10 @@ class Subnet(neutron.NeutronResource):
|
|||||||
),
|
),
|
||||||
ROUTE_NEXTHOP: properties.Schema(
|
ROUTE_NEXTHOP: properties.Schema(
|
||||||
properties.Schema.STRING,
|
properties.Schema.STRING,
|
||||||
required=True
|
required=True,
|
||||||
|
constraints=[
|
||||||
|
constraints.CustomConstraint('ip_addr')
|
||||||
|
]
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -247,6 +258,13 @@ class Subnet(neutron.NeutronResource):
|
|||||||
'they must be equal.')
|
'they must be equal.')
|
||||||
raise exception.StackValidationFailed(message=msg)
|
raise exception.StackValidationFailed(message=msg)
|
||||||
|
|
||||||
|
gateway_ip = self.properties.get(self.GATEWAY_IP)
|
||||||
|
if (gateway_ip and gateway_ip not in ['~', ''] and
|
||||||
|
not netutils.is_valid_ip(gateway_ip)):
|
||||||
|
msg = (_('Gateway IP address "%(gateway)" is in '
|
||||||
|
'invalid format.'), gateway_ip)
|
||||||
|
raise exception.StackValidationFailed(message=msg)
|
||||||
|
|
||||||
def handle_create(self):
|
def handle_create(self):
|
||||||
props = self.prepare_properties(
|
props = self.prepare_properties(
|
||||||
self.properties,
|
self.properties,
|
||||||
|
@ -339,7 +339,10 @@ class Server(stack_user.StackUser):
|
|||||||
NETWORK_FIXED_IP: properties.Schema(
|
NETWORK_FIXED_IP: properties.Schema(
|
||||||
properties.Schema.STRING,
|
properties.Schema.STRING,
|
||||||
_('Fixed IP address to specify for the port '
|
_('Fixed IP address to specify for the port '
|
||||||
'created on the requested network.')
|
'created on the requested network.'),
|
||||||
|
constraints=[
|
||||||
|
constraints.CustomConstraint('ip_addr')
|
||||||
|
]
|
||||||
),
|
),
|
||||||
NETWORK_PORT: properties.Schema(
|
NETWORK_PORT: properties.Schema(
|
||||||
properties.Schema.STRING,
|
properties.Schema.STRING,
|
||||||
|
@ -149,7 +149,10 @@ class OSDBInstance(resource.Resource):
|
|||||||
),
|
),
|
||||||
V4_FIXED_IP: properties.Schema(
|
V4_FIXED_IP: properties.Schema(
|
||||||
properties.Schema.STRING,
|
properties.Schema.STRING,
|
||||||
_('Fixed IPv4 address for this NIC.')
|
_('Fixed IPv4 address for this NIC.'),
|
||||||
|
constraints=[
|
||||||
|
constraints.CustomConstraint('ip_addr')
|
||||||
|
]
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -182,3 +182,50 @@ class NeutronConstraintsValidate(common.HeatTestCase):
|
|||||||
self.assertFalse(constraint.validate("bar", ctx))
|
self.assertFalse(constraint.validate("bar", ctx))
|
||||||
mock_find.assert_has_calls([mock.call(nc, self.resource_type, 'foo'),
|
mock_find.assert_has_calls([mock.call(nc, self.resource_type, 'foo'),
|
||||||
mock.call(nc, self.resource_type, 'bar')])
|
mock.call(nc, self.resource_type, 'bar')])
|
||||||
|
|
||||||
|
|
||||||
|
class TestIPConstraint(common.HeatTestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestIPConstraint, self).setUp()
|
||||||
|
self.constraint = neutron.IPConstraint()
|
||||||
|
|
||||||
|
def test_validate_ipv4_format(self):
|
||||||
|
validate_format = [
|
||||||
|
'1.1.1.1',
|
||||||
|
'1.0.1.1',
|
||||||
|
'255.255.255.255'
|
||||||
|
]
|
||||||
|
for ip in validate_format:
|
||||||
|
self.assertTrue(self.constraint.validate(ip, None))
|
||||||
|
|
||||||
|
def test_invalidate_ipv4_format(self):
|
||||||
|
invalidate_format = [
|
||||||
|
'1.1.1.',
|
||||||
|
'1.1.1.256',
|
||||||
|
'invalidate format',
|
||||||
|
'1.a.1.1'
|
||||||
|
]
|
||||||
|
for ip in invalidate_format:
|
||||||
|
self.assertFalse(self.constraint.validate(ip, None))
|
||||||
|
|
||||||
|
def test_validate_ipv6_format(self):
|
||||||
|
validate_format = [
|
||||||
|
'2002:2002::20c:29ff:fe7d:811a',
|
||||||
|
'::1',
|
||||||
|
'2002::',
|
||||||
|
'2002::1',
|
||||||
|
]
|
||||||
|
for ip in validate_format:
|
||||||
|
self.assertTrue(self.constraint.validate(ip, None))
|
||||||
|
|
||||||
|
def test_invalidate_ipv6_format(self):
|
||||||
|
invalidate_format = [
|
||||||
|
'2002::2001::1',
|
||||||
|
'2002::g',
|
||||||
|
'invalidate format',
|
||||||
|
'2001::0::',
|
||||||
|
'20c:29ff:fe7d:811a'
|
||||||
|
]
|
||||||
|
for ip in invalidate_format:
|
||||||
|
self.assertFalse(self.constraint.validate(ip, None))
|
||||||
|
@ -73,6 +73,7 @@ heat.constraints =
|
|||||||
cinder.vtype = heat.engine.clients.os.cinder:VolumeTypeConstraint
|
cinder.vtype = heat.engine.clients.os.cinder:VolumeTypeConstraint
|
||||||
sahara.image = heat.engine.clients.os.sahara:ImageConstraint
|
sahara.image = heat.engine.clients.os.sahara:ImageConstraint
|
||||||
trove.flavor = heat.engine.clients.os.trove:FlavorConstraint
|
trove.flavor = heat.engine.clients.os.trove:FlavorConstraint
|
||||||
|
ip_addr = heat.engine.clients.os.neutron:IPConstraint
|
||||||
|
|
||||||
heat.stack_lifecycle_plugins =
|
heat.stack_lifecycle_plugins =
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user