From d0b3d5f7757e937c1688284071072c65f8ba6222 Mon Sep 17 00:00:00 2001
From: Gareth Rushgrove <gareth@morethanseven.net>
Date: Wed, 18 Mar 2015 11:32:43 +0000
Subject: [PATCH] Add validation of types for properties

---
 lib/puppet/type/cloudwatch_alarm.rb           | 14 ++++++++-
 lib/puppet/type/ec2_autoscalinggroup.rb       | 10 ++++--
 lib/puppet/type/ec2_elastic_ip.rb             |  2 ++
 lib/puppet/type/ec2_instance.rb               | 14 +++++++++
 lib/puppet/type/ec2_launchconfiguration.rb    | 13 +++++++-
 lib/puppet/type/ec2_scalingpolicy.rb          | 10 ++++--
 lib/puppet/type/ec2_securitygroup.rb          | 16 ++++++++--
 lib/puppet/type/ec2_vpc.rb                    |  5 +++
 lib/puppet/type/ec2_vpc_customer_gateway.rb   |  2 ++
 lib/puppet/type/ec2_vpc_dhcp_options.rb       | 11 +++++++
 lib/puppet/type/ec2_vpc_internet_gateway.rb   |  5 +++
 lib/puppet/type/ec2_vpc_routetable.rb         |  5 +++
 lib/puppet/type/ec2_vpc_subnet.rb             | 14 +++++++++
 lib/puppet/type/ec2_vpc_vpn.rb                | 11 +++++++
 lib/puppet/type/ec2_vpc_vpn_gateway.rb        |  8 +++++
 lib/puppet/type/elb_loadbalancer.rb           | 11 +++++++
 lib/puppet_x/puppetlabs/property/tag.rb       |  4 +++
 spec/spec_helper.rb                           | 26 ++++++++++++++++
 spec/unit/type/cloudwatch_alarm_spec.rb       | 17 ++++++++++
 spec/unit/type/ec2_autoscalinggroup_spec.rb   | 12 +++++++
 spec/unit/type/ec2_instance_spec.rb           | 17 ++++++++++
 .../unit/type/ec2_launchconfiguration_spec.rb | 14 +++++++++
 spec/unit/type/ec2_scalingpolicy_spec.rb      | 10 ++++++
 spec/unit/type/ec2_securitygroup_spec.rb      | 31 +++++++++++++++++++
 .../type/ec2_vpc_customer_gateway_spec.rb     | 13 ++++++++
 spec/unit/type/ec2_vpc_dhcp_options_spec.rb   | 15 +++++++++
 .../type/ec2_vpc_internet_gateway_spec.rb     | 14 +++++++++
 spec/unit/type/ec2_vpc_routetable_spec.rb     | 14 +++++++++
 spec/unit/type/ec2_vpc_spec.rb                | 14 +++++++++
 spec/unit/type/ec2_vpc_subnet_spec.rb         | 17 ++++++++++
 spec/unit/type/ec2_vpc_vpn_gateway_spec.rb    | 15 +++++++++
 spec/unit/type/ec2_vpc_vpn_spec.rb            | 16 ++++++++++
 spec/unit/type/elb_loadbalancer_spec.rb       | 15 +++++++++
 33 files changed, 405 insertions(+), 10 deletions(-)

diff --git a/lib/puppet/type/cloudwatch_alarm.rb b/lib/puppet/type/cloudwatch_alarm.rb
index dc883843..ee358e2c 100644
--- a/lib/puppet/type/cloudwatch_alarm.rb
+++ b/lib/puppet/type/cloudwatch_alarm.rb
@@ -7,6 +7,7 @@
     desc 'The name of the alarm.'
     validate do |value|
       fail 'alarms must have a name' if value == ''
+      fail 'Name should be a String' unless value.is_a?(String)
     end
   end
 
@@ -14,6 +15,7 @@
     desc 'The name of the metric to track.'
     validate do |value|
       fail 'metric must not be blank' if value == ''
+      fail 'metric should be a String' unless value.is_a?(String)
     end
   end
 
@@ -21,6 +23,7 @@
     desc 'The namespace of the metric to track.'
     validate do |value|
       fail 'namespace must not be blank' if value == ''
+      fail 'namespace should be a String' unless value.is_a?(String)
     end
   end
 
@@ -28,6 +31,7 @@
     desc 'The statistic to track for the metric.'
     validate do |value|
       fail 'statistic must not be blank' if value == ''
+      fail 'statistic should be a String' unless value.is_a?(String)
     end
   end
 
@@ -64,7 +68,8 @@
   newproperty(:comparison_operator) do
     desc 'The operator to use to test the metric.'
     validate do |value|
-      fail 'comparison operator must not be blank' if value == ''
+      fail 'comparison_operator must not be blank' if value == ''
+      fail 'comparison_operator should be a String' unless value.is_a?(String)
     end
   end
 
@@ -73,6 +78,7 @@
     validate do |value|
       fail 'region should not contain spaces' if value =~ /\s/
       fail 'region should not be blank' if value == ''
+      fail 'region should be a String' unless value.is_a?(String)
     end
   end
 
@@ -81,10 +87,16 @@
     def insync?(is)
       is.to_set == should.to_set
     end
+    validate do |value|
+      fail 'dimensions should be a Hash' unless value.is_a?(Hash)
+    end
   end
 
   newproperty(:alarm_actions, :array_matching => :all) do
     desc 'The actions to trigger when the alarm triggers.'
