class Ec2ex::CLI

Public Class Methods

new(args = [], options = {}, config = {}) click to toggle source
Calls superclass method
# File lib/ec2ex/cli.rb, line 17
def initialize(args = [], options = {}, config = {})
  super(args, options, config)
  @global_options = config[:shell].base.options
  @core = Core.new
  @ec2 = @core.client
  @elb = @core.elb_client
  @logger = @core.logger
end

Public Instance Methods

acls() click to toggle source
# File lib/ec2ex/cli.rb, line 416
def acls
  puts_json(@ec2.describe_network_acls.data.to_hash[:network_acls])
end
aggregate() click to toggle source
# File lib/ec2ex/cli.rb, line 468
def aggregate
  list = @core.instances_hash(options[:condition], options[:running_only]).map do |instance|
    options[:key].map do |key|
      eval("instance.#{key} ")
    end.join('_')
  end
  puts @core.group_count(list).to_json
end
allocate_address_vpc() click to toggle source
# File lib/ec2ex/cli.rb, line 583
def allocate_address_vpc
  response = @core.allocate_address_vpc
  puts response.data
end
connect_elb(_name = options[:name]) click to toggle source
# File lib/ec2ex/cli.rb, line 529
def connect_elb(_name = options[:name])
  @core.instances_hash({ Name: options[:name] }, true).each do |instance|
    option = { load_balancer_name: options[:load_balancer_name], instances: [instance_id: instance.instance_id] }
    @elb.deregister_instances_from_load_balancer(option)
    @elb.register_instances_with_load_balancer(option)
    print 'connecting ELB...'
    loop do
      break if 'InService' == @elb.describe_instance_health(option).instance_states.first.state
      sleep 10
      print '.'
    end
  end
end
copy() click to toggle source
# File lib/ec2ex/cli.rb, line 122
def copy
  instance = @core.instances_hash_first_result({ Name: options[:name] }, true)
  image_id = @core.create_image_with_instance(instance)
  instance_count = options[:instance_count]
  Parallel.map(instance_count.times.to_a, in_threads: Parallel.processor_count) do |server_index|
    security_group_ids = instance.security_groups.map { |security_group| security_group.group_id }
    request = {
      image_id: image_id,
      min_count: 1,
      max_count: 1,
      security_group_ids: security_group_ids,
      instance_type: instance.instance_type,
      placement: instance.placement.to_hash
    }
    request[:private_ip_address] = options[:private_ip_address] if options[:private_ip_address]
    if instance.iam_instance_profile
      request[:iam_instance_profile] = { name: instance.iam_instance_profile.arn.split('/').last }
    end
    if instance.key_name
      request[:key_name] = instance.key_name
    end

    request.merge!(eval(options[:params]))
    request[:subnet_id] = if request[:private_ip_address]
      @core.get_subnet(request[:private_ip_address]).subnet_id
    else
      instance.subnet_id
    end

    response = @ec2.run_instances(request)
    instance_id = response.instances.first.instance_id
    @ec2.wait_until(:instance_running, instance_ids: [instance_id])
    @ec2.create_tags(resources: [instance_id], tags: instance.tags)
    @ec2.create_tags(resources: [instance_id], tags: [{ key: 'InstanceIndex', value: "#{server_index}" }])
    @ec2.create_tags(resources: [instance_id], tags: [{ key: 'InstanceCount', value: "#{instance_count}" }])
    unless options[:tag].nil?
      @ec2.create_tags(
        resources: [instance_id],
        tags: @core.format_tag(
          options[:tag],
          @core.get_tag_hash_from_id(instance_id)
        )
      )
    end
    public_ip_address = get_public_ip_address(options[:public_ip_address], instance.public_ip_address, false)
    @core.associate_address(instance_id, public_ip_address)
    @logger.info("created instance => #{instance_id}")
  end
end
copy_tag(_name = options[:name]) click to toggle source
# File lib/ec2ex/cli.rb, line 433
def copy_tag(_name = options[:name])
  source = @core.instances_hash({ Name: options[:source] }, true)
  dest = @core.instances_hash({ Name: options[:dest] }, true)
  @ec2.create_tags(resources: dest.map { |instance| instance.instance_id }, tags: source.first.tags)
  @ec2.create_tags(resources: dest.map { |instance| instance.instance_id }, tags: [{ key: 'Name', value: options[:dest] }])
