mirkoify, godepify
diff --git a/Gopkg.lock b/Gopkg.lock
new file mode 100644
index 0000000..ab31c34
--- /dev/null
+++ b/Gopkg.lock
@@ -0,0 +1,198 @@
+# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
+
+
+[[projects]]
+  branch = "master"
+  digest = "1:2af0bc306f77bef606f6f6033652f0de3cc80e77008f4da52197b4b0a6be5853"
+  name = "code.hackerspace.pl/q3k/hspki"
+  packages = ["."]
+  pruneopts = "UT"
+  revision = "624295da664fea57a1e3bd8cee639ae04f4c0ccf"
+
+[[projects]]
+  branch = "master"
+  digest = "1:48353f64f7cc9626e4396b286552812a40a9c1d3e653d51ecbe6cedf2c4f4778"
+  name = "code.hackerspace.pl/q3k/mirko"
+  packages = ["."]
+  pruneopts = "UT"
+  revision = "b21f9b9a2ec6ada755aac41595acdf1961d3c48d"
+
+[[projects]]
+  digest = "1:e92f5581902c345eb4ceffdcd4a854fb8f73cf436d47d837d1ec98ef1fe0a214"
+  name = "github.com/StackExchange/wmi"
+  packages = ["."]
+  pruneopts = "UT"
+  revision = "5d049714c4a64225c3c79a7cf7d02f7fb5b96338"
+  version = "1.0.0"
+
+[[projects]]
+  digest = "1:64a5a67c69b70c2420e607a8545d674a23778ed9c3e80607bfd17b77c6c87f6a"
+  name = "github.com/go-ole/go-ole"
+  packages = [
+    ".",
+    "oleutil",
+  ]
+  pruneopts = "UT"
+  revision = "a41e3c4b706f6ae8dfbff342b06e40fa4d2d0506"
+  version = "v1.2.1"
+
+[[projects]]
+  branch = "master"
+  digest = "1:1ba1d79f2810270045c328ae5d674321db34e3aae468eb4233883b473c5c0467"
+  name = "github.com/golang/glog"
+  packages = ["."]
+  pruneopts = "UT"
+  revision = "23def4e6c14b4da8ac2ed8007337bc5eb5007998"
+
+[[projects]]
+  digest = "1:5d1b5a25486fc7d4e133646d834f6fca7ba1cef9903d40e7aa786c41b89e9e91"
+  name = "github.com/golang/protobuf"
+  packages = [
+    "proto",
+    "protoc-gen-go/descriptor",
+    "ptypes",
+    "ptypes/any",
+    "ptypes/duration",
+    "ptypes/timestamp",
+  ]
+  pruneopts = "UT"
+  revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5"
+  version = "v1.2.0"
+
+[[projects]]
+  branch = "master"
+  digest = "1:a7cc4447e0c2432f217fd2bed937c100ec475272a7a9306477170c2934297357"
+  name = "github.com/q3k/statusz"
+  packages = ["."]
+  pruneopts = "UT"
+  revision = "924f04ea71149b75f5b10f426cc4c39d6d90f6f2"
+
+[[projects]]
+  branch = "master"
+  digest = "1:8f042d4b4c48d38d7a1201096299bd26d044c97c032ab20ee171fe5b0d201d2e"
+  name = "github.com/shirou/gopsutil"
+  packages = [
+    "internal/common",
+    "load",
+  ]
+  pruneopts = "UT"
+  revision = "a11c78ba2c13c5b1ee59c53296ba35f92f0ce658"
+
+[[projects]]
+  digest = "1:564b31f09a21367ada5b019d8413afe99cf770775606f94c7bef42b2ef79dfdf"
+  name = "github.com/ybbus/jsonrpc"
+  packages = ["."]
+  pruneopts = "UT"
+  revision = "dd866631e904a5df2067d934985c5def68f391ac"
+  version = "v2.1.2"
+
+[[projects]]
+  branch = "master"
+  digest = "1:505dbee0833715a72a529bb57c354826ad42a4496fad787fa143699b4de1a6d0"
+  name = "golang.org/x/net"
+  packages = [
+    "context",
+    "http/httpguts",
+    "http2",
+    "http2/hpack",
+    "idna",
+    "internal/timeseries",
+    "trace",
+  ]
+  pruneopts = "UT"
+  revision = "49bb7cea24b1df9410e1712aa6433dae904ff66a"
+
+[[projects]]
+  branch = "master"
+  digest = "1:f5aa274a0377f85735edc7fedfb0811d3cbc20af91633797cb359e29c3272271"
+  name = "golang.org/x/sys"
+  packages = [
+    "unix",
+    "windows",
+  ]
+  pruneopts = "UT"
+  revision = "fa43e7bc11baaae89f3f902b2b4d832b68234844"
+
+[[projects]]
+  digest = "1:a2ab62866c75542dd18d2b069fec854577a20211d7c0ea6ae746072a1dccdd18"
+  name = "golang.org/x/text"
+  packages = [
+    "collate",
+    "collate/build",
+    "internal/colltab",
+    "internal/gen",
+    "internal/tag",
+    "internal/triegen",
+    "internal/ucd",
+    "language",
+    "secure/bidirule",
+    "transform",
+    "unicode/bidi",
+    "unicode/cldr",
+    "unicode/norm",
+    "unicode/rangetable",
+  ]
+  pruneopts = "UT"
+  revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
+  version = "v0.3.0"
+
+[[projects]]
+  branch = "master"
+  digest = "1:56b0bca90b7e5d1facf5fbdacba23e4e0ce069d25381b8e2f70ef1e7ebfb9c1a"
+  name = "google.golang.org/genproto"
+  packages = ["googleapis/rpc/status"]
+  pruneopts = "UT"
+  revision = "af9cb2a35e7f169ec875002c1829c9b315cddc04"
+
+[[projects]]
+  digest = "1:dc0c170b110c22d9a4eccf08ab58490608053eac450bf456f3aaf9b30a668781"
+  name = "google.golang.org/grpc"
+  packages = [
+    ".",
+    "balancer",
+    "balancer/base",
+    "balancer/roundrobin",
+    "codes",
+    "connectivity",
+    "credentials",
+    "encoding",
+    "encoding/proto",
+    "grpclog",
+    "internal",
+    "internal/backoff",
+    "internal/channelz",
+    "internal/envconfig",
+    "internal/grpcrand",
+    "internal/transport",
+    "keepalive",
+    "metadata",
+    "naming",
+    "peer",
+    "reflection",
+    "reflection/grpc_reflection_v1alpha",
+    "resolver",
+    "resolver/dns",
+    "resolver/passthrough",
+    "stats",
+    "status",
+    "tap",
+  ]
+  pruneopts = "UT"
+  revision = "8dea3dc473e90c8179e519d91302d0597c0ca1d1"
+  version = "v1.15.0"
+
+[solve-meta]
+  analyzer-name = "dep"
+  analyzer-version = 1
+  input-imports = [
+    "code.hackerspace.pl/q3k/mirko",
+    "github.com/golang/glog",
+    "github.com/golang/protobuf/proto",
+    "github.com/ybbus/jsonrpc",
+    "golang.org/x/net/context",
+    "google.golang.org/grpc",
+    "google.golang.org/grpc/codes",
+    "google.golang.org/grpc/status",
+  ]
+  solver-name = "gps-cdcl"
+  solver-version = 1
diff --git a/Gopkg.toml b/Gopkg.toml
new file mode 100644
index 0000000..749416d
--- /dev/null
+++ b/Gopkg.toml
@@ -0,0 +1,54 @@
+# Gopkg.toml example
+#
+# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html
+# for detailed Gopkg.toml documentation.
+#
+# required = ["github.com/user/thing/cmd/thing"]
+# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
+#
+# [[constraint]]
+#   name = "github.com/user/project"
+#   version = "1.0.0"
+#
+# [[constraint]]
+#   name = "github.com/user/project2"
+#   branch = "dev"
+#   source = "github.com/myfork/project2"
+#
+# [[override]]
+#   name = "github.com/x/y"
+#   version = "2.4.0"
+#
+# [prune]
+#   non-go = false
+#   go-tests = true
+#   unused-packages = true
+
+
+[[constraint]]
+  branch = "master"
+  name = "code.hackerspace.pl/q3k/mirko"
+
+[[constraint]]
+  branch = "master"
+  name = "github.com/golang/glog"
+
+[[constraint]]
+  name = "github.com/golang/protobuf"
+  version = "1.2.0"
+
+[[constraint]]
+  name = "github.com/ybbus/jsonrpc"
+  version = "2.1.2"
+
+[[constraint]]
+  branch = "master"
+  name = "golang.org/x/net"
+
+[[constraint]]
+  name = "google.golang.org/grpc"
+  version = "1.15.0"
+
+[prune]
+  go-tests = true
+  unused-packages = true
diff --git a/grpc.go b/grpc.go
deleted file mode 100644
index 01d5634..0000000
--- a/grpc.go
+++ /dev/null
@@ -1,122 +0,0 @@
-package main
-
-import (
-	"context"
-	"fmt"
-	"net"
-	"net/http"
-
-	"code.hackerspace.pl/q3k/hspki"
-	"github.com/golang/glog"
-	"github.com/q3k/statusz"
-	"golang.org/x/net/trace"
-	"google.golang.org/grpc"
-	"google.golang.org/grpc/reflection"
-
-	pb "code.hackerspace.pl/q3k/arista-proxy/proto"
-)
-
-type serverOpts struct {
-	listenAddress      string
-	debugAddress       string
-	tlsCAPath          string
-	tlsCertificatePath string
-	tlsKeyPath         string
-}
-
-type server struct {
-	arista *aristaClient
-	opts   *serverOpts
-
-	grpc struct {
-		listen net.Listener
-		server *grpc.Server
-	}
-	http struct {
-		listen net.Listener
-		server *http.Server
-	}
-}
-
-func newServer(opts *serverOpts, arista *aristaClient) (*server, error) {
-	return &server{
-		opts:   opts,
-		arista: arista,
-	}, nil
-}
-
-func (s *server) trace(ctx context.Context, f string, args ...interface{}) {
-	tr, ok := trace.FromContext(ctx)
-	if !ok {
-		fmtd := fmt.Sprintf(f, args...)
-		glog.Warningf("No trace in %v: %s", ctx, fmtd)
-		return
-	}
-	tr.LazyPrintf(f, args...)
-}
-
-func (s *server) setupGRPC(options ...grpc.ServerOption) error {
-	lis, err := net.Listen("tcp", s.opts.listenAddress)
-	if err != nil {
-		return fmt.Errorf("while listening on main port: %v", err)
-	}
-
-	s.grpc.listen = lis
-	s.grpc.server = grpc.NewServer(options...)
-
-	return nil
-}
-
-func (s *server) setupDebugHTTP(mux http.Handler) error {
-	lis, err := net.Listen("tcp", s.opts.debugAddress)
-	if err != nil {
-		return fmt.Errorf("while listening on main port: %v", err)
-	}
-
-	s.http.listen = lis
-	s.http.server = &http.Server{
-		Addr:    s.opts.debugAddress,
-		Handler: mux,
-	}
-
-	return nil
-}
-
-func (s *server) serveForever() {
-	grpc.EnableTracing = true
-
-	if err := s.setupGRPC(hspki.WithServerHSPKI()...); err != nil {
-		glog.Exitf("Could not setup GRPC server: %v", err)
-	}
-	pb.RegisterAristaProxyServer(s.grpc.server, s)
-	reflection.Register(s.grpc.server)
-
-	go func() {
-		if err := s.grpc.server.Serve(s.grpc.listen); err != nil {
-			glog.Exitf("Could not start GRPC server: %v", err)
-		}
-	}()
-	glog.Infof("Listening for GRPC on %v", s.opts.listenAddress)
-
-	if s.opts.debugAddress == "" {
-		glog.Info("Disabling debug HTTP server")
-	} else {
-		httpMux := http.NewServeMux()
-		httpMux.HandleFunc("/debug/status", statusz.StatusHandler)
-		httpMux.HandleFunc("/debug/requests", trace.Traces)
-		httpMux.HandleFunc("/", statusz.StatusHandler)
-
-		if err := s.setupDebugHTTP(httpMux); err != nil {
-			glog.Exitf("Could not setup HTTP server: %v", err)
-		}
-
-		go func() {
-			if err := s.http.server.Serve(s.http.listen); err != nil {
-				glog.Exitf("Could not start HTTP server: %v", err)
-			}
-		}()
-		glog.Infof("Listening for HTTP on %v", s.opts.debugAddress)
-	}
-
-	select {}
-}
diff --git a/main.go b/main.go
index 66e8d94..f417f1f 100644
--- a/main.go
+++ b/main.go
@@ -4,17 +4,15 @@
 	"flag"
 	"fmt"
 