+    validate do |value|
+      fail 'alarm_actions should be a String' unless value.is_a?(String)
+    end
   end
 
   autorequire(:ec2_scalingpolicy) do
diff --git a/lib/puppet/type/ec2_autoscalinggroup.rb b/lib/puppet/type/ec2_autoscalinggroup.rb
index b048fdf0..5983c964 100644
--- a/lib/puppet/type/ec2_autoscalinggroup.rb
+++ b/lib/puppet/type/ec2_autoscalinggroup.rb
@@ -7,6 +7,7 @@
     desc 'The name of the auto scaling group.'
     validate do |value|
       fail 'Auto scaling groups must have a name' if value == ''
+      fail 'name should be a String' unless value.is_a?(String)
     end
   end
 
@@ -35,13 +36,15 @@
     validate do |value|
       fail 'region should not contain spaces' if value =~ /\s/
       fail 'region should not be blank' if value == ''
+      fail 'region should be a String' unless value.is_a?(String)
     end
   end
 
   newproperty(:launch_configuration) do
     desc 'The launch configuration to use for the group.'
     validate do |value|
-      fail 'launch configuration cannot be blank' if value == ''
+      fail 'launch_configuration cannot be blank' if value == ''
+      fail 'launch_configuration should be a String' unless value.is_a?(String)
     end
   end
 
@@ -55,7 +58,7 @@
   newproperty(:availability_zones, :array_matching => :all) do
     desc 'The availability zones in which to launch the instances.'
     validate do |value|
-      fail 'must provide a list of availability zones' if value.empty?
+      fail 'availability_zones should be a String' unless value.is_a?(String)
     end
     def insync?(is)
       is.to_set == should.to_set
@@ -64,6 +67,9 @@ def insync?(is)
 
   newproperty(:subnets, :array_matching => :all) do
     desc 'The subnets to associate the autoscaling group.'
+    validate do |value|
+      fail 'subnets should be a String' unless value.is_a?(String)
+    end
     def insync?(is)
       is.to_set == should.to_set
     end
diff --git a/lib/puppet/type/ec2_elastic_ip.rb b/lib/puppet/type/ec2_elastic_ip.rb
index 48e3358c..15c022d5 100644
--- a/lib/puppet/type/ec2_elastic_ip.rb
+++ b/lib/puppet/type/ec2_elastic_ip.rb
@@ -22,6 +22,7 @@
   newproperty(:region) do
     desc 'The name of the region in which the Elastic IP is found.'
     validate do |value|
+      fail 'region should be a String' unless value.is_a?(String)
       fail 'You must provide a region for Elastic IPs.' if value.nil? || value.empty?
     end
   end
@@ -29,6 +30,7 @@
   newproperty(:instance) do
     desc 'The name of the instance associated with the Elastic IP.'
     validate do |value|
+      fail 'instance should be a String' unless value.is_a?(String)
       fail 'You must provide an instance for the Elastic IP association' if value.nil? || value.empty?
     end
   end
diff --git a/lib/puppet/type/ec2_instance.rb b/lib/puppet/type/ec2_instance.rb
index f49f32a9..2d9c9259 100644
--- a/lib/puppet/type/ec2_instance.rb
+++ b/lib/puppet/type/ec2_instance.rb
@@ -32,6 +32,7 @@ def insync?(is)
     desc 'The name of the instance.'
     validate do |value|
       fail 'Instances must have a name' if value == ''
+      fail 'name should be a String' unless value.is_a?(String)
     end
   end
 
@@ -40,6 +41,9 @@ def insync?(is)
     def insync?(is)
       is.to_set == should.to_set
     end
+    validate do |value|
+      fail 'security_groups should be a String' unless value.is_a?(String)
+    end
   end
 
   newproperty(:tags, :parent => PuppetX::Property::AwsTag) do
@@ -52,6 +56,9 @@ def insync?(is)
 
   newproperty(:key_name) do
     desc 'The name of the key pair associated with this instance.'
+    validate do |value|
+      fail 'key_name should be a String' unless value.is_a?(String)
+    end
   end
 
   newproperty(:monitoring) do
@@ -67,6 +74,7 @@ def insync?(is)
     desc 'The region in which to launch the instance.'
     validate do |value|
       fail 'region should not contain spaces' if value =~ /\s/
+      fail 'region should be a String' unless value.is_a?(String)
     end
   end
 
@@ -75,6 +83,7 @@ def insync?(is)
     validate do |value|
       fail 'image_id should not contain spaces' if value =~ /\s/
       fail 'image_id should not be blank' if value == ''
+      fail 'image_id should be a String' unless value.is_a?(String)
     end
   end
 
@@ -83,6 +92,7 @@ def insync?(is)
     validate do |value|
       fail 'availability_zone should not contain spaces' if value =~ /\s/
       fail 'availability_zone should not be blank' if value == ''
+      fail 'availability_zone should be a String' unless value.is_a?(String)
     end
   end
 
@@ -91,6 +101,7 @@ def insync?(is)
     validate do |value|
       fail 'instance type should not contains spaces' if value =~ /\s/
       fail 'instance_type should not be blank' if value == ''
+      fail 'instance_type should be a String' unless value.is_a?(String)
     end
   end
 
@@ -145,6 +156,9 @@ def insync?(is)
 
   newproperty(:subnet) do
     desc 'The VPC subnet to attach the instance to.'
