<commit_before>class BuildCloud::IAMRole

    require 'json'

    include ::BuildCloud::Component

    @@objects = []

    def initialize ( fog_interfaces, log, options = {} )

        @iam     = fog_interfaces[:iam]
        @log     = log
        @options = options

        @log.debug( options.inspect )

        required_options(:rolename, :assume_role_policy_document)

    end

    def create

        policies = @options.delete(:policies)

        unless exists?

            @log.info( "Creating new IAM role for #{@options[:rolename]}" )

            # 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

            role = @iam.roles.new( @options )
            role.save

            @log.debug( role.inspect )

            @iam.create_instance_profile( @options[:rolename] )

            @iam.add_role_to_instance_profile( @options[:rolename], @options[:rolename] )

        end

        rationalise_policies( policies )

    end

    def read
        @iam.roles.select { |r| r.rolename == @options[:rolename] }.first
    end
    
    
    def rationalise_policies( policies )

        return if policies.empty?

        iam_role = read

        current_policies = []
        policies_to_add  = []

        # Read all the existing policies from the SG 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(iam_role.rolename).body["PolicyNames"]
        
        unless policy_names.nil? 

            policy_names.each do |policy_name|

                c = {
                    :policy_document => @iam.get_role_policy(iam_role.rolename, policy_name).body["Policy"]["PolicyDocument"],
                    :policy_name     => policy_name,
                }

                current_policies << c

            end
        end
        
        policies.each do |p|
            @log.debug("For role #{iam_role.rolename} checking policy #{p[:policy_name]}")
            
            # Assume adding policy
            pa = {
                :policy_document => p[:policy_document],
                :policy_name     => p[:policy_name],
            }

            policies_to_add << pa
            
            # 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] == JSON.parse(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 '#{JSON.parse(p[: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.
        # Changing a rule maps to "delete old rule, create new one".

        current_policies.each do |p|

            @log.debug( "Removing policy #{p.inspect}" )
            @log.info( "For role #{iam_role.rolename} removing policy #{p[:policy_name]}" )
            @iam.delete_role_policy(iam_role.rolename, p[:policy_name])

        end

        policies_to_add.each do |p|

            @log.debug( "For role #{iam_role.rolename} adding/updating policy #{p}" )
            @log.info( "For role #{iam_role.rolename} adding/updating policy #{p[:policy_name]}" )

            policy_document = JSON.parse( p[:policy_document] )

            @iam.put_role_policy( iam_role.rolename, p[:policy_name], policy_document )

        end<commit_msg>Clean up code<commit_after>class BuildCloud::IAMRole

    require 'json'

    include ::BuildCloud::Component

    @@objects = []

    def initialize ( fog_interfaces, log, options = {} )

        @iam     = fog_interfaces[:iam]
        @log     = log
        @options = options

        @log.debug( options.inspect )

        required_options(:rolename, :assume_role_policy_document)

    end

    def create

        policies = @options.delete(:policies)

        unless exists?

            @log.info( "Creating new IAM role for #{@options[:rolename]}" )

            # 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

            role = @iam.roles.new( @options )
            role.save

            @log.debug( role.inspect )

            @iam.create_instance_profile( @options[:rolename] )

            @iam.add_role_to_instance_profile( @options[:rolename], @options[:rolename] )

        end

        rationalise_policies( policies )

    end

    def read
        @iam.roles.select { |r| r.rolename == @options[:rolename] }.first
    end
    
    
    def rationalise_policies( policies )

        return if policies.empty?

        iam_role = read

        current_policies = []
        policies_to_add  = []

        # Read all the existing policies from the SG 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(iam_role.rolename).body["PolicyNames"]
        
        unless policy_names.nil? 

            policy_names.each do |policy_name|

                c = {
                    :policy_document => @iam.get_role_policy(iam_role.rolename, policy_name).body["Policy"]["PolicyDocument"],
                    :policy_name     => policy_name,
                }

                current_policies << c

            end
        end
        
        policies.each do |p|
            @log.debug("For role #{iam_role.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
            
            # 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.
        # Changing a rule maps to "delete old rule, create new one".

        current_policies.each do |p|

            @log.debug( "Removing policy #{p.inspect}" )
            @log.info( "For role #{iam_role.rolename} removing policy #{p[:policy_name]}" )
            @iam.delete_role_policy(iam_role.rolename, p[:policy_name])

        end

        policies_to_add.each do |p|

            @log.debug( "For role #{iam_role.rolename} adding/updating policy #{p}" )
            @log.info( "For role #{iam_role.rolename} adding/updating policy #{p[:policy_name]}" )
            @iam.put_role_policy( iam_role.rolename, p[:policy_name], p[:policy_document] )

        end
{'fraction_non_alphanumeric': 0.0920303605313093, 'fraction_numerical': 0.0, 'mean_word_length': 1.6440914158305462, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1848954', 'n_tokens_mistral': 2567, 'n_tokens_neox': 2463, 'n_words': 706}