From 8cb3fded87e99b1163565a01b3beffac11b01609 Mon Sep 17 00:00:00 2001
From: Nic Jackson <jackson.nic@gmail.com>
Date: Wed, 2 Oct 2024 11:27:05 +0100
Subject: [PATCH] Update tests and images

---
 .github/workflows/kubernetes.yml              |   9 +
 .github/workflows/nomad.yml                   |   9 +
 dind/Dockerfile                               |  19 +-
 kubernetes/tests/files/vault-values.yaml      |  11 +
 kubernetes/tests/main.hcl                     |  54 +++++
 .../tests/test/single_k3s_cluster.feature     |  31 +++
 main.hcl                                      |  72 +++++++
 nomad/Dockerfile                              |  11 +-
 nomad/files/nomad.conf                        |  10 -
 nomad/files/nomad.sh                          |  10 +-
 nomad/tests/files/example.nomad               |  71 +++++++
 nomad/tests/main.hcl                          |  41 ++++
 nomad/tests/test/single_nomad_cluster.feature |  31 +++
 pind/Dockerfile                               |  41 ++++
 pind/files/docker.conf                        |   8 +
 pind/files/dockerd.sh                         | 191 ++++++++++++++++++
 pind/files/supervisord.conf                   |  23 +++
 17 files changed, 614 insertions(+), 28 deletions(-)
 create mode 100644 kubernetes/tests/files/vault-values.yaml
 create mode 100644 kubernetes/tests/main.hcl
 create mode 100644 kubernetes/tests/test/single_k3s_cluster.feature
 create mode 100644 main.hcl
 delete mode 100644 nomad/files/nomad.conf
 create mode 100644 nomad/tests/files/example.nomad
 create mode 100644 nomad/tests/main.hcl
 create mode 100644 nomad/tests/test/single_nomad_cluster.feature
 create mode 100644 pind/Dockerfile
 create mode 100644 pind/files/docker.conf
 create mode 100644 pind/files/dockerd.sh
 create mode 100644 pind/files/supervisord.conf

diff --git a/.github/workflows/kubernetes.yml b/.github/workflows/kubernetes.yml
index 4b89046..a0cbcf9 100644
--- a/.github/workflows/kubernetes.yml
+++ b/.github/workflows/kubernetes.yml
@@ -70,3 +70,12 @@ jobs:
             KUBERNETES_VERSION=${{steps.collect.outputs.version}}
           push: true
           tags: ghcr.io/jumppad-labs/kubernetes:${{steps.collect.outputs.version}}
+
+      - name: Test built image
+        if: steps.collect.outputs.version != steps.collect.outputs.current
+        run: |-
+          # Install Jumppad
+          curl https://jumppad.dev/install | bash
+
+          # Test the image
+          jumppad test --tags @Single --var version=${{steps.collect.outputs.version}} ./kubernetes/tests 
\ No newline at end of file
diff --git a/.github/workflows/nomad.yml b/.github/workflows/nomad.yml
index 209a140..7b58ece 100644
--- a/.github/workflows/nomad.yml
+++ b/.github/workflows/nomad.yml
@@ -75,3 +75,12 @@ jobs:
             NOMAD_VERSION=${{steps.version.outputs.value}}
           push: true
           tags: ghcr.io/jumppad-labs/nomad:${{steps.collect.outputs.version}}
+
+      - name: Test built image
+        if: steps.collect.outputs.version != steps.collect.outputs.current
+        run: |-
+          # Install Jumppad
+          curl https://jumppad.dev/install | bash
+
+          # Test the image
+          jumppad test --tags @Single --var version=${{steps.collect.outputs.version}} ./nomad/tests 
\ No newline at end of file
diff --git a/dind/Dockerfile b/dind/Dockerfile
index a2e7f5b..cc9b0ff 100644
--- a/dind/Dockerfile
+++ b/dind/Dockerfile
@@ -7,20 +7,13 @@ ENV container=docker LANG=C.UTF-8
 
 RUN apt-get update && \
   apt-get install -y -o APT::Install-Suggests=0 -o APT::Install-Recommends=0 \
