/infrabin

Like httpbin, but for infrastructure

Primary LanguagePython

Infrabin

Build Status Docker Pulls Coverage Status

Warning: infrabin exposes sensitive endpoints and should NEVER be used on the public Internet.

infrabin is an HTTP server that exposes a set of JSON endpoints. It can be used to simulate blue/green deployments, to test routing and failover or as a general swiss-knife for your infrastructure.

Usage

Docker

docker run -d -p 8080:8080 maruina/infrabin

Kubernetes

# Apply only what you need
kubectl apply -f k8s/namespace.yml
kubectl apply -f k8s/deployment.yml
kubectl apply -f k8s/service.yml

# Example ingress rule to be changed according the k8s configuration
cat <<EOF | kubectl create -f -
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: infrabin
  namespace: infrabin
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
    - host: infrabin.<DOMAIN>
      http:
        paths:
        - path: /
          backend:
            serviceName: infrabin
            servicePort: 8080
EOF

To override the default settings:

  • -e PORT=<PORT> to change infrabin listening port. Default to 8080.
  • -e THREADS=<THREADS> to change uwsgi threads number. Default to 8.
  • -e MAX_DELAY=<MAX_DELAY> to change the maximum value for the /delay endpoint. Default to 120.
  • -e MAX_RETRIES=<MAX_RETRIES> to change the maximum value for the /retry endpoint. Default to 3.
  • -e MAX_SIZE=<MAX_SIZE> to change the maximum value for the /bytes endpoint. Default to 1024 * 1024 Kb (1 Mb).
  • -e USE_ENVOY_PREFLIGHT=true wrap the uwsgi process around https://github.com/monzo/envoy-preflight to work with envoy and any other service mesh envoy-based. Default to false.

Endpoints

  • GET /
    • returns: a JSON with the server hostname and {"message": "infrabin is running"}.
  • GET /headers
    • returns: a JSON with the request headers, method and origin IP address.
  • GET /networks
    • returns: a JSON with the AF_INET address family info for all the network interfaces.
  • GET /network/<interface>
    • returns: a JSON with the AF_INET address family info of the target interface or 404 if the network interface does not exist.
  • GET /healthcheck/liveness
    • returns: the JSON {"message": "liveness probe healthy"} if healthy or the status code 503 if unhealthy.
  • POST /healthcheck/liveness/pass
    • returns: 204 on success, resetting the /healthcheck/liveness endpoint to be healthy.
  • POST /healthcheck/liveness/fail
    • returns: 204 on success, forcing the /healthcheck/liveness endpoint to be unhealthy.
  • GET /healthcheck/readiness
    • returns: the JSON {"message": "readiness probe healthy"} if healthy or the status code 503 if unhealthy.
  • POST /healthcheck/readiness/pass
    • returns: 204 on success, resetting the /healthcheck/readiness endpoint to be healthy.
  • POST /healthcheck/readiness/fail
    • returns: 204 on success, forcing the /healthcheck/readiness endpoint to be unhealthy.
  • GET /env/<env_var>
    • returns: the value of env_var or 404 if the environment variable does not exist.
  • GET /aws/<metadata_endpoint>
  • GET /connectivity
    • returns: the JSON {"dns":{"status": "ok"}, "egress": {"status": "ok"}} if infrabin can resolve google.com using Google's DNS and can connect to https://www.google.com. If a test fails, infrabin returns "status": "error" and the reason.
  • POST /connectivity
    • arguments (JSON):
      • nameservers (optional): a list of DNS nameserver
      • query (optional): the DNS domain to resolve
      • egress_url (optional): the remote url to open
    • returns: same as GET /connectivity or 400 if the request is malformed.
  • GET /gzip
    • returns: the JSON {"message": "this is gzip compressed"} gzip compressed.
  • POST /proxy
    • arguments (JSON):
      • url (required): the proxy url
      • method (optional): the HTTP method to use with the proxy
      • payload (optional): the JSON data to pass to the proxy
    • returns: 400 if the request if malformed or a JSON with the a response for every request. If successful, the response contains status: ok, the status_code and the headers. If unsuccessful, the response contains status: error and the reason. If the environment variable http_proxy is set, infrabin will make the request through the proxy.
  • GET /delay/<sec>
    • returns: 200 after min(<sec>, <MAX_DELAY>) seconds.
  • GET /status/<status_code>
    • returns: the requested status_code.
  • GET /retry
    • returns: 503 for <MAX_RETRIES> times, then one 200.
  • GET /retry/max_retries
    • returns: the current value for the maximum number of retries.
  • GET, POST /bytes/<n>
    • returns: 200 on success and min(n, <MAX_SIZE>) binary payload.
  • GET, HEAD, POST, PUT, DELETE, CONNECT, OPTIONS, TRACE, PATCH /mirror
    • returns: a response with the same request headers and data sent to infrabin.
  • GET /fibonacci/<n>
    • returns: a JSON with the nth Fibonacci number.
  • POST /log
    • arguments (JSON):
    • returns: 200 on success or 400 if the request is malformed.

