lambda_wrap 0.27.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b47d747dee8ec24d3afbf8b18ebf6fdc2359afd4
4
- data.tar.gz: 7ca7e1859e904c2e1f92da462dc427a1d1bb4168
3
+ metadata.gz: cd87dbdb65df35c7a42c352ee4b619ee1f2c263a
4
+ data.tar.gz: 7bddaa1b451694fbf78f85a85a1ea35aa69a51cc
5
5
  SHA512:
6
- metadata.gz: 128c10bf9c107c209810a3d24b107d5a1881f826caa968b9ec3c950591a197f5f65055a2305f2ecaac9ceee380f1c1bb1e617e6e7646be72e75a1da67ea9c668
7
- data.tar.gz: 94edd6cc371f977713b949d2f5c59ac4c837a63f3276bb9e346b516543633523f47dbc130ce250be22dffbc07758dd89c32733e63e84f1db798879b1a59c2da1
6
+ metadata.gz: 2ddde3fd339e8d3cd88dc8a4ba8508e246d895ffacd56477857530f9335d9226859759ff66337602ca83fdb1bd6cb5f0b774f4e41ccb4cd607f64a0cebaef1cc
7
+ data.tar.gz: 68c827f0dedea73cd533e6bb4d63d529544d337889c7db8e60147905405d9a738c6cf251ed31a32428fc6152f27b7ba4b0ca3bb10f1fdf856cb002f4369ea186
@@ -1,203 +1,153 @@
1
- require 'aws-sdk'
2
-
3
1
  module LambdaWrap
4
- # The ApiGatewayManager simplifies downloading the aws-apigateway-importer binary,
5
- # importing a {swagger configuration}[http://swagger.io], and managing API Gateway stages.
6
- # Added functionality to create APIGateway deom Swagger file. Thsi API is useful for gateway's having
7
- # custom authorization.
8
-
9
- # Note: The concept of an environment of the LambdaWrap gem matches a stage in AWS ApiGateway terms.
10
- class ApiGatewayManager
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 constructor does some basic setup
13
- # * Validating basic AWS configuration
14
- # * Creating the underlying client to interact with the AWS SDK.
15
- # * Defining the temporary path of the api-gateway-importer jar file
16
- def initialize
17
- # AWS api gateway client
18
- @client = Aws::APIGateway::Client.new
19
- # path to apigateway-importer jar
20
- @jarpath = File.join(Dir.tmpdir, 'aws-apigateway-importer-1.0.3-SNAPSHOT-jar-with-dependencies.jar')
21
- @versionpath = File.join(Dir.tmpdir, 'aws-apigateway-importer-1.0.3-SNAPSHOT-jar-with-dependencies.s3version')
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
- # *Arguments*
31
- # [s3_bucket] An S3 bucket from where the aws-apigateway-importer binary can be downloaded.
32
- # [s3_key] The path (key) to the aws-apigateay-importer binary on the s3 bucket.
33
- def download_apigateway_importer(s3_bucket, s3_key)
34
- s3 = Aws::S3::Client.new
35
-
36
- # current version
37
- current_s3_version = File.open(@versionpath, 'rb').read if File.exist?(@versionpath)
38
-
39
- # online s3 version
40
- desired_s3_version = s3.head_object(bucket: s3_bucket, key: s3_key).version_id
41
-
42
- # compare local with remote version
43
- if current_s3_version != desired_s3_version || !File.exist?(@jarpath)
44
- puts "Downloading aws-apigateway-importer jar with S3 version #{desired_s3_version}"
45
- s3.get_object(response_target: @jarpath, bucket: s3_bucket, key: s3_key)
46
- File.write(@versionpath, desired_s3_version)
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
- # Sets up the API gateway by searching whether the API Gateway already exists
52
- # and updates it with the latest information from the swagger file.
53
- #
54
- # *Arguments*
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
- # Gets the ID of an existing API Gateway api, or nil if it doesn't exist
92
- #
93
- # *Arguments*
94
- # [api_name] The name of the API to be checked for existance
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
- # *Arguments*
107
- # [api_name] A String representing the name of the API Gateway Object to be created
108
- # [api_description] A String representing the description of the API
109
- def setup_apigateway_create_rest_api(api_name, api_description)
110
- puts 'Creating API with name ' + api_name
111
- api = @client.create_rest_api(name: api_name, description: api_description)
112
- api.id
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
- # Invokes the aws-apigateway-importer jar with the required parameter
117
- #
118
- # *Arguments*
119
- # [api_id] The AWS ApiGateway id where the swagger file should be applied to.
120
- # [swagger_file] The handle to a swagger definition file that should be imported into API Gateway
121
- # [region] A string representing the target region to deploy the API
122
- def setup_apigateway_create_resources(api_id, swagger_file, region)
123
- raise 'API ID not provided' unless api_id
124
-
125
- cmd = "java -jar #{@jarpath} --update #{api_id} --region #{region} #{swagger_file}"
126
- raise 'API gateway not created' unless system(cmd)
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
- # Creates a stage of the currently set resources
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
- # Deletes a stage of the API Gateway
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 'API Gateway stage ' + env + ' does not exist. Nothing to delete.'
114
+ puts "API Gateway stage #{env} does not exist. Nothing to delete."
156
115
  end
157
116
 
158
- ##
159
- # Generate or Update the API Gateway by using the swagger file and the SDK importer
160
- #
161
- # *Arguments*
162
- # [api_name] API Gateway name
163
- # [local_swagger_file] Path of the local swagger file
164
- # [env] Environment identifier
165
- # [stage_variables] hash of stage variables
166
- def setup_apigateway_by_swagger_file(api_name, local_swagger_file, env, stage_variables = {})
167
- # If API gateway with the name is already present then update it else create a new one
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
- if api_id.nil?
185
- puts "Created api gateway #{api_name} having id #{gateway_response.id}"
186
- else
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
- # Deploy the service
191
- stage_variables.store('environment', env)
192
- create_stages(gateway_response.id, env, stage_variables)
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
- private :get_existing_rest_api, :setup_apigateway_create_rest_api, :setup_apigateway_create_resources,
201
- :create_stages, :delete_stage
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