+    validate do |value|
+      fail 'subnet should be a String' unless value.is_a?(String)
+    end
   end
 
   newproperty(:ebs_optimized) do
diff --git a/lib/puppet/type/ec2_launchconfiguration.rb b/lib/puppet/type/ec2_launchconfiguration.rb
index bced674b..1133ae9c 100644
--- a/lib/puppet/type/ec2_launchconfiguration.rb
+++ b/lib/puppet/type/ec2_launchconfiguration.rb
@@ -7,13 +7,15 @@
     desc 'The name of the launch configuration.'
     validate do |value|
       fail 'launch configurations must have a name' if value == ''
+      fail 'name should be a String' unless value.is_a?(String)
     end
   end
 
   newproperty(:security_groups, :array_matching => :all) do
     desc 'The security groups to associate with the instances.'
     validate do |value|
-      fail 'you must specifiy security groups for the launch configuration' if value.empty?
+      fail 'security_groups should be a String' unless value.is_a?(String)
+      fail 'you must specify security groups for the launch configuration' if value.empty?
     end
     def insync?(is)
       is.to_set == should.to_set
@@ -26,6 +28,9 @@ def insync?(is)
 
   newproperty(:key_name) do
     desc 'The name of the key pair associated with this instance.'
+    validate do |value|
+      fail 'key_name should be a String' unless value.is_a?(String)
+    end
   end
 
   newproperty(:region) do
@@ -33,6 +38,7 @@ def insync?(is)
     validate do |value|
       fail 'region should not contain spaces' if value =~ /\s/
       fail 'region should not be blank' if value == ''
+      fail 'region should be a String' unless value.is_a?(String)
     end
   end
 
@@ -41,6 +47,7 @@ def insync?(is)
     validate do |value|
       fail 'instance_type should not contains spaces' if value =~ /\s/
       fail 'instance_type should not be blank' if value == ''
+      fail 'instance_type should be a String' unless value.is_a?(String)
     end
   end
 
@@ -49,11 +56,15 @@ def insync?(is)
     validate do |value|
       fail 'image_id should not contain spaces' if value =~ /\s/
       fail 'image_id should not be blank' if value == ''
+      fail 'image_id should be a String' unless value.is_a?(String)
     end
   end
 
   newparam(:vpc) do
     desc 'A hint to specify the VPC, useful when detecting ambiguously named security groups like default.'
+    validate do |value|
+      fail 'vpc should be a String' unless value.is_a?(String)
+    end
   end
 
   autorequire(:ec2_securitygroup) do
diff --git a/lib/puppet/type/ec2_scalingpolicy.rb b/lib/puppet/type/ec2_scalingpolicy.rb
index e8e73691..99698cb9 100644
--- a/lib/puppet/type/ec2_scalingpolicy.rb
+++ b/lib/puppet/type/ec2_scalingpolicy.rb
@@ -7,6 +7,7 @@
     desc 'The name of the scaling policy.'
     validate do |value|
       fail 'Scaling policies must have a name' if value == ''
+      fail 'name should be a String' unless value.is_a?(String)
     end
   end
 
@@ -25,21 +26,24 @@
     validate do |value|
       fail 'region should not contain spaces' if value =~ /\s/
       fail 'region should not be blank' if value == ''
+      fail 'region should be a String' unless value.is_a?(String)
     end
   end
 
   newproperty(:adjustment_type) do
     desc 'The type of policy.'
     validate do |value|
-      fail 'adjustment type should not contain spaces' if value =~ /\s/
-      fail 'adjustment type should not be blank' if value == ''
+      fail 'adjustment_type should not contain spaces' if value =~ /\s/
+      fail 'adjustment_type should not be blank' if value == ''
+      fail 'adjustment_type should be a String' unless value.is_a?(String)
     end
   end
 
   newproperty(:auto_scaling_group) do
     desc 'The auto scaling group to attach the policy to.'
     validate do |value|
-      fail 'auto scaling group cannot be blank' if value == ''
+      fail 'auto_scaling_group cannot be blank' if value == ''
+      fail 'auto_scaling_group should be a String' unless value.is_a?(String)
     end
   end
 
diff --git a/lib/puppet/type/ec2_securitygroup.rb b/lib/puppet/type/ec2_securitygroup.rb
index 5e499410..74014975 100644
--- a/lib/puppet/type/ec2_securitygroup.rb
+++ b/lib/puppet/type/ec2_securitygroup.rb
@@ -9,14 +9,16 @@
   newparam(:name, namevar: true) do
     desc 'the name of the security group'
     validate do |value|
-      fail 'Security groups must have a name' if value == ''
+      fail 'security groups must have a name' if value == ''
+      fail 'name should be a String' unless value.is_a?(String)
     end
   end
 
   newproperty(:region) do
     desc 'the region in which to launch the security group'
     validate do |value|
-      fail 'region should not contains spaces' if value =~ /\s/
+      fail 'region should not contain spaces' if value =~ /\s/
+      fail 'region should be a String' unless value.is_a?(String)
     end
   end
 
@@ -29,6 +31,10 @@ def insync?(is)
       to_delete = parser.rules_to_delete(is)
       to_create.empty? && to_delete.empty?
     end
+
+    validate do |value|
+      fail 'ingress should be a Hash' unless value.is_a?(Hash)
+    end
   end
 
   newproperty(:tags, :parent => PuppetX::Property::AwsTag) do
