123456789_123456789_123456789_123456789_123456789_

Class: Mongo::Server::AppMetadata::Environment Private

Do not use. This class is for internal use only.
Relationships & Source Files
Namespace Children
Exceptions:
Inherits: Object
Defined in: lib/mongo/server/app_metadata/environment.rb

Overview

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

This includes FaaS environment checks, as well as checks for the presence of a container (Docker) and/or orchestrator (Kubernetes).

Since:

  • 2.0.0

Constant Summary

  • COERCIONS =

    Describes how to coerce values of the specified type.

    Since:

    • 2.0.0

    # File 'lib/mongo/server/app_metadata/environment.rb', line 65
    {
      string: ->(v) { String(v) },
      integer: ->(v) { Integer(v) }
    }.freeze
  • DISCRIMINATORS =

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

    Since:

    • 2.0.0

    # File 'lib/mongo/server/app_metadata/environment.rb', line 55
    {
      'AWS_EXECUTION_ENV' => { pattern: /^AWS_Lambda_/, name: 'aws.lambda' },
      'AWS_LAMBDA_RUNTIME_API' => { name: 'aws.lambda' },
      'FUNCTIONS_WORKER_RUNTIME' => { name: 'azure.func' },
      'K_SERVICE' => { name: 'gcp.func' },
      'FUNCTION_NAME' => { name: 'gcp.func' },
      'VERCEL' => { name: 'vercel' },
    }.freeze
  • DOCKERENV_PATH =

    The name and location of the .dockerenv file that will signal the presence of Docker.

    Since:

    • 2.0.0

    # File 'lib/mongo/server/app_metadata/environment.rb', line 47
    '/.dockerenv'
  • 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.

    Since:

    • 2.0.0

    # File 'lib/mongo/server/app_metadata/environment.rb', line 73
    {
      'aws.lambda' => {
        'AWS_REGION' => { field: :region, type: :string },
        'AWS_LAMBDA_FUNCTION_MEMORY_SIZE' => { field: :memory_mb, type: :integer },
      },
    
      'azure.func' => {},
    
      'gcp.func' => {
        'FUNCTION_MEMORY_MB' => { field: :memory_mb, type: :integer },
        'FUNCTION_TIMEOUT_SEC' => { field: :timeout_sec, type: :integer },
        'FUNCTION_REGION' => { field: :region, type: :string },
      },
    
      'vercel' => {
        'VERCEL_REGION' => { field: :region, type: :string },
      },
    }.freeze
  • MAXIMUM_VALUE_LENGTH =

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

    Since:

    • 2.0.0

    # File 'lib/mongo/server/app_metadata/environment.rb', line 51
    500

Class Method Summary

  • .new ⇒ Environment constructor Internal use only

    Create a new Environment object, initializing it from the current ENV variables.

Instance Attribute Summary

Instance Method Summary

Instance Attribute Details

#aws?true | false (readonly)

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

Returns:

  • (true | false)

    whether the environment is a AWS Lambda environment or not.

Since:

  • 2.0.0

[ GitHub ]

  
# File 'lib/mongo/server/app_metadata/environment.rb', line 157

def aws?
  @name == 'aws.lambda'
end

#azure?true | false (readonly)

Queries whether the current environment is a valid Azure environment.

Returns:

  • (true | false)

    whether the environment is a Azure environment or not.

Since:

  • 2.0.0

[ GitHub ]

  
# File 'lib/mongo/server/app_metadata/environment.rb', line 166

def azure?
  @name == 'azure.func'
end

#docker_present?Boolean (readonly, private)

Checks for the existence of a .dockerenv in the root directory.

Since:

  • 2.0.0

[ GitHub ]

  
# File 'lib/mongo/server/app_metadata/environment.rb', line 234

def docker_present?
  File.exist?(dockerenv_path)
end

#errorString | nil (rw)

Note:

These error messagess are not to be propogated to the user; they are intended only for troubleshooting and debugging.)

Returns:

  • (String | nil)

    the error message explaining why a valid FaaS environment was not detected, or nil if no error occurred.

Since:

  • 2.0.0

[ GitHub ]

  
# File 'lib/mongo/server/app_metadata/environment.rb', line 105

attr_reader :error

#error=(msg) (rw, private)

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

Parameters:

  • msg (String)

    The error message to store.

Since:

  • 2.0.0

[ GitHub ]

  
# File 'lib/mongo/server/app_metadata/environment.rb', line 307

def error=(msg)
  @name = nil
  @error = msg
end

#faas?true | false (readonly)

Queries whether the current environment is a valid FaaS environment.

Returns:

  • (true | false)

    whether the environment is a FaaS environment or not.

Since:

  • 2.0.0

[ GitHub ]

  
# File 'lib/mongo/server/app_metadata/environment.rb', line 148

def faas?
  @name != nil
end

#fieldsHash | nil (readonly)

Returns:

  • (Hash | nil)

    the fields describing the detected FaaS environment.

Since:

  • 2.0.0

