Merge "devtools/ci/remote-cache: init"
diff --git a/.gitignore b/.gitignore
index 28383b8..3266982 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,4 +2,5 @@
 /bazel-*
 .kubectl
 *~
-\#*
\ No newline at end of file
+\#*
+error.log
diff --git a/README.md b/README.md
index 8c04fe4..8ba66e5 100644
--- a/README.md
+++ b/README.md
@@ -2,14 +2,6 @@
 
 `hscloud` is the main monorepo of the Warsaw Hackerspace infrastructure code.
 
-Any time you see a `//path/like/this`, it refers to the root of hscloud, ie. the path `path/like/this` in this repository. Perforce and/or Bazel users should feel right at home.
-
-
-Viewing this documentation
---------------------------
-
-For a pleaseant web viewing experience, [see this documentation in hackdoc](https://hackdoc.hackerspace.pl/). This will allow you to read this markdown file (and others) in a pretty, linkable view.
-
 Getting started
 ---------------
 
diff --git a/WORKSPACE b/WORKSPACE
index fb81739..5c987ff 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -104,9 +104,9 @@
 
 http_archive(
     name = "io_bazel_rules_docker",
-    sha256 = "1698624e878b0607052ae6131aa216d45ebb63871ec497f26c67455b34119c80",
-    strip_prefix = "rules_docker-0.15.0",
-    urls = ["https://github.com/bazelbuild/rules_docker/releases/download/v0.15.0/rules_docker-v0.15.0.tar.gz"],
+    sha256 = "59d5b42ac315e7eadffa944e86e90c2990110a1c8075f1cd145f487e999d22b3",
+    strip_prefix = "rules_docker-0.17.0",
+    urls = ["https://github.com/bazelbuild/rules_docker/releases/download/v0.17.0/rules_docker-v0.17.0.tar.gz"],
 )
 
 load("@io_bazel_rules_docker//toolchains/docker:toolchain.bzl", docker_toolchain_configure = "toolchain_configure")
diff --git a/app/matrix/lib/matrix.libsonnet b/app/matrix/lib/matrix.libsonnet
index 358b0c9..168844a 100644
--- a/app/matrix/lib/matrix.libsonnet
+++ b/app/matrix/lib/matrix.libsonnet
@@ -47,8 +47,8 @@
             riot: "vectorim/riot-web:v1.7.16",
             casProxy: "registry.k0.hswaw.net/q3k/oauth2-cas-proxy:0.1.4",
             appserviceIRC: "matrixdotorg/matrix-appservice-irc:release-0.17.1",
-            # That's v0.8.2 - we just don't trust that host to not re-tag images.
-            appserviceTelegram: "dock.mau.dev/tulir/mautrix-telegram@sha256:9e68eaa80c9e4a75d9a09ec92dc4898b12d48390e01efa4de40ce882a6f7e330",
+            # :latest tag on 2021/04/10.
+            appserviceTelegram: "dock.mau.dev/tulir/mautrix-telegram@sha256:c6e25cb57e1b67027069e8dc2627338df35d156315c004a6f2b34b6aeaa79f77",
             wellKnown: "registry.k0.hswaw.net/q3k/wellknown:1611960794-adbf560851a46ad0e58b42f0daad7ef19535687c",
         },
 
diff --git a/bgpwtf/invoice/proto/BUILD.bazel b/bgpwtf/invoice/proto/BUILD.bazel
index 2eeae64..a1a7033 100644
--- a/bgpwtf/invoice/proto/BUILD.bazel
+++ b/bgpwtf/invoice/proto/BUILD.bazel
@@ -4,7 +4,10 @@
 
 proto_library(
     name = "proto_proto",
-    srcs = ["invoice.proto"],
+    srcs = [
+        "invoice.proto",
+        "recurrent.proto",
+    ],
     visibility = ["//visibility:public"],
 )
 
diff --git a/bgpwtf/invoice/proto/recurrent.proto b/bgpwtf/invoice/proto/recurrent.proto
new file mode 100644
index 0000000..1f4ac66
--- /dev/null
+++ b/bgpwtf/invoice/proto/recurrent.proto
@@ -0,0 +1,50 @@
+syntax = "proto3";
+package invoice;
+option go_package = "code.hackerspace.pl/hscloud/bgpwtf/invoice/proto";
+
+import "bgpwtf/invoice/proto/invoice.proto";
+
+// Subscription is the subscription to a service for which we want to generate
+// monthly (at least for now) invoices.
+message Subscription {
+    // Template is the data that will be used to emit the invoice. It will be
+    // used verbatim in a CreateInvoice request, apart from the following
+    // changes:
+    // - if 'date' is not set, the current date will be substituted instead
+    // - for every item in the invoice, any %Y and %M value in its title will
+    //   be replaced by the year and month of the billing cycle. The billing
+    //   cycle is defined in relation to the date in the Cycle enum below..
+    InvoiceData template = 1;
+
+    // Cycle defines the billing cycle policy for this subscription.
+    enum Cycle {
+        CYCLE_INVALID = 0;
+        // The subscription is billed for the month that it is invoiced for.
+        // Eg., if the invoice has a date of April 1st, April 15th or April
+        // 30th, the %M in title will be replaced with 04.
+        //
+        // This is used for subscriptions that are invoiced a month in advance,
+        // with invoices being sent out in the beginning of the month.
+        //
+        // In the future, the meaning of this enum value might change to 'bill
+        // at beginning of month/cycle', but currently we only bill once per
+        // month.
+        CYCLE_CURRENT = 1;
+        // The subscription is billed for the month from when it was invoiced.
+        // Eg., if the invoice has a date of April 1st, April 15th or April
+        // 30th, the %M in the title will be replaced with 03.
+        // This is used for subscriptions that are invoiced right after a month
+        // ends.
+        // In the future, the meaning of this enum value might change to 'bill
+        // at end of month/cycle', but currently we only bill once per month.
+        CYCLE_PREV = 2;
+    }
+    Cycle cycle = 2;
+}
+
+// Configuration is a prototext defining subscriptions. Currently it's read
+// from a file by //bgpwtf/invoice/recurrent. In The future this might be
+// broken up into a database schema.
+message Configuration {
+    repeated Subscription subscription = 1;
+}
diff --git a/bgpwtf/invoice/recurrent/BUILD.bazel b/bgpwtf/invoice/recurrent/BUILD.bazel
new file mode 100644
index 0000000..b9fc578
--- /dev/null
+++ b/bgpwtf/invoice/recurrent/BUILD.bazel
@@ -0,0 +1,21 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
+
+go_library(
+    name = "go_default_library",
+    srcs = ["main.go"],
+    importpath = "code.hackerspace.pl/hscloud/bgpwtf/invoice/recurrent",
+    visibility = ["//visibility:private"],
+    deps = [
+        "//bgpwtf/invoice/proto:go_default_library",
+        "//go/pki:go_default_library",
+        "@com_github_golang_glog//:go_default_library",
+        "@com_github_golang_protobuf//proto:go_default_library",
+        "@org_golang_google_grpc//:go_default_library",
+    ],
+)
+
+go_binary(
+    name = "recurrent",
+    embed = [":go_default_library"],
+    visibility = ["//visibility:public"],
+)
diff --git a/bgpwtf/invoice/recurrent/main.go b/bgpwtf/invoice/recurrent/main.go
new file mode 100644
index 0000000..84e5622
--- /dev/null
+++ b/bgpwtf/invoice/recurrent/main.go
@@ -0,0 +1,175 @@
+package main
+
+// recurrent is a tool to bill recurrent monthly invoices. It should be run at
+// the beginning of each month against a database of customers stored as a
+// prototext.
+//
+// This is a fairly janky tool, and should be replaced by a proper billing
+// service.
+//
+//    $ bazel run //bgpwtf/invoice/recurrent -- \
+//        -invoice_configuration=$(pwd)bgpwtf/invoice/customers.pb.text \
+//        -invoice_service 10.78.253.10:4200 -hspki_disable
+//
+// q3k has the sqlite database for the invoice service and the customer
+// prototext.
+
+import (
+	"bufio"
+	"context"
+	"flag"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"os"
+	"strings"
+	"time"
+
+	"github.com/golang/glog"
+	"github.com/golang/protobuf/proto"
+	"google.golang.org/grpc"
+
+	"code.hackerspace.pl/hscloud/go/pki"
+
+	pb "code.hackerspace.pl/hscloud/bgpwtf/invoice/proto"
+)
+
+func init() {
+	flag.Set("logtostderr", "true")
+}
+
+var (
+	flagConfiguration string
+	flagService       string
+)
+
+func main() {
+	flag.StringVar(&flagService, "invoice_service", "127.0.0.1:4200", "Address of invoice service")
+	flag.StringVar(&flagConfiguration, "invoice_configuration", "customers.pb.text", "Prototext of customer data")
+	flag.Parse()
+
+	if flagConfiguration == "" {
+		glog.Exit("-invoice_configuration must be set")
+	}
+	cfgBytes, err := ioutil.ReadFile(flagConfiguration)
+	if err != nil {
+		glog.Exitf("could not read configuration: %v", err)
+	}
+
+	var cfg pb.Configuration
+	if err := proto.UnmarshalText(string(cfgBytes), &cfg); err != nil {
+		glog.Exitf("UnmarshalText: %v", err)
+	}
+
+	conn, err := grpc.Dial(flagService, pki.WithClientHSPKI())
+	if err != nil {
+		glog.Exitf("Dial(%q): %v", flagService, err)
+		return
+	}
+	svc := pb.NewInvoicerClient(conn)
+	ctx := context.Background()
+
+	var created []string
+	now := time.Now()
+	for _, sub := range cfg.Subscription {
+		glog.Infof("Emitting for %q...", sub.Template.CustomerBilling[0])
+
+		data := sub.Template
+		if data.Date == 0 {
+			data.Date = now.UnixNano()
+		}
+
+		date := time.Unix(0, data.Date)
+		year := int(date.Year())
+		month := int(date.Month())
+		switch sub.Cycle {
+		case pb.Subscription_CYCLE_CURRENT:
+		case pb.Subscription_CYCLE_PREV:
+			month -= 1
+			if month < 1 {
+				month = 12
+				year -= 1
+			}
+		default:
+			glog.Exitf("Invalid cycle: %v", sub.Cycle)
+		}
+
+		for _, item := range data.Item {
+			item.Title = strings.ReplaceAll(item.Title, "%M", fmt.Sprintf("%02d", month))
+			item.Title = strings.ReplaceAll(item.Title, "%Y", fmt.Sprintf("%04d", year))
+		}
+		res, err := svc.CreateInvoice(ctx, &pb.CreateInvoiceRequest{
+			InvoiceData: data,
+		})
+		if err != nil {
+			glog.Exitf("CreateInvoice: %v", err)
+		}
+		glog.Infof("Created invoice %q", res.Uid)
+		created = append(created, res.Uid)
+	}
+
+	reader := bufio.NewReader(os.Stdin)
+	fmt.Print("Invoices generated. Seal? [Yn]")
+	text, err := reader.ReadString('\n')
+	if err != nil {
+		glog.Exitf("Response: %v", err)
+	}
+	switch strings.TrimSpace(strings.ToLower(text)) {
+	case "", "y":
+	default:
+		glog.Exitf("Aborting.")
+	}
+	for _, uid := range created {
+		glog.Infof("Sealing %q...", uid)
+		_, err := svc.SealInvoice(ctx, &pb.SealInvoiceRequest{
+			Uid:        uid,
+			DateSource: pb.SealInvoiceRequest_DATE_SOURCE_PROFORMA,
+			Language:   "pl",
+		})
+		if err != nil {
+			glog.Errorf("Sealing %q failed: %v", uid, err)
+			continue
+		}
+		res, err := svc.GetInvoice(ctx, &pb.GetInvoiceRequest{
+			Uid: uid,
+		})
+		if err != nil {
+			glog.Errorf("Retrieving sealed invoice %q failed: %v", uid, err)
+			continue
+		}
+		fuid := res.Invoice.FinalUid
+		glog.Infof("%q: Final UID: %s", uid, fuid)
+		stream, err := svc.RenderInvoice(ctx, &pb.RenderInvoiceRequest{
+			Uid: uid,
+		})
+		if err != nil {
+			glog.Errorf("Rendering sealed invoice failed: %v", err)
+			continue
+		}
+
+		path := fmt.Sprintf("/tmp/%s.pdf", strings.ReplaceAll(fuid, "/", ""))
+		glog.Infof("Downloading %s...", path)
+		f, err := os.Create(path)
+		if err != nil {
+			glog.Errorf("Create: %v", err)
+			continue
+		}
+
+		for {
+			block, err := stream.Recv()
+			if err == io.EOF {
+				break
+			}
+			if err != nil {
+				glog.Errorf("Recv: %v", err)
+				break
+			}
+			if _, err := f.Write(block.Data); err != nil {
+				glog.Errorf("Write: %v", err)
+				break
+			}
+		}
+		f.Close()
+	}
+
+}
diff --git a/bgpwtf/invoice/render.go b/bgpwtf/invoice/render.go
index 693aa62..c0eeca1 100644
--- a/bgpwtf/invoice/render.go
+++ b/bgpwtf/invoice/render.go
@@ -4,6 +4,7 @@
 	"bytes"
 	"fmt"
 	"html/template"
+	"strings"
 	"time"
 
 	wkhtml "github.com/sebastiaanklippert/go-wkhtmltopdf"
@@ -41,6 +42,20 @@
 		Total     string
 	}
 
+	symbols := ""
+	var parts []string
+	for _, code := range i.Data.SpCode {
+		parts = append(parts, code.String())
+	}
+	for _, code := range i.GtuCode {
+		parts = append(parts, code.String())
+	}
+	if len(parts) > 0 {
+		symbols = strings.Join(parts, ", ") + "."
+	} else {
+		symbols = "<i>brak</i>."
+	}
+
 	data := struct {
 		InvoiceNumber         string
 		InvoicerBilling       []string
@@ -60,6 +75,7 @@
 		VATTotal              string
 		Total                 string
 		DeliveryCharge        string
+		Symbols               template.HTML
 	}{
 		InvoiceNumber:         i.FinalUid,
 		Date:                  time.Unix(0, i.Date),
@@ -75,6 +91,7 @@
 
 		InvoicerBilling: make([]string, len(i.Data.InvoicerBilling)),
 		InvoiceeBilling: make([]string, len(i.Data.CustomerBilling)),
+		Symbols:         template.HTML(symbols),
 	}
 
 	for d, s := range i.Data.InvoicerBilling {
diff --git a/bgpwtf/invoice/templates/invoice_en.html b/bgpwtf/invoice/templates/invoice_en.html
index 6a92022..976dbdf 100644
--- a/bgpwtf/invoice/templates/invoice_en.html
+++ b/bgpwtf/invoice/templates/invoice_en.html
@@ -92,6 +92,9 @@
     -webkit-transform: rotate(-45deg);
     text-transform: uppercase;
 }
+div.symbols {
+    padding: 0 0 0.5rem 0.1rem;
+}
         </style>
     </head>
     <body>
@@ -153,6 +156,9 @@
             </div>
         </div>
         <div style="clear: both; height: 1em;"></div>
+        <div class="symbols">
+            <b>Oznaczenia</b>: {{ .Symbols }}
+        </div>
         <table class="items">
             <tr>
                 <th style="width: 60%;">Name of goods / service</th>
@@ -195,5 +201,8 @@
                 <td><b>{{ .Total }}</b></td>
             </tr>
         </table>
+        <div class="footer">
+            {{ .Footer }}
+        </div>
     </body>
 </html>
diff --git a/bgpwtf/invoice/templates/invoice_pl.html b/bgpwtf/invoice/templates/invoice_pl.html
index 15f5d08..b09086b 100644
--- a/bgpwtf/invoice/templates/invoice_pl.html
+++ b/bgpwtf/invoice/templates/invoice_pl.html
@@ -92,6 +92,9 @@
     -webkit-transform: rotate(-45deg);
     text-transform: uppercase;
 }
+div.symbols {
+    padding: 0 0 0.5rem 0.1rem;
+}
         </style>
     </head>
     <body>
@@ -154,6 +157,9 @@
             </div>
         </div>
         <div style="clear: both; height: 1em;"></div>
