nypl_ruby_util 0.0.7 → 0.0.8

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
  SHA256:
3
- metadata.gz: 5ff3e8b400c7989c57e1398a642631a8c415a1bf982feadef5e95a813d7ad971
4
- data.tar.gz: 7818da3d0d4fc85ddd6f10b259375463bc23a6f17b34a57026d60b4d1d03f057
3
+ metadata.gz: d2086b8b4b5bef52f3459a1245af09a7364cb35190ec40c0541a7bd72681a8f6
4
+ data.tar.gz: 4e1c6a34f318b81c6659cca2f57f1930bfbf0e406040e950f681c4631177bec3
5
5
  SHA512:
6
- metadata.gz: a2a0a99e281a95583fbe84f69fdbd066556f911167527be86dbdea2cffda000d3bb132edb6c90da4846e2b4d8129f7939594ee57b1a646f167955b2d5d1ed324
7
- data.tar.gz: 0126f82acca76fd1e6c77afecce13a30c500766fd57f1ebecba075fcf85961c5c4b1c4e01d1641803cb23d86a9adadd21aed2f01d6e174f182b364e30dcc8fc6
6
+ metadata.gz: 68670e8961ed473bb3854b2320cafc0c960b9418b37d336fdaac6f9cf41ae14acca33d131565986fad25f2d8eb6cb57f225828c93e5539c685bf497b80e6bab6
7
+ data.tar.gz: 433b9dea26fa844a28a6711eff1d510a8f21df2f3f71e011d76e497f77dd2988714162973345084b681bb068771bc95433957f513e26553243cefbad521c70b3
data/lib/deploy_helper.rb CHANGED
@@ -1,152 +1,152 @@
1
- require 'aws-sdk-lambda'
2
- require 'aws-sdk-cloudwatchevents'
3
- require 'yaml'
1
+ require "aws-sdk-lambda"
2
+ require "aws-sdk-cloudwatchevents"
3
+ require "yaml"
4
4
 
5
5
  # Utility class for running rake methods
6
6
  class DeployHelper
7
- attr_reader(
8
- :travis_branch,
9
- :aws_access_key_id,
10
- :aws_secret_access_key,
11
- :aws_configuration,
12
- :region,
13
- :lambda_client,
14
- :yaml,
15
- :lambda_config,
16
- :function_name,
17
- :event
18
- )
19
-
20
- def initialize
21
- @travis_branch = ENV['TRAVIS_BRANCH'].upcase
22
- @travis_branch = ['MAIN', 'MASTER'].include?(@travis_branch) ? 'PRODUCTION' : @travis_branch
23
- @aws_access_key_id = ENV["AWS_ACCESS_KEY_ID_#{travis_branch}"]
24
- @aws_secret_access_key = ENV["AWS_SECRET_ACCESS_KEY_#{travis_branch}"]
25
- @yaml = YAML.safe_load(File.read('.travis.yml'))
26
- @lambda_config = yaml['deploy'].find { |conf| name_matches_branch?(conf['function_name'], travis_branch) }
27
- @region = @lambda_config['region']
28
- @function_name = @lambda_config['function_name']
29
- @aws_configuration = {
30
- region: region,
31
- access_key_id: aws_access_key_id,
32
- secret_access_key: aws_secret_access_key
33
- }
34
- p 'using configuration: ', aws_configuration
35
- p 'lambda config: ', lambda_config
36
- @lambda_client = Aws::Lambda::Client.new(aws_configuration) if configured?
7
+ attr_reader(
8
+ :travis_branch,
9
+ :aws_access_key_id,
10
+ :aws_secret_access_key,
11
+ :aws_configuration,
12
+ :region,
13
+ :lambda_client,
14
+ :yaml,
15
+ :lambda_config,
16
+ :function_name,
17
+ :event
18
+ )
19
+
20
+ def initialize
21
+ @travis_branch = ENV["TRAVIS_BRANCH"].upcase
22
+ @travis_branch = ["MAIN", "MASTER"].include?(@travis_branch) ? "PRODUCTION" : @travis_branch
23
+ @aws_access_key_id = ENV["AWS_ACCESS_KEY_ID_#{travis_branch}"]
24
+ @aws_secret_access_key = ENV["AWS_SECRET_ACCESS_KEY_#{travis_branch}"]
25
+ @yaml = YAML.safe_load(File.read(".travis.yml"))
26
+ @lambda_config = yaml["deploy"].find { |conf| name_matches_branch?(conf["function_name"], travis_branch) }
27
+ @region = @lambda_config["region"]
28
+ @function_name = @lambda_config["function_name"]
29
+ @aws_configuration = {
30
+ region: region,
31
+ access_key_id: aws_access_key_id,
32
+ secret_access_key: aws_secret_access_key
33
+ }
34
+ p("using configuration: ", aws_configuration)
35
+ p("lambda config: ", lambda_config)
36
+ @lambda_client = Aws::Lambda::Client.new(aws_configuration) if configured?
37
+ end
38
+
39
+ def configured?
40
+ aws_access_key_id && aws_secret_access_key && region
41
+ end
42
+
43
+ def name_matches_branch?(name, branch)
44
+ downcase_name = name.downcase
45
+ downcase_branch = branch.downcase
46
+ variants = [
47
+ ["dev", "development"],
48
+ ["qa"],
49
+ ["main", "master", "production", "prod"],
50
+ ]
51
+ variants.any? do |group|
52
+ group.any? { |variant| downcase_name.include?(variant) }\
53
+ && group.any? { |variant| downcase_branch.include?(variant) }
37
54
  end