@@ -38,12 +44,16 @@ def insync?(is)
   newproperty(:description) do
     desc 'a short description of the group'
     validate do |value|
-      fail  'description cannot be blank' if value == ''
+      fail 'description cannot be blank' if value == ''
+      fail 'description should be a String' unless value.is_a?(String)
     end
   end
 
   newproperty(:vpc) do
     desc 'A VPC to which the group should be associated'
+    validate do |value|
+      fail 'vpc should be a String' unless value.is_a?(String)
+    end
   end
 
   def should_autorequire?(rule)
diff --git a/lib/puppet/type/ec2_vpc.rb b/lib/puppet/type/ec2_vpc.rb
index cd920032..81e09189 100644
--- a/lib/puppet/type/ec2_vpc.rb
+++ b/lib/puppet/type/ec2_vpc.rb
@@ -9,6 +9,7 @@
     desc 'The name of the VPC.'
     validate do |value|
       fail 'a VPC must have a name' if value == ''
+      fail 'name should be a String' unless value.is_a?(String)
     end
   end
 
@@ -16,6 +17,7 @@
     desc 'The region in which to launch the VPC.'
     validate do |value|
       fail 'region should not contain spaces' if value =~ /\s/
+      fail 'region should be a String' unless value.is_a?(String)
     end
   end
 
@@ -25,6 +27,9 @@
 
   newproperty(:dhcp_options) do
     desc 'The DHCP option set to use for this VPC.'
+    validate do |value|
+      fail 'dhcp_options should be a String' unless value.is_a?(String)
+    end
   end
 
   newproperty(:instance_tenancy) do
diff --git a/lib/puppet/type/ec2_vpc_customer_gateway.rb b/lib/puppet/type/ec2_vpc_customer_gateway.rb
index c5e67f7d..f5badd64 100644
--- a/lib/puppet/type/ec2_vpc_customer_gateway.rb
+++ b/lib/puppet/type/ec2_vpc_customer_gateway.rb
@@ -9,6 +9,7 @@
     desc 'The name of the customer gateway.'
     validate do |value|
       fail 'customer gateways must have a name' if value == ''
+      fail 'name should be a String' unless value.is_a?(String)
     end
   end
 
@@ -34,6 +35,7 @@
     desc 'The region in which to launch the customer gateway.'
     validate do |value|
       fail 'region should not contain spaces' if value =~ /\s/
+      fail 'region should be a String' unless value.is_a?(String)
     end
   end
 
diff --git a/lib/puppet/type/ec2_vpc_dhcp_options.rb b/lib/puppet/type/ec2_vpc_dhcp_options.rb
index be120453..e1305634 100644
--- a/lib/puppet/type/ec2_vpc_dhcp_options.rb
+++ b/lib/puppet/type/ec2_vpc_dhcp_options.rb
@@ -9,6 +9,7 @@
     desc 'The name of the DHCP options set.'
     validate do |value|
       fail 'DHCP option sets must have a name' if value == ''
+      fail 'name should be a String' unless value.is_a?(String)
     end
   end
 
@@ -20,6 +21,7 @@
     desc 'The region in which to assign the DHCP option set.'
     validate do |value|
       fail 'region should not contain spaces' if value =~ /\s/
+      fail 'region should be a String' unless value.is_a?(String)
     end
   end
 
@@ -37,6 +39,9 @@ def insync?(is)
 
   newproperty(:domain_name_servers, :array_matching => :all) do
     desc 'A list of domain name servers to use for the DHCP options set.'
+    validate do |value|
+      fail 'domain_name_servers should be a String' unless value.is_a?(String)
+    end
     def insync?(is)
       is.to_set == should.to_set
     end
@@ -44,6 +49,9 @@ def insync?(is)
 
   newproperty(:ntp_servers, :array_matching => :all) do
     desc 'A list of NTP servers to use for the DHCP options set.'
+    validate do |value|
+      fail 'ntp_servers should be a String' unless value.is_a?(String)
+    end
     def insync?(is)
       is.to_set == should.to_set
     end
@@ -51,6 +59,9 @@ def insync?(is)
 
   newproperty(:netbios_name_servers, :array_matching => :all) do
     desc 'A list of netbios name servers to use for the DHCP options set.'
+    validate do |value|
+      fail 'netbios_name_servers should be a String' unless value.is_a?(String)
+    end
     def insync?(is)
       is.to_set == should.to_set
     end
diff --git a/lib/puppet/type/ec2_vpc_internet_gateway.rb b/lib/puppet/type/ec2_vpc_internet_gateway.rb
index 96df75ee..1607b57f 100644
--- a/lib/puppet/type/ec2_vpc_internet_gateway.rb
+++ b/lib/puppet/type/ec2_vpc_internet_gateway.rb
@@ -7,6 +7,7 @@
     desc 'The name of the internet gateway.'
     validate do |value|
       fail 'Empty values are not allowed' if value == ''
+      fail 'name should be a String' unless value.is_a?(String)
     end
   end
 
@@ -20,11 +21,15 @@
     desc 'The region in which to launch the internet gateway.'
     validate do |value|
       fail 'region should not contain spaces' if value =~ /\s/
+      fail 'region should be a String' unless value.is_a?(String)
     end
   end
 
   newproperty(:vpc) do
     desc 'The vpc to assign this internet gateway to.'
+    validate do |value|
+      fail 'vpc should be a String' unless value.is_a?(String)
+    end
   end
 
   autorequire(:ec2_vpc) do