end
create_image() click to toggle source
# File lib/ec2ex/cli.rb, line 72
def create_image
  results = @core.instances_hash({ Name: options[:name] }, false)
  Parallel.map(results, in_threads: options[:proc]) do |instance|
    begin
      @core.create_image_with_instance(instance, options[:region])
    rescue => e
      @logger.info "\n#{e.message}\n#{e.backtrace.join("\n")}"
    end
  end
end
delete_deny_acl_all() click to toggle source
# File lib/ec2ex/cli.rb, line 394
def delete_deny_acl_all
  acls = @ec2.describe_network_acls(network_acl_ids: [options[:acl_id]])

  allow_any_rule_number = acls.network_acl_set.first.entries.select {|r|
                     !r.egress && r.cidr_block == '0.0.0.0/0' && r.rule_action == 'allow'
                   }.first.rule_number

  deny_rules = acls.network_acls.first.entries.select {|r|
                     !r.egress && r.rule_number < allow_any_rule_number
                   }.sort_by { |r| r.rule_number }

  deny_rules.each do |deny_rule|
    option = {
      network_acl_id: options[:acl_id],
      rule_number: deny_rule.rule_number,
      egress: false
    }
    @ec2.delete_network_acl_entry(option)
  end
end
deregister_image() click to toggle source
# File lib/ec2ex/cli.rb, line 86
def deregister_image
  @core.get_old_images(options[:name], options[:older_than]).each do |image|
    image_id = image[:image_id]
    @logger.info "delete AMI #{image_id} [#{image[:name]}]"
    @ec2.deregister_image({image_id: image_id})
    snapshot_ids = image[:block_device_mappings]
        .select{ |block_device_mapping| block_device_mapping[:ebs] != nil }
        .map{ |block_device_mapping| block_device_mapping[:ebs][:snapshot_id] }

    snapshot_ids.each do |snapshot_id|
      @logger.info "delete snapshot #{snapshot_id}"
      @ec2.delete_snapshot({snapshot_id: snapshot_id})
    end
  end
end
disconnect_elb() click to toggle source
# File lib/ec2ex/cli.rb, line 546
def disconnect_elb
  @core.instances_hash({ Name: options[:name] }, true).each do |instance|
    option = { load_balancer_name: options[:load_balancer_name], instances: [instance_id: instance.instance_id] }
    @elb.deregister_instances_from_load_balancer(option)
  end
end
elbs() click to toggle source
# File lib/ec2ex/cli.rb, line 554
def elbs
  puts_json @elb.describe_load_balancers.data.to_h[:load_balancer_descriptions]
end
events() click to toggle source
# File lib/ec2ex/cli.rb, line 559
def events
  results = []
  @core.instances_hash({}, true).each do |i|
    status = @ec2.describe_instance_status(instance_ids: [i.instance_id])
    events = status.data[:instance_status_set][0][:events] rescue nil
    next if events.nil? or events.empty?
    events.each do |event|
      next if event[:description] =~ /^\[Completed\]/
      event[:id] = i.id
      event[:name] = i.tags['Name']
      event[:availability_zone] = i.availability_zone
      results << event
    end
  end
  puts_json results
end
instance_metadata() click to toggle source
# File lib/ec2ex/cli.rb, line 590
def instance_metadata
  response = @core.get_metadata(options[:path])
  puts response
end
latest_image() click to toggle source
# File lib/ec2ex/cli.rb, line 578
def latest_image
  puts_json @core.latest_image_with_name(options[:name])
end
old_images() click to toggle source
# File lib/ec2ex/cli.rb, line 105
def old_images
  puts_json(@core.get_old_images(options[:name], options[:older_than]))
end
own_tag() click to toggle source
# File lib/ec2ex/cli.rb, line 597
def own_tag
  response = @core.own_tag
  if options[:key]
    puts response[options[:key]]
  else
    puts_json response
  end
