Skip to content

Commit

Permalink
Merge pull request #8 from winebarrel/v0.2.1
Browse files Browse the repository at this point in the history
v0.2.1
  • Loading branch information
Genki Sugawara committed Jul 4, 2015
2 parents 96cf350 + aa28651 commit c5cbe07
Show file tree
Hide file tree
Showing 19 changed files with 623 additions and 62 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -16,3 +16,4 @@ test.rb
IAMfile
*.iam
account.csv
*.json
10 changes: 10 additions & 0 deletions README.md
Expand Up @@ -58,6 +58,7 @@ Usage: miam [options]
-o, --output FILE
--split
--split-more
--format=FORMAT
--export-concurrency N
--target REGEXP
--no-color
Expand Down Expand Up @@ -86,6 +87,10 @@ user "bob", :path => "/developer/" do
"Effect"=>"Allow",
"Resource"=>"*"}]}
end

attached_managed_policies(
# attached_managed_policy
)
end

user "mary", :path => "/staff/" do
Expand Down Expand Up @@ -114,6 +119,11 @@ user "mary", :path => "/staff/" do
"Effect"=>"Allow",
"Resource"=>"*"}]}
end

attached_managed_policies(
"arn:aws:iam::aws:policy/AdministratorAccess",
"arn:aws:iam::123456789012:policy/my_policy"
)
end

group "Admin", :path => "/admin/" do
Expand Down
41 changes: 33 additions & 8 deletions bin/miam
Expand Up @@ -13,9 +13,14 @@ file = DEFAULT_FILENAME
output_file = '-'
account_output = 'account.csv'
split = false
MAGIC_COMMENT = <<-EOS
# -*- mode: ruby -*-
# vi: set ft=ruby :
EOS

options = {
:dry_run => false,
:format => :ruby,
:color => true,
:debug => false,
}
Expand All @@ -29,6 +34,7 @@ ARGV.options do |opt|
region = nil
profile_name = nil
credentials_path = nil
format_passed = false

opt.on('-p', '--profile PROFILE_NAME') {|v| profile_name = v }
opt.on('' , '--credentials-path PATH') {|v| credentials_path = v }
Expand All @@ -43,6 +49,7 @@ ARGV.options do |opt|
opt.on('-o', '--output FILE') {|v| output_file = v }
opt.on('' , '--split') { split = true }
opt.on('' , '--split-more') { split = :more }
opt.on('', '--format=FORMAT', [:ruby, :json]) {|v| format_passed = true; options[:format] = v }
opt.on('' , '--export-concurrency N', Integer) {|v| options[:export_concurrency] = v }
opt.on('' , '--target REGEXP') {|v| options[:target] = Regexp.new(v) }
opt.on('' , '--no-color') { options[:color] = false }
Expand Down Expand Up @@ -70,6 +77,10 @@ ARGV.options do |opt|

aws_opts[:region] = region if region
Aws.config.update(aws_opts)

if not format_passed and [file, output_file].any? {|i| i =~ /\.json\z/ }
options[:format] = :json
end
rescue => e
$stderr.puts("[ERROR] #{e.message}")
exit 1
Expand Down Expand Up @@ -97,9 +108,9 @@ begin
output_file = DEFAULT_FILENAME if output_file == '-'
requires = []

client.export(:split_more => (split == :more)) do |args|
client.export(:split_more => (split == :more), :convert => (options[:format] == :ruby)) do |args|
type, dsl = args.values_at(:type, :dsl)
next if dsl.strip.empty?
next if dsl.empty?

type = type.to_s
dir = File.dirname(output_file)
Expand All @@ -117,27 +128,41 @@ begin
requires << iam_filename
end

if options[:format] == :json
iam_file << '.json'
end

logger.info(" write `#{iam_file}`")

open(iam_file, 'wb') do |f|
f.puts MAGIC_COMMENT if options[:format] == :ruby
f.puts dsl
end
end

logger.info(" write `#{output_file}`")
if options[:format] == :ruby
logger.info(" write `#{output_file}`")

open(output_file, 'wb') do |f|
requires.each do |iam_file|
f.puts "require '#{iam_file}'"
open(output_file, 'wb') do |f|
f.puts MAGIC_COMMENT

requires.each do |iam_file|
f.puts "require '#{iam_file}'"
end
end
end
else
exported = client.export(:convert => (options[:format] == :ruby))

if output_file == '-'
logger.info('# Export IAM')
puts client.export.strip
puts exported
else
logger.info("Export IAM to `#{output_file}`")
open(output_file, 'wb') {|f| f.puts client.export.strip }
open(output_file, 'wb') do |f|
f.puts MAGIC_COMMENT if options[:format] == :ruby
f.puts exported
end
end
end
when :apply
Expand Down
1 change: 0 additions & 1 deletion lib/miam.rb
Expand Up @@ -21,7 +21,6 @@ module Miam; end
require 'miam/dsl/context/user'
require 'miam/dsl/converter'
require 'miam/exporter'
require 'miam/ext/aws_ext'
require 'miam/ext/string_ext'
require 'miam/password_manager'
require 'miam/utils'
Expand Down
95 changes: 88 additions & 7 deletions lib/miam/client.rb
Expand Up @@ -2,7 +2,7 @@ class Miam::Client
include Miam::Logger::Helper

