nypl_ruby_util 0.0.7 → 0.0.8

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 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: []