+        <div class="symbols">
+            <b>Oznaczenia</b>: {{ .Symbols }}
+        </div>
         <table class="items">
             <tr>
                 <th style="width: 60%;">Nazwa towaru lub usługi</th>
diff --git a/bgpwtf/machines/modules/router.nix b/bgpwtf/machines/modules/router.nix
index a9de59b..88ad004 100644
--- a/bgpwtf/machines/modules/router.nix
+++ b/bgpwtf/machines/modules/router.nix
@@ -48,11 +48,11 @@
   # Enable the OpenSSH daemon.
   services.openssh.enable = true;
   users.users.root.openssh.authorizedKeys.keys = [
-    "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDD4VJXAXEHEXZk2dxNwehneuJcEGkfXG/U7z4fO79vDVIENdedtXQUyLyhZJc5RTEfHhQj66FwIqzl7mzBHd9x9PuDp6QAYXrkVNMj48s6JXqZqBvF6H/weRqFMf4a2TZv+hG8D0kpvmLheCwWAVRls7Jofnp/My+yDd57GMdsbG/yFEf6WPMiOnA7hxdSJSVihCsCSw2p8PD4GhBe8CVt7xIuinhutjm9zYBjV78NT8acjDUfJh0B1ODTjs7nuW1CC4jybSe2j/OU3Yczj4AxRxBNWuFxUq+jBo9BfpbKLh+Tt7re+zBkaicM77KM/oV6943JJxgHNBBOsv9scZE7 q3k@amnesia"
     "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIG599UildOrAq+LIOQjKqtGMwjgjIxozI1jtQQRKHtCP q3k@mimeomia"
     "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDQb3YQoiYFZLKwvHYKbu1bMqzNeDCAszQhAe1+QI5SLDOotclyY/vFmOReZOsmyMFl71G2d7d+FbYNusUnNNjTxRYQ021tVc+RkMdLJaORRURmQfEFEKbai6QSFTwErXzuoIzyEPK0lbsQuGgqT9WaVnRzHJ2Q/4+qQbxAS34PuR5NqEkmn4G6LMo3OyJ5mwPkCj9lsqz4BcxRaMWFO3mNcwGDfSW+sqgc3E8N6LKrTpZq3ke7xacpQmcG5DU9VO+2QVPdltl9jWbs3gXjmF92YRNOuKPVfAOZBBsp8JOznfx8s9wDgs7RwPmDpjIAJEyoABqW5hlXfqRbTnfnMvuR informatic@InformaticPC"
     "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDGkMgEVwQM8yeuFUYL2TwlJIq9yUNBmHnwce46zeL2PK2CkMz7sxT/om7sp/K5XDiqeD05Nioe+Dr3drP6B8uI33S5NgxPIfaqQsRS+CBEgk6cqFlcdlKETU/DT+/WsdoO173n7mgGeafPInEuQuGDUID0Fl099kIxtqfAhdeZFMM6/szAZEZsElLJ8K6dp1Ni/jmnXCZhjivZH3AZUlnqrmtDG7FY1bgcOfDXAal45LItughGPtrdiigXe9DK2fW3+9DBZZduh5DMJTNlphAZ+nfSrbyHVKUg6WsgMSprur4KdU47q1QwzqqvEj75JcdP1jOWoZi4F6VJDte9Wb9lhD1jGgjxY9O6Gs4CH35bx15W7CN9hgNa0C8NbPJe/fZYIeMZmJ1m7O2xmnYwP8j+t7RNJWu7Pa3Em4mOEXvhBF07Zfq+Ye/4SluoRgADy5eII2x5fFo5EBhInxK0/X8wF6XZvysalVifoCh7T4Edejoi91oAxFgYAxbboXGlod0eEHIi2hla8SM9+IBHOChmgawKBYp2kzAJyAmHNBF+Pah9G4arVCj/axp/SJZDZbJQoI7UT/fJzEtvlb5RWrHXRq+y6IvjpUq4pzpDWW04+9UMqEEXRmhWOakHfEVM9rN8h3aJBflLUBBnh0Z/hVsKNh8bCRHaKtah8TrD9i+wMw== patryk.jakuszew@gmail.com"
     "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC33naG1ptCvUcRWX9cj9wXM1nW1lyQC4SvMJzWlr9aMD96O8hQ2JMkuIUgUJvorAY02QRplQ2BuoVoVkdkzwjMyi1bL3OdgcKo7Z1yByClGTTocqNJYY0lcUb6EJH8+6e6F9ydrQlSxNzL1uCaA7phZr+yPcmAmWbSfioXn98yXNkE0emHxzJv/nypJY56sDCMC2IXDRd8L2goDtPwgPEW7bWfAQdIFMJ75xOidZOTxJ8eqyXLw/kxY5UlyX66jdoYz1sE5XUHuoQl1AOG9UdlMo0aMhUvP4pX5l7r7EnA9OttKMFB3oWqkVK/R6ynZ52YNOU5BZ9V+Ppaj34W0xNu+p0mbHcCtXYCTrf/OU0hcZDbDaNTjs6Vtcm2wYw9iAKX7Tex+eOMwUwlrlcyPNRV5BTot7lGNYfauHCSIuWJKN4NhCLR/NtVNh4/94eKkPTwJsY6XqDcS7q49wPAs4DAH7BJgsbHPOqygVHrY0YYEfz3Pj0HTxJHQMCP/hQX4fXEGt0BjgoVJbXPAQtPyeg0JuxiUg+b4CgVVfQ6R060MlM1BZzhmh+FY5MJH6nJppS0aHYCvSg8Z68NUlCPKy0jpcyfuAIWQWwSGG1O010WShQG2ELsvNdg5/4HVdCGNl5mmoom6JOd72FOZyQlHDFfeQUQRn9HOeCq/c51rK99SQ== bartek@IHM"
     "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICTR292kx/2CNuWYIsZ6gykQ036aBGrmheIuZa6S1D2x implr@thonk"
+    "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGfIRe1nH6vwjQTjqHNnkKAdr1VYqGEeQnqInmf3A6UN ar@khas"
   ];
 }
diff --git a/cluster/certs/etcd-bc01n01.hswaw.net.cert b/cluster/certs/etcd-bc01n01.hswaw.net.cert
index 917ad22..d16a7d7 100644
--- a/cluster/certs/etcd-bc01n01.hswaw.net.cert
+++ b/cluster/certs/etcd-bc01n01.hswaw.net.cert
@@ -1,9 +1,9 @@
 -----BEGIN CERTIFICATE-----
-MIIFHDCCBASgAwIBAgIUBd/lkgCFa6VNTU862aFQGQd6i8gwDQYJKoZIhvcNAQEL
+MIIFHDCCBASgAwIBAgIUKFAZXQEwMakUQQEyk/RkCzXhCMcwDQYJKoZIhvcNAQEL
 BQAweDELMAkGA1UEBhMCUEwxFDASBgNVBAgTC01hem93aWVja2llMQ8wDQYDVQQH
 EwZXYXJzYXcxGzAZBgNVBAoTEldhcnNhdyBIYWNrZXJzcGFjZTETMBEGA1UECxMK
-Y2x1c3RlcmNmZzEQMA4GA1UEAxMHZXRjZCBjYTAeFw0yMDAzMjgxNTUzMDBaFw0y
-MTAzMjgxNTUzMDBaMHcxCzAJBgNVBAYTAlBMMRQwEgYDVQQIEwtNYXpvd2llY2tp
+Y2x1c3RlcmNmZzEQMA4GA1UEAxMHZXRjZCBjYTAeFw0yMTAzMjcxMTI3MDBaFw0y
+MjAzMjcxMTI3MDBaMHcxCzAJBgNVBAYTAlBMMRQwEgYDVQQIEwtNYXpvd2llY2tp
 ZTEPMA0GA1UEBxMGV2Fyc2F3MSUwIwYDVQQLExxub2RlIGV0Y2Qgc2VydmVyIGNl
 cnRpZmljYXRlMRowGAYDVQQDExFiYzAxbjAxLmhzd2F3Lm5ldDCCAiIwDQYJKoZI
 hvcNAQEBBQADggIPADCCAgoCggIBAKkSjQ1EVgGR6w/MTgdnd4GSTqOOFgp/cTpk
@@ -21,10 +21,10 @@
 AQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBTKhiQ/ZeBG
 JuOq1RG7YfHouV2kSTAfBgNVHSMEGDAWgBTxWbhmTT7D50LugaPURn85U3X5DzAc
 BgNVHREEFTATghFiYzAxbjAxLmhzd2F3Lm5ldDANBgkqhkiG9w0BAQsFAAOCAQEA
-LzWMoHGuMxBJaql7y6PrlGr2cKX/3vBED1x4kIe1RVAA0JyF0lNpKf3dmWvHHWkF
-x7Op8/B0kKlhQAsjY2f2DvYTw+d9tg3Kg2OkS8xuBxFmMJupOQxSApp+Gi4k92kM
-SdgLIrtey4eQ1mFtWhssFWOKrU3NOXD1iLl+BfEqwvlhm524HTPlqKocBkAUCeFe
-gdei5U6FwlU/l7vhqm7Qr4doOblr63/2ls9/cOv14tweovPLtSJaYDbtE/Dto7RT
-khhK/MS0n19n1+aAXWTlcYU/0kHagaVFIRlvVyp6nMFhLV+T21jTrnf98q4mdybC
-+lUKqLwE5y4V7f/FWIKfhg==
+Sx40vjacrxv7+Naaunei6tACUzo6r7GyFMNbC1bNauikBtirK3MQwLupVhCUpNpu
+tqD+8QiC9FJ/nchAxxJLjs8w9reA7nO+kd0jsXhLU7TcYN9j3zHZ0MEM3IaWoK+V
+pNvvkjalhY5LkAJCRcUaLJJXxE4kE5C0VIBK8r904WpOB55htG4UUf5d6FN/pbFM
+UJm2IuV6PMdoSEJZinXIa0prHksBv/BYxWD9jqMuYQczZVuMnJIcJuO+F33iSTAh
+jW+IgrKhX0+rmQfr+0wpCVHYM4Xax7Gm9Evt8Yo31qHXNqyVNeGi1HBCy6T6Plhx
+L+ehquvUo2nZGfGtjaXV+g==
 -----END CERTIFICATE-----
diff --git a/cluster/certs/etcd-bc01n02.hswaw.net.cert b/cluster/certs/etcd-bc01n02.hswaw.net.cert
index 5fb1c6d..8994a7b 100644
--- a/cluster/certs/etcd-bc01n02.hswaw.net.cert
+++ b/cluster/certs/etcd-bc01n02.hswaw.net.cert
@@ -1,9 +1,9 @@
 -----BEGIN CERTIFICATE-----
-MIIFHDCCBASgAwIBAgIUfKVgcr+CKsr3u9FsVXFRZRXv8B0wDQYJKoZIhvcNAQEL
+MIIFHDCCBASgAwIBAgIUBPBhiwhMaJS05SkiqtKXPGIKJCcwDQYJKoZIhvcNAQEL
 BQAweDELMAkGA1UEBhMCUEwxFDASBgNVBAgTC01hem93aWVja2llMQ8wDQYDVQQH
 EwZXYXJzYXcxGzAZBgNVBAoTEldhcnNhdyBIYWNrZXJzcGFjZTETMBEGA1UECxMK
-Y2x1c3RlcmNmZzEQMA4GA1UEAxMHZXRjZCBjYTAeFw0yMDAzMjgxNjQ1MDBaFw0y
-MTAzMjgxNjQ1MDBaMHcxCzAJBgNVBAYTAlBMMRQwEgYDVQQIEwtNYXpvd2llY2tp
+Y2x1c3RlcmNmZzEQMA4GA1UEAxMHZXRjZCBjYTAeFw0yMTAzMjcxMTM3MDBaFw0y
+MjAzMjcxMTM3MDBaMHcxCzAJBgNVBAYTAlBMMRQwEgYDVQQIEwtNYXpvd2llY2tp
 ZTEPMA0GA1UEBxMGV2Fyc2F3MSUwIwYDVQQLExxub2RlIGV0Y2Qgc2VydmVyIGNl
 cnRpZmljYXRlMRowGAYDVQQDExFiYzAxbjAyLmhzd2F3Lm5ldDCCAiIwDQYJKoZI
 hvcNAQEBBQADggIPADCCAgoCggIBAMKzDo59mxEhwx8x3ju95KmjbND9wCga9YGf
@@ -21,10 +21,10 @@
 AQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBSv6oLJS4Ov
 F3EnzsT1IOfrUVwQszAfBgNVHSMEGDAWgBTxWbhmTT7D50LugaPURn85U3X5DzAc
 BgNVHREEFTATghFiYzAxbjAyLmhzd2F3Lm5ldDANBgkqhkiG9w0BAQsFAAOCAQEA
-Dd6WnaNXELgxr/xJVCSFSMiD8e3FjSpH/k/4sCUzonhFS/vIm9b8xEAT0p+bkL/4
-XCgRE/mjQQgdSFEXmZ75AEe+DqYDSjfoIJHAVxJzi/3uexd4+EauVQ4XZh8RMk05
-1HO3gP3wO8RFqUsTKGOTriUVF1zaIz4UxJEzT2BWJkgp5G60HUqXUyaKwNhTDNZL
-p9yzVpsuPHuRlyRZjAHdDafaW6sTFZWAQXxao2NKLMhSi3JLArlJuBuh/4QjhZzw
-UW0U/4yNot/H/kX6Nh41OoBY/mdGGTN7CAndFnXMEEVAuM3gja8LiG3VwDG2bpX7
-C4FJ50A5mcfOEOvnKLA6Zw==
+ilXcdHIWRduN07J0Z5xl6sJs9zYxiGW3twHpUsPZ3eTIvrT0z76RBBgUn/Qlz1dG
+jucc2lkKa+XmUpBgpm/8WNqf2lxrXXrj1KDeosZAppwxFzfhMktFHfVJH3dujbwb
+5eWnBHPp0rMluM/23Ep0hUSHTrGOmxrKplfptFqZJ5AJ3PiXKhxLp/lltUSdgngV
+x9q7fY02d5XaGP2l6QNvO7cSeq7mfvhPXuhmVFPNEU1uzrxuamVWaNcoJ11IeuUd
+JGQOfaymfj6ScOt2zQEpC2OVho5aMhWOPK7wJZ1++mvoVJ0m/hlCLWFKgVpDWocF
+n5ss/F7Gxsa7zGgYBRBwpg==
 -----END CERTIFICATE-----
