lib/build-cloud/iamrole.rb in build-cloud-0.0.19 vs lib/build-cloud/iamrole.rb in build-cloud-0.0.20

- old
+ new

@@ -17,48 +17,148 @@ required_options(:rolename, :assume_role_policy_document) end def create - - return if exists? - @log.info( "Creating new IAM role for #{@options[:rolename]}" ) - policies = @options.delete(:policies) - # Genuinely don't think I've understood the data model with - # this stuff. In particular how roles, instance profiles etc. relate - # - # It does what we need right now though, and can be revisited if necessary + unless exists? - role = @iam.roles.new( @options ) - role.save + @log.info( "Creating new IAM role for #{@options[:rolename]}" ) - @log.debug( role.inspect ) + # Genuinely don't think I've understood the data model with + # this stuff. In particular how roles, instance profiles etc. relate + # + # It does what we need right now though, and can be revisited if necessary - @iam.create_instance_profile( @options[:rolename] ) + role = @iam.roles.new( @options ) + role.save - policies.each do |policy| + @log.debug( role.inspect ) - @log.debug( "Adding policy #{policy}" ) + @iam.create_instance_profile( @options[:rolename] ) - policy_document = JSON.parse( policy[:policy_document] ) + @iam.add_role_to_instance_profile( @options[:rolename], @options[:rolename] ) - @iam.put_role_policy( @options[:rolename], policy[:policy_name], - policy_document ) - end - @iam.add_role_to_instance_profile( @options[:rolename], @options[:rolename] ) + rationalise_policies( policies ) end def read @iam.roles.select { |r| r.rolename == @options[:rolename] }.first end + + + def rationalise_policies( policies ) + policies = {} if policies.nil? + + managed_policies_to_add = [] + current_policies = [] + policies_to_add = [] + + # Read all the existing policies from the role object. Turn what we find into + # a list of hashes, where the hash parameter names match those that we use + # in the YAML description. This will aid comparison of current vs. desired policies + + policy_names = @iam.list_role_policies(fog_object.rolename).body["PolicyNames"] + + unless policy_names.nil? + + policy_names.each do |policy_name| + + c = { + :policy_document => @iam.get_role_policy(fog_object.rolename, policy_name).body["Policy"]["PolicyDocument"], + :policy_name => policy_name, + } + + current_policies << c + + end + end + + # Build add lists + policies.each do |p| + @log.debug("Policy action on is #{p}") + if p[:arn] + # Ensure any Managed Policies are attached. Fog support is limited, so always adds + @log.debug("For group #{fog_object.rolename} adding managed policy #{p[:arn]}") + managed_policies_to_add << { :arn => p[:arn] } + elsif p[:policy_name] + @log.debug("For role #{fog_object.rolename} checking policy #{p[:policy_name]}") + # Assume adding policy + pa = { + :policy_document => JSON.parse(p[:policy_document]), + :policy_name => p[:policy_name], + } + policies_to_add << pa + end + end + + + policies.each do |p| + @log.debug("For role #{fog_object.rolename} policy #{p.inspect}") + + # If we find a current policy that matches the desired policy, then + # remove that from the list of current policies - we will remove any + # remaining policies + current_policies.delete_if do |c| + if c[:policy_name] == p[:policy_name] + @log.debug( "#{p[:policy_name]} already exists" ) + + # Remove from the policies to add if the policy documents match + policies_to_add.delete_if do |a| + if (c[:policy_name] == a[:policy_name]) and + (c[:policy_document] == a[:policy_document]) + @log.debug("#{p[:policy_name]} is a match" ) + true + else + @log.debug("#{p[:policy_name]} is different" ) + @log.debug("new policy is '#{a[:policy_document]}'") + @log.debug("current policy is '#{c[:policy_document]}'") + false + end + end + true # so that delete_if removes the list item + else + false + end + end + end + + # At the end of this loop, anything left in the current_policies list + # represents a policy that's present on the infra, but should be deleted + # (since there's no matching desired policy), so delete those. + + current_policies.each do |p| + + @log.debug( "Removing policy #{p.inspect}" ) + @log.info( "For role #{fog_object.rolename} removing policy #{p[:policy_name]}" ) + @iam.delete_role_policy(fog_object.rolename, p[:policy_name]) + + end + + policies_to_add.each do |p| + + @log.debug( "For role #{fog_object.rolename} adding/updating policy #{p}" ) + @log.info( "For role #{fog_object.rolename} adding/updating policy #{p[:policy_name]}" ) + @iam.put_role_policy( fog_object.rolename, p[:policy_name], p[:policy_document] ) + + end + + # IAM Role Policy support is not complete in fog-aws, always attach policy + managed_policies_to_add.each do |p| + @log.debug( "For role #{fog_object.rolename} attaching policy #{p}" ) + @log.info( "For role #{fog_object.rolename} attaching policy #{p[:arn]}" ) + @iam.attach_role_policy(fog_object.rolename, p[:arn]) + end + + end + alias_method :fog_object, :read def delete return unless exists? @@ -80,6 +180,5 @@ fog_object.destroy end end -