smsgw: productionize, implement kube/mirko

This productionizes smsgw.

We also add some jsonnet machinery to provide a unified service for Go
micro/mirkoservices.

This machinery provides all the nice stuff:
 - a deployment
 - a service for all your types of pots
 - TLS certificates for HSPKI

We also update and test hspki for a new name scheme.

Change-Id: I292d00f858144903cbc8fe0c1c26eb1180d636bc
diff --git a/go/pki/grpc_test.go b/go/pki/grpc_test.go
new file mode 100644
index 0000000..9ce2a8c
--- /dev/null
+++ b/go/pki/grpc_test.go
@@ -0,0 +1,69 @@
+package pki
+
+import (
+	"testing"
+
+	"github.com/go-test/deep"
+)
+
+func TestParseClient(t *testing.T) {
+	flagPKIRealm = "hswaw.net"
+
+	tests := []struct {
+		name string
+		want *ClientInfo
+	}{
+		// Local cluster
+		{"foo.bar.svc.k0.hswaw.net", &ClientInfo{Cluster: "k0.hswaw.net", Principal: "bar.svc", Job: "foo"}},
+		{"foo.bar.k0.hswaw.net", nil},
+
+		// Foreign cluster
+		{"foo.bar.svc.k1.hswaw.net", &ClientInfo{Cluster: "k1.hswaw.net", Principal: "bar.svc", Job: "foo"}},
+		{"foo.bar.k1.hswaw.net", nil},
+
+		// Human admins (admins, as we know, don't have a real job)
+		{"q3k.person.hswaw.net", &ClientInfo{Cluster: "person.hswaw.net", Principal: "q3k", Job: ""}},
+
+		// External services
+		{"kasownik.external.hswaw.net", &ClientInfo{Cluster: "external.hswaw.net", Principal: "kasownik", Job: ""}},
+
+		// Broken.
+		{"foo.hswaw.net", nil},
+		{"ldap.hackerspace.pl", nil},
+		{"", nil},
+		{"..what..plz...don.t.hack.me.hswaw.net", nil},
+	}
+
+	for i, te := range tests {
+		res, err := parseClientName(te.name)
+		if err != nil {
+			if te.want != nil {
+				t.Errorf("#%d: wanted result, got err %v", i, err)
+			}
+			continue
+		}
+
+		if te.want == nil {
+			t.Errorf("#%d: wanted err, got %+v", i, res)
+			continue
+		}
+
+		if diff := deep.Equal(*te.want, *res); diff != nil {
+			t.Errorf("#%d: res diff: %v", i, diff)
+			continue
+		}
+	}
+}
+
+func TestCheckPerson(t *testing.T) {
+	flagPKIRealm = "hswaw.net"
+
+	res, err := parseClientName("q3k.person.hswaw.net")
+	if err != nil {
+		t.Fatalf("err: %v", err)
+	}
+
+	if want, got := "q3k", res.Person(); want != got {
+		t.Fatalf("wanted %q, got %q", want, got)
+	}
+}