diff --git a/cluster/certs/etcd-bc01n03.hswaw.net.cert b/cluster/certs/etcd-bc01n03.hswaw.net.cert
deleted file mode 100644
index e2575f9..0000000
--- a/cluster/certs/etcd-bc01n03.hswaw.net.cert
+++ /dev/null
@@ -1,30 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIFHDCCBASgAwIBAgIUZ5SwY4VA+3YXJ2IlKaB1LVPOYv8wDQYJKoZIhvcNAQEL
-BQAweDELMAkGA1UEBhMCUEwxFDASBgNVBAgTC01hem93aWVja2llMQ8wDQYDVQQH
-EwZXYXJzYXcxGzAZBgNVBAoTEldhcnNhdyBIYWNrZXJzcGFjZTETMBEGA1UECxMK
-Y2x1c3RlcmNmZzEQMA4GA1UEAxMHZXRjZCBjYTAeFw0yMDAzMjgxNTE1MDBaFw0y
-MTAzMjgxNTE1MDBaMHcxCzAJBgNVBAYTAlBMMRQwEgYDVQQIEwtNYXpvd2llY2tp
-ZTEPMA0GA1UEBxMGV2Fyc2F3MSUwIwYDVQQLExxub2RlIGV0Y2Qgc2VydmVyIGNl
-cnRpZmljYXRlMRowGAYDVQQDExFiYzAxbjAzLmhzd2F3Lm5ldDCCAiIwDQYJKoZI
-hvcNAQEBBQADggIPADCCAgoCggIBAL24XRDw0Edxw96O9y2XeqlccanVjZQsJRxm
-tvhImPps6U9rIS92/6IIFJn1Wi0NtE1W6VD7p4Q3gK+VmXlCdFmyJRjaeD9zJ8Gz
-0A4bQDtL9nRQM0MhkESKZBxJYkRPMUVDsBKDhq9Y31XTvsqKCYKzErPcBbuq9o8k
-sLoFijUV1EPNZtqnrGB66uQ+nspUmQHAW+aYFxJ4ak0ddSiilZdbCnWs+NpEi71d
-dIeu46GTz31cqhTwLZfvARC9lP7xCXFrGbqjr9wStfJ46sZ3E8xglhYSuKdfpCK1
-TeJGcHoa8H7cGorlqw1uocs6AzorzCE1P5I4eDVN+M6TB6Jv8T83G3JqQBKmcs5Q
-y2ERVDNx9Z273lHO42RXkhTSDjs0ri8tvYr2T4ePTtI6P8E78zC3Y4VdJ/KKiOec
-qgBgeLSFiNFhAPHR+3uOjFZYaAplWcwo9TdMAEX6AoXGhCxjEDnYp4ejgWef3BFy
-t1FL4c0JOoWjogk2FIS5uQasYSvYBFdBK2cAnrxE+w5S/Sx1TB/GC7iPiTPlSI27
-nHrz1MGXZY+WVgFQsxsElsuuuDJFtrYRZNkAAdsuyGI/F4l3AEH0NJaXNrrHBxAk
-clYuIz7tWISncJdG3R20Yl1p8hE41Y8CDse9U3AMMpyT19MPwqsuH/aOBJcSrIlE
-v22KG4SBAgMBAAGjgZ4wgZswDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsG
-AQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBTTATwq3vWr
-hLC2f+LfP1iC6GhnBTAfBgNVHSMEGDAWgBTxWbhmTT7D50LugaPURn85U3X5DzAc
-BgNVHREEFTATghFiYzAxbjAzLmhzd2F3Lm5ldDANBgkqhkiG9w0BAQsFAAOCAQEA
-StQ/e2yaZPH3wyNlLOIzID3u9WwpEyT1RVyc9pCyMzHkEGUAinHzy3X2l1XUKP1G
-t9c+aU4+7+uZgEGsGwXyT7KeoT23U1hym6DN0Azz9r0rGGvBbwyShwO9C2S17wDE
-p/6ZrdXZ3jrHhaspgmv4syAYMb0Z3MtVBpcp2M9EZZSJxxV4G789ZQbklJunKLEA
-U53+YTuzgIeARc8b8H8V8tGoX8799EytDKajm2SEXjXO2hkrSL9AnivT/0sWtEhm
-C8IS/1gS2EhzEjA/vSUjlk4acI/9nbPXOGJeCf3eeGcybx2/1QY7u9ZGXwuqsG22
-mvS9hZ09yn7stK+5RxYgQA==
------END CERTIFICATE-----
diff --git a/cluster/certs/etcd-calico.cert b/cluster/certs/etcd-calico.cert
index bbcd91d..601ae3b 100644
--- a/cluster/certs/etcd-calico.cert
+++ b/cluster/certs/etcd-calico.cert
@@ -1,9 +1,9 @@
 -----BEGIN CERTIFICATE-----
-MIIFBjCCA+6gAwIBAgIUZmjAlqCosP9W/6X/iIMLRrNb/bkwDQYJKoZIhvcNAQEL
+MIIFBjCCA+6gAwIBAgIURfleic2TJVIf8/RH1K4m9wQpqUEwDQYJKoZIhvcNAQEL
 BQAweDELMAkGA1UEBhMCUEwxFDASBgNVBAgTC01hem93aWVja2llMQ8wDQYDVQQH
 EwZXYXJzYXcxGzAZBgNVBAoTEldhcnNhdyBIYWNrZXJzcGFjZTETMBEGA1UECxMK
-Y2x1c3RlcmNmZzEQMA4GA1UEAxMHZXRjZCBjYTAeFw0yMDAzMjgxNTE1MDBaFw0y
-MTAzMjgxNTE1MDBaMGwxCzAJBgNVBAYTAlBMMRQwEgYDVQQIEwtNYXpvd2llY2tp
+Y2x1c3RlcmNmZzEQMA4GA1UEAxMHZXRjZCBjYTAeFw0yMTAzMjcxMTI3MDBaFw0y
+MjAzMjcxMTI3MDBaMGwxCzAJBgNVBAYTAlBMMRQwEgYDVQQIEwtNYXpvd2llY2tp
 ZTEPMA0GA1UEBxMGV2Fyc2F3MSUwIwYDVQQLExxyb290IGV0Y2QgY2xpZW50IGNl
 cnRpZmljYXRlMQ8wDQYDVQQDEwZjYWxpY28wggIiMA0GCSqGSIb3DQEBAQUAA4IC
 DwAwggIKAoICAQC9VRlI8AnvZKPMhtDef9mrYydfINlI/QS8+CE8aLkFfhQQJHyj
@@ -20,10 +20,10 @@
 o4GTMIGQMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYB
 BQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUYjrCSKoTAgECdKZTntUm3/7d
 2PUwHwYDVR0jBBgwFoAU8Vm4Zk0+w+dC7oGj1EZ/OVN1+Q8wEQYDVR0RBAowCIIG
-Y2FsaWNvMA0GCSqGSIb3DQEBCwUAA4IBAQCQV/w/TOPjnCJszWqLd5GeoEkPPE8o
-qevGTmTpm+/l/vlFERDsUB2kKnxb4mHBbVo2c2ux0aF53wKeIcp5/fdfH1LFjS67
-YY9hLce3zFmZMCEbkFGgpjQKpNy4zB72f4ksGRzbPienFLhghhY1dIv5Rdrhyz1O
-xhrUP9fgJHjYd33pFVfhyl8mIOon8yn+4AvGLrPATgp4dmkF+HM3EYtqd2LfeHVy
-Dc9PbjpmIGHz6IKpMKC4S6rlnnfzbk2PRULVcXHPtfX9ihXz+B892IORDK8jgSe8
-PdVe3ZGMo1EbSwQ9WwGZMrIqeiX1vfaEOhZgaw8GMuFM75OBK9yRopZ/
+Y2FsaWNvMA0GCSqGSIb3DQEBCwUAA4IBAQBt/hQm567Ov+Qptp5QipPUn4Isv/Uq
+zZHSR5xpBMiCl3IKoQuzWyjpbQNey9QAyT/m/7mq+T7p4uKsFKaNQOOOQOH8TNpj
+fWiVwUEQWvwv98zGNYikFD6c+9st+Psh8xsPjqonMgYAra3jn7pNHBV4thQ1i4cm
+YcCUT7ZLw+tyC1z148bctqIUy342srxTupC5xsfv8xkITvakwmwBfNCbeZNxKzJS
+i/zl3EK6y+/biszXGresskQ/fTVPrWfC6oGudv8AG+SASocYztYS41BCoYuy4L8d
+tIB532AqywFH5S0qMXB73bObaJy88A5qdK0kd4sMrxJ8q9NNeZy2AdaD
 -----END CERTIFICATE-----
diff --git a/cluster/certs/etcd-kube.cert b/cluster/certs/etcd-kube.cert
index dd0b91f..e82996d 100644
--- a/cluster/certs/etcd-kube.cert
+++ b/cluster/certs/etcd-kube.cert
@@ -1,9 +1,9 @@
 -----BEGIN CERTIFICATE-----
-MIIFAjCCA+qgAwIBAgIUSc+yoWMgxteBtdswAaa+RZmh6hwwDQYJKoZIhvcNAQEL
+MIIFAjCCA+qgAwIBAgIUUEhDcCROm93ooEjAxFNPNj2lqycwDQYJKoZIhvcNAQEL
 BQAweDELMAkGA1UEBhMCUEwxFDASBgNVBAgTC01hem93aWVja2llMQ8wDQYDVQQH
 EwZXYXJzYXcxGzAZBgNVBAoTEldhcnNhdyBIYWNrZXJzcGFjZTETMBEGA1UECxMK
-Y2x1c3RlcmNmZzEQMA4GA1UEAxMHZXRjZCBjYTAeFw0yMDAzMjgxNTE1MDBaFw0y
-MTAzMjgxNTE1MDBaMGoxCzAJBgNVBAYTAlBMMRQwEgYDVQQIEwtNYXpvd2llY2tp
+Y2x1c3RlcmNmZzEQMA4GA1UEAxMHZXRjZCBjYTAeFw0yMTAzMjcxMTI3MDBaFw0y
+MjAzMjcxMTI3MDBaMGoxCzAJBgNVBAYTAlBMMRQwEgYDVQQIEwtNYXpvd2llY2tp
 ZTEPMA0GA1UEBxMGV2Fyc2F3MSUwIwYDVQQLExxrdWJlIGV0Y2QgY2xpZW50IGNl
 cnRpZmljYXRlMQ0wCwYDVQQDEwRrdWJlMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
 MIICCgKCAgEAw5jdxQxtELgpg+M1jib4VklzIJ4ULrKH59xKxs6qK0iGJClc8EFv
@@ -20,10 +20,10 @@
 kTCBjjAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUF
 BwMCMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFB3FpZrvkz7oq25DKwzCMiKCCsgM
 MB8GA1UdIwQYMBaAFPFZuGZNPsPnQu6Bo9RGfzlTdfkPMA8GA1UdEQQIMAaCBGt1
-YmUwDQYJKoZIhvcNAQELBQADggEBAHGsNqvBFSQC8qWqTTCtghbmF6nQqyhwEgsn
-L/29QMgmNx234r41JPymEN8R2bMFHuMDrOgEliXcbqcirpOuCvx3nln8gFmimtN5
-q7MEjAllJHqa1sjx+O83TNToFkmc8gxUsDqdngrsS1IoEbs8tIP7P/Y80gshCUfz
-2Fnqv1/m8h04RJ7E8Vgxq9txR3JmZPWbFtiHTb7Izlv6y9c+mtCDwzFb8ZiXCfSe
-TFBOptEjx5S82kj7LgYvtngz99ZojoCeQnqczbnHagw7yLH+NqF1SpTr6xZKzdQ+
-hh5Zna0whQCAy2wF5paW3asPNb7Sh90xXARynYxuvCKAIeurAI0=
+YmUwDQYJKoZIhvcNAQELBQADggEBAAJKhH5A1TrRnfkNK/ukfbZ08c4xI1jJaJ4X
+iQ01uxL8j2L6mMiyDeFCjybdg63N/x6dVjvP+fFHd+uF9gJBq/40XD9pMXd4yFeg
+UPzuLwLEJCFEdebsl6u0SH1Gl5Enw5mGUeK1wefX0pfV5JpcLGKTE3TtiksKFYKd
+dzASP1DF7U0zGpiWjdhsIG0ISGZioUvSOCTj9t+qI7rDygaUPtSFFmSIYoiCjeSN
+qsfA78ZQA0N9a1wwmvjl+P4V0uznCcXfUQpMH6I6wDGXOwE66+h7ZJoAu2fJeTah
+2qWASJP3ojXF9Pfg5nwDvAUgAh/xZfc3zOJAIfGAuFHw5wYZ3JQ=
 -----END CERTIFICATE-----
diff --git a/cluster/certs/etcd-root.cert b/cluster/certs/etcd-root.cert
index 604ff83..0e22922 100644
--- a/cluster/certs/etcd-root.cert
+++ b/cluster/certs/etcd-root.cert
@@ -1,9 +1,9 @@
 -----BEGIN CERTIFICATE-----
-MIIFAjCCA+qgAwIBAgIULK8H0d1v3xxIrRUgoGwW+5x6GIIwDQYJKoZIhvcNAQEL
+MIIFAjCCA+qgAwIBAgIUJMEMDyux9E0GJObItOTmYZ1byL4wDQYJKoZIhvcNAQEL
 BQAweDELMAkGA1UEBhMCUEwxFDASBgNVBAgTC01hem93aWVja2llMQ8wDQYDVQQH
 EwZXYXJzYXcxGzAZBgNVBAoTEldhcnNhdyBIYWNrZXJzcGFjZTETMBEGA1UECxMK
-Y2x1c3RlcmNmZzEQMA4GA1UEAxMHZXRjZCBjYTAeFw0yMDAzMjgxNTE1MDBaFw0y
-MTAzMjgxNTE1MDBaMGoxCzAJBgNVBAYTAlBMMRQwEgYDVQQIEwtNYXpvd2llY2tp
+Y2x1c3RlcmNmZzEQMA4GA1UEAxMHZXRjZCBjYTAeFw0yMTAzMjcxMTI3MDBaFw0y
+MjAzMjcxMTI3MDBaMGoxCzAJBgNVBAYTAlBMMRQwEgYDVQQIEwtNYXpvd2llY2tp
 ZTEPMA0GA1UEBxMGV2Fyc2F3MSUwIwYDVQQLExxyb290IGV0Y2QgY2xpZW50IGNl
 cnRpZmljYXRlMQ0wCwYDVQQDEwRyb290MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
 MIICCgKCAgEAudCBVJv66aRyizfh20/PeIt7iSP9HpTorxxtG0Ti7ybjhu7gpkPY
@@ -20,10 +20,10 @@
 kTCBjjAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUF
 BwMCMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFDDZWVeg57MP21XCkTRqzFR2Omtt
 MB8GA1UdIwQYMBaAFPFZuGZNPsPnQu6Bo9RGfzlTdfkPMA8GA1UdEQQIMAaCBHJv
-b3QwDQYJKoZIhvcNAQELBQADggEBAD+Hf/kVNyXPbWL7asmMsqcldGocnzVFDK8J
-91pWLPSdbAexSUwP6sq2yHUPYMH4uVwjQOg3nKR9GImRJpHkudwZ8M876VdqmCBS
-/KgwlCWQtoN6cw9fQXGnPlJA+LN4q/YBQv0KRN1/eL/jKMPZZL3f0Hy+/4uOvK40
-L2RgNcoXhvRWsJRN+xf00ZvATiHxyhq/uC2dfTgpdCFynl1X700Z6Mk600J6vbo/
-FtGdj6F7nKwi00g2236tb3BEaL1vl2xtdm36xIDmX6F23p3dtRdIl1ULPFg1qAoa
-g8QjcUxILkhwadgKmiUDxVPA+1/afYRklPcHGziB0VJfOTgz1Rw=
+b3QwDQYJKoZIhvcNAQELBQADggEBAKRWkv+IZebFHEylkopUxxiqwX3vhkmDVQsX
+bLUaQY+1xV8mskatzL+pgK233penvibmSnqT9/AKq9iRwKHHEaN3Kr6gnh5bF36h
+uaZfrfCQg4VS2Cu5F1Y9R6ox2LUaAt/9jZRh+OXXI01GjqV7yX4wWzGs5gWrF1e5
+cQoXL024gbYxXYtM4Q/F9rVdMy+vZOuaspXaCh0BIumEDXYQdGE/AGgOWlEbP5Wj
+6NjMVg1+VVZ7GHbyxSjtWh6DW6booHVw7vsNcPafcVW2D7XHyF64YVKQql1/9BNM
+kvJsZgqI9DdWk71eS1laQTGBs3msd/yJTHiZi9COwROaVb8D6GU=
 -----END CERTIFICATE-----
diff --git a/cluster/certs/etcdpeer-bc01n01.hswaw.net.cert b/cluster/certs/etcdpeer-bc01n01.hswaw.net.cert
index 0c3d762..e9631c7 100644
--- a/cluster/certs/etcdpeer-bc01n01.hswaw.net.cert
+++ b/cluster/certs/etcdpeer-bc01n01.hswaw.net.cert
@@ -1,9 +1,9 @@
 -----BEGIN CERTIFICATE-----
-MIIFHzCCBAegAwIBAgIUbtFJibIQ+L3FalsNIadl2cqxzs4wDQYJKoZIhvcNAQEL
+MIIFHzCCBAegAwIBAgIUKW8pdXo/W4SfRl9QxvqFh7ePx1swDQYJKoZIhvcNAQEL
 BQAwfTELMAkGA1UEBhMCUEwxFDASBgNVBAgTC01hem93aWVja2llMQ8wDQYDVQQH
 EwZXYXJzYXcxGzAZBgNVBAoTEldhcnNhdyBIYWNrZXJzcGFjZTETMBEGA1UECxMK
