Class: Jets::CLI::Call

Inherits:
Object
  • Object
show all
Extended by:
Memoist
Includes:
AwsServices, Util::Logging
Defined in:
lib/jets/cli/call.rb

Direct Known Subclasses

Jets::CLI::Curl::Request, Exec::Command

Defined Under Namespace

Classes: Error

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Util::Logging

#log

Methods included from AwsServices

#apigateway, #aws_options, #cfn, #codebuild, #dynamodb, #lambda_client, #logs, #s3, #s3_resource, #sns, #sqs, #ssm, #sts, #wafv2

Methods included from AwsServices::StackStatus

#output_value, #stack_exists?

Methods included from AwsServices::GlobalMemoist

included, #reset_cache!

Constructor Details

#initialize(options = {}) ⇒ Call

Returns a new instance of Call.



10
11
12
13
14
# File 'lib/jets/cli/call.rb', line 10

def initialize(options = {})
  @options = options
  @log_type = options[:log_type] || "Tail"
  @event = options[:event] || "{}" # json string
end

Instance Attribute Details

#eventObject (readonly)

Returns the value of attribute event.



9
10
11
# File 'lib/jets/cli/call.rb', line 9

def event
  @event
end

Instance Method Details

#check_valid_json!(text) ⇒ Object

Exits with friendly error message when user provides bad just



119
120
121
122
123
124
125
# File 'lib/jets/cli/call.rb', line 119

def check_valid_json!(text)
  JSON.parse(text)
rescue JSON::ParserError => e
  puts "Invalid json provided:\n  '#{text}'"
  puts "Exiting... Please try again and provide valid json."
  exit 1
end

#function_nameObject



127
128
129
130
# File 'lib/jets/cli/call.rb', line 127

def function_name
  name = @options[:function] || "controller"
  Jets::CLI::Lambda::Lookup.function(name)
end

#invocation_typeObject

Event invocation returns a “202 Accepted” response. It means the request has accepted for processing, but the processing has not been completed. Event invocation types are asynchronous. The resp.payload.read is a empty string and is not JSON parseable. We the raw resp object so the caller can inspect the status code and headers. Example:

{
  status_code: 202,
  function_error: nil,
  log_result: nil,
  payload: "[FILTERED]",
  executed_version: nil
}

Event invocation only use by Jets::Preheat.perform



86
87
88
# File 'lib/jets/cli/call.rb', line 86

def invocation_type
  @options[:invocation_type] || "RequestResponse"
end

#invokeObject



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/jets/cli/call.rb', line 24

def invoke
  params = {
    function_name: function_name,
    invocation_type: invocation_type, # Event or RequestResponse
    log_type: @log_type, # pretty sweet
    payload: payload # json string
    # qualifier: @qualifier # "1", version or alias published version. not used yet
  }

  resp = nil
  begin
    resp = lambda_client.invoke(params)
    # Capture @log_last_4kb for log_last_4kb method
    # log_last_4kb is an interface method used by Exec::Command
    @log_last_4kb = resp.log_result
  rescue Aws::Lambda::Errors::ResourceNotFoundException
    warn "ERROR: function #{function_name} not found".color(:red)
    warn "Maybe check the spelling or the AWS_PROFILE?"
    return resp
  end

  if !/^2/.match?(resp[:status_code].to_s)
    warn "ERROR: Lambda function #{function_name} returned status code: #{resp[:status_code]}".color(:red)
    warn resp
  end

  if verbose? && invocation_type != "Event"
    log_last_4kb
  end

  if invocation_type == "Event"
    resp
  else
    text = resp.payload.read # already been normalized/JSON.dump by AWS
    data = JSON.parse(text)
    ActiveSupport::HashWithIndifferentAccess.new(data)
  end
end

#load_event_from_file(text) ⇒ Object



106
107
108
109
110
111
112
113
114
115
116
# File 'lib/jets/cli/call.rb', line 106

def load_event_from_file(text)
  path = text.gsub("file://", "")
  path = "#{Jets.root}/#{path}" unless path[0..0] == "/"
  unless File.exist?(path)
    puts "File #{path} does not exist.  Are you sure the file exists?".color(:red)
    exit 1
  end
  text = IO.read(path)
  check_valid_json!(text)
  text
end

#log_last_4kb(header_message = "Showing last 4KB of log from x-amz-log-result header:") ⇒ Object

interface method



64
65
66
67
68
# File 'lib/jets/cli/call.rb', line 64

def log_last_4kb(header_message = "Showing last 4KB of log from x-amz-log-result header:")
  return unless @log_last_4kb
  warn header_message
  warn Base64.decode64(@log_last_4kb)
end

#payloadObject

payload returns a JSON String for the lambda.invoke payload. It can be the file:// notation interface method



97
98
99
100
101
102
103
# File 'lib/jets/cli/call.rb', line 97

def payload
  text = @event
  if text&.include?("file://")
    text = load_event_from_file(text)
  end
  text
end

#runObject



16
17
18
19
20
21
22
# File 'lib/jets/cli/call.rb', line 16

def run
  warn "Calling Lambda function #{function_name}"
  result = invoke
  warn "Response:".color(:green)
  # only thing that goes to stdout. so can pipe to commands like jq
  puts JSON.pretty_generate(result)
end

#verbose?Boolean

Returns:

  • (Boolean)


90
91
92
# File 'lib/jets/cli/call.rb', line 90

def verbose?
  @options[:verbose] || @options[:logs]
end