diff --git a/lib/puppet/type/ec2_vpc_routetable.rb b/lib/puppet/type/ec2_vpc_routetable.rb
index 33c075a5..c37f0684 100644
--- a/lib/puppet/type/ec2_vpc_routetable.rb
+++ b/lib/puppet/type/ec2_vpc_routetable.rb
@@ -9,17 +9,22 @@
     desc 'The name of the route table.'
     validate do |value|
       fail 'route tables must have a name' if value == ''
+      fail 'name should be a String' unless value.is_a?(String)
     end
   end
 
   newproperty(:vpc) do
     desc 'VPC to assign the route table to.'
+    validate do |value|
+      fail 'vpc should be a String' unless value.is_a?(String)
+    end
   end
 
   newproperty(:region) do
     desc 'Region in which to launch the route table.'
     validate do |value|
       fail 'region should not contain spaces' if value =~ /\s/
+      fail 'region should be a String' unless value.is_a?(String)
     end
   end
 
diff --git a/lib/puppet/type/ec2_vpc_subnet.rb b/lib/puppet/type/ec2_vpc_subnet.rb
index 3e33b36c..1631d11f 100644
--- a/lib/puppet/type/ec2_vpc_subnet.rb
+++ b/lib/puppet/type/ec2_vpc_subnet.rb
@@ -9,26 +9,37 @@
     desc 'The name of the subnet.'
     validate do |value|
       fail 'subnets must have a name' if value == ''
+      fail 'name should be a String' unless value.is_a?(String)
     end
   end
 
   newproperty(:vpc) do
     desc 'The VPC to attach the subnet to.'
+    validate do |value|
+      fail 'vpc should be a String' unless value.is_a?(String)
+    end
   end
 
   newproperty(:region) do
     desc 'The region in which to launch the subnet.'
     validate do |value|
       fail 'region should not contain spaces' if value =~ /\s/
+      fail 'region should be a String' unless value.is_a?(String)
     end
   end
 
   newproperty(:cidr_block) do
     desc 'The IP address range for the subnet.'
+    validate do |value|
+      fail 'cidr_block should be a String' unless value.is_a?(String)
+    end
   end
 
   newproperty(:availability_zone) do
     desc 'The availability zone in which to launch the subnet.'
+    validate do |value|
+      fail 'availability_zone should be a String' unless value.is_a?(String)
+    end
   end
 
   newproperty(:tags, :parent => PuppetX::Property::AwsTag) do
@@ -37,6 +48,9 @@
 
   newproperty(:route_table) do
     desc 'The route table to attach to the subnet.'
+    validate do |value|
+      fail 'route_table should be a String' unless value.is_a?(String)
+    end
   end
 
   autorequire(:ec2_vpc) do
diff --git a/lib/puppet/type/ec2_vpc_vpn.rb b/lib/puppet/type/ec2_vpc_vpn.rb
index ae5f489d..fbdb5a47 100644
--- a/lib/puppet/type/ec2_vpc_vpn.rb
+++ b/lib/puppet/type/ec2_vpc_vpn.rb
@@ -9,15 +9,22 @@
     desc 'The name of the VPN.'
     validate do |value|
       fail 'VPNs must have a name' if value == ''
+      fail 'name should be a String' unless value.is_a?(String)
     end
   end
 
   newproperty(:vpn_gateway) do
     desc 'The VPN gateway to attach to the VPN.'
+    validate do |value|
+      fail 'vpn_gateway should be a String' unless value.is_a?(String)
+    end
   end
 
   newproperty(:customer_gateway) do
     desc 'The customer gateway to attach to the VPN.'
+    validate do |value|
+      fail 'customer_gateway should be a String' unless value.is_a?(String)
+    end
   end
 
   newproperty(:type) do
@@ -32,6 +39,9 @@
 
   newproperty(:routes, :array_matching => :all) do
     desc 'The list of routes for the VPN.'
+    validate do |value|
+      fail 'routes should be a String' unless value.is_a?(String)
+    end
   end
 
   newproperty(:static_routes) do
@@ -47,6 +57,7 @@ def insync?(is)
     desc 'The region in which to launch the VPN.'
     validate do |value|
       fail 'region should not contain spaces' if value =~ /\s/
+      fail 'region should be a String' unless value.is_a?(String)
     end
   end
 
diff --git a/lib/puppet/type/ec2_vpc_vpn_gateway.rb b/lib/puppet/type/ec2_vpc_vpn_gateway.rb
index bb29e821..d0276125 100644
--- a/lib/puppet/type/ec2_vpc_vpn_gateway.rb
+++ b/lib/puppet/type/ec2_vpc_vpn_gateway.rb
@@ -9,6 +9,7 @@
     desc 'The name of the VPN gateway.'
     validate do |value|
       fail 'VPN gateways must have a name' if value == ''
+      fail 'name should be a String' unless value.is_a?(String)
     end
   end
 
@@ -18,17 +19,24 @@
 
   newproperty(:vpc) do
     desc 'The VPN to attach the VPN gateway to.'
+    validate do |value|
+      fail 'vpc should be a String' unless value.is_a?(String)
+    end
   end
 
   newproperty(:region) do
     desc 'The region in which to launch the VPN gateway.'
     validate do |value|
       fail 'region should not contain spaces' if value =~ /\s/