-Y2x1c3RlcmNmZzEVMBMGA1UEAxMMZXRjZCBwZWVyIGNhMB4XDTIwMDMyODE1NTMw
-MFoXDTIxMDMyODE1NTMwMFowdTELMAkGA1UEBhMCUEwxFDASBgNVBAgTC01hem93
+Y2x1c3RlcmNmZzEVMBMGA1UEAxMMZXRjZCBwZWVyIGNhMB4XDTIxMDMyNzExMjcw
+MFoXDTIyMDMyNzExMjcwMFowdTELMAkGA1UEBhMCUEwxFDASBgNVBAgTC01hem93
 aWVja2llMQ8wDQYDVQQHEwZXYXJzYXcxIzAhBgNVBAsTGm5vZGUgZXRjZCBwZWVy
 IGNlcnRpZmljYXRlMRowGAYDVQQDExFiYzAxbjAxLmhzd2F3Lm5ldDCCAiIwDQYJ
 KoZIhvcNAQEBBQADggIPADCCAgoCggIBANQ4DOd1qBoznMwL9bcmjZydm0C45RPY
@@ -21,10 +21,10 @@
 CCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBQ+AVJ4
 b1WbetRtLuoHoZkRG3TyJDAfBgNVHSMEGDAWgBQte5qvaKoZpMwqiL74duS9J6ck
 DjAcBgNVHREEFTATghFiYzAxbjAxLmhzd2F3Lm5ldDANBgkqhkiG9w0BAQsFAAOC
-AQEAoeQruvpOcvGc7qr1OWFycJcwEd8k4o/1Oc5KPEKlVDNf9XcweJOetAayBMMK
-Y3lGkBuOHQ5Crx8kXruiQyi6c7tUd9rVtDWWwcLAR20CkDCYnJNn46djgRR6J4pb
-RFz+31cIDgQT2GJhO2waajrcqfrBZeuDyyqt3ZUn3hpICdTbYJWV3x/vqLIY+FpT
-Z+x8Muzb0EWFXCBxZBHsZXBuoCjtmmrNrf0ek5Ag+n5fxl1AdGAuqD4D01wJWa0L
-UJtaLmuD02Pw/c6RJ5vkWI9DRcH7/XdYZZ5yf7Ch2GNivKsz9ekIVpVz0HJMOVPM
-yw/s8FL0AczmICjx6yjlu4RQ5w==
+AQEAZUKCrNDpDTJBVcVswSaEQujA2eNOTQuj6eBuf08Nz1NZGgRYAfy+aHoTkahZ
+m5FaYFSEnL6R0qzjruvRSnBb21A9P6+8+T2Tw6NA4XWDqKwIoDzVyqjpTNeRpcTV
+Xj3l3eJPSsncZDmPrZIY8LBG9ZQSe36KfYvXPPCJT3aYLKu8ZfiJRTbxU/gH4SQg
+wgKZZin/oBqnmWWhsKdVsepCDtZHUwxa0xdqLnmjlQiCjoW8tdyS6F0EBnK6nUY9
+V18h0b7eZWPy5u+t1wnNA1Jjsu9ad0/4IipJ7oEkVcufZcWhuxgfaxddh/a+eRuB
+lQQ+/YNCpGWlQBsD5tIxpEasFg==
 -----END CERTIFICATE-----
diff --git a/cluster/certs/etcdpeer-bc01n02.hswaw.net.cert b/cluster/certs/etcdpeer-bc01n02.hswaw.net.cert
index 8776183..f660e59 100644
--- a/cluster/certs/etcdpeer-bc01n02.hswaw.net.cert
+++ b/cluster/certs/etcdpeer-bc01n02.hswaw.net.cert
@@ -1,9 +1,9 @@
 -----BEGIN CERTIFICATE-----
-MIIFHzCCBAegAwIBAgIUHPJfFvMMibUlrbwagmA8Zy9KtS4wDQYJKoZIhvcNAQEL
+MIIFHzCCBAegAwIBAgIURC6k/INjt9VF6OGcTjPG/IvihO4wDQYJKoZIhvcNAQEL
 BQAwfTELMAkGA1UEBhMCUEwxFDASBgNVBAgTC01hem93aWVja2llMQ8wDQYDVQQH
 EwZXYXJzYXcxGzAZBgNVBAoTEldhcnNhdyBIYWNrZXJzcGFjZTETMBEGA1UECxMK
-Y2x1c3RlcmNmZzEVMBMGA1UEAxMMZXRjZCBwZWVyIGNhMB4XDTIwMDMyODE2NDUw
-MFoXDTIxMDMyODE2NDUwMFowdTELMAkGA1UEBhMCUEwxFDASBgNVBAgTC01hem93
+Y2x1c3RlcmNmZzEVMBMGA1UEAxMMZXRjZCBwZWVyIGNhMB4XDTIxMDMyNzExMzcw
+MFoXDTIyMDMyNzExMzcwMFowdTELMAkGA1UEBhMCUEwxFDASBgNVBAgTC01hem93
 aWVja2llMQ8wDQYDVQQHEwZXYXJzYXcxIzAhBgNVBAsTGm5vZGUgZXRjZCBwZWVy
 IGNlcnRpZmljYXRlMRowGAYDVQQDExFiYzAxbjAyLmhzd2F3Lm5ldDCCAiIwDQYJ
 KoZIhvcNAQEBBQADggIPADCCAgoCggIBAMWfZpYs+wH/qg95+KXgIPMDUN5fuwmp
@@ -21,10 +21,10 @@
 CCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBQzpNgs
 s57/rdxm88PxZpnFUvIiTzAfBgNVHSMEGDAWgBQte5qvaKoZpMwqiL74duS9J6ck
 DjAcBgNVHREEFTATghFiYzAxbjAyLmhzd2F3Lm5ldDANBgkqhkiG9w0BAQsFAAOC
-AQEAiKtRlm+8J5X0/SvRK9urYX7KvgE+yEYQ+pm4ZXtxbk8aXqbwnBiyH24+0mlK
-Csn/iLv5b0GS4pZcjczBA+SE4Yi4Vx7Ekz0byagYPj9idlQYRX4vl/Osmm/svj5f
-KWyv2/rdaq/0rkoPvnT29uC29CDCqPguaS8zYgVOinSfdN9dfPw10lBiCgSLLacd
-ReI74GCgUVv14QlWColz0ILtDmwKS3nEnDtNVBfMR5jxViSiG/1ZWZt2C+/66kAr
-YI1LXxkg/ZyVtArSe3uDqWL/oGOcGHoj8QnOljDn/7GcNCH4NDfQ+KkmjqIHygYo
-aKEgxEqoYvpE9ls1tSaOXS2iLw==
+AQEAje4XXzWeRhe68C95xlJEmVcYUft5lj30ZWEjWI0+xzv+KCEQ7KiE9tgEgDI3
+TPROCNoolLIRbOEsuVliYzxLzMvgJsA9rwH8BkrbP/4Cj6yvMPUwrq/C/kRHukvr
+uKhdOY/XhvpNstO6CvGpehyeu55rGgrLFJLJ4TLm/kTpiXdb7btFd9QX0e54ReEg
+Q6C8eFOODyTR3rSgaI6Wt7IlNNCMCvjtQ2z+9TNNzGPJloFFwJES2wFT7lXJPsxQ
+nT+T13YyoFPUfII0C9tNy6+xJdMMh+pCCy7DH/pQ4DNr6t5J4CZqdJLrlJ4eaqQG
+csf6xcegXNuoDAW+csi1VnUyDg==
 -----END CERTIFICATE-----
diff --git a/cluster/certs/etcdpeer-bc01n03.hswaw.net.cert b/cluster/certs/etcdpeer-bc01n03.hswaw.net.cert
deleted file mode 100644
index a67d385..0000000
--- a/cluster/certs/etcdpeer-bc01n03.hswaw.net.cert
+++ /dev/null
@@ -1,30 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIFHzCCBAegAwIBAgIUY0PqPfxno72apj4xsBsQPC/QTbUwDQYJKoZIhvcNAQEL
-BQAwfTELMAkGA1UEBhMCUEwxFDASBgNVBAgTC01hem93aWVja2llMQ8wDQYDVQQH
-EwZXYXJzYXcxGzAZBgNVBAoTEldhcnNhdyBIYWNrZXJzcGFjZTETMBEGA1UECxMK
-Y2x1c3RlcmNmZzEVMBMGA1UEAxMMZXRjZCBwZWVyIGNhMB4XDTIwMDMyODE1MTUw
-MFoXDTIxMDMyODE1MTUwMFowdTELMAkGA1UEBhMCUEwxFDASBgNVBAgTC01hem93
-aWVja2llMQ8wDQYDVQQHEwZXYXJzYXcxIzAhBgNVBAsTGm5vZGUgZXRjZCBwZWVy
-IGNlcnRpZmljYXRlMRowGAYDVQQDExFiYzAxbjAzLmhzd2F3Lm5ldDCCAiIwDQYJ
-KoZIhvcNAQEBBQADggIPADCCAgoCggIBAL7GrtNL0y7cK7qu0z4d8WdWOTWbzlBX
-xdx+PMDnhWeVONtVUaQ+wD1Js7e9d1myIujZfltWnPzA4OymJtjI3CmFip/9SylR
-ggaGtHaF7nXte+yaoK+Uvc7AD+vRjCnmdnJgUz3yoAogEnGxdeWwy8L/QnGGYNvx
-kboeH3WxLkqBW9BWYsDcDK1uVzEszfpbFYV1CaCqzQ455GsyjFquRZ4pwkPJp5xM
-BYvfo/2jf1AiWDH+wZ3SByL6yxq0skFCcEA/DJTy+ggYVtmjn6C1MDHiQUnWFVR+
-f0CLDR9V6GmQbQ2GbOgY2jLQnEzdKdv3Bc+QVeMs+Fj+wgjAk1vuuKwA/zPCWTtb
-PR0H3NI1RKl3411UgBJ1CUPmJWBsRitqMgFgPIheK2iwK6fMhW1tEp3V9lkNU9ob
-NsCaep+Rlw9c05dKBgatj8TiPJd5ZTyw5SnC+UZ60u9d0wuyku6U6++keVpq0sbV
-s5qP4zCAkoOcrJt1HIyS/a0zPXBHPTrAwk07aZ32X8GnutetO5tUM03+6OuNY65Q
-NW3v4rYP7jW0NvtKZo8KXvmVn/1sltGhYVqGVqqZKvkhbQFN3RIfZMZKUn+d81pA
-2cMAYXtGqn1fcOFIfXBEF2qWpvOrVwEg34pNRU0fwvqh62nfIk4L2iBzI4rpj+Pv
-CEI53DIQlVLjAgMBAAGjgZ4wgZswDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQG
-CCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBSQjE6Q
-JEigxzqbPAfgSJNQH+MX6jAfBgNVHSMEGDAWgBQte5qvaKoZpMwqiL74duS9J6ck
-DjAcBgNVHREEFTATghFiYzAxbjAzLmhzd2F3Lm5ldDANBgkqhkiG9w0BAQsFAAOC
-AQEARkvDE+dGvSXWF8iHeXrasd+MoZz6+ifpFA27dsGLDfbEfmbks+nbJCAGhIqf
-YqKJ8H+lopIBDtxbcRfTjXDLsncmNTrWf/FVEx/WLbGQsYrqncW8ym2Xz1qBCMde
-/QBKKXSEEiBpVLYn0+41dvtxw8nAfIPin98pScnY04p+5BGaxFsKb2CsshBJlDOR
-g7BFYiWpQz2mAr6tyO/lG2KqN0B07P07jszej0c8Xl+tkbMtpghIi2GcJ75VXNJf
-XRtmeTw7YqcLgKTknBfJ9+GotmFUfAF2f+jA21URWY/6f4Yr+BniZj6Ikahx3eD+
-fw+y3c4eBLl5G3WugIFj5cM0UQ==
------END CERTIFICATE-----
diff --git a/cluster/certs/kube-controllermanager.cert b/cluster/certs/kube-controllermanager.cert
index 291c604..10ce219 100644
--- a/cluster/certs/kube-controllermanager.cert
+++ b/cluster/certs/kube-controllermanager.cert
@@ -1,9 +1,9 @@
 -----BEGIN CERTIFICATE-----
-MIIFdjCCBF6gAwIBAgIUFcalvELfl2XL6uFIqLjD+5G2tD4wDQYJKoZIhvcNAQEL
+MIIFdjCCBF6gAwIBAgIUGOVHVh0NR+sSqL9n0ALIrUHxVgMwDQYJKoZIhvcNAQEL
 BQAwgYMxCzAJBgNVBAYTAlBMMRQwEgYDVQQIEwtNYXpvd2llY2tpZTEPMA0GA1UE
 BxMGV2Fyc2F3MRswGQYDVQQKExJXYXJzYXcgSGFja2Vyc3BhY2UxEzARBgNVBAsT
-CmNsdXN0ZXJjZmcxGzAZBgNVBAMTEmt1YmVybmV0ZXMgbWFpbiBDQTAeFw0yMDAz
-MjgxNTE1MDBaFw0yMTAzMjgxNTE1MDBaMIG3MQswCQYDVQQGEwJQTDEUMBIGA1UE
+CmNsdXN0ZXJjZmcxGzAZBgNVBAMTEmt1YmVybmV0ZXMgbWFpbiBDQTAeFw0yMTAz
+MjcxMTI3MDBaFw0yMjAzMjcxMTI3MDBaMIG3MQswCQYDVQQGEwJQTDEUMBIGA1UE
 CBMLTWF6b3dpZWNraWUxDzANBgNVBAcTBldhcnNhdzEnMCUGA1UEChMec3lzdGVt
 Omt1YmUtY29udHJvbGxlci1tYW5hZ2VyMS8wLQYDVQQLEyZLdWJlcm5ldGVzIENv
 bXBvbmVudCBjb250cm9sbGVybWFuYWdlcjEnMCUGA1UEAxMec3lzdGVtOmt1YmUt
@@ -22,11 +22,11 @@
 BgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMAwG
 A1UdEwEB/wQCMAAwHQYDVR0OBBYEFAjGzAQ6wd1qf2er14tBEmwSV76JMB8GA1Ud
 IwQYMBaAFJgyXQ5PMx77CemJJBMWQmqA0ZnQMCkGA1UdEQQiMCCGHnN5c3RlbTpr
-dWJlLWNvbnRyb2xsZXItbWFuYWdlcjANBgkqhkiG9w0BAQsFAAOCAQEAjeeYwCxm
-8yfTfiWSKMMW9HTlK7zAl8PKngOvARihFgUfO1MbWQLTqYvkZ8/b8d3tXqxGHIY8
-TqLtK0N4a3ty+7IFwqnA29+apSPQOjK2f6RfSwUPFLqGDFXcM0pHHRbalYmUM///
-pEu3B223yimrtacAj3NFy1c5Jd7V36ZhwBAzzh3raWpqbuvm80MZccmb1gml1a/G
-KuyLzrtu8N6ObpsMFQSDbelgvgVvNh0akPANqrDc8BG5gDWkurIhsRWQC+POMKlE
-/c/EgyGXpZfvLtTprgCz+RRIGhV3GNRRbN/sdc3jO7M9QyJod3639VCf5gg5EU2l
-5sbxhHL+mvqJwA==
+dWJlLWNvbnRyb2xsZXItbWFuYWdlcjANBgkqhkiG9w0BAQsFAAOCAQEAterGoD4V
+aBT2qxqsUrZKcg9RyPyKNZM+ixZq3boOw1+8x1mryKrmb8pNS9BV28jbhwFu5G9I
+XIwU6Ugzf18LFHUZj/MRGEaKz+lNfwbgQjFrNu2fZaqzyXBhnvbiPOERfzDn6s3R
+35gj3AO/1Rg2DR0qGQhNw1IiRerg+IDBdNq1rVHZ8qJi8bwLmT1GnWNinzEnOOKT
+i86oS5z86Mqa5DQQt2EOUtzm5XSBLfHj1xciBSMqRJzoKThR71lUG50Vcoha5ra8
+6ZR/iOvdMEUZqElhZI31tToGikkJ0RQ6xLnSnC8GxNcGzI+m40U77Ltof5xKqZPR
+1iMUGkJYznjjcw==
 -----END CERTIFICATE-----
