class Mongo::Server::AppMetadata::Environment

Implements the logic from the handshake spec, for deducing and reporting the current FaaS environment in which the program is executing.

@api private

Constants

COERCIONS

Describes how to coerce values of the specified type.

DISCRIMINATORS

The mapping that determines which FaaS environment is active, based on which environment variable(s) are present.

FIELDS

Describes which fields are required for each FaaS environment, along with their expected types, and how they should be named in the handshake document.

MAXIMUM_VALUE_LENGTH

This value is not explicitly specified in the spec, only implied to be less than 512.

Attributes

error[R]

@return [ String | nil ] the error message explaining why a valid

FaaS environment was not detected, or nil if no error occurred.

@note These error messagess are not to be propogated to the

user; they are intended only for troubleshooting and debugging.)
fields[R]

@return [ Hash | nil ] the fields describing the detected FaaS

environment.
name[R]

@return [ String | nil ] the name of the FaaS environment that was

detected, or nil if no valid FaaS environment was detected.

Public Class Methods

new() click to toggle source

Create a new AppMetadata::Environment object, initializing it from the current ENV variables. If no FaaS environment is detected, or if the environment contains invalid or contradictory state, it will be initialized with {{name}} set to {{nil}}.

# File lib/mongo/server/app_metadata/environment.rb, line 104
def initialize
  @error = nil
  @name = detect_environment
  populate_fields
rescue TooManyEnvironments => e
  self.error = "too many environments detected: #{e.message}"
rescue MissingVariable => e
  self.error = "missing environment variable: #{e.message}"
rescue TypeMismatch => e
  self.error = e.message
rescue ValueTooLong => e
  self.error = "value for #{e.message} is too long"
end

Public Instance Methods

aws?() click to toggle source

Queries whether the current environment is a valid AWS Lambda environment.

@return [ true | false ] whether the environment is a AWS Lambda

environment or not.
# File lib/mongo/server/app_metadata/environment.rb, line 131
def aws?
  @name == 'aws.lambda'
end
azure?() click to toggle source

Queries whether the current environment is a valid Azure environment.

@return [ true | false ] whether the environment is a Azure

environment or not.
# File lib/mongo/server/app_metadata/environment.rb, line 140
def azure?
  @name == 'azure.func'
end
faas?() click to toggle source

Queries whether the current environment is a valid FaaS environment.

@return [ true | false ] whether the environment is a FaaS

environment or not.
# File lib/mongo/server/app_metadata/environment.rb, line 122
def faas?
  @name != nil
end
gcp?() click to toggle source

Queries whether the current environment is a valid GCP environment.

@return [ true | false ] whether the environment is a GCP

environment or not.
# File lib/mongo/server/app_metadata/environment.rb, line 149
def gcp?
  @name == 'gcp.func'
end
to_h() click to toggle source

Compiles the detected environment information into a Hash. It will always include a {{name}} key, but may include other keys as well, depending on the detected FaaS environment. (See the handshake spec for details.)

@return [ Hash ] the detected environment information.

# File lib/mongo/server/app_metadata/environment.rb, line 168
def to_h
  fields.merge(name: name)
end
vercel?() click to toggle source

Queries whether the current environment is a valid Vercel environment.

@return [ true | false ] whether the environment is a Vercel

environment or not.
# File lib/mongo/server/app_metadata/environment.rb, line 158
def vercel?
  @name == 'vercel'
end

Private Instance Methods

detect_environment() click to toggle source

Searches the DESCRIMINATORS list to see which (if any) apply to the current environment.

@return [ String | nil ] the name of the detected FaaS provider.

@raise [ TooManyEnvironments ] if the environment contains

discriminating variables for more than one FaaS provider.
# File lib/mongo/server/app_metadata/environment.rb, line 181
def detect_environment
  matches = DISCRIMINATORS.keys.select { |k| discriminator_matches?(k) }
  names = matches.map { |m| DISCRIMINATORS[m][:name] }.uniq

  # From the spec:
  # When variables for multiple ``client.env.name`` values are present,
  # ``vercel`` takes precedence over ``aws.lambda``; any other
  # combination MUST cause ``client.env`` to be entirely omitted.
  return 'vercel' if names.sort == %w[ aws.lambda vercel ]
  raise TooManyEnvironments, names.join(', ') if names.length > 1

  names.first
end
discriminator_matches?(var) click to toggle source

Determines whether the named environment variable exists, and (if a pattern has been declared for that descriminator) whether the pattern matches the value of the variable.

@param [ String ] var the name of the environment variable

@return [ true | false ] if the variable describes the current

environment or not.
# File lib/mongo/server/app_metadata/environment.rb, line 203
def discriminator_matches?(var)
  return false unless ENV[var]

  disc = DISCRIMINATORS[var]
  return true unless disc[:pattern]

  disc[:pattern].match?(ENV[var])
end
error=(msg) click to toggle source

Sets the error message to the given value and sets the name to nil.

@param [ String ] msg The error message to store.

# File lib/mongo/server/app_metadata/environment.rb, line 252
def error=(msg)
  @name = nil
  @error = msg
end
extract_field(var, definition) click to toggle source

Extracts the named variable from the environment and validates it against its declared definition.

@param [ String ] var The name of the environment variable to look

for.

@param [ Hash ] definition The definition of the field that applies

to the named variable.

@return [ Integer | String ] the validated and coerced value of the

given environment variable.

@raise [ MissingVariable ] if the environment does not include a

variable required by the current FaaS provider.

@raise [ ValueTooLong ] if a required variable is too long. @raise [ TypeMismatch ] if a required variable cannot be coerced to

the expected type.
# File lib/mongo/server/app_metadata/environment.rb, line 239
def extract_field(var, definition)
  raise MissingVariable, var unless ENV[var]
  raise ValueTooLong, var if ENV[var].length > MAXIMUM_VALUE_LENGTH

  COERCIONS[definition[:type]].call(ENV[var])
rescue ArgumentError
  raise TypeMismatch,
        "#{var} must be #{definition[:type]} (got #{ENV[var].inspect})"
end
populate_fields() click to toggle source

Extracts environment information from the current environment variables, based on the detected FaaS environment. Populates the {{@fields}} instance variable.

# File lib/mongo/server/app_metadata/environment.rb, line 215
def populate_fields
  return unless name

  @fields = FIELDS[name].each_with_object({}) do |(var, defn), fields|
    fields[defn[:field]] = extract_field(var, defn)
  end
end