ClusterManager: Implements support of remote clusters.

After this change users will be able to:
* Create cluster and add/remove servers to it
* Install apps on remote cluster
* Move already installed apps between clusters
* Apps running on server being removed will auto-migrate
  to another server from that same cluster

This is achieved by:
* Installing and running minimal version of dodo on remote cluster
* Ingress-nginx is installed automatically on new clusters
* Next to nginx we run VPN client in the same pod, so that
  default cluster can establish secure communication with it
* Multiple reverse proxies are configured to get to the
  remote cluster service from ingress installed on default cluster.

Next steps:
* Support remote clusters in dodo apps (prototype ready)
* Clean up old cluster when moving app to the new one. Currently
  old cluster keeps running app pods even though no ingress can
  reach it anymore.

Change-Id: Iffc908c93416d4126a8e1c2832eae7b659cb8044
diff --git a/core/installer/cluster/manager.go b/core/installer/cluster/manager.go
new file mode 100644
index 0000000..c8e62d1
--- /dev/null
+++ b/core/installer/cluster/manager.go
@@ -0,0 +1,43 @@
+package cluster
+
+import (
+	"net"
+)
+
+const (
+	whichTailscale      = "which tailscale"
+	tailscaleInstallCmd = "curl -fsSL https://tailscale.com/install.sh | sh"
+	tailscaleUpCmd      = "sudo tailscale up --login-server=%s --auth-key=%s --hostname=%s --reset"
+)
+
+type Server struct {
+	Name      string `json:"name"`
+	IP        net.IP `json:"ip"`
+	Port      int    `json:"port"`
+	HostKey   string `json:"hostKey"`
+	User      string `json:"user"`
+	Password  string `json:"password"`
+	ClientKey string `json:"clientKey"`
+	AuthKey   string `json:"authKey"`
+}
+
+type State struct {
+	Name             string   `json:"name"`
+	IngressClassName string   `json:"ingressClassName"`
+	IngressIP        net.IP   `json:"ingressIP"`
+	ServerAddr       string   `json:"serverAddr"`
+	ServerToken      string   `json:"serverToken"`
+	Kubeconfig       string   `json:"kubeconfig"`
+	Controllers      []Server `json:"controllers"`
+	Workers          []Server `json:"workers"`
+}
+
+type ClusterSetupFunc func(name, kubeconfig, ingressClassName string) (net.IP, error)
+
+type Manager interface {
+	Init(s Server, setupFn ClusterSetupFunc) (net.IP, error)
+	JoinController(s Server) error
+	JoinWorker(s Server) error
+	RemoveServer(name string) error
+	State() State
+}