+      fail 'region should be a String' unless value.is_a?(String)
     end
   end
 
   newparam(:availability_zone) do
     desc 'The availability zone in which to launch the VPN gateway.'
+    validate do |value|
+      fail 'availability_zone should be a String' unless value.is_a?(String)
+    end
   end
 
   newproperty(:type) do
diff --git a/lib/puppet/type/elb_loadbalancer.rb b/lib/puppet/type/elb_loadbalancer.rb
index 37c50e81..17ae30ec 100644
--- a/lib/puppet/type/elb_loadbalancer.rb
+++ b/lib/puppet/type/elb_loadbalancer.rb
@@ -9,6 +9,7 @@
     desc 'The name of the load balancer.'
     validate do |value|
       fail 'Load Balancers must have a name' if value == ''
+      fail 'name should be a String' unless value.is_a?(String)
     end
   end
 
@@ -16,6 +17,7 @@
     desc 'The region in which to launch the load balancer.'
     validate do |value|
       fail 'region must not contain spaces' if value =~ /\s/
+      fail 'region should be a String' unless value.is_a?(String)
     end
   end
 
@@ -47,6 +49,9 @@ def normalise(listeners)
   newproperty(:subnets, :array_matching => :all) do
     defaultto []
     desc 'The region in which to launch the load balancer.'
+    validate do |value|
+      fail 'subnets should be a String' unless value.is_a?(String)
+    end
     def insync?(is)
       is.to_set == should.to_set
     end
@@ -54,6 +59,9 @@ def insync?(is)
 
   newproperty(:security_groups, :array_matching => :all) do
     desc 'The security groups to associate the load balancer (VPC only).'
+    validate do |value|
+      fail 'security_groups should be a String' unless value.is_a?(String)
+    end
     def insync?(is)
       is.to_set == should.to_set
     end
@@ -66,6 +74,9 @@ def insync?(is)
 
   newproperty(:instances, :array_matching => :all) do
     desc 'The instances to associate with the load balancer.'
+    validate do |value|
+      fail 'instances should be a String' unless value.is_a?(String)
+    end
   end
 
   newproperty(:scheme) do
diff --git a/lib/puppet_x/puppetlabs/property/tag.rb b/lib/puppet_x/puppetlabs/property/tag.rb
index 6f491807..af759df3 100644
--- a/lib/puppet_x/puppetlabs/property/tag.rb
+++ b/lib/puppet_x/puppetlabs/property/tag.rb
@@ -9,6 +9,10 @@ def format_tags(value)
       [:should_to_s, :is_to_s].each { |method|
         alias_method method, :format_tags
       }
+
+      validate do |value|
+        fail 'tags should be a Hash' unless value.is_a?(Hash)
+      end
     end
   end
 end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index b3b4ca1e..200c6b63 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -29,3 +29,29 @@
     "expected that #{actual} would order tags"
   end
 end