end
reboot() click to toggle source
# File lib/ec2ex/cli.rb, line 479
def reboot
  @core.instances_hash({ Name: options[:name] }, true).each do |instance|
    @ec2.reboot_instances(instance_ids: [instance.instance_id])
    sleep 5
    @ec2.wait_until(:instance_running, instance_ids: [instance.instance_id])
  end
end
regist_deny_acl() click to toggle source
# File lib/ec2ex/cli.rb, line 366
def regist_deny_acl
  acls = @ec2.describe_network_acls(network_acl_ids: [options[:acl_id]])

  allow_any_rule_number = acls.network_acls.first.entries.select {|r|
                     !r.egress && r.cidr_block == '0.0.0.0/0' && r.rule_action == 'allow'
                   }.first.rule_number

  deny_rules = acls.network_acls.first.entries.select {|r|
                     !r.egress && r.rule_number < allow_any_rule_number
                   }.sort_by { |r| r.rule_number }

  next_rule_number = deny_rules.empty? ? 1 : deny_rules.last.rule_number + 1

  unless deny_rules.any? { |r| r.cidr_block == "#{options[:ip_address]}/32" }
    option = {
      network_acl_id: options[:acl_id],
      rule_number: next_rule_number,
      rule_action: 'deny',
      protocol: '-1',
      cidr_block: "#{options[:ip_address]}/32",
      egress: false
    }
    @ec2.create_network_acl_entry(option)
  end
end
renew() click to toggle source
# File lib/ec2ex/cli.rb, line 176
def renew
  params = eval(options[:params])
  results = @core.instances_hash({ Name: options[:name] }, false)
  results.each do |instance|
    tags = instance.tags
    tag_hash = @core.get_tag_hash(tags)
    if options[:stop]
      @core.stop_instance(instance.instance_id)
    end

    image_id = @core.create_image_with_instance(instance)

    @core.terminate_instance(instance)
    security_group_ids = instance.security_groups.map { |security_group| security_group.group_id }
    request = {
      image_id: image_id,
      min_count: 1,
      max_count: 1,
      security_group_ids: security_group_ids,
      instance_type: instance.instance_type,
      placement: instance.placement.to_hash,
      private_ip_address: instance.private_ip_address
    }
    if instance.iam_instance_profile
      request[:iam_instance_profile] = { name: instance.iam_instance_profile.arn.split('/').last }
    end

    if instance.key_name
      request[:key_name] = instance.key_name
    end
    request.merge!(params)
    request[:subnet_id] = @core.get_subnet(request[:private_ip_address]).subnet_id

    response = @ec2.run_instances(request)
    instance_id = response.instances.first.instance_id
    sleep 5
    @ec2.wait_until(:instance_running, instance_ids: [instance_id])
    @ec2.create_tags(resources: [instance_id], tags: instance.tags)

    @core.associate_address(instance_id, instance.public_ip_address)
  end
end
reserved() click to toggle source
# File lib/ec2ex/cli.rb, line 42
def reserved
  filter = []
  filter << { name: 'state', values: ['active'] }
  reserved_hash = {}
  @ec2.describe_reserved_instances(filters: filter)[:reserved_instances].each{ |reserved|
    sum = reserved_hash[reserved[:instance_type] + '_' + reserved[:availability_zone]] || 0
    reserved_hash[reserved[:instance_type] + '_' + reserved[:availability_zone]] = sum + reserved[:instance_count]
  }
  list = @core.instances_hash({}, true).select { |instance| instance[:instance_lifecycle].nil? }
  list = list.map{ |_instance|
    ['instance_type', 'placement.availability_zone'].map do |key|
      eval("_instance.#{key} ")
    end.join('_')
  }
  result = {}
  @core.group_count(list).each do |k, v|
    result[k] = { instance_count: v, reserved_count: 0 }
  end
  reserved_hash.each do |k, v|
    hash = result[k] || { instance_count: 0 }
    hash[:reserved_count] = v
    result[k] = hash
  end
  puts_json(result)