[ GitHub ]

  
# File 'lib/mongo/server/app_metadata/environment.rb', line 98

attr_reader :fields

#gcp?true | false (readonly)

Queries whether the current environment is a valid GCP environment.

Returns:

  • (true | false)

    whether the environment is a GCP environment or not.

Since:

  • 2.0.0

[ GitHub ]

  
# File 'lib/mongo/server/app_metadata/environment.rb', line 175

def gcp?
  @name == 'gcp.func'
end

#kubernetes_present?Boolean (readonly, private)

Checks for the presence of a non-empty KUBERNETES_SERVICE_HOST environment variable.

Since:

  • 2.0.0

[ GitHub ]

  
# File 'lib/mongo/server/app_metadata/environment.rb', line 246

def kubernetes_present?
  !ENV['KUBERNETES_SERVICE_HOST'].to_s.empty?
end

#nameString | nil (readonly)

Returns:

  • (String | nil)

    the name of the FaaS environment that was detected, or nil if no valid FaaS environment was detected.

Since:

  • 2.0.0

[ GitHub ]

  
# File 'lib/mongo/server/app_metadata/environment.rb', line 94

attr_reader :name

#present?true | false (readonly)

Queries whether any environment information was able to be detected.

Returns:

  • (true | false)

    if any environment information was detected.

Since:

  • 2.0.0

[ GitHub ]

  
# File 'lib/mongo/server/app_metadata/environment.rb', line 140

def present?
  @name || fields.any?
end

#vercel?true | false (readonly)

Queries whether the current environment is a valid Vercel environment.

Returns:

  • (true | false)

    whether the environment is a Vercel environment or not.

Since:

  • 2.0.0

[ GitHub ]

  
# File 'lib/mongo/server/app_metadata/environment.rb', line 184

def vercel?
  @name == 'vercel'
end

Instance Method Details

#containerHash | nil

Queries the detected container information.

Returns:

  • (Hash | nil)

    the detected container information, or nil if no container was detected.

Since:

  • 2.0.0

[ GitHub ]

  
# File 'lib/mongo/server/app_metadata/environment.rb', line 131

def container
  fields[:container]
end

#detect_container (private)

Looks for the presence of a container. Currently can detect Docker (by the existence of a .dockerenv file in the root directory) and Kubernetes (by the existence of the KUBERNETES_SERVICE_HOST environment variable).

Since:

  • 2.0.0

[ GitHub ]

  
# File 'lib/mongo/server/app_metadata/environment.rb', line 222

def detect_container
  runtime = docker_present? && 'docker'
  orchestrator = kubernetes_present? && 'kubernetes'

  return unless runtime || orchestrator

  fields[:container] = {}
  fields[:container][:runtime] = runtime if runtime
  fields[:container][:orchestrator] = orchestrator if orchestrator
end

#detect_environmentString | nil (private)

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

Returns:

  • (String | nil)

    the name of the detected FaaS provider.

Raises:

  • (TooManyEnvironments)

    if the environment contains discriminating variables for more than one FaaS provider.

Since:

  • 2.0.0

[ GitHub ]

  
# File 'lib/mongo/server/app_metadata/environment.rb', line 204

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) ⇒ true | false (private)

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.

Parameters:

  • var (String)

    the name of the environment variable

Returns:

  • (true | false)

    if the variable describes the current environment or not.

Since:

  • 2.0.0

[ GitHub ]

  
# File 'lib/mongo/server/app_metadata/environment.rb', line 258

def discriminator_matches?(var)
  return false unless ENV[var]

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

  disc[:pattern].match?(ENV[var])
end

#dockerenv_path (private)

Implementing this as a method so that it can be mocked in tests, to test the presence or absence of Docker.

Since:

  • 2.0.0

[ GitHub ]

  
# File 'lib/mongo/server/app_metadata/environment.rb', line 240

def dockerenv_path
  DOCKERENV_PATH
end

#extract_field(var, definition) ⇒ Integer | String (private)

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

Parameters:

  • var (String)

    The name of the environment variable to look for.

  • definition (Hash)

    The definition of the field that applies to the named variable.

Returns:

  • (Integer | String)

    the validated and coerced value of the given environment variable.

Raises:

  • (MissingVariable)

    if the environment does not include a variable required by the current FaaS provider.

  • (ValueTooLong)

    if a required variable is too long.

  • (TypeMismatch)

    if a required variable cannot be coerced to the expected type.

Since:

  • 2.0.0

[ GitHub ]

  
# File 'lib/mongo/server/app_metadata/environment.rb', line 294

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_faas_fields (private)

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

Since:

  • 2.0.0

[ GitHub ]

  
# File 'lib/mongo/server/app_metadata/environment.rb', line 270

def populate_faas_fields
  return unless name

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

#to_hHash

Compiles the detected environment information into a Hash.

Returns:

  • (Hash)

    the detected environment information.

Since:

  • 2.0.0

[ GitHub ]

  
# File 'lib/mongo/server/app_metadata/environment.rb', line 191

def to_h
  name ? fields.merge(name: name) : fields
end