class Piculet::Client

Public Class Methods

new(options = {}) click to toggle source
# File lib/piculet/client.rb, line 5
def initialize(options = {})
  @options = OpenStruct.new(options)
  @options_hash = options
  @options.ec2 = AWS::EC2.new
end

Public Instance Methods

apply(file) click to toggle source
# File lib/piculet/client.rb, line 11
def apply(file)
  @options.ec2.owner_id
  AWS.memoize { walk(file) }
end
export(options = {}) { |exported, converter| ... } click to toggle source
# File lib/piculet/client.rb, line 40
def export(options = {})
  exported = AWS.memoize do
    Exporter.export(@options.ec2, @options_hash.merge(options))
  end

  converter = proc do |src|
    if options[:without_convert]
      exported
    else
      DSL.convert(src, @options.ec2.owner_id)
    end
  end

  if block_given?
    yield(exported, converter)
  else
    converter.call(exported)
  end
end
should_skip(sg_name, sg) click to toggle source
# File lib/piculet/client.rb, line 16
def should_skip(sg_name, sg)
  # Name
  if @options.sg_names
    if not @options.sg_names.include?(sg_name)
      return true
    end
  end

  if @options.exclude_sgs
    if @options.exclude_sgs.any? {|regex| sg_name =~ regex}
      return true
    end
  end

  # Tag
  if @options.exclude_tags
    if sg and (@options.exclude_tags & sg.tags.keys).any?
      return true
    end
  end

  false
end

Private Instance Methods

collect_to_hash(collection, *key_attrs) { |item| ... } click to toggle source
# File lib/piculet/client.rb, line 204
def collect_to_hash(collection, *key_attrs)
  options = key_attrs.last.kind_of?(Hash) ? key_attrs.pop : {}
  hash = {}

  collection.each do |item|
    key = block_given? ? yield(item) : key_attrs.map {|k| item.send(k) }

    if options[:has_many]
      hash[key] ||= []
      hash[key] << item
    else
      hash[key] = item
    end
  end

  return hash
end
load_by_format(src, path) click to toggle source
# File lib/piculet/client.rb, line 73
def load_by_format(src, path)
  if @options.format == :json
    src = load_json(src, path)
  end

  DSL.define(src, path).result
end
load_file(file) click to toggle source
# File lib/piculet/client.rb, line 61
def load_file(file)
  if file.kind_of?(String)
    open(file) do |f|
      load_by_format(f.read, file)
    end
  elsif file.respond_to?(:read)
    load_by_format(file.read, file.path)
  else
    raise TypeError, "can't convert #{file} into File"
  end
end
load_json(json, path) click to toggle source
# File lib/piculet/client.rb, line 81
def load_json(json, path)
  json = JSON.parse(json, :symbolize_names => true)

  if json.has_key?(:'')
    json[nil] = json.delete(:'')
  end

  DSL.convert(json, @options.ec2.owner_id)
end
walk(file) click to toggle source
# File lib/piculet/client.rb, line 91
def walk(file)
  dsl = load_file(file)

  dsl_ec2s = dsl.ec2s
  ec2 = EC2Wrapper.new(@options.ec2, @options)

  aws_ec2s = collect_to_hash(ec2.security_groups, :has_many => true) do |item|
    item.vpc? ? item.vpc_id : nil
  end

  dsl_ec2s.each do |vpc, ec2_dsl|
    if @options.ec2s
      next unless @options.ec2s.any? {|i| (i == 'classic' and vpc.nil?) or i == vpc }
    end

    ec2_aws = aws_ec2s[vpc]

    if ec2_aws
      walk_ec2(vpc, ec2_dsl, ec2_aws, ec2.security_groups)
    else
      log(:warn, "EC2 `#{vpc || :classic}` is not found", :yellow)
    end
  end

  ec2.updated?
end
walk_ec2(vpc, ec2_dsl, ec2_aws, collection_api) click to toggle source
# File lib/piculet/client.rb, line 118
def walk_ec2(vpc, ec2_dsl, ec2_aws, collection_api)
  sg_list_dsl = collect_to_hash(ec2_dsl.security_groups, :name)
  sg_list_aws = collect_to_hash(ec2_aws, :name)

  sg_list_dsl.each do |key, sg_dsl|
    name = key[0]
    sg_aws = sg_list_aws[key]

    next if should_skip(name, sg_aws)

    unless sg_aws
      sg_aws = collection_api.create(name, :vpc => vpc, :description => sg_dsl.description)

      if vpc and sg_dsl.egress.empty?
        log(:warn, '`egress any 0.0.0.0/0` is implicitly defined', :yellow)
      end

      sg_list_aws[key] = sg_aws
    end
  end

  sg_list_dsl.each do |key, sg_dsl|
    name = key[0]
    sg_aws = sg_list_aws.delete(key)

    next if should_skip(name, sg_aws)

    walk_security_group(sg_dsl, sg_aws)
  end

  sg_list_aws.each do |key, sg_aws|
    name = key[0]

    next if should_skip(name, sg_aws)

    sg_aws.ingress_ip_permissions.each {|i| i.delete }
    sg_aws.egress_ip_permissions.each {|i| i.delete } if vpc
  end

  sg_list_aws.each do |key, sg_aws|
    name = key[0]

    next if should_skip(name, sg_aws)

    sg_aws.delete
  end
end
walk_permissions(permissions_dsl, permissions_aws) click to toggle source
# File lib/piculet/client.rb, line 182
def walk_permissions(permissions_dsl, permissions_aws)
  perm_list_dsl = collect_to_hash(permissions_dsl, :protocol, :port_range)
  perm_list_aws = collect_to_hash(permissions_aws, :protocol, :port_range)

  perm_list_aws.each do |key, perm_aws|
    perm_dsl = perm_list_dsl.delete(key)

    if perm_dsl
      unless perm_aws.eql?(perm_dsl)
        perm_aws.update(perm_dsl)
      end
    else
      perm_aws.delete
    end
  end

  perm_list_dsl.each do |key, perm_dsl|
    protocol, port_range = key
    permissions_aws.create(protocol, port_range, perm_dsl)
  end
end
walk_security_group(security_group_dsl, security_group_aws) click to toggle source
# File lib/piculet/client.rb, line 166
def walk_security_group(security_group_dsl, security_group_aws)
  unless security_group_aws.eql?(security_group_dsl)
    security_group_aws.update(security_group_dsl)
  end

  walk_permissions(
    security_group_dsl.ingress,
    security_group_aws.ingress_ip_permissions)

  if security_group_aws.vpc?
    walk_permissions(
      security_group_dsl.egress,
      security_group_aws.egress_ip_permissions)
  end
end