go/svc/leasifier: fixes, add statusz table
diff --git a/go/svc/leasifier/BUILD.bazel b/go/svc/leasifier/BUILD.bazel
index 386f886..c03fb35 100644
--- a/go/svc/leasifier/BUILD.bazel
+++ b/go/svc/leasifier/BUILD.bazel
@@ -2,15 +2,17 @@
 
 go_library(
     name = "go_default_library",
-    srcs = ["main.go"],
+    srcs = [
+        "main.go",
+        "statusz.go",
+    ],
     importpath = "code.hackerspace.pl/hscloud/go/svc/leasifier",
     visibility = ["//visibility:private"],
     deps = [
         "//go/mirko:go_default_library",
+        "//go/statusz:go_default_library",
         "//proto/hswaw:go_default_library",
         "@com_github_golang_glog//:go_default_library",
-        "@org_golang_google_grpc//codes:go_default_library",
-        "@org_golang_google_grpc//status:go_default_library",
     ],
 )
 
diff --git a/go/svc/leasifier/main.go b/go/svc/leasifier/main.go
index 9b2cf5a..09090b6 100644
--- a/go/svc/leasifier/main.go
+++ b/go/svc/leasifier/main.go
@@ -138,14 +138,16 @@
 }
 
 type service struct {
-	leaseFile string
-	leaseC    chan chan []lease
+	leaseFile          string
+	leaseRefreshString string
+	leaseRefresh       time.Duration
+	leaseC             chan chan []lease
 }
 
 func (s *service) work(ctx context.Context) {
 	leases := []lease{}
 
-	ticker := time.NewTicker(30 * time.Second)
+	ticker := time.NewTicker(s.leaseRefresh)
 	start := make(chan struct{}, 1)
 	start <- struct{}{}
 
@@ -189,7 +191,9 @@
 	s.leaseC <- c
 	leases := <-c
 
-	res := &hpb.LeasifierLeasesResponse{}
+	res := &hpb.LeasifierLeasesResponse{
+		Leases: make([]*hpb.LeasifierLease, len(leases)),
+	}
 
 	for i, l := range leases {
 		res.Leases[i] = &hpb.LeasifierLease{
@@ -207,8 +211,15 @@
 	}
 
 	flag.StringVar(&s.leaseFile, "lease_file", "/var/db/dhcpd.leases", "Location of leasefile")
+	flag.StringVar(&s.leaseRefreshString, "lease_refresh", "1m", "How often to refresh leases")
 	flag.Parse()
 
+	d, err := time.ParseDuration(s.leaseRefreshString)
+	if err != nil {
+		glog.Exit(err)
+	}
+	s.leaseRefresh = d
+
 	m := mirko.New()
 	if err := m.Listen(); err != nil {
 		glog.Exitf("Could not listen: %v", err)
@@ -216,6 +227,7 @@
 
 	hpb.RegisterLeasifierServer(m.GRPC(), s)
 
+	s.setupStatusz(m)
 	go s.work(m.Context())
 
 	if err := m.Serve(); err != nil {
diff --git a/go/svc/leasifier/statusz.go b/go/svc/leasifier/statusz.go
new file mode 100644
index 0000000..7f34a37
--- /dev/null
+++ b/go/svc/leasifier/statusz.go
@@ -0,0 +1,73 @@
+package main
+
+import (
+	"context"
+
+	mirko "code.hackerspace.pl/hscloud/go/mirko"
+	"code.hackerspace.pl/hscloud/go/statusz"
+)
+
+const statuszFragment = `
+    <style type="text/css">
+		.table td,th {
+			background-color: #eee;
+			padding: 0.2em 0.4em 0.2em 0.4em;
+		}
+		.table th {
+			background-color: #c0c0c0;
+		}
+		.table {
+			background-color: #fff;
+			border-spacing: 0.2em;
+		}
+	</style>
+	<div>
+	<b>Current leases:</b> {{ .Leases | len }}<br />
+	<table class="table">
+		<tr>
+      		<th>IP Address</th>
+      		<th>MAC Address</th>
+			<th>Start</th>
+			<th>End</th>
+		</tr>
+		{{range .Leases }}
+		<tr>
+			<td>{{ .IP }}</td>
+			<td>{{ .MAC }}</td>
+			<td>{{ .Start }}</td>
+			<td>{{ .End }}</td>
+		</tr>
+		{{end}}
+	</table>
+	</div>
+`
+
+type szLeases struct {
+	IP    string
+	MAC   string
+	Start string
+	End   string
+}
+
+func (s *service) setupStatusz(m *mirko.Mirko) {
+	statusz.AddStatusPart("Leases", statuszFragment, func(ctx context.Context) interface{} {
+		c := make(chan []lease)
+		s.leaseC <- c
+		leases := <-c
+
+		ls := make([]szLeases, len(leases))
+
+		for i, l := range leases {
+			ls[i].IP = l.ip.String()
+			ls[i].MAC = l.hardware.String()
+			ls[i].Start = l.from.String()
+			ls[i].End = l.to.String()
+		}
+
+		return struct {
+			Leases []szLeases
+		}{
+			Leases: ls,
+		}
+	})
+}