55
+ end
38
56
 
39
- def configured?
40
- aws_access_key_id && aws_secret_access_key && region
57
+ def update_lambda_configuration
58
+ unless configured? && lambda_config
59
+ p("insufficient configuration")
60
+ return nil
41
61
  end
42
62
 
43
- def name_matches_branch?(name, branch)
44
- downcase_name = name.downcase
45
- downcase_branch = branch.downcase
46
- variants = [
47
- ['dev', 'development'],
48
- ['qa'],
49
- ['main', 'master', 'production', 'prod'],
50
- ]
51
- variants.any? do |group|
52
- group.any? { |variant| downcase_name.include? variant }\
53
- && group.any? { |variant| downcase_branch.include?(variant) }
54
- end
63
+ updated_lambda_configuration = {
64
+ function_name: function_name,
65
+ vpc_config: lambda_config["vpc_config"],
66
+ environment: lambda_config["environment"],
67
+ layers: lambda_config["layers"]
68
+ }
69
+ updated_lambda_configuration[:function_name] = function_name
70
+ p("updating_function_configuration with: ", updated_lambda_configuration)
71
+ update_configuration_resp = lambda_client.update_function_configuration(updated_lambda_configuration)
72
+ p("update_configuration_resp: ", update_configuration_resp)
73
+ end
74
+
75
+ def update_event
76
+ unless lambda_config["event"]
77
+ p("no event config")
78
+ return nil
55
79
  end
56
80
 
57
- def update_lambda_configuration
58
- unless configured? && lambda_config
59
- p 'insufficient configuration'
60
- return nil
61
- end
62
-
63
- updated_lambda_configuration = {
64
- function_name: function_name,
65
- vpc_config: lambda_config['vpc_config'],
66
- environment: lambda_config['environment'],
67
- layers: lambda_config['layers']
68
- }
69
- updated_lambda_configuration[:function_name] = function_name
70
- p 'updating_function_configuration with: ', updated_lambda_configuration
71
- update_configuration_resp = lambda_client.update_function_configuration(updated_lambda_configuration)
72
- p 'update_configuration_resp: ', update_configuration_resp
81
+ @event = lambda_config["event"]
82
+ if event["event_source_arn"]
83
+ add_event_source
84
+ elsif event["schedule_expression"]
85
+ add_cron
73
86
  end
87
+ end
74
88
 
75
- def update_event
76
- unless lambda_config['event']
77
- p 'no event config'
78
- return nil
79
- end
80
-
81
- @event = lambda_config['event']
82
- if event['event_source_arn']
83
- add_event_source
84
- elsif event['schedule_expression']
85
- add_cron
86
- end
87
- end
89
+ def add_event_source
90
+ existing_events = lambda_client.list_event_source_mappings({
91
+ function_name: function_name
92
+ }).event_source_mappings
88
93
 