+
+RSpec::Matchers.define :require_string_for do |property|
+  match do |type_class|
+    config = {name: 'name'}
+    config[property] = 2
+    expect {
+      type_class.new(config)
+    }.to raise_error(Puppet::Error, /#{property} should be a String/)
+  end
+  failure_message_for_should do |type_class|
+    "#{type_class} should require #{property} to be a String"
+  end
+end
+
+RSpec::Matchers.define :require_hash_for do |property|
+  match do |type_class|
+    config = {name: 'name'}
+    config[property] = 2
+    expect {
+      type_class.new(config)
+    }.to raise_error(Puppet::Error, /#{property} should be a Hash/)
+  end
+  failure_message_for_should do |type_class|
+    "#{type_class} should require #{property} to be a Hash"
+  end
+end
diff --git a/spec/unit/type/cloudwatch_alarm_spec.rb b/spec/unit/type/cloudwatch_alarm_spec.rb
index b1b21543..b77e556d 100644
--- a/spec/unit/type/cloudwatch_alarm_spec.rb
+++ b/spec/unit/type/cloudwatch_alarm_spec.rb
@@ -67,6 +67,23 @@ def alarm_config
     end
   end
 
+  [
+    'metric',
+    'namespace',
+    'statistic',
+    'comparison_operator',
+    'region',
+    'alarm_actions',
+  ].each do |property|
+    it "should require #{property} to be a string" do
+      expect(type_class).to require_string_for(property)
+    end
+  end
+
+  it "should require dimensions to be a hash" do
+    expect(type_class).to require_hash_for('dimensions')
+  end
+
   context 'with a full set of properties' do
     before :all do
       @instance = type_class.new(alarm_config)
diff --git a/spec/unit/type/ec2_autoscalinggroup_spec.rb b/spec/unit/type/ec2_autoscalinggroup_spec.rb
index 0745face..2353f8b8 100644
--- a/spec/unit/type/ec2_autoscalinggroup_spec.rb
+++ b/spec/unit/type/ec2_autoscalinggroup_spec.rb
@@ -51,6 +51,18 @@ def asg_config
     }.to raise_error(Puppet::Error, 'Title or name must be provided')
   end
 
+  [
+    'subnets',
+    'availability_zones',
+    'launch_configuration',
+    'name',
+    'region',
+  ].each do |property|
+    it "should require #{property} to be a string" do
+      expect(type_class).to require_string_for(property)
+    end
+  end
+
   asg_config.keys.each do |key|
     it "should require a value for #{key}" do
       modified_config = asg_config
diff --git a/spec/unit/type/ec2_instance_spec.rb b/spec/unit/type/ec2_instance_spec.rb
index 0269a70a..0479b524 100644
--- a/spec/unit/type/ec2_instance_spec.rb
+++ b/spec/unit/type/ec2_instance_spec.rb
@@ -102,4 +102,21 @@
   it 'should order tags on output' do
     expect(type_class).to order_tags_on_output
   end
+
+  [
+    'name',
+    'region',
+    'security_groups',
+    'key_name',
+    'region',
+    'image_id',
+    'availability_zone',
+    'instance_type',
+    'subnet',
+  ].each do |property|
+    it "should require #{property} to be a string" do
+      expect(type_class).to require_string_for(property)
+    end
+  end
+
 end
diff --git a/spec/unit/type/ec2_launchconfiguration_spec.rb b/spec/unit/type/ec2_launchconfiguration_spec.rb
index 0c0582a3..3517508f 100644
--- a/spec/unit/type/ec2_launchconfiguration_spec.rb
+++ b/spec/unit/type/ec2_launchconfiguration_spec.rb
@@ -67,4 +67,18 @@ def launchconfig_config
     end
   end
 
+  [
+    'name',
+    'security_groups',
+    'key_name',
+    'region',
+    'instance_type',
+    'image_id',
+    'vpc',
+  ].each do |property|
+    it "should require #{property} to be a string" do
+      expect(type_class).to require_string_for(property)
+    end
+  end
+
 end
diff --git a/spec/unit/type/ec2_scalingpolicy_spec.rb b/spec/unit/type/ec2_scalingpolicy_spec.rb
index edccdc7e..fce449d5 100644
--- a/spec/unit/type/ec2_scalingpolicy_spec.rb
+++ b/spec/unit/type/ec2_scalingpolicy_spec.rb
@@ -66,7 +66,17 @@ def policy_config
     it 'should convert scaling adjustment values to an Integer' do
       expect(@instance[:scaling_adjustment].kind_of?(Integer)).to be true
     end
+  end
 
+  [
+    'name',
+    'region',
+    'adjustment_type',
+    'auto_scaling_group',
+  ].each do |property|
+    it "should require #{property} to be a string" do
+      expect(type_class).to require_string_for(property)
+    end
   end
 
 end
diff --git a/spec/unit/type/ec2_securitygroup_spec.rb b/spec/unit/type/ec2_securitygroup_spec.rb
index 5adae959..ce5c56b2 100644
--- a/spec/unit/type/ec2_securitygroup_spec.rb
+++ b/spec/unit/type/ec2_securitygroup_spec.rb
@@ -32,6 +32,37 @@
     end
   end
 
+  it 'should require a name' do
+    expect {
+      type_class.new({})
+    }.to raise_error(Puppet::Error, 'Title or name must be provided')
+  end
+
+  it 'should require region to not contain spaces' do
+    expect {
+      type_class.new({name: 'name', region: 'invalid region'})
+    }.to raise_error(Puppet::Error, /region should not contain spaces/)
+  end
+
+  [
+    'vpc',
+    'name',
+    'description',
+    'region',
+  ].each do |property|
+    it "should require #{property} to be a string" do
+      expect(type_class).to require_string_for(property)
+    end
+  end
+
+  it "should require ingress to be a hash" do
+    expect(type_class).to require_hash_for('ingress')
+  end
+
+   it "should require tags to be a hash" do
+    expect(type_class).to require_hash_for('tags')
+  end
+
   it 'should order tags on output' do
     expect(type_class).to order_tags_on_output
   end
diff --git a/spec/unit/type/ec2_vpc_customer_gateway_spec.rb b/spec/unit/type/ec2_vpc_customer_gateway_spec.rb
index 628cf965..149f873d 100644
--- a/spec/unit/type/ec2_vpc_customer_gateway_spec.rb
+++ b/spec/unit/type/ec2_vpc_customer_gateway_spec.rb
@@ -70,4 +70,17 @@
     expect(srv[:type]).to eq('ipsec.1')
   end
 
+  [
+    'name',
+    'region',
+  ].each do |property|
+    it "should require #{property} to be a string" do
+      expect(type_class).to require_string_for(property)
+    end
+  end
+
+  it "should require tags to be a hash" do
+    expect(type_class).to require_hash_for('tags')
+  end
+
 end
diff --git a/spec/unit/type/ec2_vpc_dhcp_options_spec.rb b/spec/unit/type/ec2_vpc_dhcp_options_spec.rb
index 88c9d6b1..d1588810 100644
--- a/spec/unit/type/ec2_vpc_dhcp_options_spec.rb
+++ b/spec/unit/type/ec2_vpc_dhcp_options_spec.rb
@@ -86,5 +86,20 @@
     end
   end
 
+  [
+    'name',
+    'region',
+    'ntp_servers',
+    'domain_name_servers',
+    'netbios_name_servers',
+  ].each do |property|
+    it "should require #{property} to be a string" do
+      expect(type_class).to require_string_for(property)
+    end
+  end
+
+  it "should require tags to be a hash" do
+    expect(type_class).to require_hash_for('tags')
+  end
 
 end
diff --git a/spec/unit/type/ec2_vpc_internet_gateway_spec.rb b/spec/unit/type/ec2_vpc_internet_gateway_spec.rb
index 66c1dd65..74c4fcfc 100644
--- a/spec/unit/type/ec2_vpc_internet_gateway_spec.rb
+++ b/spec/unit/type/ec2_vpc_internet_gateway_spec.rb
@@ -42,4 +42,18 @@
     }.to raise_error(Puppet::ResourceError, /region should not contain spaces/)
   end
 