-  software-properties-common supervisor rsyslog iproute2 python3 python3-apt sudo bash ca-certificates \
-  curl net-tools jq unzip vim dnsutils iputils-ping socat wget
-
-# Setup bash
-RUN sed -i 's/\/bin\/ash/\/bin\/bash/g' /etc/passwd
-
-# Setup supervisor
-COPY files/supervisord.conf /etc/supervisor/supervisord.conf
+  ca-certificates curl gnupg lsb-release
 
 # Setup docker
-RUN curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg && \
+RUN curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg && \
   echo \
   "deb [arch=${TARGETARCH} signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
-  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null && \
+  $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null && \
   apt-get update && \
   apt-get install -y -o APT::Install-Suggests=0 -o APT::Install-Recommends=0 docker-ce docker-ce-cli containerd.io && \
   apt-get clean && rm -rf /var/lib/apt/lists/*
@@ -29,13 +22,11 @@ RUN curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor
 ENV DIND_COMMIT d58df1fc6c866447ce2cd129af10e5b507705624
 
 RUN set -eux; \
-  wget -O /usr/local/bin/dind "https://raw.githubusercontent.com/docker/docker/${DIND_COMMIT}/hack/dind"; \
+  curl -o /usr/local/bin/dind "https://raw.githubusercontent.com/docker/docker/${DIND_COMMIT}/hack/dind"; \
   chmod +x /usr/local/bin/dind
 
 COPY --chmod=0755 files/dockerd.sh /usr/local/bin/dockerd.sh
-COPY files/docker.conf /etc/supervisor/conf.d/docker.conf
 
 VOLUME /var/lib/docker
 
-ENTRYPOINT ["/usr/bin/supervisord"]
-CMD ["-c", "/etc/supervisor/supervisord.conf"]
\ No newline at end of file
+ENTRYPOINT ["/usr/local/bin/dockerd.sh"]
\ No newline at end of file
diff --git a/kubernetes/tests/files/vault-values.yaml b/kubernetes/tests/files/vault-values.yaml
new file mode 100644
index 0000000..2869d2b
--- /dev/null
+++ b/kubernetes/tests/files/vault-values.yaml
@@ -0,0 +1,11 @@
+server:
+  dataStorage:
+    size: "128Mb"
+  dev:
+    enabled: true
+
+  standalone:
+    enabled: true
+
+  authDelegator:
+    enabled: true
diff --git a/kubernetes/tests/main.hcl b/kubernetes/tests/main.hcl
new file mode 100644
index 0000000..e5df0be
--- /dev/null
+++ b/kubernetes/tests/main.hcl
@@ -0,0 +1,54 @@
+variable "version" {
+  default = "v1.29.1"
+}
+
+resource "network" "cloud" {
+  subnet = "10.5.0.0/16"
+}
+
+resource "k8s_cluster" "k3s" {
+  image {
+    name = "ghcr.io/jumppad-labs/kubernetes:${variable.version}"
+  }
+
+  network {
+    id = resource.network.cloud.meta.id
+  }
+}
+
+resource "helm" "vault" {
+  cluster = resource.k8s_cluster.k3s
+
+  repository {
+    name = "hashicorp"
+    url  = "https://helm.releases.hashicorp.com"
+  }
+
+  chart   = "hashicorp/vault"
+  version = "v0.18.0"
+
+  values = "./files/vault-values.yaml"
+
+  health_check {
+    timeout = "240s"
+    pods    = ["app.kubernetes.io/name=vault"]
+  }
+}
+
+resource "ingress" "vault_http" {
+  port = 18200
+
+  target {
+    resource = resource.k8s_cluster.k3s
+    port     = 8200
+
+    config = {
+      service   = "vault"
+      namespace = "default"
+    }
+  }
+}
+
+output "KUBECONFIG" {
+  value = resource.k8s_cluster.k3s.kube_config.path
+}
\ No newline at end of file
diff --git a/kubernetes/tests/test/single_k3s_cluster.feature b/kubernetes/tests/test/single_k3s_cluster.feature
new file mode 100644
index 0000000..b29b68b
--- /dev/null
+++ b/kubernetes/tests/test/single_k3s_cluster.feature
@@ -0,0 +1,31 @@
+Feature: Kubernetes Cluster
+  In order to test Kubernetes clusters
+  I should apply a blueprint
+  And test the output
+  
+  @Single 
+  Scenario Outline: K3s Cluster
+    Given I have a running blueprint
+    Then the following resources should be running
+      | name                                    |
+      | resource.network.cloud                  |
+      | resource.k8s_cluster.k3s                |
+    And a HTTP call to "http://localhost:18200" should result in status 200
+
+  @All
+  Scenario Outline: K3s Cluster
+    Given the jumppad variable "version" has a value "<version>"
+    And I have a running blueprint
+    Then the following resources should be running
+      | name                                    |
+      | resource.network.cloud                  |
+      | resource.k8s_cluster.k3s                |
+    And a HTTP call to "http://localhost:18200" should result in status 200
+  
+  Examples: 
+    | version           |
+    | v1.27.8           |
+    | v1.29.0           |
+    | v1.29.1           |
+    | v1.31.0           |
+    | v1.31.1           |
diff --git a/main.hcl b/main.hcl
new file mode 100644
index 0000000..50664b7
--- /dev/null
+++ b/main.hcl
@@ -0,0 +1,72 @@
+resource "network" "main" {
+  subnet = "10.5.0.0/16"
+}
+
+resource "container" "postgres" {
+  network {
+    id = resource.network.main.meta.id
+  }
+
+  image {
+    name = "postgres:13"
+  }
+
+  environment = {
+    POSTGRES_PASSWORD = "temporal"
+    POSTGRES_USER     = "temporal"
+  }
+
+  health_check {
+    timeout = "30s"
+
+    exec {
+      script = "pg_isready"
+    }
+  }
+
+  port {
+    local = 5432
+    host  = 5432
+  }
+}
+
+resource "template" "temporal_config" {
+  source      = <<-EOF
+  limit.maxIDLength:
+  - value: 255
+    constraints: {}
+  system.forceSearchAttributesCacheRefreshOnRead:
+    - value: true # Dev setup only. Please don't turn this on in production.
+      constraints: {}
+  EOF
+  destination = "${data("temporal")}/config.yaml"
+}
+
+resource "container" "temporal" {
+  network {
+    id = resource.network.main.meta.id
+  }
+
+  image {
+    name = "temporalio/auto-setup:1.24.2"
+  }
+
+  environment = {
+    DB             = "postgres12"
+    ID             = resource.container.postgres.meta.id
+    DB_PORT_3      = "${resource.container.postgres.port.0.local}"
+    POSTGRES_SEEDS = "postgres"
+    POSTGRES_USER  = "temporal"
+    POSTGRES_PWD   = "temporal"
+  }
+
+  volume {
+    source      = data("temporal")
+    destination = "/etc/temporal/config/dynamicconfig"
+  }
+
+  port {
+    local = 7233
+    host  = 7233
+  }
+}
\ No newline at end of file
diff --git a/nomad/Dockerfile b/nomad/Dockerfile
index bb8b5b2..bce2c40 100644
--- a/nomad/Dockerfile
+++ b/nomad/Dockerfile
@@ -1,9 +1,14 @@
-FROM ghcr.io/jumppad-labs/dind:v1.0.0
+FROM ghcr.io/jumppad-labs/dind:v1.1.2
 
 ARG NOMAD_VERSION
 ARG TARGETARCH
 
-ENV CNI_PLUGINS=1.3.0
+ENV CNI_PLUGINS=1.5.1
+
+RUN apt-get update && \
+  apt-get install -y -o APT::Install-Suggests=0 -o APT::Install-Recommends=0 \
+  unzip iproute2 \
+  && apt-get clean && rm -rf /var/lib/apt/lists/*
 
 RUN curl -L https://releases.hashicorp.com/nomad/${NOMAD_VERSION}/nomad_${NOMAD_VERSION}_linux_${TARGETARCH}.zip -o /tmp/nomad.zip && \
   cd /tmp && \
@@ -78,4 +83,4 @@ RUN mkdir -p /var/lib/nomad
 COPY files/config.hcl /etc/nomad.d/config.hcl
 COPY --chmod=0755 files/nomad.sh /usr/local/bin/nomad.sh
 
-COPY files/nomad.conf /etc/supervisor/conf.d/nomad.conf
\ No newline at end of file
+ENTRYPOINT ["/usr/local/bin/nomad.sh"]
\ No newline at end of file
diff --git a/nomad/files/nomad.conf b/nomad/files/nomad.conf
deleted file mode 100644
index 890eb29..0000000
--- a/nomad/files/nomad.conf
+++ /dev/null
@@ -1,10 +0,0 @@
-[program:nomad]
-command=/usr/local/bin/nomad.sh
-autorestart=true
-priority=300
-stopsignal=SIGTERM
-stdout_logfile=/dev/stdout
-stderr_logfile=/dev/stderr
-stdout_logfile_maxbytes=0
-stderr_logfile_maxbytes=0
-environment=HTTP_PROXY="",HTTPS_PROXY="",NO_PROXY=""
\ No newline at end of file
diff --git a/nomad/files/nomad.sh b/nomad/files/nomad.sh
index 7a86ed7..2a6c8ff 100644
--- a/nomad/files/nomad.sh
+++ b/nomad/files/nomad.sh
@@ -10,4 +10,12 @@ else
   update-ca-certificates
 fi
 
-exec /usr/bin/nomad agent -config /etc/nomad.d -log-level=DEBUG
\ No newline at end of file
+# Start the docker daemon
+/usr/local/bin/dockerd.sh &
+
+# Start the nomad agent
+/usr/bin/nomad agent -config /etc/nomad.d -log-level=DEBUG &
+
+wait -n
+
+exit $?
\ No newline at end of file
diff --git a/nomad/tests/files/example.nomad b/nomad/tests/files/example.nomad
new file mode 100644
index 0000000..b718f98
--- /dev/null
+++ b/nomad/tests/files/example.nomad
@@ -0,0 +1,71 @@
+job "example_1" {
+  datacenters = ["dc1"]
+  type = "service"
+
+  update {
+    max_parallel = 1
+    min_healthy_time = "10s"
+    healthy_deadline = "3m"
+    progress_deadline = "10m"
+    auto_revert = false
+    canary = 0
+  }
+  
+  migrate {
+    max_parallel = 1
+    health_check = "checks"
+    min_healthy_time = "10s"
+    healthy_deadline = "5m"
+  }
+  
+  group "fake_service" {
+    count = 1
+
+    network {
+      port  "http" { 
+        to = 19090
+        static = 19090
+      }
+    }
+
+    restart {
+      # The number of attempts to run the job within the specified interval.
+      attempts = 2
+      interval = "30m"
+      delay = "15s"
+      mode = "fail"
+    }
+    
+    ephemeral_disk {
+      size = 30
+    }
+
+    task "fake_service" {
+      # The "driver" parameter specifies the task driver that should be used to
+      # run the task.
+      driver = "docker"
+      
+      logs {
+        max_files     = 2
+        max_file_size = 10
+      }
+
+      env {
+        LISTEN_ADDR = ":19090"
+        NAME = "Example1"
+      }
+
+      config {
+        image = "nicholasjackson/fake-service:v0.18.1"
+
+        ports = ["http"]
+      }
+
+      resources {
+        cpu    = 500 # 500 MHz
+        memory = 256 # 256MB
+
+      }
+    }
+  }
+}
diff --git a/nomad/tests/main.hcl b/nomad/tests/main.hcl
new file mode 100644
index 0000000..7e8fdd3
--- /dev/null
+++ b/nomad/tests/main.hcl
@@ -0,0 +1,41 @@
+variable "version" {
+  default = "v1.8.0"
+}
+
+resource "network" "cloud" {
+  subnet = "10.5.0.0/16"
+}
+
+resource "nomad_cluster" "dev" {
+  client_nodes = 3
+
+  network {
+    id = resource.network.cloud.meta.id
+  }
+}
+
+resource "nomad_job" "example_1" {
+  cluster = resource.nomad_cluster.dev
+
+  paths = ["./files/example.nomad"]
+
+  health_check {
+    timeout = "60s"
+    jobs    = ["example_1"]
+  }
+}
+
+resource "ingress" "fake_service_1" {
+  port = 19090
+
+  target {
+    resource   = resource.nomad_cluster.dev
+    named_port = "http"
+
+    config = {
+      job   = "example_1"
+      group = "fake_service"
+      task  = "fake_service"
+    }
+  }
+}
\ No newline at end of file
diff --git a/nomad/tests/test/single_nomad_cluster.feature b/nomad/tests/test/single_nomad_cluster.feature
new file mode 100644
index 0000000..e99650d
--- /dev/null
+++ b/nomad/tests/test/single_nomad_cluster.feature
@@ -0,0 +1,31 @@
+Feature: Nomad Cluster
+  In order to test Nomad clusters
+  I should apply a blueprint
+  And test the output
+  
+  @Single
+  Scenario Outline: Nomad Cluster
+    Given I have a running blueprint
+    Then the following resources should be running
+      | name                                    |
+      | resource.network.cloud                  |
+      | resource.nomad_cluster.dev                |
+    And a HTTP call to "http://localhost:19090" should result in status 200
+
+  @All
+  Scenario Outline: Nomad Cluster
+    Given the jumppad variable "version" has a value "<version>"
+    And I have a running blueprint
+    Then the following resources should be running
+      | name                                    |
+      | resource.network.cloud                  |
+      | resource.nomad_cluster.dev                |
+    And a HTTP call to "http://localhost:19090" should result in status 200
+  
+  Examples: 
+    | version          |
+    | v1.8.0           |
+    | v1.8.1           |
+    | v1.8.2           |
+    | v1.8.3           |
+    | v1.8.4           |
diff --git a/pind/Dockerfile b/pind/Dockerfile
new file mode 100644
index 0000000..a2e7f5b
--- /dev/null
+++ b/pind/Dockerfile
@@ -0,0 +1,41 @@
+FROM ubuntu:22.04
+
+ARG TARGETARCH
+
+ENV DEBIAN_FRONTEND=noninteractive
+ENV container=docker LANG=C.UTF-8
+
+RUN apt-get update && \
+  apt-get install -y -o APT::Install-Suggests=0 -o APT::Install-Recommends=0 \
+  software-properties-common supervisor rsyslog iproute2 python3 python3-apt sudo bash ca-certificates \
+  curl net-tools jq unzip vim dnsutils iputils-ping socat wget
+
+# Setup bash
+RUN sed -i 's/\/bin\/ash/\/bin\/bash/g' /etc/passwd
+
+# Setup supervisor
+COPY files/supervisord.conf /etc/supervisor/supervisord.conf
+
+# Setup docker
+RUN curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg && \
+  echo \
+  "deb [arch=${TARGETARCH} signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
+  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null && \
+  apt-get update && \
+  apt-get install -y -o APT::Install-Suggests=0 -o APT::Install-Recommends=0 docker-ce docker-ce-cli containerd.io && \
+  apt-get clean && rm -rf /var/lib/apt/lists/*
+
+# https://github.com/docker/docker/tree/master/hack/dind
+ENV DIND_COMMIT d58df1fc6c866447ce2cd129af10e5b507705624
+
+RUN set -eux; \
+  wget -O /usr/local/bin/dind "https://raw.githubusercontent.com/docker/docker/${DIND_COMMIT}/hack/dind"; \
+  chmod +x /usr/local/bin/dind
+
+COPY --chmod=0755 files/dockerd.sh /usr/local/bin/dockerd.sh
+COPY files/docker.conf /etc/supervisor/conf.d/docker.conf
+
+VOLUME /var/lib/docker
+
+ENTRYPOINT ["/usr/bin/supervisord"]
+CMD ["-c", "/etc/supervisor/supervisord.conf"]
\ No newline at end of file
diff --git a/pind/files/docker.conf b/pind/files/docker.conf
new file mode 100644
index 0000000..5c06f9d
--- /dev/null
+++ b/pind/files/docker.conf
@@ -0,0 +1,8 @@
+[program:docker]
+command=/usr/local/bin/dockerd.sh
+autorestart=true
+priority=100
+#stdout_logfile=/dev/stdout
+#stderr_logfile=/dev/stderr
+#stdout_logfile_maxbytes=0
+#stderr_logfile_maxbytes=0
\ No newline at end of file
diff --git a/pind/files/dockerd.sh b/pind/files/dockerd.sh
new file mode 100644
index 0000000..a29fd70
--- /dev/null
+++ b/pind/files/dockerd.sh
@@ -0,0 +1,191 @@
+#!/bin/sh
+set -eu
+
+_tls_ensure_private() {
+	local f="$1"; shift
+	[ -s "$f" ] || openssl genrsa -out "$f" 4096
+}
+_tls_san() {
+	{
+		ip -oneline address | awk '{ gsub(/\/.+$/, "", $4); print "IP:" $4 }'
+		{
+			cat /etc/hostname
+			echo 'docker'
+			echo 'localhost'
+			hostname -f
+			hostname -s
+		} | sed 's/^/DNS:/'
+		[ -z "${DOCKER_TLS_SAN:-}" ] || echo "$DOCKER_TLS_SAN"
+	} | sort -u | xargs printf '%s,' | sed "s/,\$//"
+}
+_tls_generate_certs() {
+	local dir="$1"; shift
+
+	# if ca/key.pem || !ca/cert.pem, generate CA public if necessary
+	# if ca/key.pem, generate server public
+	# if ca/key.pem, generate client public
+	# (regenerating public certs every startup to account for SAN/IP changes and/or expiration)
+
+	# https://github.com/FiloSottile/mkcert/issues/174
+	local certValidDays='825'
+
+	if [ -s "$dir/ca/key.pem" ] || [ ! -s "$dir/ca/cert.pem" ]; then
+		# if we either have a CA private key or do *not* have a CA public key, then we should create/manage the CA
+		mkdir -p "$dir/ca"
+		_tls_ensure_private "$dir/ca/key.pem"
+		openssl req -new -key "$dir/ca/key.pem" \
+			-out "$dir/ca/cert.pem" \
+			-subj '/CN=docker:dind CA' -x509 -days "$certValidDays"
+	fi
+
+	if [ -s "$dir/ca/key.pem" ]; then
+		# if we have a CA private key, we should create/manage a server key
+		mkdir -p "$dir/server"
+		_tls_ensure_private "$dir/server/key.pem"
+		openssl req -new -key "$dir/server/key.pem" \
+			-out "$dir/server/csr.pem" \
+			-subj '/CN=docker:dind server'
+		cat > "$dir/server/openssl.cnf" <<-EOF
+			[ x509_exts ]
+			subjectAltName = $(_tls_san)
+		EOF
+		openssl x509 -req \
+				-in "$dir/server/csr.pem" \
+				-CA "$dir/ca/cert.pem" \
+				-CAkey "$dir/ca/key.pem" \
+				-CAcreateserial \
+				-out "$dir/server/cert.pem" \
+				-days "$certValidDays" \
+				-extfile "$dir/server/openssl.cnf" \
+				-extensions x509_exts
+		cp "$dir/ca/cert.pem" "$dir/server/ca.pem"
+		openssl verify -CAfile "$dir/server/ca.pem" "$dir/server/cert.pem"
+	fi
+
+	if [ -s "$dir/ca/key.pem" ]; then
+		# if we have a CA private key, we should create/manage a client key
+		mkdir -p "$dir/client"
+		_tls_ensure_private "$dir/client/key.pem"
+		chmod 0644 "$dir/client/key.pem" # openssl defaults to 0600 for the private key, but this one needs to be shared with arbitrary client contexts
+		openssl req -new \
+				-key "$dir/client/key.pem" \
+				-out "$dir/client/csr.pem" \
+				-subj '/CN=docker:dind client'
+		cat > "$dir/client/openssl.cnf" <<-'EOF'
+			[ x509_exts ]
+			extendedKeyUsage = clientAuth
+		EOF
+		openssl x509 -req \
+				-in "$dir/client/csr.pem" \
+				-CA "$dir/ca/cert.pem" \
+				-CAkey "$dir/ca/key.pem" \
+				-CAcreateserial \
+				-out "$dir/client/cert.pem" \
+				-days "$certValidDays" \
+				-extfile "$dir/client/openssl.cnf" \
+				-extensions x509_exts
+		cp "$dir/ca/cert.pem" "$dir/client/ca.pem"
+		openssl verify -CAfile "$dir/client/ca.pem" "$dir/client/cert.pem"
+	fi
+}
+
+# no arguments passed
+# or first arg is `-f` or `--some-option`
+if [ "$#" -eq 0 ] || [ "${1#-}" != "$1" ]; then
+	# set "dockerSocket" to the default "--host" *unix socket* value (for both standard or rootless)
+	uid="$(id -u)"
+	if [ "$uid" = '0' ]; then
+		dockerSocket='unix:///var/run/docker.sock'
+	else
+		# if we're not root, we must be trying to run rootless
+		: "${XDG_RUNTIME_DIR:=/run/user/$uid}"
+		dockerSocket="unix://$XDG_RUNTIME_DIR/docker.sock"
+	fi
+	case "${DOCKER_HOST:-}" in
+		unix://*)
+			dockerSocket="$DOCKER_HOST"
+			;;
+	esac
+
+	# add our default arguments
+	if [ -n "${DOCKER_TLS_CERTDIR:-}" ] \
+		&& _tls_generate_certs "$DOCKER_TLS_CERTDIR" \
+		&& [ -s "$DOCKER_TLS_CERTDIR/server/ca.pem" ] \
+		&& [ -s "$DOCKER_TLS_CERTDIR/server/cert.pem" ] \
+		&& [ -s "$DOCKER_TLS_CERTDIR/server/key.pem" ] \
+	; then
+		# generate certs and use TLS if requested/possible (default in 19.03+)
+		set -- dockerd \
+			--host="$dockerSocket" \
+			--host=tcp://0.0.0.0:2376 \
+			--tlsverify \
+			--tlscacert "$DOCKER_TLS_CERTDIR/server/ca.pem" \
+			--tlscert "$DOCKER_TLS_CERTDIR/server/cert.pem" \
+			--tlskey "$DOCKER_TLS_CERTDIR/server/key.pem" \
+			"$@"
+		DOCKERD_ROOTLESS_ROOTLESSKIT_FLAGS="${DOCKERD_ROOTLESS_ROOTLESSKIT_FLAGS:-} -p 0.0.0.0:2376:2376/tcp"
+	else
+		# TLS disabled (-e DOCKER_TLS_CERTDIR='') or missing certs
+		set -- dockerd \
+			--host="$dockerSocket" \
+			--host=tcp://0.0.0.0:2375 \
+			"$@"
+		DOCKERD_ROOTLESS_ROOTLESSKIT_FLAGS="${DOCKERD_ROOTLESS_ROOTLESSKIT_FLAGS:-} -p 0.0.0.0:2375:2375/tcp"
+	fi
+fi
+
+if [ "$1" = 'dockerd' ]; then
+	# explicitly remove Docker's default PID file to ensure that it can start properly if it was stopped uncleanly (and thus didn't clean up the PID file)
+	find /run /var/run -iname 'docker*.pid' -delete || :
+
+	if dockerd --version | grep -qF ' 20.10.'; then
+		# XXX inject "docker-init" (tini) as pid1 to workaround https://github.com/docker-library/docker/issues/318 (zombie container-shim processes)
+		set -- docker-init -- "$@"
+	fi
+
+	uid="$(id -u)"
+	if [ "$uid" != '0' ]; then
+		# if we're not root, we must be trying to run rootless
+		if ! command -v rootlesskit > /dev/null; then
+			echo >&2 "error: attempting to run rootless dockerd but missing 'rootlesskit' (perhaps the 'docker:dind-rootless' image variant is intended?)"
+			exit 1
+		fi
+		user="$(id -un 2>/dev/null || :)"
+		if ! grep -qE "^($uid${user:+|$user}):" /etc/subuid || ! grep -qE "^($uid${user:+|$user}):" /etc/subgid; then
+			echo >&2 "error: attempting to run rootless dockerd but missing necessary entries in /etc/subuid and/or /etc/subgid for $uid"
+			exit 1
+		fi
+		: "${XDG_RUNTIME_DIR:=/run/user/$uid}"
+		export XDG_RUNTIME_DIR
+		if ! mkdir -p "$XDG_RUNTIME_DIR" || [ ! -w "$XDG_RUNTIME_DIR" ] || ! mkdir -p "$HOME/.local/share/docker" || [ ! -w "$HOME/.local/share/docker" ]; then
+			echo >&2 "error: attempting to run rootless dockerd but need writable HOME ($HOME) and XDG_RUNTIME_DIR ($XDG_RUNTIME_DIR) for user $uid"
+			exit 1
+		fi
+		if [ -f /proc/sys/kernel/unprivileged_userns_clone ] && unprivClone="$(cat /proc/sys/kernel/unprivileged_userns_clone)" && [ "$unprivClone" != '1' ]; then
+			echo >&2 "error: attempting to run rootless dockerd but need 'kernel.unprivileged_userns_clone' (/proc/sys/kernel/unprivileged_userns_clone) set to 1"
+			exit 1
+		fi
+		if [ -f /proc/sys/user/max_user_namespaces ] && maxUserns="$(cat /proc/sys/user/max_user_namespaces)" && [ "$maxUserns" = '0' ]; then
+			echo >&2 "error: attempting to run rootless dockerd but need 'user.max_user_namespaces' (/proc/sys/user/max_user_namespaces) set to a sufficiently large value"
+			exit 1
+		fi
+		# TODO overlay support detection?
+		exec rootlesskit \
+			--net="${DOCKERD_ROOTLESS_ROOTLESSKIT_NET:-vpnkit}" \
+			--mtu="${DOCKERD_ROOTLESS_ROOTLESSKIT_MTU:-1500}" \
+			--disable-host-loopback \
+			--port-driver=builtin \
+			--copy-up=/etc \
+			--copy-up=/run \
+			${DOCKERD_ROOTLESS_ROOTLESSKIT_FLAGS:-} \
+			"$@"
+	elif [ -x '/usr/local/bin/dind' ]; then
+		# if we have the (mostly defunct now) Docker-in-Docker wrapper script, use it
+		set -- '/usr/local/bin/dind' "$@"
+	fi
+else
+	# if it isn't `dockerd` we're trying to run, pass it through `docker-entrypoint.sh` so it gets `DOCKER_HOST` set appropriately too
+	set -- docker-entrypoint.sh "$@"
+fi
+
+exec "$@"
\ No newline at end of file
diff --git a/pind/files/supervisord.conf b/pind/files/supervisord.conf
new file mode 100644
index 0000000..2b44364
--- /dev/null
+++ b/pind/files/supervisord.conf
@@ -0,0 +1,23 @@
+[include]
+files = /etc/supervisor/conf.d/*.conf
+
+[unix_http_server]
+file=/var/run/supervisor.sock
+chmod=0700
+username=username
+password=password
+
+[supervisord]
+user=root
+nodaemon=true
+logfile=/var/log/supervisor/supervisord.log
+pidfile=/var/run/supervisord.pid
+childlogdir=/var/log/supervisor
+
+[rpcinterface:supervisor]
+supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
+
+[supervisorctl]
+serverurl=unix:///var/run/supervisor.sock
+username=username
+password=password
\ No newline at end of file
-- 
GitLab