cfn-vpn 0.5.0 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/build-gem.yml +25 -0
- data/.github/workflows/release-gem.yml +34 -0
- data/.github/workflows/release-image.yml +33 -0
- data/Gemfile.lock +33 -39
- data/README.md +1 -232
- data/cfn-vpn.gemspec +4 -4
- data/docs/README.md +44 -0
- data/docs/certificate-users.md +89 -0
- data/docs/getting-started.md +128 -0
- data/docs/modifying.md +67 -0
- data/docs/routes.md +98 -0
- data/docs/scheduling.md +32 -0
- data/docs/sessions.md +27 -0
- data/lib/cfnvpn.rb +31 -27
- data/lib/cfnvpn/{client.rb → actions/client.rb} +5 -6
- data/lib/cfnvpn/{embedded.rb → actions/embedded.rb} +15 -15
- data/lib/cfnvpn/actions/init.rb +144 -0
- data/lib/cfnvpn/actions/modify.rb +169 -0
- data/lib/cfnvpn/actions/params.rb +73 -0
- data/lib/cfnvpn/{revoke.rb → actions/revoke.rb} +6 -6
- data/lib/cfnvpn/actions/routes.rb +196 -0
- data/lib/cfnvpn/{sessions.rb → actions/sessions.rb} +5 -5
- data/lib/cfnvpn/{share.rb → actions/share.rb} +10 -10
- data/lib/cfnvpn/actions/subnets.rb +78 -0
- data/lib/cfnvpn/certificates.rb +5 -5
- data/lib/cfnvpn/clientvpn.rb +49 -65
- data/lib/cfnvpn/compiler.rb +23 -0
- data/lib/cfnvpn/config.rb +34 -78
- data/lib/cfnvpn/{cloudformation.rb → deployer.rb} +48 -20
- data/lib/cfnvpn/log.rb +26 -26
- data/lib/cfnvpn/s3.rb +34 -4
- data/lib/cfnvpn/s3_bucket.rb +48 -0
- data/lib/cfnvpn/string.rb +33 -0
- data/lib/cfnvpn/templates/helper.rb +14 -0
- data/lib/cfnvpn/templates/lambdas.rb +35 -0
- data/lib/cfnvpn/templates/lambdas/auto_route_populator/app.py +175 -0
- data/lib/cfnvpn/templates/lambdas/scheduler/app.py +36 -0
- data/lib/cfnvpn/templates/vpn.rb +449 -0
- data/lib/cfnvpn/version.rb +1 -1
- metadata +73 -23
- data/lib/cfnvpn/cfhighlander.rb +0 -49
- data/lib/cfnvpn/init.rb +0 -109
- data/lib/cfnvpn/modify.rb +0 -103
- data/lib/cfnvpn/routes.rb +0 -84
- data/lib/cfnvpn/templates/cfnvpn.cfhighlander.rb.tt +0 -27
data/lib/cfnvpn/certificates.rb
CHANGED
@@ -6,7 +6,7 @@ require 'cfnvpn/log'
|
|
6
6
|
|
7
7
|
module CfnVpn
|
8
8
|
class Certificates
|
9
|
-
|
9
|
+
|
10
10
|
|
11
11
|
def initialize(build_dir, cfnvpn_name, easyrsa_local = false)
|
12
12
|
@cfnvpn_name = cfnvpn_name
|
@@ -44,7 +44,7 @@ module CfnVpn
|
|
44
44
|
@docker_cmd << "-v #{@cert_dir}:/easy-rsa/output"
|
45
45
|
@docker_cmd << @easyrsa_image
|
46
46
|
@docker_cmd << "sh -c 'create-ca'"
|
47
|
-
Log.logger.debug `#{@docker_cmd.join(' ')}`
|
47
|
+
CfnVpn::Log.logger.debug `#{@docker_cmd.join(' ')}`
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
@@ -59,7 +59,7 @@ module CfnVpn
|
|
59
59
|
@docker_cmd << "-v #{@cert_dir}:/easy-rsa/output"
|
60
60
|
@docker_cmd << @easyrsa_image
|
61
61
|
@docker_cmd << "sh -c 'create-client'"
|
62
|
-
Log.logger.debug `#{@docker_cmd.join(' ')}`
|
62
|
+
CfnVpn::Log.logger.debug `#{@docker_cmd.join(' ')}`
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
@@ -76,7 +76,7 @@ module CfnVpn
|
|
76
76
|
@docker_cmd << "-v #{@cert_dir}:/easy-rsa/output"
|
77
77
|
@docker_cmd << @easyrsa_image
|
78
78
|
@docker_cmd << "sh -c 'revoke-client'"
|
79
|
-
Log.logger.debug `#{@docker_cmd.join(' ')}`
|
79
|
+
CfnVpn::Log.logger.debug `#{@docker_cmd.join(' ')}`
|
80
80
|
end
|
81
81
|
end
|
82
82
|
|
@@ -84,7 +84,7 @@ module CfnVpn
|
|
84
84
|
cn = cn.nil? ? cert : cn
|
85
85
|
acm = CfnVpn::Acm.new(region, @cert_dir)
|
86
86
|
arn = acm.import_certificate("#{cert}.crt", "#{cert}.key", "ca.crt")
|
87
|
-
Log.logger.debug "Uploaded #{type} certificate to ACM #{arn}"
|
87
|
+
CfnVpn::Log.logger.debug "Uploaded #{type} certificate to ACM #{arn}"
|
88
88
|
acm.tag_certificate(arn,cn,type,@cfnvpn_name)
|
89
89
|
return arn
|
90
90
|
end
|
data/lib/cfnvpn/clientvpn.rb
CHANGED
@@ -4,11 +4,12 @@ require 'netaddr'
|
|
4
4
|
|
5
5
|
module CfnVpn
|
6
6
|
class ClientVpn
|
7
|
-
|
7
|
+
|
8
8
|
|
9
9
|
def initialize(name,region)
|
10
10
|
@client = Aws::EC2::Client.new(region: region)
|
11
11
|
@name = name
|
12
|
+
@endpoint_id = self.get_endpoint_id()
|
12
13
|
end
|
13
14
|
|
14
15
|
def get_endpoint()
|
@@ -16,7 +17,7 @@ module CfnVpn
|
|
16
17
|
filters: [{ name: "tag:cfnvpn:name", values: [@name] }]
|
17
18
|
})
|
18
19
|
if resp.client_vpn_endpoints.empty?
|
19
|
-
Log.logger.error "unable to find endpoint with tag Key: cfnvpn:name with Value: #{@name}"
|
20
|
+
CfnVpn::Log.logger.error "unable to find endpoint with tag Key: cfnvpn:name with Value: #{@name}"
|
20
21
|
raise "Unable to find client vpn"
|
21
22
|
end
|
22
23
|
return resp.client_vpn_endpoints.first
|
@@ -68,86 +69,69 @@ module CfnVpn
|
|
68
69
|
})
|
69
70
|
end
|
70
71
|
|
71
|
-
def
|
72
|
-
resp = @client.describe_client_vpn_target_networks({
|
73
|
-
client_vpn_endpoint_id: endpoint_id
|
74
|
-
})
|
75
|
-
return resp.client_vpn_target_networks.first
|
76
|
-
end
|
77
|
-
|
78
|
-
def add_route(cidr,description)
|
72
|
+
def get_routes()
|
79
73
|
endpoint_id = get_endpoint_id()
|
80
|
-
|
81
|
-
|
82
|
-
@client.create_client_vpn_route({
|
74
|
+
resp = @client.describe_client_vpn_routes({
|
83
75
|
client_vpn_endpoint_id: endpoint_id,
|
84
|
-
|
85
|
-
target_vpc_subnet_id: subnet_id,
|
86
|
-
description: description
|
76
|
+
max_results: 20
|
87
77
|
})
|
78
|
+
return resp.routes
|
79
|
+
end
|
88
80
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
81
|
+
def get_groups_for_route(endpoint, cidr)
|
82
|
+
auth_resp = @client.describe_client_vpn_authorization_rules({
|
83
|
+
client_vpn_endpoint_id: endpoint,
|
84
|
+
filters: [
|
85
|
+
{
|
86
|
+
name: 'destination-cidr',
|
87
|
+
values: [cidr]
|
88
|
+
}
|
89
|
+
]
|
94
90
|
})
|
95
|
-
|
96
|
-
return resp.status
|
91
|
+
return auth_resp.authorization_rules.map {|rule| rule.group_id }
|
97
92
|
end
|
98
93
|
|
99
|
-
def
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
revoke = @client.revoke_client_vpn_ingress({
|
104
|
-
revoke_all_groups: true,
|
105
|
-
client_vpn_endpoint_id: endpoint_id,
|
106
|
-
target_network_cidr: cidr
|
94
|
+
def get_associations(endpoint)
|
95
|
+
associations = []
|
96
|
+
resp = @client.describe_client_vpn_target_networks({
|
97
|
+
client_vpn_endpoint_id: endpoint
|
107
98
|
})
|
108
99
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
100
|
+
resp.client_vpn_target_networks.each do |net|
|
101
|
+
subnet_resp = @client.describe_subnets({
|
102
|
+
subnet_ids: [net.target_network_id]
|
103
|
+
})
|
104
|
+
subnet = subnet_resp.subnets.first
|
105
|
+
groups = get_groups_for_route(endpoint, subnet.cidr_block)
|
106
|
+
|
107
|
+
associations.push({
|
108
|
+
association_id: net.association_id,
|
109
|
+
target_network_id: net.target_network_id,
|
110
|
+
status: net.status.code,
|
111
|
+
cidr: subnet.cidr_block,
|
112
|
+
az: subnet.availability_zone,
|
113
|
+
groups: groups.join(' ')
|
114
|
+
})
|
115
|
+
end
|
114
116
|
|
115
|
-
return
|
117
|
+
return associations
|
116
118
|
end
|
117
119
|
|
118
|
-
def
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
120
|
+
def delete_route(cidr, subnet)
|
121
|
+
@client.delete_client_vpn_route({
|
122
|
+
client_vpn_endpoint_id: @endpoint_id,
|
123
|
+
target_vpc_subnet_id: subnet,
|
124
|
+
destination_cidr_block: cidr
|
123
125
|
})
|
124
|
-
return resp.routes
|
125
|
-
end
|
126
|
-
|
127
|
-
def route_exists?(cidr)
|
128
|
-
routes = get_routes()
|
129
|
-
resp = routes.select { |route| route if route.destination_cidr == cidr }
|
130
|
-
return resp.any?
|
131
126
|
end
|
132
127
|
|
133
|
-
def
|
128
|
+
def revoke_auth(cidr)
|
134
129
|
endpoint_id = get_endpoint_id()
|
135
|
-
|
136
|
-
client_vpn_endpoint_id: endpoint_id,
|
137
|
-
|
130
|
+
@client.revoke_client_vpn_ingress({
|
131
|
+
client_vpn_endpoint_id: @endpoint_id,
|
132
|
+
target_network_cidr: cidr,
|
133
|
+
revoke_all_groups: true
|
138
134
|
})
|
139
|
-
return resp.routes
|
140
|
-
end
|
141
|
-
|
142
|
-
def get_route_with_mask()
|
143
|
-
routes = get_routes()
|
144
|
-
routes
|
145
|
-
.select { |r| r if r.destination_cidr != '0.0.0.0/0' }
|
146
|
-
.collect { |r| { route: r.destination_cidr.split('/').first, mask: NetAddr::IPv4Net.parse(r.destination_cidr).netmask.extended }}
|
147
|
-
end
|
148
|
-
|
149
|
-
def valid_cidr?(cidr)
|
150
|
-
return !(cidr =~ /^([0-9]{1,3}\.){3}[0-9]{1,3}(\/([0-9]|[1-2][0-9]|3[0-2]))?$/).nil?
|
151
135
|
end
|
152
136
|
|
153
137
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'cfnvpn/log'
|
2
|
+
require 'cfnvpn/templates/vpn'
|
3
|
+
|
4
|
+
module CfnVpn
|
5
|
+
class Compiler
|
6
|
+
|
7
|
+
def initialize(name, config)
|
8
|
+
@name = name
|
9
|
+
@config = config
|
10
|
+
end
|
11
|
+
|
12
|
+
def compile
|
13
|
+
CfnVpn::Log.logger.debug "Compiling cloudformation"
|
14
|
+
template = CfnVpn::Templates::Vpn.new()
|
15
|
+
template.render(@name, @config)
|
16
|
+
CfnVpn::Log.logger.debug "Validating cloudformation"
|
17
|
+
valid = template.validate
|
18
|
+
CfnVpn::Log.logger.debug "Clouformation Template\n\n#{JSON.parse(valid.to_json).to_yaml}"
|
19
|
+
return JSON.parse(valid.to_json).to_yaml
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
data/lib/cfnvpn/config.rb
CHANGED
@@ -1,89 +1,45 @@
|
|
1
|
-
require '
|
2
|
-
require '
|
3
|
-
require 'cfnvpn/
|
1
|
+
require 'aws-sdk-ssm'
|
2
|
+
require 'json'
|
3
|
+
require 'cfnvpn/deployer'
|
4
4
|
|
5
5
|
module CfnVpn
|
6
|
-
class Config
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
class_option :bucket, required: true, desc: 's3 bucket'
|
16
|
-
class_option :client_cn, required: true, desc: "client certificates to download"
|
17
|
-
class_option :easyrsa_local, type: :boolean, default: false, desc: 'run the easyrsa executable from your local rather than from docker'
|
18
|
-
class_option :ignore_routes, alias: :i, type: :boolean, desc: "Ignore client VPN pushed routes and set routes in config file"
|
19
|
-
|
20
|
-
def self.source_root
|
21
|
-
File.dirname(__FILE__)
|
22
|
-
end
|
23
|
-
|
24
|
-
def set_loglevel
|
25
|
-
Log.logger.level = Logger::DEBUG if @options['verbose']
|
26
|
-
end
|
27
|
-
|
28
|
-
def create_config_directory
|
29
|
-
@build_dir = "#{CfnVpn.cfnvpn_path}/#{@name}"
|
30
|
-
@config_dir = "#{@build_dir}/config"
|
31
|
-
Log.logger.debug("Creating config directory #{@config_dir}")
|
32
|
-
FileUtils.mkdir_p(@config_dir)
|
33
|
-
end
|
34
|
-
|
35
|
-
def download_config
|
36
|
-
vpn = CfnVpn::ClientVpn.new(@name,@options['region'])
|
37
|
-
@endpoint_id = vpn.get_endpoint_id()
|
38
|
-
Log.logger.info "downloading client config for #{@endpoint_id}"
|
39
|
-
@config = vpn.get_config(@endpoint_id)
|
40
|
-
end
|
41
|
-
|
42
|
-
def download_certificates
|
43
|
-
download = true
|
44
|
-
if File.exists?("#{@config_dir}/#{@options['client_cn']}.crt")
|
45
|
-
download = yes? "Certificates for #{@options['client_cn']} already exist in #{@config_dir}. Do you want to download again? ", :green
|
46
|
-
end
|
47
|
-
|
48
|
-
if download
|
49
|
-
Log.logger.info "Downloading certificates for #{@options['client_cn']} to #{@config_dir}"
|
50
|
-
s3 = CfnVpn::S3.new(@options['region'],@options['bucket'],@name)
|
51
|
-
s3.get_object("#{@config_dir}/#{@options['client_cn']}.tar.gz")
|
52
|
-
cert = CfnVpn::Certificates.new(@build_dir,@name,@options['easyrsa_local'])
|
53
|
-
Log.logger.debug cert.extract_certificate(@options['client_cn'])
|
6
|
+
class Config
|
7
|
+
|
8
|
+
def self.get_config(region, name)
|
9
|
+
client = Aws::SSM::Client.new(region: region)
|
10
|
+
begin
|
11
|
+
resp = client.get_parameter({name: "/cfnvpn/config/#{name}"})
|
12
|
+
return JSON.parse(resp.parameter.value, {:symbolize_names => true})
|
13
|
+
rescue Aws::SSM::Errors::ParameterNotFound => e
|
14
|
+
return self.get_config_from_parameter(region, name)
|
54
15
|
end
|
55
16
|
end
|
56
17
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
18
|
+
# to support upgrade from <=0.5.1 to >1.0
|
19
|
+
def self.get_config_from_parameter(region, name)
|
20
|
+
deployer = CfnVpn::Deployer.new(region, name)
|
21
|
+
parameters = deployer.get_parameters_from_stack_hash()
|
22
|
+
{
|
23
|
+
type: 'certificate',
|
24
|
+
server_cert_arn: parameters[:ServerCertificateArn],
|
25
|
+
client_cert_arn: parameters[:ClientCertificateArn],
|
26
|
+
region: region,
|
27
|
+
subnet_ids: [parameters[:AssociationSubnetId]],
|
28
|
+
cidr: parameters[:ClientCidrBlock],
|
29
|
+
dns_servers: parameters[:DnsServers].split(','),
|
30
|
+
split_tunnel: parameters[:SplitTunnel] == "true",
|
31
|
+
internet_route: parameters[:InternetRoute] == "true" ? parameters[:AssociationSubnetId] : nil,
|
32
|
+
protocol: parameters[:Protocol],
|
33
|
+
routes: []
|
34
|
+
}
|
62
35
|
end
|
63
36
|
|
64
|
-
def
|
65
|
-
|
66
|
-
Log.logger.debug "Ignoring routes pushed by the client vpn"
|
67
|
-
@config.concat("\nroute-nopull\n")
|
68
|
-
vpn = CfnVpn::ClientVpn.new(@name,@options['region'])
|
69
|
-
routes = vpn.get_route_with_mask
|
70
|
-
Log.logger.debug "Found routes #{routes}"
|
71
|
-
routes.each do |r|
|
72
|
-
@config.concat("route #{r[:route]} #{r[:mask]}\n")
|
73
|
-
end
|
74
|
-
dns_servers = vpn.get_dns_servers()
|
75
|
-
if dns_servers.any?
|
76
|
-
Log.logger.debug "Found DNS servers #{dns_servers.join(' ')}"
|
77
|
-
@config.concat("dhcp-option DNS #{dns_servers.first}\n")
|
78
|
-
end
|
79
|
-
end
|
37
|
+
def self.get_config_from_yaml_file(file)
|
38
|
+
YAML.load(File.read(file), symbolize_names: true)
|
80
39
|
end
|
81
40
|
|
82
|
-
def
|
83
|
-
|
84
|
-
File.write(config_file, @config)
|
85
|
-
Log.logger.info "downloaded client config #{config_file}"
|
41
|
+
def self.dump_config_to_yaml_file(name, params)
|
42
|
+
File.write(File.join(Dir.pwd, "cfnvpn.#{name}.yaml"), Hash[params.collect{|k,v| [k.to_s, v]}].to_yaml)
|
86
43
|
end
|
87
|
-
|
88
44
|
end
|
89
|
-
end
|
45
|
+
end
|
@@ -2,10 +2,10 @@ require 'aws-sdk-cloudformation'
|
|
2
2
|
require 'fileutils'
|
3
3
|
require 'cfnvpn/version'
|
4
4
|
require 'cfnvpn/log'
|
5
|
+
require 'cfnvpn/string'
|
5
6
|
|
6
7
|
module CfnVpn
|
7
|
-
class
|
8
|
-
include CfnVpn::Log
|
8
|
+
class Deployer
|
9
9
|
|
10
10
|
def initialize(region,name)
|
11
11
|
@name = name
|
@@ -29,28 +29,25 @@ module CfnVpn
|
|
29
29
|
return does_cf_stack_exist() ? 'UPDATE' : 'CREATE'
|
30
30
|
end
|
31
31
|
|
32
|
-
def create_change_set(
|
32
|
+
def create_change_set(template_body: nil, parameters: {})
|
33
33
|
change_set_name = "#{@stack_name}-#{CfnVpn::CHANGE_SET_VERSION}-#{Time.now.utc.strftime("%Y%m%d%H%M%S")}"
|
34
34
|
change_set_type = get_change_set_type()
|
35
35
|
|
36
|
-
if
|
37
|
-
params = get_parameters_from_template(
|
36
|
+
if !template_body.nil?
|
37
|
+
params = get_parameters_from_template(template_body)
|
38
38
|
else
|
39
39
|
params = get_parameters_from_stack()
|
40
40
|
end
|
41
|
-
|
41
|
+
|
42
42
|
params.each do |param|
|
43
43
|
if !parameters[param[:parameter_key]].nil?
|
44
|
-
param[
|
45
|
-
param[
|
44
|
+
param[:parameter_value] = parameters[param[:parameter_key]]
|
45
|
+
param[:use_previous_value] = false
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
49
|
-
|
50
|
-
Log.logger.debug "Creating changeset"
|
51
|
-
change_set = @client.create_change_set({
|
49
|
+
changeset_args = {
|
52
50
|
stack_name: @stack_name,
|
53
|
-
template_body: template_body,
|
54
51
|
parameters: params,
|
55
52
|
tags: [
|
56
53
|
{
|
@@ -63,18 +60,28 @@ module CfnVpn
|
|
63
60
|
}
|
64
61
|
],
|
65
62
|
change_set_name: change_set_name,
|
66
|
-
change_set_type: change_set_type
|
67
|
-
|
63
|
+
change_set_type: change_set_type,
|
64
|
+
capabilities: ['CAPABILITY_IAM']
|
65
|
+
}
|
66
|
+
|
67
|
+
if !template_body.nil?
|
68
|
+
changeset_args[:template_body] = template_body
|
69
|
+
else
|
70
|
+
changeset_args[:use_previous_template] = true
|
71
|
+
end
|
72
|
+
|
73
|
+
CfnVpn::Log.logger.debug "Creating changeset"
|
74
|
+
change_set = @client.create_change_set(changeset_args)
|
68
75
|
return change_set, change_set_type
|
69
76
|
end
|
70
77
|
|
71
78
|
def wait_for_changeset(change_set_id)
|
72
|
-
Log.logger.debug "Waiting for changeset to be created"
|
79
|
+
CfnVpn::Log.logger.debug "Waiting for changeset to be created"
|
73
80
|
begin
|
74
81
|
@client.wait_until :change_set_create_complete, change_set_name: change_set_id
|
75
82
|
rescue Aws::Waiters::Errors::FailureStateError => e
|
76
83
|
change_set = get_change_set(change_set_id)
|
77
|
-
Log.logger.error("change set status: #{change_set.status} reason: #{change_set.status_reason}")
|
84
|
+
CfnVpn::Log.logger.error("change set status: #{change_set.status} reason: #{change_set.status_reason}")
|
78
85
|
exit 1
|
79
86
|
end
|
80
87
|
end
|
@@ -86,7 +93,7 @@ module CfnVpn
|
|
86
93
|
end
|
87
94
|
|
88
95
|
def execute_change_set(change_set_id)
|
89
|
-
Log.logger.debug "Executing the changeset"
|
96
|
+
CfnVpn::Log.logger.debug "Executing the changeset"
|
90
97
|
stack = @client.execute_change_set({
|
91
98
|
change_set_name: change_set_id
|
92
99
|
})
|
@@ -94,7 +101,7 @@ module CfnVpn
|
|
94
101
|
|
95
102
|
def wait_for_execute(change_set_type)
|
96
103
|
waiter = change_set_type == 'CREATE' ? :stack_create_complete : :stack_update_complete
|
97
|
-
Log.logger.info "Waiting for changeset to #{change_set_type}"
|
104
|
+
CfnVpn::Log.logger.info "Waiting for changeset to #{change_set_type}"
|
98
105
|
resp = @client.wait_until waiter, stack_name: @stack_name
|
99
106
|
end
|
100
107
|
|
@@ -103,11 +110,32 @@ module CfnVpn
|
|
103
110
|
return resp.parameters.collect { |p| { parameter_key: p.parameter_key, use_previous_value: true } }
|
104
111
|
end
|
105
112
|
|
106
|
-
def get_parameters_from_template(
|
107
|
-
template_body = File.read(template_path)
|
113
|
+
def get_parameters_from_template(template_body)
|
108
114
|
resp = @client.get_template_summary({ template_body: template_body })
|
109
115
|
return resp.parameters.collect { |p| { parameter_key: p.parameter_key, parameter_value: p.default_value } }
|
110
116
|
end
|
111
117
|
|
118
|
+
def get_parameter_value(parameter)
|
119
|
+
resp = @client.describe_stacks({ stack_name: @stack_name })
|
120
|
+
stack = resp.stacks.first
|
121
|
+
parameter = stack.parameters.detect {|p| p.parameter_key == parameter}
|
122
|
+
return parameter ? parameter.parameter_value : nil
|
123
|
+
end
|
124
|
+
|
125
|
+
def get_parameters_from_stack_hash()
|
126
|
+
resp = @client.describe_stacks({
|
127
|
+
stack_name: @stack_name,
|
128
|
+
})
|
129
|
+
stack = resp.stacks.first
|
130
|
+
return Hash[stack.parameters.collect {|parameter| [parameter.parameter_key.to_sym, parameter.parameter_value]}]
|
131
|
+
end
|
132
|
+
|
133
|
+
def get_outputs_from_stack()
|
134
|
+
resp = @client.describe_stacks({
|
135
|
+
stack_name: @stack_name,
|
136
|
+
})
|
137
|
+
stack = resp.stacks.first
|
138
|
+
return Hash[stack.outputs.collect {|output| [output.output_key.underscore.to_sym, output.output_value]}]
|
139
|
+
end
|
112
140
|
end
|
113
141
|
end
|