+  [
+    'name',
+    'region',
+    'vpc',
+  ].each do |property|
+    it "should require #{property} to be a string" do
+      expect(type_class).to require_string_for(property)
+    end
+  end
+
+  it "should require tags to be a hash" do
+    expect(type_class).to require_hash_for('tags')
+  end
+
 end
diff --git a/spec/unit/type/ec2_vpc_routetable_spec.rb b/spec/unit/type/ec2_vpc_routetable_spec.rb
index 9ee9d6cf..d0ecd0ca 100644
--- a/spec/unit/type/ec2_vpc_routetable_spec.rb
+++ b/spec/unit/type/ec2_vpc_routetable_spec.rb
@@ -55,4 +55,18 @@
     }.to raise_error(Puppet::ResourceError, /routes must include a gateway/)
   end
 
+  [
+    'name',
+    'vpc',
+    'region',
+  ].each do |property|
+    it "should require #{property} to be a string" do
+      expect(type_class).to require_string_for(property)
+    end
+  end
+
+  it "should require tags to be a hash" do
+    expect(type_class).to require_hash_for('tags')
+  end
+
 end
diff --git a/spec/unit/type/ec2_vpc_spec.rb b/spec/unit/type/ec2_vpc_spec.rb
index bf12d7e0..0907486b 100644
--- a/spec/unit/type/ec2_vpc_spec.rb
+++ b/spec/unit/type/ec2_vpc_spec.rb
@@ -64,4 +64,18 @@
     expect(type_class).to order_tags_on_output
   end
 
+  [
+    'name',
+    'region',
+    'dhcp_options',
+  ].each do |property|
+    it "should require #{property} to be a string" do
+      expect(type_class).to require_string_for(property)
+    end
+  end
+
+  it "should require tags to be a hash" do
+    expect(type_class).to require_hash_for('tags')
+  end
+
 end
diff --git a/spec/unit/type/ec2_vpc_subnet_spec.rb b/spec/unit/type/ec2_vpc_subnet_spec.rb
index f50337f5..c94c1bd5 100644
--- a/spec/unit/type/ec2_vpc_subnet_spec.rb
+++ b/spec/unit/type/ec2_vpc_subnet_spec.rb
@@ -44,4 +44,21 @@
     }.to raise_error(Puppet::ResourceError, /region should not contain spaces/)
   end
 
+  [
+    'name',
+    'region',
+    'vpc',
+    'cidr_block',
+    'availability_zone',
+    'route_table',
+  ].each do |property|
+    it "should require #{property} to be a string" do
+      expect(type_class).to require_string_for(property)
+    end
+  end
+
+  it "should require tags to be a hash" do
+    expect(type_class).to require_hash_for('tags')
+  end
+
 end
diff --git a/spec/unit/type/ec2_vpc_vpn_gateway_spec.rb b/spec/unit/type/ec2_vpc_vpn_gateway_spec.rb
index 64f992e4..73e41619 100644
--- a/spec/unit/type/ec2_vpc_vpn_gateway_spec.rb
+++ b/spec/unit/type/ec2_vpc_vpn_gateway_spec.rb
@@ -50,4 +50,19 @@
     expect(srv[:type]).to eq('ipsec.1')
   end
 
+  [
+    'name',
+    'region',
+    'vpc',
+    'availability_zone',
+  ].each do |property|
+    it "should require #{property} to be a string" do
+      expect(type_class).to require_string_for(property)
+    end
+  end
+
+  it "should require tags to be a hash" do
+    expect(type_class).to require_hash_for('tags')
+  end
+
 end
diff --git a/spec/unit/type/ec2_vpc_vpn_spec.rb b/spec/unit/type/ec2_vpc_vpn_spec.rb
index 3765be29..7bfc95c1 100644
--- a/spec/unit/type/ec2_vpc_vpn_spec.rb
+++ b/spec/unit/type/ec2_vpc_vpn_spec.rb
@@ -68,4 +68,20 @@
     }.to raise_error(Puppet::ResourceError, /region should not contain spaces/)
   end
 
+  [
+    'name',
+    'vpn_gateway',
+    'customer_gateway',
+    'routes',
+    'region',
+  ].each do |property|
+    it "should require #{property} to be a string" do
+      expect(type_class).to require_string_for(property)
+    end
+  end
+
+  it "should require tags to be a hash" do
+    expect(type_class).to require_hash_for('tags')
+  end
+
 end
diff --git a/spec/unit/type/elb_loadbalancer_spec.rb b/spec/unit/type/elb_loadbalancer_spec.rb
index 8ae4753e..1bef0cd6 100644
--- a/spec/unit/type/elb_loadbalancer_spec.rb
+++ b/spec/unit/type/elb_loadbalancer_spec.rb
@@ -147,4 +147,19 @@ def elb_config
     }.to raise_error(Puppet::Error)
   end
 
+  [
+    'name',
+    'region',
+    'security_groups',
+    'instances',
+    'subnets',
+  ].each do |property|
+    it "should require #{property} to be a string" do
+      expect(type_class).to require_string_for(property)
+    end
+  end
+
+  it "should require tags to be a hash" do
+    expect(type_class).to require_hash_for('tags')
+  end
 end