diff --git a/cluster/certs/kube-kubelet-bc01n01.hswaw.net.cert b/cluster/certs/kube-kubelet-bc01n01.hswaw.net.cert
index d846aa9..08b5db4 100644
--- a/cluster/certs/kube-kubelet-bc01n01.hswaw.net.cert
+++ b/cluster/certs/kube-kubelet-bc01n01.hswaw.net.cert
@@ -1,9 +1,9 @@
 -----BEGIN CERTIFICATE-----
-MIIFVjCCBD6gAwIBAgIUfBwlWrk6L56SB1jAWUjjt4c5rOUwDQYJKoZIhvcNAQEL
+MIIFVjCCBD6gAwIBAgIURyres5fkxiPk8K2ExffpNz+1ZTUwDQYJKoZIhvcNAQEL
 BQAwgYMxCzAJBgNVBAYTAlBMMRQwEgYDVQQIEwtNYXpvd2llY2tpZTEPMA0GA1UE
 BxMGV2Fyc2F3MRswGQYDVQQKExJXYXJzYXcgSGFja2Vyc3BhY2UxEzARBgNVBAsT
-CmNsdXN0ZXJjZmcxGzAZBgNVBAMTEmt1YmVybmV0ZXMgbWFpbiBDQTAeFw0yMDAz
-MjgxNTUzMDBaFw0yMTAzMjgxNTUzMDBaMIGFMQswCQYDVQQGEwJQTDEUMBIGA1UE
+CmNsdXN0ZXJjZmcxGzAZBgNVBAMTEmt1YmVybmV0ZXMgbWFpbiBDQTAeFw0yMTAz
+MjcxMTI3MDBaFw0yMjAzMjcxMTI3MDBaMIGFMQswCQYDVQQGEwJQTDEUMBIGA1UE
 CBMLTWF6b3dpZWNraWUxDzANBgNVBAcTBldhcnNhdzEVMBMGA1UEChMMc3lzdGVt
 Om5vZGVzMRAwDgYDVQQLEwdLdWJlbGV0MSYwJAYDVQQDEx1zeXN0ZW06bm9kZTpi
 YzAxbjAxLmhzd2F3Lm5ldDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB
@@ -22,10 +22,10 @@
 HRMBAf8EAjAAMB0GA1UdDgQWBBRQZwM3WgGW+l8MKQBF2DZ5IWBh6jAfBgNVHSME
 GDAWgBSYMl0OTzMe+wnpiSQTFkJqgNGZ0DA7BgNVHREENDAyghFiYzAxbjAxLmhz
 d2F3Lm5ldIYdc3lzdGVtOm5vZGU6YmMwMW4wMS5oc3dhdy5uZXQwDQYJKoZIhvcN
-AQELBQADggEBAKfYV2qyVs9yvsOhjKo8/A/t8Juz6FCBbPuuTdUt0TVENro3/njr
-wvl+TrtdvRwOfgYbzl+UUKgmwOY9gBumWeEOHeOUSJS+Cz9Ad5YgrQzQ9T9stOAC
-/8DdGq4rMaU2tbxpNCAc38XJUmwOnSrVbreWc98LZSlV17FFoB45R7FFhz0VZHpM
-B0/I+fK/IkF3CbSHVViGqjPcTwASU4AQaw8mcEAvpT4yXF7nUY+jORZSH/48y6U4
-6hApMGjLrdnSyCPddvPxfW6BFw15TNh2PnCNIb5P0fwitjVcArtock7T/vHVe+8Y
-+Xc7y0kqHBNKNDFRaA5I4HIF+Jc+kzZgeaA=
+AQELBQADggEBAAbi2ovuQnqWwlM9QVtWNvitIUslQ8X3ghpW7ZcnurfGeCZLBvoX
+p4dWpzMlh7taHVpERrBEamRuANuOZZciQjBrbfAWyL7K+vhpiUa0Y4q5hAafyoe/
+vIOzgmP6wCD3mbyFZG2TbX8yD1A7lycrvEqbCA87ujh3vUmbscKeUKg8RjjcqZaL
+GmdM9iDmZwuxZRSB1tpIGTT7mZJw8MAYY8gqyCBxtFGkuQELxjErHl2mIHo/Jej6
+8oGl7EVMQHiyXQ5H8aFIWu+HOAauX/V3HcaynMG06tFLApLNZ8DWaRcDg+XqZZ5U
+b14Dddmcj5/EtddCJYbobajXmQ98i8s0fpw=
 -----END CERTIFICATE-----
diff --git a/cluster/certs/kube-kubelet-bc01n02.hswaw.net.cert b/cluster/certs/kube-kubelet-bc01n02.hswaw.net.cert
index 919dcc2..22a1472 100644
--- a/cluster/certs/kube-kubelet-bc01n02.hswaw.net.cert
+++ b/cluster/certs/kube-kubelet-bc01n02.hswaw.net.cert
@@ -1,9 +1,9 @@
 -----BEGIN CERTIFICATE-----
-MIIFVjCCBD6gAwIBAgIUXvb9hqtoTXFM458nQblwXTSNeLAwDQYJKoZIhvcNAQEL
+MIIFVjCCBD6gAwIBAgIUcy5dWej8r/XrcG0CFLw1vsYbHMYwDQYJKoZIhvcNAQEL
 BQAwgYMxCzAJBgNVBAYTAlBMMRQwEgYDVQQIEwtNYXpvd2llY2tpZTEPMA0GA1UE
 BxMGV2Fyc2F3MRswGQYDVQQKExJXYXJzYXcgSGFja2Vyc3BhY2UxEzARBgNVBAsT
-CmNsdXN0ZXJjZmcxGzAZBgNVBAMTEmt1YmVybmV0ZXMgbWFpbiBDQTAeFw0yMDAz
-MjgxNjQ1MDBaFw0yMTAzMjgxNjQ1MDBaMIGFMQswCQYDVQQGEwJQTDEUMBIGA1UE
+CmNsdXN0ZXJjZmcxGzAZBgNVBAMTEmt1YmVybmV0ZXMgbWFpbiBDQTAeFw0yMTAz
+MjcxMTM3MDBaFw0yMjAzMjcxMTM3MDBaMIGFMQswCQYDVQQGEwJQTDEUMBIGA1UE
 CBMLTWF6b3dpZWNraWUxDzANBgNVBAcTBldhcnNhdzEVMBMGA1UEChMMc3lzdGVt
 Om5vZGVzMRAwDgYDVQQLEwdLdWJlbGV0MSYwJAYDVQQDEx1zeXN0ZW06bm9kZTpi
 YzAxbjAyLmhzd2F3Lm5ldDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB
@@ -22,10 +22,10 @@
 HRMBAf8EAjAAMB0GA1UdDgQWBBSnIgfLJiK7R+k9wfSCeKuqjpkYNjAfBgNVHSME
 GDAWgBSYMl0OTzMe+wnpiSQTFkJqgNGZ0DA7BgNVHREENDAyghFiYzAxbjAyLmhz
 d2F3Lm5ldIYdc3lzdGVtOm5vZGU6YmMwMW4wMi5oc3dhdy5uZXQwDQYJKoZIhvcN
-AQELBQADggEBAJ0HFPiLL+Opy04Zm3H5bRHOlUcPiSrRUi4QM8PnnrC0t9R1Wvlb
-PvuvAG2EI2rQsN9qi73riOW5KwUmvxe3ArpHH20uhUumBfyikK3nqnQW6XNBzirQ
-pv/2b0Pm9CCn71ETcCrUaenGaUjUhmY4Ojvbp4Ycc5LQ2E4PlsR11GnETM15CK7K
-0z1VUtiu1+XubS+1trYw5aUF3WQGitTDl4T8VCdQRUKeyygO1HMQwmJmRwuMMLrP
-MTbaNOQBD+c+QIzQDE/+yGPkItU2efBmNvsp6B54AHznEkUMrqJWzkt4SnJ2KbAu
-DtzSfnNpaGpluvOyh0NxHsCcUMlm9J8ajNk=
+AQELBQADggEBAJbbXs8GScqQRGJwyuhCOhfxZZytBUjsa1e+52wHBDPgzdetbXiK
+mzy/xp0Ll7Stbl9S3qqw9Cd3bcN5Y+PqxKPB9rjOICtf9Ah7ICL17U0gC97WEtSV
+jqfG1lyavcltufMRaWMDJUcPU7x2k+OpUJI4Z2OXD4RDVyaZ8iIU5l7ML/qn3uTH
+N2uVhQHjdbNqlZvl5Vw600rwnATIbv23kITuSxeqRS4I5qXsK0PpH192dUPCfPfe
+amHvib38cbvH929jGAmySDWOSSI8W0uSwvL3AAMYZG6l58G0xFMrfzZA0g356kyX
+0sG9E8tbZl+NMkEzD6+8IeVG4Gg3SCVrJ8E=
 -----END CERTIFICATE-----
diff --git a/cluster/certs/kube-kubelet-bc01n03.hswaw.net.cert b/cluster/certs/kube-kubelet-bc01n03.hswaw.net.cert
deleted file mode 100644
index 52a01c0..0000000
--- a/cluster/certs/kube-kubelet-bc01n03.hswaw.net.cert
+++ /dev/null
@@ -1,31 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIFVjCCBD6gAwIBAgIUbS3md+5hxDAJRfmGxv8lV5m21x0wDQYJKoZIhvcNAQEL
-BQAwgYMxCzAJBgNVBAYTAlBMMRQwEgYDVQQIEwtNYXpvd2llY2tpZTEPMA0GA1UE
-BxMGV2Fyc2F3MRswGQYDVQQKExJXYXJzYXcgSGFja2Vyc3BhY2UxEzARBgNVBAsT
-CmNsdXN0ZXJjZmcxGzAZBgNVBAMTEmt1YmVybmV0ZXMgbWFpbiBDQTAeFw0yMDAz
-MjgxNTE1MDBaFw0yMTAzMjgxNTE1MDBaMIGFMQswCQYDVQQGEwJQTDEUMBIGA1UE
-CBMLTWF6b3dpZWNraWUxDzANBgNVBAcTBldhcnNhdzEVMBMGA1UEChMMc3lzdGVt
-Om5vZGVzMRAwDgYDVQQLEwdLdWJlbGV0MSYwJAYDVQQDEx1zeXN0ZW06bm9kZTpi
-YzAxbjAzLmhzd2F3Lm5ldDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB
-AL39o8eEvKxuTomo/6bb1UyLyjqXHkhqCZOvAQjPTq+GnCikZZj/n2cbIMJ09duO
-sItQtOy7wUWH9gDnlgp8fW4zA+AubhtXITXGTVMlrXps3VWAA3ywxIT3LpeXOHdz
-RLRnSK1g5J5yB+Jid10/Fz8pVV7GTTUnkDVsglyWUkXNpuWJNGrjQacb3l0n0Dr4
-6BssLWSZl0id7Hq3VlFHjgvjGnUkPzYFnhMeS16oAI24diASmAVw3K3nYtQoLroV
-DDN32o7+lAlPMLjVHlCoXUts/lx4Ikm+iQ1JVj5JHgWccg+wjJdH+K+XYaizOcpg
-jsiXli4oxTV7zNxkj/9n75b6XTkeq+CfnYTNZE/iukdlBtZaH9/jCy+c5mZWNPwR
-z9dvkMSA1hrHjJJI70nz6NSsIufLiiBfuqE0JjQvJzvyCS/ioj3xfQI1fVRf1A1E
-Cr2R2T+AXWKPOqLZWtJ/8BY50xMPNZYRDPAuYCRAKoZ7EKr5YbEKzMgk9pMJMYaX
-wASmyBAxOQlfjUBs4nQpgL6XrJ8EQzkOsRJPtD+MjEG9JkSf71pzIIexlwj1NnYa
-/dPdIKaO6UBD3WMJjPhFozRgvmJdzRtH4oJ2p0NpMzTxzSOqh3yyfWQl+Gr3bxWr
-H0ShXe8QV2yvt0ISPzJjHNxG+pv79moribfs1gX5KUYpAgMBAAGjgb0wgbowDgYD
-VR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNV
-HRMBAf8EAjAAMB0GA1UdDgQWBBT1m3RgBiqGCDhqwxutcUg0f9nBzDAfBgNVHSME
-GDAWgBSYMl0OTzMe+wnpiSQTFkJqgNGZ0DA7BgNVHREENDAyghFiYzAxbjAzLmhz
-d2F3Lm5ldIYdc3lzdGVtOm5vZGU6YmMwMW4wMy5oc3dhdy5uZXQwDQYJKoZIhvcN
-AQELBQADggEBAFmt/mBuQHW0mfWNgc91OhNRUAL4Y23zFy1hpL4t0VNtGwEv51K1
-hTV7GlQHAcjE0Ti8Ivb9b+gU0FV6E1xFDsXg3w/unmZBhFMnKkwR/f8AIadgO/JT
-MgV4XvQgxXwVRetetXbr2uQV4Nz5cji9E2Rcad6NkN67FNpKratKR0+sPWCz9DYJ
-5mPlfmGBBW6ptAMGnekg0ttvup1a2FbCCxKpMnL+X4hv0a05Pgviwemm+uwckl/k
-zTqB7VDYtlS5SloRpHP4D3VxXU6j2vwkV7D/pEWKY5kXTHmBN2VDL+9mU03LB+aa
-NAeu2cme5Cu80BfzG+Eit7AD6hapm1WLmuM=
------END CERTIFICATE-----
diff --git a/cluster/certs/kube-proxy.cert b/cluster/certs/kube-proxy.cert
index c638345..11790c0 100644
--- a/cluster/certs/kube-proxy.cert
+++ b/cluster/certs/kube-proxy.cert
@@ -1,9 +1,9 @@
 -----BEGIN CERTIFICATE-----
-MIIFQzCCBCugAwIBAgIUNOcUBxeoeF2k8lsdrL+mqCe0O7swDQYJKoZIhvcNAQEL
+MIIFQzCCBCugAwIBAgIUAaW3eAYNLLYjQqg45/6XqRwBMGIwDQYJKoZIhvcNAQEL
 BQAwgYMxCzAJBgNVBAYTAlBMMRQwEgYDVQQIEwtNYXpvd2llY2tpZTEPMA0GA1UE
 BxMGV2Fyc2F3MRswGQYDVQQKExJXYXJzYXcgSGFja2Vyc3BhY2UxEzARBgNVBAsT
-CmNsdXN0ZXJjZmcxGzAZBgNVBAMTEmt1YmVybmV0ZXMgbWFpbiBDQTAeFw0yMDAz
-MjgxNTE1MDBaFw0yMTAzMjgxNTE1MDBaMIGRMQswCQYDVQQGEwJQTDEUMBIGA1UE
+CmNsdXN0ZXJjZmcxGzAZBgNVBAMTEmt1YmVybmV0ZXMgbWFpbiBDQTAeFw0yMTAz
+MjcxMTI3MDBaFw0yMjAzMjcxMTI3MDBaMIGRMQswCQYDVQQGEwJQTDEUMBIGA1UE
 CBMLTWF6b3dpZWNraWUxDzANBgNVBAcTBldhcnNhdzEaMBgGA1UEChMRc3lzdGVt
 Omt1YmUtcHJveHkxIzAhBgNVBAsTGkt1YmVybmV0ZXMgQ29tcG9uZW50IHByb3h5
 MRowGAYDVQQDExFzeXN0ZW06a3ViZS1wcm94eTCCAiIwDQYJKoZIhvcNAQEBBQAD
@@ -21,11 +21,11 @@
 AAGjgZ4wgZswDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggr
 BgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBTn0MVsvuVE2ZiSJNZfEp6Q
 pb8u9jAfBgNVHSMEGDAWgBSYMl0OTzMe+wnpiSQTFkJqgNGZ0DAcBgNVHREEFTAT
