Class: AwsEc2Environment

Inherits:
Object
  • Object
show all
Defined in:
lib/aws_ec2_environment/config.rb,
lib/aws_ec2_environment.rb,
lib/aws_ec2_environment/version.rb,
lib/aws_ec2_environment/ci_service.rb,
lib/aws_ec2_environment/ssm_port_forwarding_session.rb

Overview

Holds the details about an application environment composed primarily of EC2 instances, including

- what region they're in
- the user to use for sshing
- how to identify those instances
- how to identify the bastion instance to use to connect (if any)
- if SSM should be used to connect to the instances

Defined Under Namespace

Classes: BastionNotExpectedError, BastionNotFoundError, CiService, Config, EnvironmentConfigNotFound, Error, SsmPortForwardingSession

Constant Summary collapse

VERSION =
"0.1.0"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config, logger: Logger.new($stdout)) ⇒ AwsEc2Environment

Returns a new instance of AwsEc2Environment.



26
27
28
29
30
# File 'lib/aws_ec2_environment.rb', line 26

def initialize(config, logger: Logger.new($stdout))
  @config = config
  @logger = logger
  @ssm_port_forwarding_sessions = []
end

Instance Attribute Details

#configObject (readonly)

Returns the value of attribute config.



16
17
18
# File 'lib/aws_ec2_environment.rb', line 16

def config
  @config
end

Class Method Details

.from_yaml_file(path, env_name) ⇒ Object



18
19
20
21
22
23
24
# File 'lib/aws_ec2_environment.rb', line 18

def self.from_yaml_file(path, env_name)
  config = YAML.safe_load_file(path).fetch(env_name.to_s, nil)

  raise EnvironmentConfigNotFound, "#{path} does not have an environment named \"#{env_name}\"" if config.nil?

  new(AwsEc2Environment::Config.new(env_name, config))
end

Instance Method Details

#bastion_public_ipObject

Finds the public ip of the bastion instance for this environment.

An error will be thrown if any of the following are true:

- no bastion filters have been provided (indicating a bastion should not be used)
- no instances are matched
- multiple instance are matched
- the matched instance does not have a public ip


76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/aws_ec2_environment.rb', line 76

def bastion_public_ip
  if @config.bastion_filters.nil?
    raise BastionNotExpectedError, "The #{@config.env_name} environment is not configured with a bastion"
  end

  instances = ec2_describe_instances(@config.bastion_filters)

  if instances.length != 1
    raise(
      BastionNotFoundError,
      "#{instances.length} potential bastion instances were found - " \
      "please ensure your filters are specific enough to only return a single instance"
    )
  end

  ip_address = instances[0].public_ip_address

  if ip_address.nil?
    raise BastionNotFoundError, "a potential bastion instance was found, but it does not have a public ip"
  end

  log "using bastion with ip #{ip_address}"

  ip_address
end

#build_ssh_bastion_proxy_commandObject

Builds a ProxyCommand that can be used with ssh to connect through the bastion instance, which can also be used with tools like Capistrano.

Calling this command implies that a bastion server is expected to exist, so an error is thrown if one cannot be found.

Usage with Capistrano:

set :ssh_options, proxy: Net::SSH::Proxy::Command.new(instances.build_ssh_bastion_proxy_command)



113
114
115
# File 'lib/aws_ec2_environment.rb', line 113

def build_ssh_bastion_proxy_command
  "ssh -o StrictHostKeyChecking=no #{@config.bastion_ssh_user}@#{bastion_public_ip} -W %h:%p"
end

#hosts_for_sshingObject

Lists the hosts to use for sshing into the EC2 instances matched by the environment instance filters.

If SSM should be used to connect to the instances, then porting sessions will created.



55
56
57
58
59
60
61
62
63
# File 'lib/aws_ec2_environment.rb', line 55

def hosts_for_sshing
  return ips unless @config.use_ssm

  log "using SSM to connect to instances"

  reason = ssm_session_reason

  ids.map { |id| "#{@config.ssm_host.gsub("\#{id}", id)}:#{start_ssh_port_forwarding_session(id, reason)}" }
end

#idsObject

Lists the IDs of the EC2 instances matched by the environment instance filters



44
45
46
47
48
49
50
# File 'lib/aws_ec2_environment.rb', line 44

def ids
  ids = ec2_instances.map(&:instance_id)

  log "found the following instances: #{ids.join(", ")}"

  ids
end

#ipsObject

Lists the IDs of the EC2 instances matched by the environment instance filters

If an instance does not have a public ip, its private ip will be used instead.



35
36
37
38
39
40
41
# File 'lib/aws_ec2_environment.rb', line 35

def ips
  ips = ec2_instances.map { |instance| instance.public_ip_address || instance.private_ip_address }

  log "found the following instances: #{ips.join(", ")}"

  ips
end

#stop_ssh_port_forwarding_sessionsObject



117
118
119
# File 'lib/aws_ec2_environment.rb', line 117

def stop_ssh_port_forwarding_sessions
  @ssm_port_forwarding_sessions.each(&:close)
end

#use_bastion_server?Boolean

Returns:

  • (Boolean)


65
66
67
# File 'lib/aws_ec2_environment.rb', line 65

def use_bastion_server?
  !@config.bastion_filters.nil?
end