Skip to content

A customizable metadata server that can be used for local debugging of applications that are intended to run in cloud environments that providing metadata server functionality.

License

Notifications You must be signed in to change notification settings

minherz/metadataserver

Repository files navigation

Metadata Server

GitHub release (latest SemVer) Go Report Card Build codecov PkgGoDev GitHub go.mod Go version Repo license

This is a simulation of the metadata server that run on cloud environments of such providers as Amazon, Google or Azure. This server is intended to assist in local debugging of applications that are intended for run in cloud environments and make use of the environment's metadata server.

The default configuration of the metadataserver package sets up the following endpoint:

  • http://169.254.169.254/computeMetadata/v1

All other endpoints are served by appending the path of the metadata to the default endpoint path.

Note

Currently metadataserver does not support HTTPS endpoints

Use the package

To use the package do the following:

  1. Import the package into your code:

    import "github.com/minherz/metadataserver"
  2. Instantiate the server:

    ms, err := metadataserver.New(metadataserver.WithConfigFile("path/to/config/file"))

    See other [options] for more configurations.

  3. Start the server:

    err := ms.Start(context.Background())
  4. Stop the server:

    err := ms.Stop(context.Background())

Using for unit testing

This package can be used for local unit testing of the code that uses metadata server.

Important

If your code sends requests to the metadata server using IP address, make sure that this IP address is reachable. Reference to Metadata server IP address section for more details.

If your code sends requests to the metadata server using hostname, edit hostname file to link the hostname to localhost.

In your test file start and stop the server as shown above.

Test function example

The following example configures the metadata server to run on interloop interface, listening at port 80 and serving requests at the following two endpoints:

  • computeMetadata/v1/project-id
  • computeMetadata/v1/instance/zone
package service_test

import (
 "context"
 "testing"

 "github.com/org/project/service"
 "github.com/minherz/metadataserver"
)

func TestMyService(t *testing.T) {
 if testing.Short() {
  t.Skip()
 }
 tests := []struct {
  name  string
  // rest of input/want/expected data
 }{
  name: "test1",
 }}

 s, err := metadataserver.New(
    metadataserver.WithAddress("0.0.0.0"),
    metadataserver.WithPort(80),
    metadataserver.WithHandlers(
      map[string]metadataserver.Metadata {
        "project-id": func() string { return "your-test-project" },
        "instance/zone": func() string { return "us-central1" },
      }))
 if err != nil {
  t.Errorf("expected no errors, got: %v", err)
 }
 err = s.Start()
 if err != nil {
  t.Errorf("expected no errors, got: %v", err)
 }
 defer s.Stop()
 for _, test := range tests {
  t.Run(test.name, func(t *testing.T) {
    // you test code
  })
 }
}

Options

You can initialize server with the following options:

  • WithConfigFile() -- allows to configure server using the JSON configuration file. See Custom configuration for the file format. Mind the order of options when use with WithConfiguration(), WithAddress() and WithPort().
  • WithConfiguration() -- allows to configure server with the Configuration object. Mind the order of options when use with WithConfigFile(), WithAddress() and WithPort().
  • WithAddress() -- allows to set up the serving address for the server. Mind the order of options when use with WithConfigFile() and WithConfiguration().
  • WithPort() -- allows to set up the port that the server will be listening at. Mind the order of options when use with WithConfigFile() and WithConfiguration().
  • WithEndpoint() -- allows to set up the default endpoint path. Mind the order of options when use with WithConfigFile() and WithConfiguration().
  • WithHandlers() -- allows to set up the metadata paths and responses when the metadata request is served at the paths. Mind the order of options when use with WithConfigFile() and WithConfiguration().
  • WithLogger -- allows to setup a custom slog.Logger. If no logger is set up the metadata server writes logs to io.Discard.

Custom configuration

You can define custom configurations using JSON configuration file instead of setting them up in the code. See example configurations in the repo. You also can use WithConfiguration() option to define the configuration in the code instead of using other With* functions.

The JSON file schema is described below:

Name Type Description
address string IP address of where the server serves the requests. Default value 169.254.169.254.
port numeric Port number at which the server listens. Default value 80.
endpoint string The default path. Together with address and port it defined the default endpoint and also is used as a prefix for other handler's paths. Sending request to the default endpoint always returns "ok". Default value computeMetadata/v1.
shutdownTimeout numeric The time in seconds that takes to server to timeout at shutdown. Default value 5 (sec).
metadata map Collection of key-values describing the returned metadata. See next paragraph for more information.

Metadata keys and values

Metadata maps keys to values allowing customization of data that the server returns on different paths. The path is composed of concatinating the endpoint with the metadata's key string. For example, for the default endpoint and the key "project/project-id", the server will respond at the path "/computeMetadata/v1/project/project-id" with the value defined in the metadata map.

Metadata map supports two types of values:

  • Static values -- literals that are returned when a request is send using the path of the endpoint + key. Use the following JSON to define the static value:

    {
      "value": "STATIC_VALUE"
    }
  • Environment-based values -- the returned value is retrieved from the environment variable which name is defined in the metadata's value. When a request is send using the path of the endpoint + key, the server will read and return the value of the environment variable. Use the following JSON to define the environment-based value:

    {
      "env": "ENV_VARIABLE_NAME"
    }

The following example of the custom configuration sets up the server to serve three metadata values at the following paths:

  • /custom/endpoint/static path will return always the same
  • /custom/endpoint/environment_a path will return the value of the environment variable with the name X_A
  • /custom/endpoint/another/static path will return this is another always the same value
{
    "endpoint": "custom/endpoint",
    "metadata": {
        "static": {
            "value": "always the same"
        },
        "environment_a": {
            "env": "X_A"
        },
        "another/static": {
            "value": "this is another always the same value"
        }
    }
}

Note

Configuration values that were not customized keep their default values. If no metadata is configured, the server will respond at the path defined by the endpoint only.

Metadata server IP address

The package does not implement any networking configuration on the local host. If you code uses a hostname (e.g. metadata.google.internal for Google's metadata server), this hostname has to be explicitly configured in your debug environment or your code has to run the metadataserver using IP address instead. Majority of providers run their metadata servers using 169.254.169.254 IP address. It is a link-local address. This means that these addresses are usually have to be configured in the environment prior to use.

Use the following Linux shell command to configure link this address to your localhost interface:

sudo ip addr add 169.254.169.254/16 dev lo

Use the following PowerShell to do the same on Windows:

New-NetIPAddress -InterfaceAlias "Loopback" -IPAddress "169.254.169.254" -PrefixLength 16

Note

It is highly unlikely that you already have a link for "169.254.169.254" in your environment. However, take precautions not to override the already existing configuration.

About

A customizable metadata server that can be used for local debugging of applications that are intended to run in cloud environments that providing metadata server functionality.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages