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