chef-provisioning-aws 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +2 -0
  3. data/lib/chef/provider/aws_auto_scaling_group.rb +30 -41
  4. data/lib/chef/provider/aws_dhcp_options.rb +70 -0
  5. data/lib/chef/provider/aws_ebs_volume.rb +182 -34
  6. data/lib/chef/provider/aws_eip_address.rb +63 -60
  7. data/lib/chef/provider/aws_key_pair.rb +18 -27
  8. data/lib/chef/provider/aws_launch_configuration.rb +50 -0
  9. data/lib/chef/provider/aws_route_table.rb +122 -0
  10. data/lib/chef/provider/aws_s3_bucket.rb +42 -49
  11. data/lib/chef/provider/aws_security_group.rb +252 -59
  12. data/lib/chef/provider/aws_sns_topic.rb +10 -26
  13. data/lib/chef/provider/aws_sqs_queue.rb +16 -38
  14. data/lib/chef/provider/aws_subnet.rb +85 -32
  15. data/lib/chef/provider/aws_vpc.rb +163 -23
  16. data/lib/chef/provisioning/aws_driver.rb +18 -1
  17. data/lib/chef/provisioning/aws_driver/aws_provider.rb +206 -0
  18. data/lib/chef/provisioning/aws_driver/aws_resource.rb +186 -0
  19. data/lib/chef/provisioning/aws_driver/aws_resource_with_entry.rb +114 -0
  20. data/lib/chef/provisioning/aws_driver/driver.rb +317 -255
  21. data/lib/chef/provisioning/aws_driver/resources.rb +8 -5
  22. data/lib/chef/provisioning/aws_driver/super_lwrp.rb +45 -0
  23. data/lib/chef/provisioning/aws_driver/version.rb +1 -1
  24. data/lib/chef/resource/aws_auto_scaling_group.rb +15 -13
  25. data/lib/chef/resource/aws_dhcp_options.rb +57 -0
  26. data/lib/chef/resource/aws_ebs_volume.rb +20 -22
  27. data/lib/chef/resource/aws_eip_address.rb +50 -25
  28. data/lib/chef/resource/aws_image.rb +20 -0
  29. data/lib/chef/resource/aws_instance.rb +20 -0
  30. data/lib/chef/resource/aws_internet_gateway.rb +16 -0
  31. data/lib/chef/resource/aws_key_pair.rb +6 -10
  32. data/lib/chef/resource/aws_launch_configuration.rb +15 -0
  33. data/lib/chef/resource/aws_load_balancer.rb +16 -0
  34. data/lib/chef/resource/aws_network_interface.rb +16 -0
  35. data/lib/chef/resource/aws_route_table.rb +76 -0
  36. data/lib/chef/resource/aws_s3_bucket.rb +8 -18
  37. data/lib/chef/resource/aws_security_group.rb +49 -19
  38. data/lib/chef/resource/aws_sns_topic.rb +14 -15
  39. data/lib/chef/resource/aws_sqs_queue.rb +16 -14
  40. data/lib/chef/resource/aws_subnet.rb +87 -17
  41. data/lib/chef/resource/aws_vpc.rb +137 -15
  42. data/spec/integration/aws_security_group_spec.rb +55 -0
  43. data/spec/spec_helper.rb +8 -2
  44. data/spec/support/aws_support.rb +211 -0
  45. metadata +33 -10
  46. data/lib/chef/provider/aws_launch_config.rb +0 -43
  47. data/lib/chef/provider/aws_provider.rb +0 -22
  48. data/lib/chef/provisioning/aws_driver/aws_profile.rb +0 -73
  49. data/lib/chef/resource/aws_launch_config.rb +0 -14
  50. data/lib/chef/resource/aws_resource.rb +0 -10
  51. data/spec/chef_zero_rspec_helper.rb +0 -8
  52. data/spec/unit/provider/aws_subnet_spec.rb +0 -67
  53. data/spec/unit/resource/aws_subnet_spec.rb +0 -23
@@ -1,3 +1,20 @@
1
1
  require 'chef/provisioning'
2
2
  require 'chef/provisioning/aws_driver/driver'