Metrics

infrabin exports Prometheus metrics at the /metrics endpoint.

Examples

  • POST /status
curl -d '{"nameservers":["208.67.222.222"],"query":"facebook.com","egress_url":"https://www.facebook.com"}' -H "Content-Type: application/json" -X POST localhost:8080/status
{
  "dns": {
    "status": "ok"
  },
  "egress": {
    "status": "ok"
  }
}
  • POST /proxy
curl -d '[{"url":"https://www.google.com"},{"url":"http://httpbin.org/post","method":"POST","payload":{"key":"42"}}]' -H "Content-Type: application/json" -X POST localhost:8080/proxy
{
  "http://httpbin.org/post": {
    "headers": {
      "Access-Control-Allow-Credentials": "true",
      "Access-Control-Allow-Origin": "*",
      "Connection": "keep-alive",
      "Content-Length": "435",
      "Content-Type": "application/json",
      "Date": "Sat, 19 Aug 2017 23:39:35 GMT",
      "Server": "meinheld/0.6.1",
      "Via": "1.1 vegur",
      "X-Powered-By": "Flask",
      "X-Processed-Time": "0.00157999992371"
    },
    "status": "ok",
    "status_code": 200
  },
  "https://www.google.com": {
    "headers": {
      "Alt-Svc": "quic=\":443\"; ma=2592000; v=\"39,38,37,35\"",
      "Cache-Control": "private, max-age=0",
      "Content-Encoding": "gzip",
      "Content-Type": "text/html; charset=ISO-8859-1",
      "Date": "Sat, 19 Aug 2017 23:39:35 GMT",
      "Expires": "-1",
      "P3P": "CP=\"This is not a P3P policy! See https://www.google.com/support/accounts/answer/151657?hl=en for more info.\"",
      "Server": "gws",
      "Set-Cookie": "NID=110=gR5VUAdefT9VbTSdOHEaiP-_ryClfvAV3ovON-uOh7d59L8YsQjkQsbDwSNMwEl0JOj-7aXIQnbceL5WGZGnmbz9GFWFHsHPqRsCPaquyHIsboWMNkzhVr4Te2E6-D94; expires=Sun, 18-Feb-2018 23:39:35 GMT; path=/; domain=.google.co.uk; HttpOnly",
      "Transfer-Encoding": "chunked",
      "X-Frame-Options": "SAMEORIGIN",
      "X-XSS-Protection": "1; mode=block"
    },
    "status": "ok",
    "status_code": 200
  }
}
  • GET /fibonacci/10
curl localhost:8080/fibonacci/10
{
    "response": 55
}

Development and Testing on OSX

With pipenv

Clone the repository and create a local Python 3 virtual environment

brew install pipenv
git clone git@github.com:maruina/infrabin.git
cd infrabin
pipenv --python 3.7
pipenv shell
make install-dev

Run infrabin locally

pipenv shell
make run-dev

Run the tests

pipenv shell
make test

Inspired by