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/dns-api/server.go b/core/dns-api/server.go
index 37db8ff..d67ccf6 100644
--- a/core/dns-api/server.go
+++ b/core/dns-api/server.go
@@ -31,6 +31,8 @@
 	}
 	m.HandleFunc("/records-to-publish", s.recordsToPublish)
 	m.HandleFunc("/create-txt-record", s.createTxtRecord)
+	m.HandleFunc("/create-a-record", s.createARecord)
+	m.HandleFunc("/delete-a-record", s.deleteARecord)
 	m.HandleFunc("/delete-txt-record", s.deleteTxtRecord)
 	return s
 }
@@ -69,22 +71,44 @@
 		http.Error(w, err.Error(), http.StatusBadRequest)
 		return
 	}
-	fmt.Printf("CREATE: %+v\n", req)
 	if err := s.store.Add(req.Entry, req.Text); err != nil {
 		http.Error(w, err.Error(), http.StatusInternalServerError)
 		return
 	}
 }
 
+func (s *Server) createARecord(w http.ResponseWriter, r *http.Request) {
+	var req record
+	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
+		http.Error(w, err.Error(), http.StatusBadRequest)
+		return
+	}
+	if err := s.store.AddARecord(req.Entry, req.Text); err != nil {
+		http.Error(w, err.Error(), http.StatusInternalServerError)
+		return
+	}
+}
+
 func (s *Server) deleteTxtRecord(w http.ResponseWriter, r *http.Request) {
 	var req record
 	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
 		http.Error(w, err.Error(), http.StatusBadRequest)
 		return
 	}
-	fmt.Printf("DELETE: %+v\n", req)
 	if err := s.store.Delete(req.Entry, req.Text); err != nil {
 		http.Error(w, err.Error(), http.StatusInternalServerError)
 		return
 	}
 }
+
+func (s *Server) deleteARecord(w http.ResponseWriter, r *http.Request) {
+	var req record
+	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
+		http.Error(w, err.Error(), http.StatusBadRequest)
+		return
+	}
+	if err := s.store.DeleteARecord(req.Entry, req.Text); err != nil {
+		http.Error(w, err.Error(), http.StatusInternalServerError)
+		return
+	}
+}