def initialize(options = {})
@options = options
@options = {:format => :ruby}.merge(options)
aws_config = options.delete(:aws_config) || {}
@iam = Aws::IAM::Client.new(aws_config)
@driver = Miam::Driver.new(@iam, options)
Expand All @@ -21,15 +21,30 @@ def export(export_options = {})
more_splitted = splitted.dup
more_splitted[type] = {}
more_splitted[type][name] = attrs
yield(:type => type, :name => name, :dsl => Miam::DSL.convert(more_splitted, @options).strip)

dsl = exec_by_format(
:ruby => proc { Miam::DSL.convert(more_splitted, @options).strip },
:json => proc { JSON.pretty_generate(more_splitted) }
)

yield(:type => type, :name => name, :dsl => dsl)
end
else
splitted[type] = exported[type]
yield(:type => type, :dsl => Miam::DSL.convert(splitted, @options).strip)

dsl = exec_by_format(
:ruby => proc { Miam::DSL.convert(splitted, @options).strip },
:json => proc { JSON.pretty_generate(splitted) }
)

yield(:type => type, :dsl => dsl)
end
end
else
Miam::DSL.convert(exported, @options)
dsl = exec_by_format(
:ruby => proc { Miam::DSL.convert(exported, @options).strip },
:json => proc { JSON.pretty_generate(exported) }
)
end
end

Expand Down Expand Up @@ -97,6 +112,7 @@ def walk_users(expected, actual, group_users)
def walk_user(user_name, expected_attrs, actual_attrs)
updated = walk_login_profile(user_name, expected_attrs[:login_profile], actual_attrs[:login_profile])
updated = walk_user_groups(user_name, expected_attrs[:groups], actual_attrs[:groups]) || updated
updated = walk_attached_managed_policies(:user, user_name, expected_attrs[:attached_managed_policies], actual_attrs[:attached_managed_policies]) || updated
walk_policies(:user, user_name, expected_attrs[:policies], actual_attrs[:policies]) || updated
end

Expand Down Expand Up @@ -182,7 +198,8 @@ def walk_groups(expected, actual, actual_users, group_users)
end

def walk_group(group_name, expected_attrs, actual_attrs)
walk_policies(:group, group_name, expected_attrs[:policies], actual_attrs[:policies])
updated = walk_policies(:group, group_name, expected_attrs[:policies], actual_attrs[:policies])
walk_attached_managed_policies(:group, group_name, expected_attrs[:attached_managed_policies], actual_attrs[:attached_managed_policies]) || updated
end

def walk_roles(expected, actual, instance_profile_roles)
Expand Down Expand Up @@ -232,6 +249,7 @@ def walk_role(role_name, expected_attrs, actual_attrs)

updated = walk_assume_role_policy(role_name, expected_attrs[:assume_role_policy_document], actual_attrs[:assume_role_policy_document])
updated = walk_role_instance_profiles(role_name, expected_attrs[:instance_profiles], actual_attrs[:instance_profiles]) || updated
updated = walk_attached_managed_policies(:role, role_name, expected_attrs[:attached_managed_policies], actual_attrs[:attached_managed_policies]) || updated
walk_policies(:role, role_name, expected_attrs[:policies], actual_attrs[:policies]) || updated
end

Expand Down Expand Up @@ -389,13 +407,43 @@ def walk_policy(type, user_or_group_name, policy_name, expected_document, actual
updated
end

def walk_attached_managed_policies(type, name, expected_attached_managed_policies, actual_attached_managed_policies)
expected_attached_managed_policies = expected_attached_managed_policies.sort
actual_attached_managed_policies = actual_attached_managed_policies.sort
updated = false

if expected_attached_managed_policies != actual_attached_managed_policies
add_attached_managed_policies = expected_attached_managed_policies - actual_attached_managed_policies
remove_attached_managed_policies = actual_attached_managed_policies - expected_attached_managed_policies

unless add_attached_managed_policies.empty?
@driver.attach_policies(type, name, add_attached_managed_policies)
end

unless remove_attached_managed_policies.empty?
@driver.detach_policies(type, name, remove_attached_managed_policies)
end

updated = true
end

updated
end


def load_file(file)
if file.kind_of?(String)
open(file) do |f|
Miam::DSL.parse(f.read, file)
exec_by_format(
:ruby => proc { Miam::DSL.parse(f.read, file) },
:json => proc { load_json(f) }
)
end
elsif file.respond_to?(:read)
Miam::DSL.parse(file.read, file.path)
exec_by_format(
:ruby => proc { Miam::DSL.parse(file.read, file.path) },
:json => proc { load_json(f) }
)
else
raise TypeError, "can't convert #{file} into File"
end
Expand All @@ -408,4 +456,37 @@ def target_matched?(name)
true
end
end

def exec_by_format(proc_by_format)
format_proc = proc_by_format[@options[:format]]
raise "Invalid format: #{@options[:format]}" unless format_proc
format_proc.call
end

def load_json(json)
json = JSON.load(json)
normalized = {}

json.each do |top_key, top_value|
normalized[top_key.to_sym] = top_attrs = {}

top_value.each do |second_key, second_value|
top_attrs[second_key] = second_attrs = {}

second_value.each do |third_key, third_value|
third_key = third_key.to_sym

if third_key == :login_profile
new_third_value = {}
third_value.each {|k, v| new_third_value[k.to_sym] = v }
third_value = new_third_value
end

second_attrs[third_key] = third_value
end
end
end

normalized
end
end

0 comments on commit c5cbe07

Please sign in to comment.