end
run_spot() click to toggle source
# File lib/ec2ex/cli.rb, line 316
def run_spot
  image = @core.latest_image_with_name(options[:name])

  tag_hash = @core.get_tag_hash(image[:tags])
  private_ip_address = options[:private_ip_address] || tag_hash.private_ip_address
  exit 0 if @core.ping?(private_ip_address)

  option = {
    instance_count: 1,
    spot_price: options[:price],
    launch_specification: {
      image_id: image[:image_id],
      instance_type: tag_hash.instance_type
    },
  }

  option[:block_duration_minutes] = options[:block_duration_minutes] if options[:block_duration_minutes]

  if tag_hash.iam_instance_profile
    option[:launch_specification][:iam_instance_profile] = { name: tag_hash.iam_instance_profile }
  end

  if tag_hash.key_name
    option[:launch_specification][:key_name] = tag_hash.key_name
  end

  network_interface = {
    device_index: 0,
    subnet_id: @core.get_subnet(private_ip_address).subnet_id,
    groups: JSON.parse(tag_hash.security_groups),
    private_ip_addresses: [{ private_ip_address: private_ip_address, primary: true }]
  }
  option[:launch_specification][:network_interfaces] = [network_interface]
  option[:launch_specification].merge!(eval(options[:params]))

  response = @ec2.request_spot_instances(option)
  spot_instance_request_id = response.spot_instance_requests.first.spot_instance_request_id
  sleep 5
  instance_id = @core.wait_spot_running(spot_instance_request_id)
  @core.set_delete_on_termination(@core.instances_hash_with_id(instance_id))
  @ec2.create_tags(resources: [instance_id], tags: JSON.parse(tag_hash[:tags]))

  if tag_hash.public_ip_address
    @core.associate_address(instance_id, tag_hash.public_ip_address)
  end
end
search_by_tags() click to toggle source
# File lib/ec2ex/cli.rb, line 37
def search_by_tags
  puts_json @core.instances_hash(options[:condition], options[:running_only])
end
search_images(name = options[:name]) click to toggle source
# File lib/ec2ex/cli.rb, line 460
def search_images(name = options[:name])
  puts_json @core.images(name)
end
set_delete_on_termination() click to toggle source
# File lib/ec2ex/cli.rb, line 451
def set_delete_on_termination
  @core.instances_hash({ Name: options[:name] }, true).each do |instance|
    @core.set_delete_on_termination(instance)
    @logger.info "set delete on termination => #{instance.instance_id}"
  end
end
set_tag() click to toggle source
# File lib/ec2ex/cli.rb, line 443
def set_tag
  instances = @core.instances_hash({ Name: options[:name] }, true)
  tags = @core.format_tag(options[:tag])
  @ec2.create_tags(resources: instances.map { |instance| instance.instance_id }, tags: tags)
end
sg() click to toggle source
# File lib/ec2ex/cli.rb, line 426
def sg
  puts_json(@ec2.describe_security_groups.data.to_hash[:security_groups])