89
- def add_event_source
90
- existing_events = lambda_client.list_event_source_mappings({
91
- function_name: function_name
92
- }).event_source_mappings
93
-
94
- existing_events.each do |existing_event|
95
- p 'deleting event with uuid: ', existing_event.uuid, 'and arn: ', existing_event.event_source_arn
96
- lambda_client.delete_event_source_mapping({ uuid: existing_event.uuid })
97
- end
98
- event_to_create = event.map { |k, v| [k.to_sym, v] }.to_h
99
- event_to_create[:function_name] = function_name
100
- p 'creating event: ', event_to_create
101
- create_resp = lambda_client.create_event_source_mapping(event_to_create)
102
- p 'created: ', create_resp
94
+ existing_events.each do |existing_event|
95
+ p("deleting event with uuid: ", existing_event.uuid, "and arn: ", existing_event.event_source_arn)
96
+ lambda_client.delete_event_source_mapping({ uuid: existing_event.uuid })
97
+ end
98
+ event_to_create = event.map { |k, v| [k.to_sym, v] }.to_h
99
+ event_to_create[:function_name] = function_name
100
+ p("creating event: ", event_to_create)
101
+ create_resp = lambda_client.create_event_source_mapping(event_to_create)
102
+ p("created: ", create_resp)
103
+ end
104
+
105
+ def add_cron
106
+ ## create the event
107
+ events_client = Aws::CloudWatchEvents::Client.new(aws_configuration)
108
+ schedule_expression = event["schedule_expression"]
109
+ rule_name = "#{function_name}-rule"
110
+ p("rule_name: ", rule_name, "schedule_expression: ", schedule_expression)
111
+ events_client.put_rule(name: rule_name, schedule_expression: schedule_expression)
112
+
113
+ ## next we have to connect the event to the lambda
114
+ ## the first step is to get the lambda
115
+
116
+ return "missing function_name" unless function_name
117
+
118
+ p("getting lambda with function name", function_name)
119
+ lambda_resp = lambda_client.get_function(function_name: function_name).configuration
120
+ arn = lambda_resp.function_arn
121
+
122
+ ## next figure out if the lambda already has granted cloudwatch
123
+ ## permission to invoke
124
+ begin
125
+ policy_resp = lambda_client.get_policy(function_name: function_name)
126
+ if policy_resp.policy.include?("#{function_name}-permission")
127
+ p("lambda already has permission")
128
+ else
129
+ add_policy = true
130
+ end
131
+ rescue Aws::Lambda::Errors::ResourceNotFoundException
132
+ add_policy = true
133
+ p("no policy")
103
134
  end
104
135
 
105
- def add_cron
106
- ## create the event
107
- events_client = Aws::CloudWatchEvents::Client.new(aws_configuration)
108
- schedule_expression = event['schedule_expression']
109
- rule_name = "#{function_name}-rule"
110
- p 'rule_name: ', rule_name, 'schedule_expression: ', schedule_expression
111
- events_client.put_rule(name: rule_name, schedule_expression: schedule_expression)
112
-
113
- ## next we have to connect the event to the lambda
114
- ## the first step is to get the lambda
115
-
116
- return 'missing function_name' unless function_name
117
-
118
- p 'getting lambda with function name', function_name
119
- lambda_resp = lambda_client.get_function(function_name: function_name).configuration
120
- arn = lambda_resp.function_arn
121
-
122
- ## next figure out if the lambda already has granted cloudwatch
123
- ## permission to invoke
124
- begin
125
- policy_resp = lambda_client.get_policy(function_name: function_name)
126
- unless policy_resp.policy.include?("#{function_name}-permission")
127
- add_policy = true
128
- else
129
- p 'lambda already has permission'
130
- end
131
- rescue Aws::Lambda::Errors::ResourceNotFoundException
132
- add_policy = true
133
- p 'no policy'
134
- end
135
-
136
- ## if not, add permission to invoke
137
- if add_policy
138
- permission = lambda_client.add_permission({
139
- function_name: function_name,
140
- principal: 'events.amazonaws.com',
141
- statement_id: "#{function_name}-permission",
142
- action: 'lambda:InvokeFunction'
143
- })
144
- p 'permission: ', permission
145
- end
146
-
147
- ## finally we can tell the event to invoke the lambda
148
- target_id = "#{function_name}-lambda"
149
- p 'putting targets ', 'rule: ', rule_name, 'target_id: ', target_id, 'arn: ', arn
150
- events_client.put_targets(rule: rule_name, targets: [{ id: target_id, arn: arn }])
136
+ ## if not, add permission to invoke
137
+ if add_policy
138
+ permission = lambda_client.add_permission({
139
+ function_name: function_name,
140
+ principal: "events.amazonaws.com",
141
+ statement_id: "#{function_name}-permission",
142
+ action: "lambda:InvokeFunction"
143
+ })
144
+ p("permission: ", permission)
151
145
  end