3
- require 'chef/provisioning/aws_driver/resources'
3
+
4
+ require "chef/resource/aws_auto_scaling_group"
5
+ require "chef/resource/aws_dhcp_options"
6
+ require "chef/resource/aws_ebs_volume"
7
+ require "chef/resource/aws_eip_address"
8
+ require "chef/resource/aws_image"
9
+ require "chef/resource/aws_instance"
10
+ require "chef/resource/aws_internet_gateway"
11
+ require "chef/resource/aws_launch_configuration"
12
+ require "chef/resource/aws_load_balancer"
13
+ require "chef/resource/aws_network_interface"
14
+ require "chef/resource/aws_route_table"
15
+ require "chef/resource/aws_s3_bucket"
16
+ require "chef/resource/aws_security_group"
17
+ require "chef/resource/aws_sns_topic"
18
+ require "chef/resource/aws_sqs_queue"
19
+ require "chef/resource/aws_subnet"
20
+ require "chef/resource/aws_vpc"
@@ -0,0 +1,206 @@
1
+ require 'chef/provider/lwrp_base'
2
+ require 'chef/provisioning/aws_driver/aws_resource'
3
+ require 'chef/provisioning/aws_driver/aws_resource_with_entry'
4
+ require 'chef/provisioning/chef_managed_entry_store'
5
+ require 'chef/provisioning/chef_provider_action_handler'
6
+
7
+ module Chef::Provisioning::AWSDriver
8
+ class AWSProvider < Chef::Provider::LWRPBase
9
+ use_inline_resources
10
+
11
+ AWSResource = Chef::Provisioning::AWSDriver::AWSResource
12
+
13
+ def action_handler
14
+ @action_handler ||= Chef::Provisioning::ChefProviderActionHandler.new(self)
15
+ end
16
+
17
+ # All these need to implement whyrun
18
+ def whyrun_supported?
19
+ true
20
+ end
21
+
22
+ def region
23
+ new_resource.driver.aws_config.region
24
+ end
25
+
26
+ #
27
+ # Return the damned value from the block, not whatever weirdness converge_by
28
+ # normally returns.
29
+ #
30
+ def converge_by(*args, &block)
31
+ result = nil
32
+ super(*args) do
33
+ result = block.call
34
+ end
35
+ result
36
+ end
37
+
38
+ action :create do
39
+ #
40
+ # If the user specified an ID, get the object for it, and fail if it does not exist.
41
+ #
42
+ desired_driver = new_resource.driver
43
+ desired_id = new_resource.public_send(new_resource.class.aws_id_attribute) if new_resource.class.aws_id_attribute
44
+ if desired_id
45
+ aws_object = new_resource.class.get_aws_object(desired_id, resource: new_resource)
46
+ end
47
+
48
+ #
49
+ # If Chef has already associated the object with an AWS ID, check if it's
50
+ # the same as the desired AWS ID.
51
+ #
52
+ if new_resource.is_a?(AWSResourceWithEntry)
53
+ entry_driver, entry_id, entry = new_resource.get_id_from_managed_entry
54
+ if entry_id
55
+ if desired_id
56
+
57
+ #
58
+ # We have both a desired ID and an entry ID. Find out whether they
59
+ # match and warn if they don't (because we're going to reassociate and
60
+ # update the *desired* AWS thing.).
61
+ #
62
+ if desired_driver.driver_url == entry_driver.driver_url && desired_id == entry_id
63
+ Chef::Log.debug "#{new_resource.to_s} is already associated with #{entry_id} in #{entry_driver.driver_url}"
64
+ else
65
+ Chef::Log.warn "#{new_resource.to_s} is currently associated with #{entry_id} in #{entry_driver.driver_url}, but the desired ID is #{desired_id} in #{new_resource.driver.driver_url}! Will associate with new desired ID #{desired_id}."
66
+ end
67
+
68
+ else
69
+
70
+ #
71
+ # If we don't have desired (common case), we'll update the existing
72
+ # resource or create a new one if it's been deleted.
73
+ #
74
+ aws_object = new_resource.class.get_aws_object(entry_id, driver: entry_driver, resource: new_resource, required: false)
75
+ if aws_object
76
+ Chef::Log.debug "#{new_resource.to_s} is currently associated with #{entry_id} in #{entry_driver.driver_url}."
77
+ else
78
+ Chef::Log.warn "#{new_resource.to_s} is currently associated with #{entry_id} in #{entry_driver.driver_url}, but it does not exist! We will create a new one to replace it."
79
+ end
80
+ end
81
+
82
+ else
83
+
84
+ #
85
+ # If we don't currently have an AWS ID associated with this resource, we
86
+ # will either associate the desired one, or create a new one.
87
+ #
88
+ if desired_id
89
+ Chef::Log.debug "#{new_resource.to_s} is not yet associated with anything. Associating with desired object #{desired_id} in #{desired_driver.driver_url}."
90
+ else
91
+ Chef::Log.debug "#{new_resource.to_s} is not yet associated with anything. Creating a new one in #{desired_driver.driver_url} ..."
92
+ end
93
+ end
94
+
95
+ else
96
+
97
+ #
98
+ # If it does not support storing IDs in Chef at all, just grab the existing
99
+ # object and we'll update (or not) based on that.
100
+ #
101
+ aws_object ||= new_resource.aws_object
102
+
103
+ end
104
+
105
+ #
106
+ # Actually update or create the AWS object
107
+ #
108
+ if aws_object
109
+ action, new_obj = update_aws_object(aws_object)
110
+ if action == :replaced_aws_object
111
+ aws_object = new_obj
112
+ end
113
+ else
114
+ aws_object = create_aws_object
115
+ end
116
+
117
+ #
118
+ # Associate the managed entry with the AWS object
119
+ #
120
+ if new_resource.is_a?(AWSResourceWithEntry)
121
+ new_resource.save_managed_entry(aws_object, action_handler, existing_entry: entry)
122
+ end
123
+
124
+ aws_object
125
+ end
126
+
127
+ action :destroy do
128
+ desired_driver = new_resource.driver
129
+ desired_id = new_resource.public_send(new_resource.class.aws_id_attribute) if new_resource.class.aws_id_attribute
130
+
131
+ #
132
+ # If the user specified an ID, delete THAT; do NOT delete the associated object.
133
+ #
134
+ if desired_id
135
+ aws_object = new_resource.class.get_aws_object(desired_id, resource: new_resource, required: false)
136
+ if aws_object
137
+ Chef::Log.debug "#{new_resource.to_s} provided #{new_resource.class.aws_id_attribute} #{desired_id} in #{desired_driver.driver_url}. Will delete."
138
+ end
139
+ end
140
+
141
+ #
142
+ # Managed entries are looked up by ID.
143
+ #
144
+ if new_resource.is_a?(AWSResourceWithEntry)
145
+ entry_driver, entry_id, entry = new_resource.get_id_from_managed_entry
146
+ if entry_id
147
+ if desired_id && (desired_id != entry_id || desired_driver.driver_url != entry_driver.driver_url)
148
+ if new_resource.class.get_aws_object(entry_id, driver: entry_driver, resource: new_resource, required: false)
149
+ # If the desired ID / driver differs from the entry, don't delete. We
150
+ # certainly can't delete the AWS object itself, and we don't *want* to
151
+ # delete the association, because the expectation is that after doing a
152
+ # delete, you should be able to create a new thing.
153
+ raise "#{new_resource.to_s} provided #{new_resource.class.aws_id_attribute} #{desired_id} in #{desired_driver.driver_url}, but is currently associated with #{entry_id} in #{entry_driver.driver_url}. Cannot delete the entry or the association until this inconsistency is resolved."
154
+ else
155
+ Chef::Log.debug "#{new_resource.to_s} provided #{new_resource.class.aws_id_attribute} #{desired_id} in #{desired_driver.driver_url}, but is currently associated with #{entry_id} in #{entry_driver.driver_url}, which does not exist. Will delete #{desired_id} and disassociate from #{entry_id}."
156
+ end
157
+ else
158
+
159
+ # Normal case: entry exists, and is the same as desired (or no desired)
160
+ aws_object = new_resource.class.get_aws_object(entry_id, driver: entry_driver, resource: new_resource, required: false)
161
+ if aws_object
162
+ Chef::Log.debug "#{new_resource.to_s} is associated with #{entry_id} in #{entry_driver.driver_url}. Will delete."
163
+ else
164
+ Chef::Log.debug "#{new_resource.to_s} is associated with #{entry_id} in #{entry_driver.driver_url}, but it does not exist. Will disassociate the entry but not delete."
165
+ end
166
+ end
167
+ end
168
+
169
+ #
170
+ # Non-managed entries all have their own way of looking it up
171
+ #
172
+ else
173
+ aws_object ||= new_resource.aws_object
174
+ end
175
+
176
+ #
177
+ # Call the delete method
178
+ #
179
+ if aws_object
180
+ destroy_aws_object(aws_object)
181
+ end
182
+
183
+ #
184
+ # Associate the managed entry with the AWS object
185
+ #
186
+ if new_resource.is_a?(AWSResourceWithEntry) && entry
187
+ new_resource.delete_managed_entry(action_handler)
188
+ end
189
+ end
190
+
191
+ protected
192
+
193
+ def create_aws_object
194
+ raise NotImplementedError, :create_aws_object
195
+ end
196
+
197
+ def update_aws_object(obj)
198
+ raise NotImplementedError, :update_aws_object
199
+ end
200
+
201
+ def destroy_aws_object(obj)
202
+ raise NotImplementedError, :destroy_aws_object
203
+ end
204
+
205
+ end
206
+ end
@@ -0,0 +1,186 @@
1
+ require 'aws'
2
+ require 'chef/provisioning/aws_driver/super_lwrp'
3
+ require 'chef/provisioning/chef_managed_entry_store'
4
+
5
+ # Common AWS resource - contains metadata that all AWS resources will need
6
+ module Chef::Provisioning::AWSDriver
7
+ class AWSResource < Chef::Provisioning::AWSDriver::SuperLWRP
8
+ actions :create, :destroy, :nothing
9
+ default_action :create
10
+
11
+ def initialize(name, run_context=nil)
12
+ name = name.public_send(self.class.aws_sdk_class_id) if name.is_a?(self.class.aws_sdk_class)
13
+ super
14
+ if run_context
15
+ driver run_context.chef_provisioning.current_driver
16
+ chef_server run_context.cheffish.current_chef_server
17
+ end
18
+ end
19
+
20
+ # Backwards compatibility for action :destroy
21
+ def action(*args)
22
+ if args == [ :delete ]
23
+ super(:destroy)
24
+ else
25
+ super
26
+ end
27
+ end
28
+ def action=(value)
29
+ action(value)
30
+ end
31
+
32
+ #
33
+ # The desired driver.
34
+ #
35
+ attribute :driver, kind_of: Chef::Provisioning::Driver,
36
+ coerce: (proc do |value|
37
+ case value
38
+ when nil, Chef::Provisioning::Driver
39
+ value
40
+ else
41
+ run_context.chef_provisioning.driver_for(value)
42
+ end
43
+ end)
44
+
45
+ #
46
+ # The Chef server on which any IDs should be looked up.
47
+ #
48
+ attribute :chef_server, kind_of: Hash
49
+
50
+ #
51
+ # The managed entry store.
52
+ #
53
+ attribute :managed_entry_store, kind_of: Chef::Provisioning::ManagedEntryStore,
54
+ lazy_default: proc { Chef::Provisioning::ChefManagedEntryStore.new(chef_server) }
55
+
56
+ #
57
+ # Get the current AWS object.
58
+ #
59
+ def aws_object
60
+ raise NotImplementedError, :aws_object
61
+ end
62
+
63
+ #
64
+ # Look up an AWS options list, translating standard names using the appropriate
65
+ # classes.
66
+ #
67
+ # For example, `load_balancer_options` is passed into `lookup_options`, and if
68
+ # it looks like this: `{ subnets: `[ 'subnet1', 'subnet2' ] }`, then
69
+ # `AWSResource.lookup_options` will translate each ID with
70
+ # `AwsSubnet.get_aws_object('subnet1')`, which supports Chef names
71
+ # (`mysubnet`) as well as AWS subnet Ids (`subnet-1234abcd`) or AWS objects
72
+ # (`AWS::EC2::Subnet`).
73
+ #
74
+ # Keys that represent non-AWS-objects (such as `timeout`) are left alone.
75
+ #
76
+ def self.lookup_options(options, **handler_options)
77
+ options = options.dup
78
+ options.each do |name, value|
79
+ if name.to_s.end_with?('s')
80
+ handler_name = :"#{name[0..-2]}"
81
+ if aws_option_handlers[handler_name]
82
+ options[name] = [options[name]].flatten.map { |value| aws_option_handlers[handler_name].get_aws_object_id(value, **handler_options) }
83
+ end
84
+ else
85
+ if aws_option_handlers[name]
86
+ options[name] = aws_option_handlers[name].get_aws_object_id(value, **handler_options)
87
+ end
88
+ end
89
+ end
90
+ options
91
+ end
92
+
93
+ def self.get_aws_object(value, resource: nil, run_context: nil, driver: nil, managed_entry_store: nil, required: true)
94
+ return nil if value.nil?
95
+
96
+ if resource
97
+ run_context ||= resource.run_context
98
+ driver ||= resource.driver
99
+ managed_entry_store ||= resource.managed_entry_store
100
+ end
101
+ if value.is_a?(self)
102
+ resource = value
103
+ else
104
+ resource = new(value, run_context)
105
+ resource.driver driver if driver
106
+ resource.managed_entry_store managed_entry_store if managed_entry_store
107
+ end
108
+ result = resource.aws_object
109
+ if required && result.nil?
110
+ raise "#{self}[#{value}] does not exist!"
111
+ end
112
+ result
113
+ end
114
+
115
+ def self.get_aws_object_id(value, **options)
116
+ aws_object = get_aws_object(value, **options)
117
+ aws_object.public_send(aws_sdk_class_id) if aws_object
118
+ end
119
+
120
+ protected
121
+
122
+ NOT_PASSED = Object.new
123
+
124
+ def self.aws_sdk_type(sdk_class,
125
+ option_names: nil,
126
+ option_name: NOT_PASSED,
127
+ load_provider: true,
128
+ id: :name,
129
+ aws_id_prefix: nil)
130
+ self.resource_name = self.dsl_name
131
+ @aws_sdk_class = sdk_class
132
+ @aws_sdk_class_id = id
133
+ @aws_id_prefix = aws_id_prefix
134
+
135
+ # Go ahead and require the provider since we're here anyway ...
136
+ require "chef/provider/#{resource_name}" if load_provider
137
+
138
+ option_name = :"#{resource_name[4..-1]}" if option_name == NOT_PASSED
139
+ @aws_sdk_option_name = option_name
140
+
141
+ option_names ||= begin
142
+ option_names = []
143
+ option_names << aws_sdk_option_name
144
+ option_names << :"#{option_name}_#{aws_sdk_class_id}" if aws_sdk_class_id
145
+ option_names
146
+ end
147
+ option_names.each do |option_name|
148
+ aws_option_handlers[option_name] = self
149
+ end
150
+
151
+ name = self.name.split('::')[-1]
152
+ eval("Chef::Provisioning::AWSDriver::Resources::#{name} = self", binding, __FILE__, __LINE__)
153
+ end
154
+
155
+ def self.aws_sdk_class
156
+ @aws_sdk_class
157
+ end
158
+
159
+ def self.aws_sdk_class_id
160
+ @aws_sdk_class_id
161
+ end
162
+
163
+ def self.aws_id_prefix
164
+ @aws_id_prefix
165
+ end
166
+
167
+ def self.aws_sdk_option_name
168
+ @aws_sdk_option_name
169
+ end
170
+
171
+ @@aws_option_handlers = {}
172
+ def self.aws_option_handlers
173
+ @@aws_option_handlers
174
+ end
175
+
176
+ # Add support for aws_id_attribute: true
177
+ def self.attribute(name, aws_id_attribute: false, **validation_opts)
178
+ @aws_id_attribute = name if aws_id_attribute
179
+ super(name, validation_opts)
180
+ end
181
+
182
+ def self.aws_id_attribute
183
+ @aws_id_attribute
184
+ end
185
+ end
186
+ end
@@ -0,0 +1,114 @@
1
+ require 'chef/provisioning/aws_driver/aws_resource'
2
+ require 'chef/provisioning/aws_driver/resources'
3
+
4
+ # Common AWS resource - contains metadata that all AWS resources will need
5
+ class Chef::Provisioning::AWSDriver::AWSResourceWithEntry < Chef::Provisioning::AWSDriver::AWSResource
6
+ #
7
+ # Dissociate the ID of this object from Chef.
8
+ #
9
+ # @param action_handler [Chef::Provisioning::ActionHandler] The action handler,
10
+ # which handles progress reporting, update reporting ("little green text")
11
+ # and dry run.
12
+ #
13
+ def delete_managed_entry(action_handler)
14
+ if should_have_managed_entry?
15
+ managed_entry_store.delete(self.class.resource_name, name, action_handler)
16
+ end
17
+ end
18
+
19
+ #
20
+ # Save the ID of this object to Chef.
21
+ #
22
+ # @param aws_object [AWS::EC2::Core] The AWS object containing the ID.
23
+ # @param action_handler [Chef::Provisioning::ActionHandler] The action handler,
24
+ # which handles progress reporting, update reporting ("little green text")
25
+ # and dry run.
26
+ # @param existing_entry [Chef::Provisioning::ManagedEntry] The existing entry
27
+ # (if any). If this is passed in, and no values are changed, we will
28
+ # not attempt to update it (this prevents us from retrieving it twice).
29
+ #
30
+ def save_managed_entry(aws_object, action_handler, existing_entry: nil)
31
+ if should_have_managed_entry?
32
+ managed_entry = existing_entry ||
33
+ managed_entry_store.new_entry(self.class.resource_name, name)
34
+ updated = update_managed_entry(aws_object, managed_entry)
35
+ if updated || !existing_entry
36
+ managed_entry.save(action_handler)
37
+ end
38
+ end
39
+ end
40
+
41
+ def get_id_from_managed_entry
42
+ if should_have_managed_entry?
43
+ entry = managed_entry_store.get(self.class.managed_entry_type, name)
44
+ if entry
45
+ driver = self.driver
46
+ if entry.driver_url != driver.driver_url
47
+ # TODO some people don't send us run_context (like Drivers). We might need
48
+ # to exit early here if the driver_url doesn't match the provided driver.
49
+ driver = run_context.chef_provisioning.driver_for(entry.driver_url)
50
+ end
51
+ [ driver, entry.reference[self.class.managed_entry_id_name], entry ]
52
+ end
53
+ end
54
+ end
55
+
56
+ # Formatted output for logging statements - contains resource type, resource name and aws object id (if available)
57
+ def to_s
58
+ id = get_driver_and_id[1]
59
+ "#{declared_type}[#{@name}] (#{ id ? id : 'no AWS object id'})"
60
+ end
61
+
62
+ protected
63
+
64
+ #
65
+ # Update an existing ManagedEntry object.
66
+ #
67
+ # @return true if the entry was changed, and false if not
68
+ #
69
+ def update_managed_entry(aws_object, managed_entry)
70
+ new_value = { self.class.managed_entry_id_name => aws_object.public_send(self.class.aws_sdk_class_id) }
71
+ if managed_entry.reference != new_value
72
+ managed_entry.reference = new_value
73
+ changed = true
74
+ end
75
+ if managed_entry.driver_url != driver.driver_url
76
+ managed_entry.driver_url = driver.driver_url
77
+ changed = true
78
+ end
79
+ changed
80
+ end
81
+
82
+ def get_driver_and_id
83
+ driver, id, entry = get_id_from_managed_entry
84
+ # If the value isn't already stored, look up the user-specified public_ip
85
+ driver, id = self.driver, self.public_send(self.class.aws_id_attribute) if !id
86
+ [ driver, id ]
87
+ end
88
+
89
+ def self.aws_sdk_type(sdk_class,
90
+ id: :id,
91
+ managed_entry_type: nil,
92
+ managed_entry_id_name: 'id',
93
+ backcompat_data_bag_name: nil,
94
+ **options)
95
+ super(sdk_class, id: id, **options)
96
+ @managed_entry_type = managed_entry_type || resource_name.to_sym
97
+ @managed_entry_id_name = managed_entry_id_name
98
+ if backcompat_data_bag_name
99
+ Chef::Provisioning::ChefManagedEntryStore.type_names_for_backcompat[resource_name] = backcompat_data_bag_name
100
+ end
101
+ end
102
+
103
+ def self.managed_entry_type
104
+ @managed_entry_type
105
+ end
106
+
107
+ def self.managed_entry_id_name
108
+ @managed_entry_id_name
109
+ end
110
+
111
+ def should_have_managed_entry?
112
+ name != public_send(self.class.aws_id_attribute)
113
+ end
114
+ end