-hhFzeXN0ZW06a3ViZS1wcm94eTANBgkqhkiG9w0BAQsFAAOCAQEAa+LkfAbWHUSs
-19veJ09P0uo6PYKqXsOrh9soWX8lusI3Zt3zhTdSXkzJwKi8bH3zFx8niWAIHNwZ
-mxesvJIH6fPA0/401MkjhSRo3cyMUnjKmjx5+DD2qIEKKBPsr/xNMpJGPKaDjGtk
-YyRHW8Bg7kX+Jc/uv7Gg6U+/xtdbELaxL/USufRN7obC7gNtenXkdOUgINrfllX/
-66+K7yqaAqaCR4gEGSLUnUvkbFZ/+XB7Z1tLKgWurJj5v82ZxnkBI+aU3tVwLtoT
-tnH7OLi5Tbo+RYuf3iMd1vGxVwEPcD9cBUz0lRsK9TTJxRytS8CnS3EIwcitYo86
-+yl7LltiSA==
+hhFzeXN0ZW06a3ViZS1wcm94eTANBgkqhkiG9w0BAQsFAAOCAQEAk1cL0SzdLP2E
+KhV6VNpjGT1/V1u31V6SXueucesstPubEFDUrlGeDeaww8dJXBx694jpGKXBvD/F
+kskLsOTABlK2h/CuXHoWImSZxUmTHOEZLB1u1coAUfy/C1pegg1OklW3judbbQQM
+4mArJh+JNXR6SW3J9Q9HKmgBUV2O5C8PuxMyB51zWkA2ZMLIXtNv4OSjrVRoyc57
+URopH5ZBucq+T+GzmEQB4Xgs39fpvWX+6rqB49TcfF3jqTVGJD38nkVUnfj06Tl6
+VGN2GZiec5/dmVKCqdqFefezQVXjEooA4TwXr+l4xtQECTMapSHBPdHnFavY5PDY
+G53Txq4iBA==
 -----END CERTIFICATE-----
diff --git a/cluster/certs/kube-scheduler.cert b/cluster/certs/kube-scheduler.cert
index abdf6a4..db6c585 100644
--- a/cluster/certs/kube-scheduler.cert
+++ b/cluster/certs/kube-scheduler.cert
@@ -1,9 +1,9 @@
 -----BEGIN CERTIFICATE-----
-MIIFUzCCBDugAwIBAgIUSlMSojfxDUiCtKO/7Mr5kJbxBxQwDQYJKoZIhvcNAQEL
+MIIFUzCCBDugAwIBAgIUENQVIR+6ek6Sv86i+ELInvCc6GAwDQYJKoZIhvcNAQEL
 BQAwgYMxCzAJBgNVBAYTAlBMMRQwEgYDVQQIEwtNYXpvd2llY2tpZTEPMA0GA1UE
 BxMGV2Fyc2F3MRswGQYDVQQKExJXYXJzYXcgSGFja2Vyc3BhY2UxEzARBgNVBAsT
-CmNsdXN0ZXJjZmcxGzAZBgNVBAMTEmt1YmVybmV0ZXMgbWFpbiBDQTAeFw0yMDAz
-MjgxNTE1MDBaFw0yMTAzMjgxNTE1MDBaMIGdMQswCQYDVQQGEwJQTDEUMBIGA1UE
+CmNsdXN0ZXJjZmcxGzAZBgNVBAMTEmt1YmVybmV0ZXMgbWFpbiBDQTAeFw0yMTAz
+MjcxMTI3MDBaFw0yMjAzMjcxMTI3MDBaMIGdMQswCQYDVQQGEwJQTDEUMBIGA1UE
 CBMLTWF6b3dpZWNraWUxDzANBgNVBAcTBldhcnNhdzEeMBwGA1UEChMVc3lzdGVt
 Omt1YmUtc2NoZWR1bGVyMScwJQYDVQQLEx5LdWJlcm5ldGVzIENvbXBvbmVudCBz
 Y2hlZHVsZXIxHjAcBgNVBAMTFXN5c3RlbTprdWJlLXNjaGVkdWxlcjCCAiIwDQYJ
@@ -22,10 +22,10 @@
 CCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBQw8PPX
 ExubjWf7o/eChtV5jnt1kTAfBgNVHSMEGDAWgBSYMl0OTzMe+wnpiSQTFkJqgNGZ
 0DAgBgNVHREEGTAXhhVzeXN0ZW06a3ViZS1zY2hlZHVsZXIwDQYJKoZIhvcNAQEL
-BQADggEBABw3aqj8FQtaZKHHzGY+cpjvOT1VUKax1k0iQAbYS5/8d3kaToDed05M
-omXDcIxb3VHs6+sWxJYWAiRPiA5mrDdA7XQcfIv1xtP+DL3dbRqhz276XNM4/NIj
-vt9aQox/WSE0HCDTUSN/clYbB6tigLfSxXhnuz214N6NwkcTl8xQVvXxg3z6ryc7
-XUTEA0fvl/fe+KsO2l4kxBk9Ef5cud3j2e4F4l8tFHz1bRXfcEEcS5uLLgK3KIAu
-sf3Sf+t/jcTTrJ+3YVFBAY+F7AN4UjNdlAfyvTG7xB+pxD7RlEd6Ycozd0tYppg4
-VBbXtQ4TOxHLVvrlANi3MJAzYSUuB54=
+BQADggEBAF2/ClyjH45S5oscrhLFWMcv9sVvS9M9FanBFibipUw3HyLvpjorl1fo
+nLvrAxIUHgtDsjkS5lWh4f/LAO8ju1DJA1L5vC4zEMXuWPMcbRCBrx/7q/kQY9yB
+apHlm1oKXQQ6/8Icz0rJZsEfVpqWoQMKRefRZKEYQa2KdvCEqyBHvUjLRG+hLzgH
+5O00AfUoT89DiLQfqXCcYi5GR7ulyrCbw/SlPaFFAglbT7uVLZLC8amcYAEMDb1t
+xvWdTil4opXnI8YQwr4ZopcByqaEomgfILbHrbW4kdEW7Lel+imbjo/lJ0CN+6Ra
+yOYeaOSBmCknhdEzpuuue4f6xJJx+SY=
 -----END CERTIFICATE-----
diff --git a/cluster/certs/kube-serviceaccounts.cert b/cluster/certs/kube-serviceaccounts.cert
index 7ba5a5f..b572b1b 100644
--- a/cluster/certs/kube-serviceaccounts.cert
+++ b/cluster/certs/kube-serviceaccounts.cert
@@ -1,9 +1,9 @@
 -----BEGIN CERTIFICATE-----
-MIIFKjCCBBKgAwIBAgIUC8G46cdD+fUIfepfl2RRtz7D5FgwDQYJKoZIhvcNAQEL
+MIIFKjCCBBKgAwIBAgIUXRB0XNQ/Tdv1fPq8iQTbrkHH1q0wDQYJKoZIhvcNAQEL
 BQAwgYMxCzAJBgNVBAYTAlBMMRQwEgYDVQQIEwtNYXpvd2llY2tpZTEPMA0GA1UE
 BxMGV2Fyc2F3MRswGQYDVQQKExJXYXJzYXcgSGFja2Vyc3BhY2UxEzARBgNVBAsT
-CmNsdXN0ZXJjZmcxGzAZBgNVBAMTEmt1YmVybmV0ZXMgbWFpbiBDQTAeFw0yMDAz
-MjgxNTE1MDBaFw0yMTAzMjgxNTE1MDBaMHsxCzAJBgNVBAYTAlBMMRQwEgYDVQQI
+CmNsdXN0ZXJjZmcxGzAZBgNVBAMTEmt1YmVybmV0ZXMgbWFpbiBDQTAeFw0yMTAz
+MjcxMTI3MDBaFw0yMjAzMjcxMTI3MDBaMHsxCzAJBgNVBAYTAlBMMRQwEgYDVQQI
 EwtNYXpvd2llY2tpZTEPMA0GA1UEBxMGV2Fyc2F3MSswKQYDVQQLEyJLdWJlcm5l
 dGVzIFNlcnZpY2UgQWNjb3VudHMgU2lnbmVyMRgwFgYDVQQDEw9zZXJ2aWNlYWNj
 b3VudHMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDFSCquXVjQANUN
@@ -21,10 +21,10 @@
 oDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAd
 BgNVHQ4EFgQUliCshdOww6BLgNw1Cu+0XiqCpg8wHwYDVR0jBBgwFoAUmDJdDk8z
 HvsJ6YkkExZCaoDRmdAwGgYDVR0RBBMwEYIPc2VydmljZWFjY291bnRzMA0GCSqG
-SIb3DQEBCwUAA4IBAQB7xM6vfvk3dw9cFP0F2YTAxLVot1E+KzHWz952uIm3CrtU
-Vq3WHBX3NRTVrzg3Ycx4tNniOHBqNrzgksz0XmFZw7VyiY+yEzueVCJ9HU9y8Kb2
-XdL5zqTtgVYspr0dI/34NbGnFVJAOJ57fAc4LxhPwAZMG6s4LwDiBDYIBw+KoJsD
-FOiHJ+AfW5taGONEGY+HuNnSo+RllCgFdjPW0hK4X8Jt4p5Qr+oICO4Nzp4jZwv0
-WqxHzmX4DYDQLztqrQelSDkaQaP/xAhq7nsaK91sMob1OqQcYSMckm2SFEmTwBCs
-VpJg24y/LRw1LPK4lE7GGGIkyko+aDCsIm+YDX7U
+SIb3DQEBCwUAA4IBAQAUVM1a6fB91WStX1xqKBfujxfWba3od5EaHQsKzXqsY6F3
+C87ush2JdJ/4Tq/D6xqcaOY7MUOSuL8LLlBafErbfjfVEKpG1muYwignYn0B0376
+nq9knFNYGQsNP3DwVqoFq/7hoQiyF/aBndL5gTAdoj/C30pIjG/wi8MlLsuX5h0n
+Qip3Fq6kjb6GY49Yo2Z9AchPIYotuubJEOwMLXqo48uWR2FOBrrDNSJtFIm6wcn3
+B2sjpApxv+p+lD0tApHSMbrJhijqAv5MOG6p3zIL62QM+zwBK4dtsOAeYX/cEE24
+tb56uVqXXoCICv2+TyO5NCJRP98ML+/WdHxlYvIw
 -----END CERTIFICATE-----
diff --git a/cluster/certs/kubefront-apiserver.cert b/cluster/certs/kubefront-apiserver.cert
index 409beb3..c7e90a1 100644
--- a/cluster/certs/kubefront-apiserver.cert
+++ b/cluster/certs/kubefront-apiserver.cert
@@ -1,9 +1,9 @@
 -----BEGIN CERTIFICATE-----
-MIIFEzCCA/ugAwIBAgIURk8WW4qapypnrPH9a2aMG+oMUpgwDQYJKoZIhvcNAQEL
+MIIFEzCCA/ugAwIBAgIUMFLqy/yR+qaJxJmqesPU+M+xVKwwDQYJKoZIhvcNAQEL
 BQAwgYcxCzAJBgNVBAYTAlBMMRQwEgYDVQQIEwtNYXpvd2llY2tpZTEPMA0GA1UE
 BxMGV2Fyc2F3MRswGQYDVQQKExJXYXJzYXcgSGFja2Vyc3BhY2UxEzARBgNVBAsT
 CmNsdXN0ZXJjZmcxHzAdBgNVBAMTFmt1YmVybmV0ZXMgZnJvbnRlbmQgQ0EwHhcN
-MjAwMzI4MTUxNTAwWhcNMjEwMzI4MTUxNTAwWjBmMQswCQYDVQQGEwJQTDEUMBIG
+MjEwMzI3MTEyNzAwWhcNMjIwMzI3MTEyNzAwWjBmMQswCQYDVQQGEwJQTDEUMBIG
 A1UECBMLTWF6b3dpZWNraWUxDzANBgNVBAcTBldhcnNhdzEcMBoGA1UECxMTS3Vi
 ZXJuZXRlcyBGcm9udGVuZDESMBAGA1UEAxMJYXBpc2VydmVyMIICIjANBgkqhkiG
 9w0BAQEFAAOCAg8AMIICCgKCAgEAuVXNUv1oJrLw9XxagSTyHegDeHT71JSdeYWx
@@ -20,11 +20,11 @@
 /xZzYekCAwEAAaOBljCBkzAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYB
 BQUHAwEGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFKkQFBbQv3W0
 jUMCdTBkmb0YlS7DMB8GA1UdIwQYMBaAFI+XbXEIcmDLzHcqyvkE9KRqvCX0MBQG
-A1UdEQQNMAuCCWFwaXNlcnZlcjANBgkqhkiG9w0BAQsFAAOCAQEAGI6MmkpsH4Ur
-mU20a8EmXkaGK9pD4hvbnsFsnzR0CjE8KHmDWIKlkg6RJZlnZnsd4UmnJTbnpM6A
-IkOycdwXsD8QrWwOMOqT3mIw4OYZqog4WqXcXlpeQwDmzC5mqEPWmy/Vr0CCIzFF
-Cx2ElcoIBQ46o9hm4Lx91uyWqDFRsBLleE+rgr9nCqesG4kYylT4Tb21l+YGQqtC
-v1mpXD7jaoyVVGpm28zUE2v/bGZsBfmd5cC9MVvyVrlhL4soI1UCO5aP/n/DxY0a
-iJ3UvlNnUbFuo0GUalbIwlTlVK/l6o6XRPINGbxTPEaueDLPKIqvvF+ZZBDMx7Hl
-k3IBIbEW8A==
+A1UdEQQNMAuCCWFwaXNlcnZlcjANBgkqhkiG9w0BAQsFAAOCAQEAaYm8tzCnm2BW
+IijcvHFnEmubdsYXYanIUzI60zQaUQueke9RhM/fJzO0Sga5tCHArU4diQgmimu3
+qtO+WUNNlxWw40XP7ZvxjYZZDCdYa+1fwdpcim8OtQjpIiwMe9rZ1tT6HRBCav3R
+jCzEQo0MrB8rSiwltSKRJRFc+zirmAhFwcD4zhZtc8tEiruG7HD5f7tdzFk1byY9
+R53Uug6iDvg0iyjBiPZ2R9JqUQ22ip1aa0Oymd8yLXjeNsN+F+sOD+R6m14feUyt
+jRYnfe0vvU70ct8gUAgVsHxkAqruca44SX5cY8djcKn4GHtwDa98rKJffBb4jnXA
+I36kVU5YmQ==
 -----END CERTIFICATE-----
diff --git a/cluster/kube/k0.libsonnet b/cluster/kube/k0.libsonnet
index 84863d7..57d39d0 100644
--- a/cluster/kube/k0.libsonnet
+++ b/cluster/kube/k0.libsonnet
@@ -83,6 +83,7 @@
                 herpDev: k0.cockroach.waw2.Client("herp-dev"),
                 gitea: k0.cockroach.waw2.Client("gitea"),
                 issues: k0.cockroach.waw2.Client("issues"),
+                dns: k0.cockroach.waw2.Client("dns"),
             },
         },
 
@@ -355,6 +356,7 @@
                         { namespace: "gerrit", dns: "gerrit.hackerspace.pl" },
                         { namespace: "gitea-prod", dns: "gitea.hackerspace.pl" },
                         { namespace: "hswaw-prod", dns: "*.hackerspace.pl" },
+                        { namespace: "hswaw-prod", dns: "*.hswaw.net" },
                         { namespace: "internet", dns: "internet.hackerspace.pl" },
                         { namespace: "matrix", dns: "matrix.hackerspace.pl" },
                         { namespace: "onlyoffice-prod", dns: "office.hackerspace.pl" },