146
+
147
+ ## finally we can tell the event to invoke the lambda
148
+ target_id = "#{function_name}-lambda"
149
+ p("putting targets ", "rule: ", rule_name, "target_id: ", target_id, "arn: ", arn)
150
+ events_client.put_targets(rule: rule_name, targets: [{ id: target_id, arn: arn }])
151
+ end
152
152
  end
@@ -1,7 +1,7 @@
1
- require 'securerandom'
2
- require 'aws-sdk-kinesis'
3
- require_relative 'nypl_avro'
4
- require_relative 'errors'
1
+ require "securerandom"
2
+ require "aws-sdk-kinesis"
3
+ require_relative "nypl_avro"
4
+ require_relative "errors"
5
5
  # Model representing the result message posted to Kinesis stream about everything that has gone on here -- good, bad, or otherwise.
6
6
 
7
7
  class KinesisClient
@@ -12,17 +12,15 @@ class KinesisClient
12
12
  @stream_name = @config[:stream_name]
13
13
  @avro = nil
14
14
  @batch_size = @config[:batch_size] || 1
15
- @batch = []
16
- @automatically_push = @config[:automatically_push] == false ? false : true
15
+ @batch_count = 0
16
+ @records = []
17
+ @automatically_push = !(@config[:automatically_push] == false)
17
18
  @client_options = config[:profile] ? { profile: config[:profile] } : {}
18
- @client = Aws::Kinesis::Client.new @client_options
19
+ @client = Aws::Kinesis::Client.new(@client_options)
19
20
 
20
- if config[:schema_string]
21
- @avro = NYPLAvro.by_name(config[:schema_string])
22
- end
23
-
24
- @shovel_method = @batch_size > 1 ? :push_to_batch : :push_record
21
+ @avro = NYPLAvro.by_name(config[:schema_string]) if config[:schema_string]
25
22
 
23
+ @shovel_method = @batch_size > 1 ? :push_to_records : :push_record
26
24
  end
27
25
 
28
26
  def convert_to_record(json_message)
@@ -37,7 +35,6 @@ class KinesisClient
37
35
  data: message,
38
36
  partition_key: partition_key
39
37
  }
40
-
41
38
  end
42
39
 
43
40
  def <<(json_message)
@@ -45,10 +42,10 @@ class KinesisClient
45
42
  end
46
43
 
47
44
  def push_record(json_message)
48
- record = convert_to_record json_message
45
+ record = convert_to_record(json_message)
49
46
  record[:stream_name] = @stream_name
50
47
 
51
- @client.put_record record
48
+ @client.put_record(record)
52
49
 
53
50
  return_hash = {}
54
51
 
@@ -57,21 +54,19 @@ class KinesisClient
57
54
  return_hash["message"] = json_message, resp
58
55
  $logger.info("Message sent to #{config[:stream_name]} #{json_message}, #{resp}") if $logger
59
56
  else
60
- $logger.error("message" => "FAILED to send message to HoldRequestResult #{json_message}, #{resp}.") if $logger
61
- raise NYPLError.new json_message, resp
57
+ $logger.error("message" => "FAILED to send message to #{@stream_name} #{json_message}, #{resp}.") if $logger
58
+ raise(NYPLError.new(json_message, resp))
62
59
  end
63
60
  return_hash
64
61
  end
65
62
 
66
- def push_to_batch(json_message)
63
+ def push_to_records(json_message)
67
64
  begin
68
- @batch << convert_to_record(json_message)
65
+ @records << convert_to_record(json_message)
69
66
  rescue AvroError => e
70
67
  $logger.error("message" => "Avro encoding error #{e.message} for #{json_message}")
71
68
  end