+	"code.hackerspace.pl/q3k/mirko"
 	"github.com/golang/glog"
 	"github.com/ybbus/jsonrpc"
+
+	pb "code.hackerspace.pl/q3k/arista-proxy/proto"
 )
 
 var (
-	flagAristaAPI       string
-	flagListenAddress   string
-	flagDebugAddress    string
-	flagCAPath          string
-	flagCertificatePath string
-	flagKeyPath         string
+	flagAristaAPI string
 )
 
 type aristaClient struct {
@@ -39,32 +37,31 @@
 	return nil
 }
 
+type server struct {
+	arista *aristaClient
+}
+
 func main() {
 	flag.StringVar(&flagAristaAPI, "arista_api", "http://admin:password@1.2.3.4:80/command-api", "Arista remote endpoint")
-	flag.StringVar(&flagListenAddress, "listen_address", "127.0.0.1:42000", "gRPC listen address")
-	flag.StringVar(&flagDebugAddress, "debug_address", "127.0.0.1:42001", "Debug HTTP listen address, or empty to disable")
-	flag.StringVar(&flagCAPath, "tls_ca_path", "pki/ca.pem", "Path to PKI CA certificate")
-	flag.StringVar(&flagCertificatePath, "tls_certificate_path", "pki/service.pem", "Path to PKI service certificate")
-	flag.StringVar(&flagKeyPath, "tls_key_path", "pki/service-key.pem", "Path to PKI service private key")
-	flag.Set("logtostderr", "true")
 	flag.Parse()
 
 	arista := &aristaClient{
 		rpc: jsonrpc.NewClient(flagAristaAPI),
 	}
 
-	opts := &serverOpts{
-		listenAddress:      flagListenAddress,
-		debugAddress:       flagDebugAddress,
-		tlsCAPath:          flagCAPath,
-		tlsCertificatePath: flagCertificatePath,
-		tlsKeyPath:         flagKeyPath,
-	}
-	server, err := newServer(opts, arista)
-	if err != nil {
-		glog.Errorf("Could not create server: %v", err)
+	m := mirko.New()
+	if err := m.Listen(); err != nil {
+		glog.Exitf("Listen(): %v", err)
 	}
 
-	glog.Info("Starting up...")
-	server.serveForever()
+	s := &server{
+		arista: arista,
+	}
+	pb.RegisterAristaProxyServer(m.GRPC(), s)
+
+	if err := m.Serve(); err != nil {
+		glog.Exitf("Serve(): %v", err)
+	}
+
+	select {}
 }