lambda_wrap 0.27.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/lambda_wrap/api_gateway_manager.rb +123 -173
- data/lib/lambda_wrap/api_manager.rb +270 -0
- data/lib/lambda_wrap/aws_service.rb +40 -0
- data/lib/lambda_wrap/dynamo_db_manager.rb +425 -146
- data/lib/lambda_wrap/environment.rb +53 -0
- data/lib/lambda_wrap/lambda_manager.rb +266 -171
- data/lib/lambda_wrap/version.rb +2 -1
- data/lib/lambda_wrap.rb +12 -2
- metadata +9 -8
- data/lib/lambda_wrap/s3_bucket_manager.rb +0 -32
- data/lib/lambda_wrap/zip_file_generator.rb +0 -67
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cd87dbdb65df35c7a42c352ee4b619ee1f2c263a
|
4
|
+
data.tar.gz: 7bddaa1b451694fbf78f85a85a1ea35aa69a51cc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2ddde3fd339e8d3cd88dc8a4ba8508e246d895ffacd56477857530f9335d9226859759ff66337602ca83fdb1bd6cb5f0b774f4e41ccb4cd607f64a0cebaef1cc
|
7
|
+
data.tar.gz: 68c827f0dedea73cd533e6bb4d63d529544d337889c7db8e60147905405d9a738c6cf251ed31a32428fc6152f27b7ba4b0ca3bb10f1fdf856cb002f4369ea186
|
@@ -1,203 +1,153 @@
|
|
1
|
-
require 'aws-sdk'
|
2
|
-
|
3
1
|
module LambdaWrap
|
4
|
-
# The
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
|
9
|
-
#
|
10
|
-
|
2
|
+
# The ApiGateway class simplifies creation, deployment, and management of API Gateway objects.
|
3
|
+
# The specification for the API MUST be detailed in a provided Open API Formatted file (fka Swagger).
|
4
|
+
#
|
5
|
+
# @!attribute [r] specification
|
6
|
+
# @return [Hash] The Swagger spec parsed into a Hash
|
7
|
+
#
|
8
|
+
# @since 1.0
|
9
|
+
class ApiGateway < AwsService
|
10
|
+
attr_reader :specification
|
11
|
+
|
12
|
+
# Initializes the APIGateway Manager Object. A significant majority of the configuration of your
|
13
|
+
# API should be configured through your Swagger File (e.g. Integrations, API Name, Version).
|
11
14
|
#
|
12
|
-
# The
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
def initialize
|
17
|
-
|
18
|
-
@
|
19
|
-
|
20
|
-
@
|
21
|
-
@
|
15
|
+
# @param [Hash] options The Options initialize the API Gateway Manager with.
|
16
|
+
# @option options [String] :path_to_swagger_file File path the Swagger File to load and parse.
|
17
|
+
# @option options [String] :import_mode (overwrite) How the API Gateway Object will handle updates.
|
18
|
+
# Accepts <tt>overwrite</tt> and <tt>merge</tt>.
|
19
|
+
def initialize(options)
|
20
|
+
options_with_defaults = options.reverse_merge(import_mode: 'overwrite')
|
21
|
+
@path_to_swagger_file = options_with_defaults[:path_to_swagger_file]
|
22
|
+
@specification = extract_specification(@path_to_swagger_file)
|
23
|
+
@api_name = @specification['info']['title']
|
24
|
+
@api_version = @specification['info']['version']
|
25
|
+
@import_mode = options_with_defaults[:import_mode]
|
22
26
|
end
|
23
27
|
|
24
|
-
|
25
|
-
# Downloads the aws-apigateway-importer jar from an S3 bucket.
|
26
|
-
# This is a workaround since aws-apigateway-importer does not provide a binary.
|
27
|
-
# Once a binary is available on the public internet, we'll start using this instead
|
28
|
-
# of requiring users of this gem to upload their custom binary to an S3 bucket.
|
28
|
+
# Deploys the API Gateway Object to a specified environment
|
29
29
|
#
|
30
|
-
#
|
31
|
-
# [
|
32
|
-
# [
|
33
|
-
def
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
30
|
+
# @param environment_options [LambdaWrap::Environment] The environment to deploy
|
31
|
+
# @param client [Aws::APIGateway::Client] Client to use with SDK. Should be passed in by the API class.
|
32
|
+
# @param region [String] AWS Region string. Should be passed in by the API class.
|
33
|
+
def deploy(environment_options, client, region = 'AWS_REGION')
|
34
|
+
super
|
35
|
+
puts "Deploying API: #{@api_name} to Environment: #{environment_options.name}"
|
36
|
+
@stage_variables = environment_options.variables || {}
|
37
|
+
@stage_variables.store('environment', environment_options.name)
|
38
|
+
|
39
|
+
api_id = get_id_for_api(@api_name)
|
40
|
+
service_response =
|
41
|
+
if api_id
|
42
|
+
@client.put_rest_api(
|
43
|
+
fail_on_warnings: false, mode: @import_mode, rest_api_id:
|
44
|
+
api_id, body: File.open(@path_to_swagger_file, 'rb').read
|
45
|
+
)
|
46
|
+
else
|
47
|
+
@client.import_rest_api(
|
48
|
+
fail_on_warnings: false,
|
49
|
+
body: File.open(@path_to_swagger_file, 'rb').read
|
50
|
+
)
|
51
|
+
end
|
52
|
+
|
53
|
+
if service_response.nil? || service_response.id.nil?
|
54
|
+
raise "Failed to create API gateway with name #{@api_name}"
|
47
55
|
end
|
48
|
-
end
|
49
56
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
# [api_name] The name of the API to which the swagger file should be applied to.
|
56
|
-
# [env] The environment where it should be published (which is matching an API gateway stage)
|
57
|
-
# [swagger_file] A handle to a swagger file that should be used by aws-apigateway-importer
|
58
|
-
# [api_description] The description of the API to be displayed.
|
59
|
-
# [stage_variables] A Hash of stage variables to be deployed with the stage. Adds an 'environment' by default.
|
60
|
-
# [region] A string representing the region to deploy the API. Defaults to what is set as an environment variable.
|
61
|
-
def setup_apigateway(api_name, env, swagger_file, api_description = 'Deployed with LambdaWrap',
|
62
|
-
stage_variables = {}, region = ENV['AWS_REGION'])
|
63
|
-
# ensure API is created
|
64
|
-
api_id = get_existing_rest_api(api_name)
|
65
|
-
api_id = setup_apigateway_create_rest_api(api_name, api_description) unless api_id
|
66
|
-
|
67
|
-
# create resources
|
68
|
-
setup_apigateway_create_resources(api_id, swagger_file, region)
|
69
|
-
|
70
|
-
# create stages
|
71
|
-
stage_variables.store('environment', env)
|
72
|
-
create_stages(api_id, env, stage_variables)
|
73
|
-
|
74
|
-
# return URI of created stage
|
75
|
-
"https://#{api_id}.execute-api.#{region}.amazonaws.com/#{env}/"
|
76
|
-
end
|
57
|
+
if api_id
|
58
|
+
"Created API Gateway Object: #{@api_name} having id #{service_response.id}"
|
59
|
+
else
|
60
|
+
"Updated API Gateway Object: #{@api_name} having id #{service_response.id}"
|
61
|
+
end
|
77
62
|
|
78
|
-
|
79
|
-
# Shuts down an environment from the API Gateway. This basically deletes the stage
|
80
|
-
# from the API Gateway, but does not delete the API Gateway itself.
|
81
|
-
#
|
82
|
-
# *Argument*
|
83
|
-
# [api_name] The name of the API where the environment should be shut down.
|
84
|
-
# [env] The environment (matching an API Gateway stage) to shutdown.
|
85
|
-
def shutdown_apigateway(api_name, env)
|
86
|
-
api_id = get_existing_rest_api(api_name)
|
87
|
-
delete_stage(api_id, env)
|
88
|
-
end
|
63
|
+
create_stage(service_response.id, environment_options)
|
89
64
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
def get_existing_rest_api(api_name)
|
96
|
-
apis = @client.get_rest_apis(limit: 500).data
|
97
|
-
api = apis.items.select { |a| a.name == api_name }.first
|
98
|
-
|
99
|
-
return api.id if api
|
100
|
-
# nil is returned otherwise
|
65
|
+
service_uri = "https://#{service_response.id}.execute-api.#{@region}.amazonaws.com/#{environment_options.name}/"
|
66
|
+
|
67
|
+
puts "API: #{@api_name} deployed at #{service_uri}"
|
68
|
+
|
69
|
+
service_uri
|
101
70
|
end
|
102
71
|
|
103
|
-
|
104
|
-
# Creates the API with a given name using the SDK and returns the id
|
72
|
+
# Tearsdown environment for API Gateway. Deletes stage.
|
105
73
|
#
|
106
|
-
#
|
107
|
-
# [
|
108
|
-
# [
|
109
|
-
def
|
110
|
-
|
111
|
-
|
112
|
-
|
74
|
+
# @param environment_options [LambdaWrap::Environment] The environment to teardown.
|
75
|
+
# @param client [Aws::APIGateway::Client] Client to use with SDK. Should be passed in by the API class.
|
76
|
+
# @param region [String] AWS Region string. Should be passed in by the API class.
|
77
|
+
def teardown(environment_options, client, region = 'AWS_REGION')
|
78
|
+
super
|
79
|
+
api_id = get_id_for_api(@api_name)
|
80
|
+
if api_id
|
81
|
+
delete_stage(api_id, environment_options.name)
|
82
|
+
else
|
83
|
+
puts "API Gateway Object #{@api_name} not found. No environment to tear down."
|
84
|
+
end
|
85
|
+
true
|
113
86
|
end
|
114
87
|
|
115
|
-
|
116
|
-
#
|
117
|
-
#
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
88
|
+
# Deletes all stages and API Gateway object.
|
89
|
+
# @param client [Aws::APIGateway::Client] Client to use with SDK. Should be passed in by the API class.
|
90
|
+
# @param region [String] AWS Region string. Should be passed in by the API class.
|
91
|
+
def delete(client, region = 'AWS_REGION')
|
92
|
+
super
|
93
|
+
api_id = get_id_for_api(@api_name)
|
94
|
+
if api_id
|
95
|
+
@client.delete_rest_api(rest_api_id: api_id)
|
96
|
+
puts "Deleted API: #{@api_name} ID:#{api_id}"
|
97
|
+
else
|
98
|
+
puts "API Gateway Object #{@api_name} not found. Nothing to delete."
|
99
|
+
end
|
100
|
+
true
|
127
101
|
end
|
128
102
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
# *Arguments*
|
133
|
-
# [api_id] The AWS ApiGateway id where the stage should be created at.
|
134
|
-
# [env] The environment (which matches the stage in API Gateway) to create.
|
135
|
-
# [stage_variables] A Hash of stage variables to deploy with the stage
|
136
|
-
def create_stages(api_id, env, stage_variables)
|
137
|
-
deployment_description = 'Deployment of service to ' + env
|
138
|
-
deployment = @client.create_deployment(
|
139
|
-
rest_api_id: api_id, stage_name: env, cache_cluster_enabled: false, description: deployment_description,
|
140
|
-
variables: stage_variables
|
141
|
-
).data
|
142
|
-
puts deployment
|
103
|
+
def to_s
|
104
|
+
return @api_name if @api_name && @api_name.is_a?(String)
|
105
|
+
super
|
143
106
|
end
|
144
107
|
|
145
|
-
|
146
|
-
|
147
|
-
#
|
148
|
-
# *Arguments*
|
149
|
-
# [api_id] The AWS ApiGateway id from which the stage should be deleted from.
|
150
|
-
# [env]The environment (which matches the stage in API Gateway) to delete.
|
108
|
+
private
|
109
|
+
|
151
110
|
def delete_stage(api_id, env)
|
152
111
|
@client.delete_stage(rest_api_id: api_id, stage_name: env)
|
153
112
|
puts 'Deleted API gateway stage ' + env
|
154
113
|
rescue Aws::APIGateway::Errors::NotFoundException
|
155
|
-
puts
|
114
|
+
puts "API Gateway stage #{env} does not exist. Nothing to delete."
|
156
115
|
end
|
157
116
|
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
api_id = get_existing_rest_api(api_name)
|
169
|
-
swagger_file_content = File.read(local_swagger_file)
|
170
|
-
|
171
|
-
gateway_response = nil
|
172
|
-
if api_id.nil?
|
173
|
-
# Create a new APIGateway
|
174
|
-
gateway_response = @client.import_rest_api(fail_on_warnings: false, body: swagger_file_content)
|
175
|
-
else
|
176
|
-
# Update the exsiting APIgateway. By Merge the exsisting gateway will be merged with the new
|
177
|
-
# one supplied in the Swagger file.
|
178
|
-
gateway_response = @client.put_rest_api(rest_api_id: api_id, mode: 'merge', fail_on_warnings: false,
|
179
|
-
body: swagger_file_content)
|
180
|
-
end
|
181
|
-
|
182
|
-
raise "Failed to create API gateway with name #{api_name}" if gateway_response.nil? && gateway_response.id.nil?
|
117
|
+
def create_stage(api_id, environment_options)
|
118
|
+
deployment_description = "Deploying API #{@api_name} v#{@api_version}\
|
119
|
+
to Environment:#{environment_options.name}"
|
120
|
+
stage_description = "#{environment_options.name} - #{environment_options.description}"
|
121
|
+
@client.create_deployment(
|
122
|
+
rest_api_id: api_id, stage_name: environment_options.name,
|
123
|
+
stage_description: stage_description, description: deployment_description,
|
124
|
+
cache_cluster_enabled: false, variables: environment_options.variables
|
125
|
+
)
|
126
|
+
end
|
183
127
|
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
puts "Updated api gateway #{api_name} having id #{gateway_response.id}"
|
128
|
+
def extract_specification(file_path)
|
129
|
+
unless File.exist?(file_path)
|
130
|
+
raise ArgumentError, "Open API Spec (Swagger) File does not exist: #{file_path}!"
|
188
131
|
end
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
service_uri = "https://#{gateway_response.id}.execute-api.#{ENV['AWS_REGION']}.amazonaws.com/#{env}/"
|
195
|
-
puts "Service deployed at #{service_uri}"
|
196
|
-
|
197
|
-
service_uri
|
132
|
+
spec = Psych.load_file(file_path)
|
133
|
+
raise ArgumentError, 'LambdaWrap only supports swagger v2.0' unless spec['swagger'] == '2.0'
|
134
|
+
raise ArgumentError, 'Invalid Title field in the OAPISpec' unless spec['info']['title'] =~ /[A-Za-z0-9]{1,1024}/
|
135
|
+
spec
|
198
136
|
end
|
199
137
|
|
200
|
-
|
201
|
-
|
138
|
+
def get_id_for_api(api_name)
|
139
|
+
response = nil
|
140
|
+
loop do
|
141
|
+
response =
|
142
|
+
if !response || response.position.nil?
|
143
|
+
@client.get_rest_apis(limit: 500)
|
144
|
+
else
|
145
|
+
@client.get_rest_apis(limit: 500, position: response.position)
|
146
|
+
end
|
147
|
+
api = response.items.detect { |item| item.name == api_name }
|
148
|
+
return api.id if api
|
149
|
+
return if response.items.empty? || response.position.nil? || response.position.empty?
|
150
|
+
end
|
151
|
+
end
|
202
152
|
end
|
203
153
|
end
|
@@ -0,0 +1,270 @@
|
|
1
|
+
module LambdaWrap
|
2
|
+
# Top level class that manages the Serverless Microservice API deployment.
|
3
|
+
#
|
4
|
+
# @!attribute [r] lambdas
|
5
|
+
# @return [Array<LambdaWrap::Lambda>] The List of Lambdas to be deployed with the API.
|
6
|
+
#
|
7
|
+
# @!attribute [r] dynamo_tables
|
8
|
+
# @return [Array<LambdaWrap::DynamoTables>] The List of DynamoTables to be deployed with the API.
|
9
|
+
#
|
10
|
+
# @!attribute [r] api_gateways
|
11
|
+
# @return [Array<LambdaWrap::ApiGateway>] The List of API Gateways to be deployed with the API.
|
12
|
+
#
|
13
|
+
# @!attribute [r] region
|
14
|
+
# @return [String] The AWS Region to deploy the API.
|
15
|
+
#
|
16
|
+
# @since 1.0
|
17
|
+
class API
|
18
|
+
attr_reader :lambdas
|
19
|
+
attr_reader :dynamo_tables
|
20
|
+
attr_reader :api_gateways
|
21
|
+
attr_reader :region
|
22
|
+
|
23
|
+
# Constructor for the high level API Manager class.
|
24
|
+
#
|
25
|
+
# @param [Hash] options The Options to configure the API.
|
26
|
+
# @option options [String] :access_key_id The AWS Access Key Id to communicate with AWS. Will also check the
|
27
|
+
# environment variables for this value.
|
28
|
+
# @option options [String] :secret_access_key The AWS Secret Access Key to communicate with AWS. Also checks
|
29
|
+
# environment variables for this value.
|
30
|
+
# @option options [String] :region The AWS Region to deploy API to. Also checks environment variables for this
|
31
|
+
# value.
|
32
|
+
#
|
33
|
+
# @todo Allow clients to pass in a YAML file for all construction.
|
34
|
+
def initialize(options = {})
|
35
|
+
unless options[:lambda_client] && options[:dynamo_client] && options[:api_gateway_client]
|
36
|
+
access_key_id = options[:access_key_id] || ENV['AWS_ACCESS_KEY_ID'] || ENV['ACCESS_KEY'] ||
|
37
|
+
raise(ArgumentError, 'Cannot find AWS Access Key ID.')
|
38
|
+
|
39
|
+
secret_access_key = options[:secret_access_key] || ENV['AWS_SECRET_ACCESS_KEY'] || ENV['SECRET_KEY'] ||
|
40
|
+
raise(ArgumentError, 'Cannot find AWS Secret Key.')
|
41
|
+
|
42
|
+
credentials = Aws::Credentials.new(access_key_id, secret_access_key)
|
43
|
+
end
|
44
|
+
|
45
|
+
region = options[:region] || ENV['AWS_REGION'] || ENV['AMAZON_REGION'] || ENV['AWS_DEFAULT_REGION'] ||
|
46
|
+
raise(ArgumentError, 'Cannot find AWS Region.')
|
47
|
+
|
48
|
+
@lambdas = []
|
49
|
+
@dynamo_tables = []
|
50
|
+
@api_gateways = []
|
51
|
+
|
52
|
+
@region = region
|
53
|
+
@lambda_client = options[:lambda_client] ||
|
54
|
+
Aws::Lambda::Client.new(credentials: credentials, region: region)
|
55
|
+
@dynamo_client = options[:dynamo_client] ||
|
56
|
+
Aws::DynamoDB::Client.new(credentials: credentials, region: region)
|
57
|
+
@api_gateway_client = options[:api_gateway_client] ||
|
58
|
+
Aws::APIGateway::Client.new(credentials: credentials, region: region)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Add Lambda Object(s) to the API.
|
62
|
+
#
|
63
|
+
# @param [LambdaWrap::Lambda Array<LambdaWrap::Lambda>] new_lambda Splat of LambdaWrap Lambda
|
64
|
+
# objects to add to the API. Overloaded as:
|
65
|
+
# add_lambda(lambda1) OR add_lambda([lambda1, lambda2]) OR add_lambda(lambda1, lambda2)
|
66
|
+
def add_lambda(*new_lambda)
|
67
|
+
flattened_lambdas = new_lambda.flatten
|
68
|
+
flattened_lambdas.each { |lambda| parameter_guard(lambda, LambdaWrap::Lambda, 'LambdaWrap::Lambda') }
|
69
|
+
lambdas.concat(flattened_lambdas)
|
70
|
+
end
|
71
|
+
|
72
|
+
# Add Dynamo Table Object(s) to the API.
|
73
|
+
#
|
74
|
+
# @param [LambdaWrap::DynamoTable, Array<LambdaWrap::DynamoTable>] new_table Splat of LambdaWrap DynamoTable
|
75
|
+
# objects to add to the API. Overloaded as:
|
76
|
+
# add_dynamo_table(table1) OR add_dynamo_table([table1, table2]) OR add_dynamo_table(table1, table2)
|
77
|
+
def add_dynamo_table(*new_table)
|
78
|
+
flattened_tables = new_table.flatten
|
79
|
+
flattened_tables.each { |table| parameter_guard(table, LambdaWrap::DynamoTable, 'LambdaWrap::DynamoTable') }
|
80
|
+
dynamo_tables.concat(flattened_tables)
|
81
|
+
end
|
82
|
+
|
83
|
+
# Add API Gateway Object(s) to the API.
|
84
|
+
#
|
85
|
+
# @param [LambdaWrap::ApiGateway, Array<LambdaWrap::ApiGateway>] new_api_gateway Splat of LambdaWrap API Gateway
|
86
|
+
# objects to add to the API. Overloaded as:
|
87
|
+
# add_api_gateway(apig1) OR add_api_gateway([apig1, apig2]) OR add_api_gateway(apig1, apig2)
|
88
|
+
def add_api_gateway(*new_api_gateway)
|
89
|
+
flattened_api_gateways = new_api_gateway.flatten
|
90
|
+
flattened_api_gateways.each { |apig| parameter_guard(apig, LambdaWrap::ApiGateway, 'LambdaWrap::ApiGateway') }
|
91
|
+
api_gateways.concat(flattened_api_gateways)
|
92
|
+
end
|
93
|
+
|
94
|
+
# Deploys all services to the specified environment.
|
95
|
+
#
|
96
|
+
# @param [LambdaWrap::Environment] environment_options the Environment to deploy
|
97
|
+
def deploy(environment_options)
|
98
|
+
environment_parameter_guard(environment_options)
|
99
|
+
if no_op?
|
100
|
+
puts 'Nothing to deploy.'
|
101
|
+
return
|
102
|
+
end
|
103
|
+
|
104
|
+
deployment_start_message = 'Deploying '
|
105
|
+
deployment_start_message += "#{dynamo_tables.length} Dynamo Tables, " unless dynamo_tables.empty?
|
106
|
+
deployment_start_message += "#{lambdas.length} Lambdas, " unless lambdas.empty?
|
107
|
+
deployment_start_message += "#{api_gateways.length} API Gateways " unless api_gateways.empty?
|
108
|
+
deployment_start_message += "to Environment: #{environment_options.name}"
|
109
|
+
puts deployment_start_message
|
110
|
+
|
111
|
+
total_time_start = Time.now
|
112
|
+
|
113
|
+
services_time_start = total_time_start
|
114
|
+
dynamo_tables.each { |table| table.deploy(environment_options, @dynamo_client, @region) }
|
115
|
+
services_time_end = Time.now
|
116
|
+
|
117
|
+
unless dynamo_tables.empty?
|
118
|
+
puts "Deploying #{dynamo_tables.length} Table(s) took: \
|
119
|
+
#{Time.at(services_time_end - services_time_start).utc.strftime('%H:%M:%S')}"
|
120
|
+
end
|
121
|
+
|
122
|
+
services_time_start = Time.now
|
123
|
+
lambdas.each { |lambda| lambda.deploy(environment_options, @lambda_client, @region) }
|
124
|
+
services_time_end = Time.now
|
125
|
+
|
126
|
+
unless lambdas.empty?
|
127
|
+
puts "Deploying #{lambdas.length} Lambda(s) took: \
|
128
|
+
#{Time.at(services_time_end - services_time_start).utc.strftime('%H:%M:%S')}"
|
129
|
+
end
|
130
|
+
|
131
|
+
services_time_start = Time.now
|
132
|
+
api_gateways.each { |apig| apig.deploy(environment_options, @api_gateway_client, @region) }
|
133
|
+
services_time_end = Time.now
|
134
|
+
|
135
|
+
unless api_gateways.empty?
|
136
|
+
puts "Deploying #{api_gateways.length} API Gateway(s) took: \
|
137
|
+
#{Time.at(services_time_end - services_time_start).utc.strftime('%H:%M:%S')}"
|
138
|
+
end
|
139
|
+
|
140
|
+
total_time_end = Time.now
|
141
|
+
|
142
|
+
puts "Total API Deployment took: \
|
143
|
+
#{Time.at(total_time_end - total_time_start).utc.strftime('%H:%M:%S')}"
|
144
|
+
puts "Successfully deployed API to #{environment_options.name}"
|
145
|
+
|
146
|
+
true
|
147
|
+
end
|
148
|
+
|
149
|
+
# Tearsdown Environment for all services.
|
150
|
+
#
|
151
|
+
# @param [LambdaWrap::Environment] environment_options the Environment to teardown
|
152
|
+
def teardown(environment_options)
|
153
|
+
environment_parameter_guard(environment_options)
|
154
|
+
if no_op?
|
155
|
+
puts 'Nothing to teardown.'
|
156
|
+
return
|
157
|
+
end
|
158
|
+
|
159
|
+
deployment_start_message = 'Tearing-down '
|
160
|
+
deployment_start_message += "#{dynamo_tables.length} Dynamo Tables, " unless dynamo_tables.empty?
|
161
|
+
deployment_start_message += "#{lambdas.length} Lambdas, " unless lambdas.empty?
|
162
|
+
deployment_start_message += "#{api_gateways.length} API Gateways " unless api_gateways.empty?
|
163
|
+
deployment_start_message += " Environment: #{environment_options.name}"
|
164
|
+
puts deployment_start_message
|
165
|
+
|
166
|
+
total_time_start = Time.now
|
167
|
+
|
168
|
+
services_time_start = total_time_start
|
169
|
+
dynamo_tables.each { |table| table.teardown(environment_options, @dynamo_client, @region) }
|
170
|
+
services_time_end = Time.now
|
171
|
+
|
172
|
+
unless dynamo_tables.empty?
|
173
|
+
puts "Tearing-down #{dynamo_tables.length} Table(s) took: \
|
174
|
+
#{Time.at(services_time_end - services_time_start).utc.strftime('%H:%M:%S')}"
|
175
|
+
end
|
176
|
+
|
177
|
+
services_time_start = Time.now
|
178
|
+
lambdas.each { |lambda| lambda.teardown(environment_options, @lambda_client, @region) }
|
179
|
+
services_time_end = Time.now
|
180
|
+
|
181
|
+
unless lambdas.empty?
|
182
|
+
puts "Tearing-down #{lambdas.length} Lambda(s) took: \
|
183
|
+
#{Time.at(services_time_end - services_time_start).utc.strftime('%H:%M:%S')}"
|
184
|
+
end
|
185
|
+
|
186
|
+
services_time_start = Time.now
|
187
|
+
api_gateways.each { |apig| apig.teardown(environment_options, @api_gateway_client, @region) }
|
188
|
+
services_time_end = Time.now
|
189
|
+
|
190
|
+
unless api_gateways.empty?
|
191
|
+
puts "Tearing-down #{api_gateways.length} API Gateway(s) took: \
|
192
|
+
#{Time.at(services_time_end - services_time_start).utc.strftime('%H:%M:%S')}"
|
193
|
+
end
|
194
|
+
|
195
|
+
total_time_end = Time.now
|
196
|
+
|
197
|
+
puts "Total API Tear-down took: \
|
198
|
+
#{Time.at(total_time_end - total_time_start).utc.strftime('%H:%M:%S')}"
|
199
|
+
puts "Successful Teardown API to #{environment_options.name}"
|
200
|
+
|
201
|
+
true
|
202
|
+
end
|
203
|
+
|
204
|
+
# Deletes all services from the cloud.
|
205
|
+
def delete
|
206
|
+
if dynamo_tables.empty? && lambdas.empty? && api_gateways.empty?
|
207
|
+
puts 'Nothing to Deleting.'
|
208
|
+
return
|
209
|
+
end
|
210
|
+
|
211
|
+
deployment_start_message = 'Deleting '
|
212
|
+
deployment_start_message += "#{dynamo_tables.length} Dynamo Tables, " unless dynamo_tables.empty?
|
213
|
+
deployment_start_message += "#{lambdas.length} Lambdas, " unless lambdas.empty?
|
214
|
+
deployment_start_message += "#{api_gateways.length} API Gateways " unless api_gateways.empty?
|
215
|
+
puts deployment_start_message
|
216
|
+
|
217
|
+
total_time_start = Time.now
|
218
|
+
|
219
|
+
services_time_start = total_time_start
|
220
|
+
dynamo_tables.each { |table| table.delete(@dynamo_client, @region) }
|
221
|
+
services_time_end = Time.now
|
222
|
+
|
223
|
+
unless dynamo_tables.empty?
|
224
|
+
puts "Deleting #{dynamo_tables.length} Table(s) took: \
|
225
|
+
#{Time.at(services_time_end - services_time_start).utc.strftime('%H:%M:%S')}"
|
226
|
+
end
|
227
|
+
|
228
|
+
services_time_start = Time.now
|
229
|
+
lambdas.each { |lambda| lambda.delete(@lambda_client, @region) }
|
230
|
+
services_time_end = Time.now
|
231
|
+
|
232
|
+
unless lambdas.empty?
|
233
|
+
puts "Deleting #{lambdas.length} Lambda(s) took: \
|
234
|
+
#{Time.at(services_time_end - services_time_start).utc.strftime('%H:%M:%S')}"
|
235
|
+
end
|
236
|
+
|
237
|
+
services_time_start = Time.now
|
238
|
+
api_gateways.each { |apig| apig.delete(@api_gateway_client, @region) }
|
239
|
+
services_time_end = Time.now
|
240
|
+
|
241
|
+
unless api_gateways.empty?
|
242
|
+
puts "Deleting #{api_gateways.length} API Gateway(s) took: \
|
243
|
+
#{Time.at(services_time_end - services_time_start).utc.strftime('%H:%M:%S')}"
|
244
|
+
end
|
245
|
+
|
246
|
+
total_time_end = Time.now
|
247
|
+
|
248
|
+
puts "Total API Deletion took: \
|
249
|
+
#{Time.at(total_time_end - total_time_start).utc.strftime('%H:%M:%S')}"
|
250
|
+
puts 'Successful Deletion of API'
|
251
|
+
|
252
|
+
true
|
253
|
+
end
|
254
|
+
|
255
|
+
private
|
256
|
+
|
257
|
+
def environment_parameter_guard(parameter)
|
258
|
+
parameter_guard(parameter, LambdaWrap::Environment, 'LambdaWrap::Environment')
|
259
|
+
end
|
260
|
+
|
261
|
+
def parameter_guard(parameter, type, type_name)
|
262
|
+
return if parameter.is_a?(type)
|
263
|
+
raise ArgumentError, "Must pass a #{type_name} to the API Manager. Got: #{parameter}"
|
264
|
+
end
|
265
|
+
|
266
|
+
def no_op?
|
267
|
+
dynamo_tables.empty? && lambdas.empty? && api_gateways.empty?
|
268
|
+
end
|
269
|
+
end
|
270
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module LambdaWrap
|
2
|
+
# Super Abstract Class for all AWS services and their calls.
|
3
|
+
# @abstract
|
4
|
+
# @since 1.0
|
5
|
+
class AwsService
|
6
|
+
def deploy(environment, client, region = 'AWS_REGION')
|
7
|
+
unless environment.is_a?(LambdaWrap::Environment)
|
8
|
+
raise ArgumentError, 'Must pass a LambdaWrap::Environment class.'
|
9
|
+
end
|
10
|
+
@client = client
|
11
|
+
@region = region
|
12
|
+
client_guard
|
13
|
+
end
|
14
|
+
|
15
|
+
def teardown(environment, client, region = 'AWS_REGION')
|
16
|
+
unless environment.is_a?(LambdaWrap::Environment)
|
17
|
+
raise ArgumentError, 'Must pass a LambdaWrap::Environment class.'
|
18
|
+
end
|
19
|
+
@client = client
|
20
|
+
@region = region
|
21
|
+
client_guard
|
22
|
+
end
|
23
|
+
|
24
|
+
def delete(client, region = 'AWS_REGION')
|
25
|
+
@client = client
|
26
|
+
@region = region
|
27
|
+
client_guard
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def client_guard
|
33
|
+
unless @client.class == Aws::Lambda::Client || @client.class == Aws::DynamoDB::Client ||
|
34
|
+
@client.class == Aws::APIGateway::Client
|
35
|
+
raise ArgumentError, 'AWS client not initialized.'
|
36
|
+
end
|
37
|
+
raise ArgumentError, 'Invalid region' if @region.empty? || !Aws.partition('aws').region(@region)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|