diff --git a/cluster/kube/lib/cockroachdb.libsonnet b/cluster/kube/lib/cockroachdb.libsonnet
index 9f206f0..2486570 100644
--- a/cluster/kube/lib/cockroachdb.libsonnet
+++ b/cluster/kube/lib/cockroachdb.libsonnet
@@ -334,7 +334,7 @@
                                 command: [
                                     "/bin/bash",
                                     "-ecx",
-                                    "/cockroach/cockroach init --host=%s.cluster.local:%d" % [cluster.servers[0].service.host, cluster.cfg.portServe],
+                                    "/cockroach/cockroach init --host=%s.cluster.local:%d || true" % [cluster.servers[0].service.host, cluster.cfg.portServe],
                                 ],
                                 volumeMounts: [
                                     {
diff --git a/cluster/secrets/cipher/etcd-bc01n03.hswaw.net.key b/cluster/secrets/cipher/etcd-bc01n03.hswaw.net.key
deleted file mode 100644
index 84be5a5..0000000
--- a/cluster/secrets/cipher/etcd-bc01n03.hswaw.net.key
+++ /dev/null
@@ -1,91 +0,0 @@
------BEGIN PGP MESSAGE-----
-
-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
-=sxdX
------END PGP MESSAGE-----
diff --git a/cluster/secrets/cipher/etcdpeer-bc01n03.hswaw.net.key b/cluster/secrets/cipher/etcdpeer-bc01n03.hswaw.net.key
deleted file mode 100644
index fb0ef5b..0000000
--- a/cluster/secrets/cipher/etcdpeer-bc01n03.hswaw.net.key
+++ /dev/null
@@ -1,91 +0,0 @@
------BEGIN PGP MESSAGE-----
-
-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
-=KgJ/
------END PGP MESSAGE-----
diff --git a/cluster/secrets/cipher/kube-kubelet-bc01n03.hswaw.net.key b/cluster/secrets/cipher/kube-kubelet-bc01n03.hswaw.net.key
deleted file mode 100644
index 936ecc4..0000000
--- a/cluster/secrets/cipher/kube-kubelet-bc01n03.hswaw.net.key
+++ /dev/null
@@ -1,91 +0,0 @@
------BEGIN PGP MESSAGE-----
-
-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
-=Q5eO
------END PGP MESSAGE-----
diff --git a/dc/hbj11/flasher/README.md b/dc/hbj11/flasher/README.md
index b6a69e7..ae9f8b5 100644
--- a/dc/hbj11/flasher/README.md
+++ b/dc/hbj11/flasher/README.md
@@ -15,6 +15,6 @@
 The Web Interface (WebI2C)
 ---------------------------
 
-A WebUSB-based flashing tool that will run under any Chromium-based browser (eg. Chrome, Edge. See [web](web/) for more information and a link to a publicly available instance.
+A WebUSB-based flashing tool that will run under any Chromium-based browser (eg. Chrome, Edge. See [web](web/) for more information or [start WebI2C now](web/index.html).
 
 ![](../doc/webi2c.png)
diff --git a/dc/hbj11/flasher/bluepill/src/i2c.rs b/dc/hbj11/flasher/bluepill/src/i2c.rs
index 35f52d6..c66a133 100644
--- a/dc/hbj11/flasher/bluepill/src/i2c.rs
+++ b/dc/hbj11/flasher/bluepill/src/i2c.rs
@@ -157,7 +157,7 @@
 impl<'a, B: UsbBus, LED: OutputPin> UsbClass<B> for I2CClass<'a, B, LED> {
     fn reset(&mut self) {
         self.expect_bulk_out = false;
-        self.status = Status::OK,
+        self.status = Status::OK;
     }
 
     fn control_in(&mut self, xfer: ControlIn<B>) {
diff --git a/dc/hbj11/flasher/bluepill/src/main.rs b/dc/hbj11/flasher/bluepill/src/main.rs
index da6cefd..45279c2 100644
--- a/dc/hbj11/flasher/bluepill/src/main.rs
+++ b/dc/hbj11/flasher/bluepill/src/main.rs
@@ -23,8 +23,9 @@
 mod i2c;
 mod print;
 
-/// The main RTIC application object. See RTIC documentation for more information about how to read
-/// this.
+// The main RTIC application object. See RTIC documentation for more information about how to read
+// this.
+
 #[app(device = stm32f1xx_hal::stm32, peripherals = true)]
 const APP: () = {
     struct Resources {
diff --git a/dc/hbj11/flasher/web/README.md b/dc/hbj11/flasher/web/README.md
index 7301255..e9f34be 100644
--- a/dc/hbj11/flasher/web/README.md
+++ b/dc/hbj11/flasher/web/README.md
@@ -6,13 +6,13 @@
 Usage
 -----
 
-TODO(q3k): host public instance
+[Start WebI2C](index.html). This should work on any browser with WebUSB (eg. Chrome, Chromium, Edge).
 
 Development
 -----------
 
-Plain javascript, bring a static file server, eg. Python's builtin one:
+Plain javascript, bring a static file server, or use hackdoc:
 
-    $ cd hscloud/dc/hjb11/flasher/web/
-    $ python3 -m http.server
+    bazel run //devtools/hackdoc  -- -hspki_disable -docroot ~/hscloud
 
+And visit http://127.0.0.1:8080/dc/hbj11/flasher/web/index.html in your web browser.
diff --git a/dc/hbj11/flasher/web/fru.js b/dc/hbj11/flasher/web/fru.js
index a06fec9..0924418 100644
--- a/dc/hbj11/flasher/web/fru.js
+++ b/dc/hbj11/flasher/web/fru.js
@@ -246,9 +246,14 @@
             0x01, // Version 1
             0x09, // Length (9*8 == 72 bytes)
             0x00, 0x00, 0x00, 0x00, // Manufacturing time (unspecified)
-            0xC7, 98, 103, 112, 46, 119, 116, 102, // Manufacturer: bgp.wtf
-            0xDE, 83, 65, 84, 65, 32, 82, 101, 112, 101, 97, 116, 101, 114, // Product name: SATA Repeater
-            32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, // ... pad above to 30 chars.
+            // Manufacturer: HELL (we can't use anything longer, as the product
+            // name below needs to be in this exact byte offset in the ROM for
+            // the iDRAC to display the name correctly).
+            0x83, 0x68, 0xc9, 0xb2,
+
+            // Product name: bgpwtf SATA Repeater
+            0xDE, 98, 103, 112, 119, 116, 102, 32, 83, 65, 84, 65, 32, 82, 101, 112, 101, 97, 116, 101, 114,
+            32, 32, 32, 32, 32, 32, 32, 32, 32, 32, // ... pad above to 30 chars.
         ];
         // Serial number tag/length.
         board.push(0xC0 | (this.serial.length));
diff --git a/devtools/hackdoc/markdown.go b/devtools/hackdoc/markdown.go
index 8923545..a6f206d 100644
--- a/devtools/hackdoc/markdown.go
+++ b/devtools/hackdoc/markdown.go
@@ -151,7 +151,14 @@
 	}
 
 	// Just serve the file.
-	mime := mimetype.Detect(data)
-	r.w.Header().Set("Content-Type", mime.String())
+	var mime string
+	if strings.HasSuffix(path, ".js") {
+		// Force .js to always be the correct MIME type.
+		mime = "text/javascript"
+	} else {
+		// Otherwise, use magic to detect type.
+		mime = mimetype.Detect(data).String()
+	}
+	r.w.Header().Set("Content-Type", mime)
 	r.w.Write(data)
 }
diff --git a/devtools/kube/hackdoc.libsonnet b/devtools/kube/hackdoc.libsonnet
index 93b01bc..4fd7ad6 100644
--- a/devtools/kube/hackdoc.libsonnet
+++ b/devtools/kube/hackdoc.libsonnet
@@ -3,7 +3,7 @@
 
 {
     cfg:: {
-        image: "registry.k0.hswaw.net/q3k/hackdoc:315532800-a415ced850425a195f96b331f57cd78f15e622d9",
+        image: "registry.k0.hswaw.net/q3k/hackdoc:315532800-f4d02581f60b18a8635d026079ed67039cdc45e6",
         publicFQDN: error "public FQDN must be set",
     },
 
diff --git a/doc/codelabs/getting-started/checking-out.md b/doc/codelabs/getting-started/checking-out.md
new file mode 100644
index 0000000..1e3a8c6
--- /dev/null
+++ b/doc/codelabs/getting-started/checking-out.md
@@ -0,0 +1,110 @@
+Checking out hscloud
+====================
+
+This codelab will introduce you to the basics of working with hscloud - including what it it, how to use it, and what next steps can you take afterwards. **It's strongly recommended for everyone who wants to interact with hscloud, k0, or any of the 'new style' Warsaw Hackerspace infrastructure**.
+
+By the end, you'll have a hscloud checkout and general understanding of what's where and what tools are available to interact with hscloud.
+
+[TOC]
+
+Background
+----------
+
+Welcome to **hscloud**! This is a repository of code and set of infrastructure born around the Warsaw Hackerspace. It started off as a monorepo for infrastructure-as-code for a set of cloud-like infrastructure at the hackerspace, but has since grown to accumulate a bunch of semi-related code: everything from Nix machine definitions to game servers.
+
+What do I use it for?
+---------------------
+
+If you've been pointed towards hscloud, it's probably due to one of the below reasons:
+
+ - You want to deploy something for the Hackerspace
+ - You want to fix/patch some software already running
+ - You want to run some of your personal projects on our compute cluster
+
+All of these are first-class functionality within **hscloud**, and they should be as straightforward to use as possible. If anything doesn't make immediate sense, or you are confused by something that seems unclear - contact q3k and he will make sure to help you out and update the documentation so that the next person doesn't have this issue.
+
+This documentation, by the way, is also kept within hscloud!
+
+What is hackdoc?
+----------------
+
+If you're viewing this on [https://hackdoc.hackerspace.pl/doc/codelabs/getting-started/checking-out.md](https://hackdoc.hackerspace.pl/doc/codelabs/getting-started/checking-out.md) - you're using [Hackdoc](/devtools/hackdoc)! Hackdoc renders some of the code within hscloud as more prose-oriented documentation, like these codelabs. Somewhere on the right hand side of this page you should be able to click a *View Source* button to see what document this was rendered from.
+
+You could instead also be reading this from [cs.hackerspace.pl, our code browser view](https://cs.hackerspace.pl/hscloud) or [gerrit.hackerspace.pl, our code review tool](https://gerrit.hackerspace.pl). Both of these will show you the same content as the hackdoc view, but less richly rendered and linked. We highly recommend viewing this via Hackdoc as linked above for the best possible experience.
+
+Local requirements & Git clone
+==============================
+
+First, you need to make a local clone of hscloud on your development machine - ie., the computer/laptop you want to work on. We support generic glibc-based Linux distributions (eg. Ubuntu, Debian, Fedora), NixOS and to a certain degree, macOS.
+
+Unless you're running something different from the above, we **highly recommend not working on hscloud from within a container or VM**, as our build system already takes care of hermetic builds and reproducibility - and containers/VMs will only get in the way.
+
+Once you've found a machine and `cd`'d to a directory where you want to clone hscloud, do the following:
+
+    $ git clone https://gerrit.hackerspace.pl/hscloud.git
+    [...]
+    $ cd hscloud
+    $ head -n 4 doc/codelabs/getting-started/checking-out.md
+
+and you should see the source for this document, proving that you've succesfully gotten hold of a copy of hscloud.
+
+Code organization
+-----------------
+
+**hscloud is a branchless monorepo**. If you've never worked with such a setup before, you might find it slightly odd and coutnerintuitive. Here's what we mean by branchless monorepo:
+
+  - There is only a single branch we work on: `master`. Any time you want to introduce a change to hscloud, you always start off `master` at the newest possible HEAD, add some changes on top, and then get these reviewed and merged. We do not do feature branches, release trains, or release versions.
+  - There are no personal branches. Instead, if you want to commit some stuff for personal/experimental use, just drop it into a `//personal/$your-username`, and you will be able to land things there without review.
+  - There is a single repository. All projects and code lives within hscloud. This allows you to make a single change that alters, for examplle, client and server side code of an application simultaneously, without having to coordinate this change across multiple repositories.
+
+What's up with `//these/paths`?
+-------------------------------
+
+These paths, sometimes called *depot paths*, are a convention to refer to paths within hscloud. For example, `//foo/bar` means a file or directory named `bar` within a directory named `foo` in the root of the hscloud repository.
+
+These paths are notably used by Bazel, our build system, which extends the syntax slightly: `//foo/bar:baz` means a file or *build target* named baz within a directory bar within a diredctory foo inside hscloud.
+
+What are changes?
+-----------------
+
+Changes, or Change Requests, or Change Lists (all used interchangably) are modifications to the hscloud repository. Each change corresponds to a single Git commit that has been reviewed on [gerrit, our code review tool](https://gerrit.hackerspace.pl). Each change can be identified by:
+
+ - The git commit hash when it got merged into `master` (eg. `146c99e58e46f3c026e170794326521de6bf13e1`)
+ - The ChangeId hash within the git commit message (eg. `I8b64103cb87d8b185ff35165695a18cb19fea523`)
+ - The Change number on gerrit (eg. [https://gerrit.hackerspace.pl/841](https://gerrit.hackerspace.pl/841))
+
+Going from Change number to git commit hash or ChangeId is easy - gerrit will show these to you when you visit the page for any given Change number. Going the otherway is currently not super intuitive - you have to use Gerrit's web interface to search for either git commit hash or ChangeId.
+
+Viewing hscloud online
+----------------------
+
+We have a **code search** tool/web interface available on [https://cs.hackerspace.pl/hscloud](https://cs.hackerspace.pl/hscloud), which is probably the most convenient way to browse hscloud online, and link it to others. Gerrit also has its own built-in code viewer (Gitiles), but its use is being phased out.
+
+So what's in hscloud? Where do I start?
+---------------------------------------
+
+If you want to modify something, you'll first have to figure out where is it in hscloud. For that, either use codesearch, or ask any of the people who work on hscloud for guidance. There is also a somewhat up-to-date directory of interesting top-level things at [//README.md](/README.md).
+
+Once you have that, look at other [codelabs](../) for guidance on working with specific technologies within hscloud. If something's missing - ask someone knowledgeable to either document it, or help you document it!
+
+Where do we report and track issues?
+------------------------------------
+
+We have an issue tracker at [https://issues.hackerspace.pl/](https://issues.hackerspace.pl/). It's a Redmine instance so it's not super friendly, so we made some shorthand links:
+
+ - [https://b.hswaw.net](https://b.hswaw.net) will take you to a page with you personal dashboard.
+ - [https://b.hswaw.net/123](https://b.hswaw.net/123) will take you to issue number 123.
+ - [https://b.hswaw.net/new](https://b.hswaw.net/new) will take you to a page to file a new issue.
+
+**File issues often, file issues early, ask for forgiveness later!** It's much easier to keep track of things on there than to chat up people. Don't worry about categorizing, and feel free to assign q3k for anything.
+
+You can naturally also ask on #members:hackerspace.pl or even #general:hackerspace.pl - but if you encounter an problem, we highly recommend filing issues instead of chatting people up :).
+
+Further steps
+=============
+
+Now that you have a local hscloud checkout and mostly know why it exists and how it's laid out, there's a few next steps you can take:
+
+ - [Your first hscloud Change](your-first-change.md) will guide you through using Gerrit to send your first contribution to hscloud - a small file change in your personal directory.
+ - **TODO** will guide you through building some code using Bazel, and then writing a tiny bit of Go code of your own.
+ - **TODO** will guide you through accessing our production Kubernetes cluster and running some code on it.
diff --git a/doc/codelabs/getting-started/your-first-change.md b/doc/codelabs/getting-started/your-first-change.md
index 93990d0..d0b6fad 100644
--- a/doc/codelabs/getting-started/your-first-change.md
+++ b/doc/codelabs/getting-started/your-first-change.md
@@ -8,9 +8,7 @@
 Prerequisites
 -------------
 
-hscloud is a git repository. If you're new to git, this might be slightly confusing to you, but you should still be able to follow along. In case you need brush up on that, links to relevant resources await you at the bottom of this document.
-
-As for software, you'll need to have git installed on your workstation.
+**Required**: [Checking out hscloud](checking-out.md) to understand the basics of the hscloud code structure.
 
 Gerrit concepts
 ---------------
@@ -65,10 +63,19 @@
 
 Note that you should be using your Warsaw Hackerspace SSO user name. If that's different from your local workstation username, you'll have to specify `user@gerrit.hackerspace.pl` in all the following commands.
 
-Cloning hscloud and looking around
-----------------------------------
+Connecting your hscloud checkout to Gerrit
+------------------------------------------
 
-Now, clone hscloud and take a look around:
+If you've come here from the [Checking out hscloud](checking-out.md) codelab, you probably already have a read-only hscloud checkout over HTTPS. If so, you will have to switch its remote to access Gerrit through your SSH key:
+
+    $ cd hscloud
+    $ git remote remove origin
+    $ # If your local username is the same as your SSO username:
+    $ git remote add origin gerrit.hackerspace.pl:hscloud
+    $ # Otherwise, you'll have to specify your SSO username explicitly:
+    $ git remote add origin user@gerrit.hackerspace.pl:hscloud
+
+Or, **if you don't have a hscloud checkout on hand**, just clone it from scratch using the authenticated Gerrit endpoint:
 
     $ git clone gerrit.hackerspace.pl:hscloud
     Cloning into 'hscloud'...
@@ -78,20 +85,11 @@
     Receiving objects: 100% (5469/5469), 15.25 MiB | 14.08 MiB/s, done.
     Resolving deltas: 100% (2686/2686), done.
     $ cd hscloud
-    $ ls
-    app  bgpwtf  BUILD  bzl  cluster  COPYING  dc  devtools  doc  env.fish  env.sh  gcp  go  hackdoc.toml  hswaw  kube  OWNERS  personal  README.md  third_party  tools  WORKSPACE
-    $
-
-If you've already cloned hscloud before (eg. over https), either clone it again or update your origin to point at `user@gerrit.hackerspace.pl:hscloud`.
-
-You can also use Gitiles (a part of Gerrit) to view hscloud in your web browser: https://gerrit.hackerspace.pl/plugins/gitiles/hscloud/+/refs/heads/master
-
-Any time you see a `//path/written/like/this`, `//` refers to the root of the hscloud checkout. For example, `//devtools/gerrit` contains all code related to our Gerrit instance. If you want to learn more about hscloud's directory structure, start at [//README.md](/README.md).
 
 Configuring git for Gerrit
 --------------------------
 
-There's just a bit more of one-time setup that you'll need to do in order to send changes to Gerrit:
+You now have hscloud cloned from an authenticated Gerrit endpoint. Gerrit knows it's you trying to access (and/or write) code. However, there's just a bit more of one-time setup that you'll need to do in order to send changes to Gerrit:
 
     $ git config user.email 'user@hackerspace.pl' # replace user with your SSO login name
     $ curl -Lo .git/hooks/commit-msg https://gerrit.hackerspace.pl/tools/hooks/commit-msg
@@ -190,6 +188,6 @@
 -------------
 
  - If you need a **Git refresher** - we highly recommend the [Git Visual Reference](https://marklodato.github.io/visual-git-guide/index-en.html)
- - While this codelab showed you how to create and submit CRs, you didn't see anything about code review. Watch this space for a codelab about that.
- - You should now be able to commit and change code. Watch this space for a link to a codelab on using Bazel or writing a simple microservice in Go.
+ - **TODO** will guide you through building some code using Bazel, and then writing a tiny bit of Go code of your own.
+ - **TODO** will guide you through accessing our production Kubernetes cluster and running some code on it.
 
diff --git a/doc/codelabs/index.md b/doc/codelabs/index.md
index 790447f..1d6dea5 100644
--- a/doc/codelabs/index.md
+++ b/doc/codelabs/index.md
@@ -8,4 +8,5 @@
 Getting started
 ---------------
 
+- [**Checking out hscloud**](getting-started/checking-out.md) - how to get a copy of hscloud, how to navigate around it, and what's what. This is nearly **mandatory** for anyone who wishes to interact with hscloud.
 - [**Your First Change**](getting-started/your-first-change.md) - how to use Gerrit and git to send your first change to hscloud, and an intro to personal directories. Using Gerrit can be somewhat confusing even (or especially) if you're used to Gitflow or GitHub.
diff --git a/ops/machines.nix b/ops/machines.nix
index 03cd541..0e63228 100644
--- a/ops/machines.nix
+++ b/ops/machines.nix
@@ -11,7 +11,10 @@
 # To then deploy derivation $d on $machine:
 #
 #    nix-copy-closure --to root@$machine $d
-#    ssh root@$machine $d/bin/switch-to-configuration
+#    ssh root@$machine $d/bin/switch-to-configuration dry-activate
+#    ssh root@$machine $d/bin/switch-to-configuration test
+#    ssh root@$machine nix-env -p /nix/var/nix/profiles/system --set $d
+#    ssh root@$machine $d/bin/switch-to-configuration boot
 #
 # TODO(q3k): merge this with //cluster/clustercfg - this should be unified!
 
diff --git a/personal/implr/vpn/vpn.jsonnet b/personal/implr/vpn/vpn.jsonnet
index 3f39231..c467c5e 100644
--- a/personal/implr/vpn/vpn.jsonnet
+++ b/personal/implr/vpn/vpn.jsonnet
@@ -19,7 +19,27 @@
                     keepalive 10 60
                     persist-tun
                     persist-key
-                    compress lz4
+                    cipher AES-256-CBC
+                    dh none
+                    ca /mnt/pki/ca.crt
+                    cert /mnt/pki/tls.crt
+                    key /mnt/pki/tls.key
+                |||
+            }
+        },
+        curssys: vpn.Server("openvpn-implr-curssys", 11224, top.tls) {
+            cfg+: {
+                namespace: "implr-vpn",
+                configFile: |||
+                    dev tun
+                    tmp-dir /dev/shm/
+                    proto udp
+                    port 11224
+                    topology subnet
+                    server 172.20.1.0 255.255.255.0
+                    keepalive 10 60
+                    persist-tun
+                    persist-key
                     cipher AES-256-CBC
                     dh none
                     ca /mnt/pki/ca.crt
@@ -33,5 +53,7 @@
         kektop: vpn.Client("kektop", top.servers.praisethesun),
         admin1: vpn.Client("admin1", top.servers.praisethesun),
         desk1: vpn.Client("desk1", top.servers.praisethesun),
+        desk2: vpn.Client("desk2", top.servers.curssys),
+        thonk: vpn.Client("thonk", top.servers.curssys),
     }
 }
diff --git a/personal/q3k/mirko.jsonnet b/personal/q3k/mirko.jsonnet
new file mode 100644
index 0000000..bfeccff
--- /dev/null
+++ b/personal/q3k/mirko.jsonnet
@@ -0,0 +1,49 @@
+local mirko = import "../../kube/mirko.libsonnet";
+
+{
+    local top = self,
+    shipstuck:: {
+        cfg:: {
+            image: "registry.k0.hswaw.net/q3k/shipstuck:315532800-0939d664a3eac4c0c67b447265c67bbcda9939d4",
+            domain: error "domain must be set",
+        },
+        component(cfg, env): mirko.Component(env, "shipstuck") {
+            local shipstuck = self,
+            cfg+: {
+                image: cfg.image,
+                container: shipstuck.GoContainer("main", "/personal/q3k/shipstuck") {
+                    command+: [
+                        "-public_address", "0.0.0.0:8080",
+                    ],
+                },
+                ports+: {
+                    publicHTTP: {
+                        public: {
+                            port: 8080,
+                            dns: cfg.domain,
+                        },
+                    },
+                },
+            },
+        },
+    },
+
+    env(name):: mirko.Environment(name) {
+        local env = self,
+        local cfg = self.cfg,
+        cfg+: {
+            shipstuck: top.shipstuck.cfg,
+        },
+        components: {
+            shipstuck: top.shipstuck.component(cfg.shipstuck, env),
+        },
+    },
+
+    prod: top.env("personal-q3k") {
+        cfg+: {
+            shipstuck+: {
+                domain: "shipstuck.q3k.org",
+            },
+        },
+    },
+}
diff --git a/personal/q3k/shipstuck/BUILD.bazel b/personal/q3k/shipstuck/BUILD.bazel
new file mode 100644
index 0000000..08e77f6
--- /dev/null
+++ b/personal/q3k/shipstuck/BUILD.bazel
@@ -0,0 +1,47 @@
+load("@io_bazel_rules_docker//container:container.bzl", "container_image", "container_layer", "container_push")
+load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
+
+go_library(
+    name = "go_default_library",
+    srcs = ["main.go"],
+    importpath = "code.hackerspace.pl/hscloud/personal/q3k/shipstuck",
+    visibility = ["//visibility:private"],
+    deps = [
+        "//go/mirko:go_default_library",
+        "//personal/q3k/shipstuck/proto:go_default_library",
+        "@com_github_golang_glog//:go_default_library",
+        "@com_github_grpc_ecosystem_grpc_gateway//runtime:go_default_library",
+    ],
+)
+
+go_binary(
+    name = "shipstuck",
+    embed = [":go_default_library"],
+    visibility = ["//visibility:public"],
+)
+
+container_layer(
+    name = "layer_bin",
+    files = [
+        ":shipstuck",
+    ],
+    directory = "/personal/q3k/",
+)
+
+container_image(
+    name = "runtime",
+    base = "@prodimage-bionic//image",
+    layers = [
+        ":layer_bin",
+    ],
+)
+
+container_push(
+    name = "push",
+    image = ":runtime",
+    format = "Docker",
+    registry = "registry.k0.hswaw.net",
+    repository = "q3k/shipstuck",
+    tag = "{BUILD_TIMESTAMP}-{STABLE_GIT_COMMIT}",
+)
+
diff --git a/personal/q3k/shipstuck/main.go b/personal/q3k/shipstuck/main.go
new file mode 100644
index 0000000..bacbc5d
--- /dev/null
+++ b/personal/q3k/shipstuck/main.go
@@ -0,0 +1,160 @@
+package main
+
+import (
+	"context"
+	"flag"
+	"net/http"
+	"sync"
+	"time"
+
+	"code.hackerspace.pl/hscloud/go/mirko"
+	"github.com/golang/glog"
+	"github.com/grpc-ecosystem/grpc-gateway/runtime"
+
+	pb "code.hackerspace.pl/hscloud/personal/q3k/shipstuck/proto"
+)
+
+type vessel struct {
+	Speed float64 `json:"ss"`
+}
+
+// get retrieves the current status of the ship - returns true if stack, false
+// otherwise.
+func get(ctx context.Context) (shipState, error) {
+	// 2021/03/29/ 17:23 UTC+2 it's been freed!
+	return shipStateFreed, nil
+}
+
+type shipState string
+
+const (
+	shipStateUnknown shipState = "UNKNOWN"
+	shipStateStuck   shipState = "STUCK"
+	shipStateFreed   shipState = "FREED"
+	shipStateTowed   shipState = "TOWED"
+)
+
+type service struct {
+	lastStateMu   sync.RWMutex
+	lastState     shipState
+	lastStateTime time.Time
+}
+
+func (s *service) worker(ctx context.Context) {
+	update := func() {
+		state := shipStateUnknown
+		// shitty back off, good enough.
+		retries := 10
+		for {
+			stuck, err := get(ctx)
+			if err != nil {
+				glog.Warningf("get: %v", err)
+				if retries > 0 {
+					time.Sleep(60 * time.Second)
+					retries -= 1
+				} else {
+					glog.Errorf("giving up on get")
+					break
+				}
+			} else {
+				state = stuck
+				break
+			}
+		}
+
+		glog.Infof("New state: %v", state)
+		s.lastStateMu.Lock()
+		s.lastState = state
+		s.lastStateTime = time.Now()
+		s.lastStateMu.Unlock()
+	}
+
+	update()
+	ticker := time.NewTicker(15 * 60 * time.Second)
+	for {
+		select {
+		case <-ctx.Done():
+			return
+		case <-ticker.C:
+			update()
+		}
+	}
+}
+
+func timeMust(t time.Time, err error) time.Time {
+	if err != nil {
+		panic(err)
+	}
+	return t
+}
+
+var (
+	timeStuck = timeMust(time.Parse(
+		"At 15:04 Eastern European Time (-0700) on 2 January 2006",
+		"At 07:40 Eastern European Time (+0200) on 23 March 2021",
+	))
+)
+
+func (s *service) Status(ctx context.Context, req *pb.StatusRequest) (*pb.StatusResponse, error) {
+	s.lastStateMu.RLock()
+	state := s.lastState
+	lastChecked := s.lastStateTime
+	s.lastStateMu.RUnlock()
+
+	res := &pb.StatusResponse{
+		LastChecked: lastChecked.UnixNano(),
+	}
+	switch state {
+	case shipStateUnknown:
+		res.Current = pb.StatusResponse_STUCKNESS_UNKNOWN
+	case shipStateStuck:
+		res.Current = pb.StatusResponse_STUCKNESS_STUCK
+		res.Elapsed = time.Since(timeStuck).Nanoseconds()
+	case shipStateFreed:
+		res.Current = pb.StatusResponse_STUCKNESS_FREE
+	case shipStateTowed:
+		res.Current = pb.StatusResponse_STUCKNESS_TOWED
+		res.Elapsed = time.Since(timeStuck).Nanoseconds()
+	}
+
+	return res, nil
+}
+
+var (
+	flagPublicAddress string
+)
+
+func main() {
+	flag.StringVar(&flagPublicAddress, "public_address", "127.0.0.1:8080", "Public HTTP/JSON listen address")
+	flag.Parse()
+	m := mirko.New()
+	if err := m.Listen(); err != nil {
+		glog.Exitf("Listen(): %v", err)
+	}
+
+	s := &service{}
+	pb.RegisterShipStuckServer(m.GRPC(), s)
+
+	publicMux := runtime.NewServeMux()
+	publicSrv := http.Server{
+		Addr:    flagPublicAddress,
+		Handler: publicMux,
+	}
+	go func() {
+		glog.Infof("REST listening on %s", flagPublicAddress)
+		if err := publicSrv.ListenAndServe(); err != nil {
+			glog.Exitf("public ListenAndServe: %v", err)
+		}
+	}()
+	if err := pb.RegisterShipStuckHandlerServer(m.Context(), publicMux, s); err != nil {
+		glog.Exitf("RegisterShipStuckHandlerSerever: %v", err)
+	}
+
+	go s.worker(m.Context())
+
+	if err := m.Serve(); err != nil {
+		glog.Exitf("Serve(): %v", err)
+	}
+
+	<-m.Done()
+}
diff --git a/personal/q3k/shipstuck/proto/BUILD.bazel b/personal/q3k/shipstuck/proto/BUILD.bazel
new file mode 100644
index 0000000..c1fba40
--- /dev/null
+++ b/personal/q3k/shipstuck/proto/BUILD.bazel
@@ -0,0 +1,31 @@
+load("@rules_proto//proto:defs.bzl", "proto_library")
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
+load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library")
+
+proto_library(
+    name = "proto_proto",
+    srcs = ["shipstuck.proto"],
+    visibility = ["//visibility:public"],
+    deps = ["@go_googleapis//google/api:annotations_proto"],
+)
+
+go_proto_library(
+    name = "proto_go_proto",
+    compilers = [
+        "@com_github_grpc_ecosystem_grpc_gateway//protoc-gen-grpc-gateway:go_gen_grpc_gateway",  # keep
+        "@io_bazel_rules_go//proto:go_grpc",
+    ],
+    importpath = "code.hackerspace.pl/hscloud/personal/q3k/shipstuck/proto",
+    proto = ":proto_proto",
+    visibility = ["//visibility:public"],
+    deps = [
+        "@go_googleapis//google/api:annotations_go_proto",
+    ],
+)
+
+go_library(
+    name = "go_default_library",
+    embed = [":proto_go_proto"],
+    importpath = "code.hackerspace.pl/hscloud/personal/q3k/shipstuck/proto",
+    visibility = ["//visibility:public"],
+)
diff --git a/personal/q3k/shipstuck/proto/shipstuck.proto b/personal/q3k/shipstuck/proto/shipstuck.proto
new file mode 100644
index 0000000..a76d199
--- /dev/null
+++ b/personal/q3k/shipstuck/proto/shipstuck.proto
@@ -0,0 +1,31 @@
+syntax = "proto3";
+package proto;
+option go_package = "code.hackerspace.pl/hscloud/personal/q3k/shipstuck/proto";
+
+import "google/api/annotations.proto";
+
+service ShipStuck {
+    rpc Status(StatusRequest) returns (StatusResponse) {
+        option (google.api.http) = {
+          get: "/v1/shipstuck/status"
+        };
+    };
+}
+
+message StatusRequest {
+}
+
+message StatusResponse {
+    // Timestamp (nanos from epoch) of last check.
+    int64 last_checked = 1;
+    enum Stuckness {
+        STUCKNESS_INVALID = 0;
+        STUCKNESS_STUCK = 1;
+        STUCKNESS_FREE = 2;
+        STUCKNESS_UNKNOWN = 3;
+        STUCKNESS_TOWED = 4;
+    };
+    Stuckness current = 2;
+    // If STUCK or TOWED, how many nanoseconds have elapsed since the whoopsie?
+    int64 elapsed = 3;
+}