end
spot() click to toggle source
# File lib/ec2ex/cli.rb, line 231
def spot
  instance = @core.instances_hash_first_result({ Name: options[:name] }, true)
  if options[:stop]
    @core.stop_instance(instance.instance_id)
  end
  image_id = @core.create_image_with_instance(instance)

  instance_count = options[:instance_count]
  Parallel.map(instance_count.times.to_a, in_threads: Parallel.processor_count) do |server_index|
    security_group_ids = instance.security_groups.map { |security_group| security_group.group_id }
    option = {
      instance_count: 1,
      spot_price: options[:price],
      launch_specification: {
        image_id: image_id,
        instance_type: instance.instance_type,
        security_group_ids: security_group_ids,
        subnet_id: instance.subnet_id
      },
    }
    option[:type] = 'persistent' if options[:persistent]
    option[:block_duration_minutes] = options[:block_duration_minutes] if options[:block_duration_minutes]

    if instance.iam_instance_profile
      option[:launch_specification][:iam_instance_profile] = { name: instance.iam_instance_profile.arn.split('/').last }
    end

    if instance.key_name
      option[:launch_specification][:key_name] = instance.key_name
    end

    option[:launch_specification].merge!(eval(options[:params]))

    private_ip_address = nil
    if options[:private_ip_address].nil?
      private_ip_address = instance.private_ip_address if options[:renew]
    else
      private_ip_address = options[:private_ip_address]
    end

    if private_ip_address
      network_interface = {
        device_index: 0,
        subnet_id: @core.get_subnet(private_ip_address).subnet_id,
        groups: option[:launch_specification][:security_group_ids],
        private_ip_addresses: [{ private_ip_address: private_ip_address, primary: true }]
      }
      option[:launch_specification][:network_interfaces] = [network_interface]
      option[:launch_specification].delete(:security_group_ids)
      option[:launch_specification].delete(:subnet_id)
    end
    @core.terminate_instance(instance) if options[:renew]

    response = @ec2.request_spot_instances(option)
    spot_instance_request_id = response.spot_instance_requests.first.spot_instance_request_id
    sleep 5
    instance_id = @core.wait_spot_running(spot_instance_request_id)
    @core.set_delete_on_termination(@core.instances_hash_with_id(instance_id))

    @ec2.create_tags(resources: [instance_id], tags: instance.tags)
    @ec2.create_tags(resources: [instance_id], tags: [{ key: 'Spot', value: 'true' }])
    @ec2.create_tags(resources: [instance_id], tags: [{ key: 'InstanceIndex', value: "#{server_index}" }])
    @ec2.create_tags(resources: [instance_id], tags: [{ key: 'InstanceCount', value: "#{instance_count}" }])

    unless options[:tag].empty?
      @ec2.create_tags(
        resources: [instance_id],
        tags: @core.format_tag(
          options[:tag],
          @core.get_tag_hash_from_id(instance_id)
        )
      )
    end

    public_ip_address = get_public_ip_address(options[:public_ip_address], instance.public_ip_address, options[:renew])
    @core.associate_address(instance_id, public_ip_address)
  end
end
start() click to toggle source
# File lib/ec2ex/cli.rb, line 512
def start
  @core.instances_hash({ Name: options[:name] }, false).each do |instance|
    @core.start_instance(instance.instance_id)
  end
end
stop() click to toggle source
# File lib/ec2ex/cli.rb, line 520
def stop
  @core.instances_hash({ Name: options[:name] }, false).each do |instance|
    @core.stop_instance(instance.instance_id)
  end
end
stop_start() click to toggle source
# File lib/ec2ex/cli.rb, line 489
def stop_start
  options[:names].each do |name|
    @core.instances_hash({ Name: name }, true).each do |instance|
      instance.stop
      @ec2.wait_until(:instance_stopped, instance_ids: [instance.instance_id])
      instance.start
      @ec2.wait_until(:instance_running, instance_ids: [instance.instance_id])
      @logger.info "#{instance.tags['Name']} restart complete!"
    end
  end
end
subnets() click to toggle source
# File lib/ec2ex/cli.rb, line 421
def subnets
  puts_json(@ec2.describe_subnets.data.to_hash[:subnets])
end
terminate() click to toggle source
# File lib/ec2ex/cli.rb, line 503
def terminate
  instances = @core.instances_hash({ Name: options[:name] }, false)
  Parallel.map(instances, in_threads: Parallel.processor_count) do |instance|
    @core.terminate_instance(instance)
  end
end

Private Instance Methods

get_public_ip_address(define_public_ip_address, instance_public_ip_address, renew) click to toggle source
# File lib/ec2ex/cli.rb, line 618
def get_public_ip_address(define_public_ip_address, instance_public_ip_address, renew)
  public_ip_address = nil
  if define_public_ip_address == 'auto'
    allocate_address_result = @core.allocate_address_vpc
    public_ip_address = allocate_address_result.public_ip
  elsif define_public_ip_address.nil?
    public_ip_address = instance_public_ip_address if renew
  else
    public_ip_address = define_public_ip_address
  end
  public_ip_address
end
instances(name, _running_only = true) click to toggle source
# File lib/ec2ex/cli.rb, line 607
def instances(name, _running_only = true)
  @ec2.instances.with_tag('Name', "#{name}")
end
puts_json(data) click to toggle source
# File lib/ec2ex/cli.rb, line 611
def puts_json(data)
  unless @global_options[:fields].nil?
    data = @core.extract_fields(data, @global_options[:fields])
  end
  puts JSON.pretty_generate(data)
end