72
- if @automatically_push && @batch.length >= @batch_size
73
- push_records
74
- end
69
+ push_records if @automatically_push && @records.length >= @batch_size
75
70
  end
76
71
 
77
72
  def push_batch(batch)
@@ -82,21 +77,31 @@ class KinesisClient
82
77
 
83
78
  $logger.debug("Received #{resp} from #{@stream_name}")
84
79
 
85
- return_message = {
86
- failures: resp.failed_record_count,
87
- error_messages: resp.records.map {|record| record.error_message }.compact
88
- }
89
-
90
- $logger.info("Message sent to #{config[:stream_name]} #{return_message}") if $logger
91
-
92
- return {
93
- "code": "200",
94
- "message": return_message.to_json
95
- }
80
+ if resp.failed_record_count > 0
81
+ return_message = {
82
+ failures: resp.failed_record_count,
83
+ failures_data: filter_failures(resp)
84
+ }
85
+ $logger.warn("Message sent to #{config[:stream_name]} #{return_message}") if $logger
86
+ else
87
+ $logger.info("Message sent to #{config[:stream_name]} successfully") if $logger
88
+ end
96
89
  end
97
90
 
98
91
  def push_records
99
- @batch.each_slice(@batch_size) {|slice| push_batch slice}
100
- @batch = []
92
+ if @records.length > 0
93
+ @records.each_slice(@batch_size) do |slice|
94
+ push_batch(slice)
95
+ @batch_count += 1
96
+ end
97
+ @records = []
98
+ @batch_count = 0
99
+ end
100
+ end
101
+
102
+ def filter_failures(resp)
103
+ resp.records.filter_map.with_index do |record, i|
104
+ avro.decode(@records[i + @batch_size * @batch_count]) if record.responds_to?(:error_message)
105
+ end
101
106
  end
102
107
  end
data/lib/kms_client.rb CHANGED
@@ -1,5 +1,5 @@
1
- require 'aws-sdk-kms'
2
- require 'base64'
1
+ require "aws-sdk-kms"
2
+ require "base64"
3
3
 
4
4
  class KmsClient
5
5
  @@kms = nil
@@ -11,15 +11,15 @@ class KmsClient
11
11
 
12
12
  def decrypt(cipher)
13
13
  # Assume value is base64 encoded:
14
- decoded = Base64.decode64 cipher
15
- decrypted = @kms.decrypt ciphertext_blob: decoded
14
+ decoded = Base64.decode64(cipher)
15
+ decrypted = @kms.decrypt(ciphertext_blob: decoded)
16
16
  decrypted[:plaintext]
17
17
  end
18
18
 
19
19
  def self.aws_kms_client(options)
20
20
  params = {
21
- region: 'us-east-1',
22
- stub_responses: ENV['APP_ENV'] == 'test'
21
+ region: "us-east-1",
22
+ stub_responses: ENV["APP_ENV"] == "test"
23
23
  }.merge(options)
24
24
  @@kms = Aws::KMS::Client.new(params) if @@kms.nil?
25
25
  @@kms
metadata CHANGED
@@ -1,11 +1,11 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nypl_ruby_util
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.7
4
+ version: 0.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Appel
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
  date: 2020-09-08 00:00:00.000000000 Z
@@ -109,7 +109,7 @@ dependencies:
109
109
  - !ruby/object:Gem::Version
110
110
  version: 1.0.3
111
111
  description: A repository of common utilities for NYPL Ruby application
112
- email:
112
+ email:
113
113
  executables: []
114
114
  extensions: []
115
115
  extra_rdoc_files: []
@@ -126,7 +126,7 @@ homepage: https://github.com/NYPL/NYPLRubyUtil
126
126
  licenses:
127
127
  - MIT
128
128
  metadata: {}
129
- post_install_message:
129
+ post_install_message:
130
130
  rdoc_options: []
131
131
  require_paths:
132
132
  - lib
@@ -141,8 +141,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
141
141
  - !ruby/object:Gem::Version
142
142
  version: '0'
143
143
  requirements: []
144
- rubygems_version: 3.2.3
145
- signing_key:
144
+ rubygems_version: 3.1.2
145
+ signing_key:
146
146
  specification_version: 4
147
147
  summary: A repository of common utilities for NYPL Ruby application
148
148
  test_files: []