| 
									
										
										
										
											2019-02-01 18:28:08 +11:00
										 |  |  | package main | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"log" | 
					
						
							|  |  |  | 	"net" | 
					
						
							| 
									
										
										
										
											2019-02-01 18:35:50 +11:00
										 |  |  | 	"net/http" | 
					
						
							| 
									
										
										
										
											2019-02-01 18:28:08 +11:00
										 |  |  | 	"strings" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/emicklei/go-restful" | 
					
						
							| 
									
										
										
										
											2019-02-04 15:06:02 +11:00
										 |  |  | 	"novit.nc/direktil/local-server/pkg/mime" | 
					
						
							| 
									
										
										
										
											2019-02-04 13:56:43 +11:00
										 |  |  | 	"novit.nc/direktil/pkg/localconfig" | 
					
						
							| 
									
										
										
										
											2019-02-01 18:28:08 +11:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-15 18:56:31 +01:00
										 |  |  | func registerWS(rest *restful.Container) { | 
					
						
							| 
									
										
										
										
											2019-04-19 17:07:22 +01:00
										 |  |  | 	// Admin-level APIs | 
					
						
							| 
									
										
										
										
											2019-04-18 18:47:31 +01:00
										 |  |  | 	ws := &restful.WebService{} | 
					
						
							| 
									
										
										
										
											2019-04-15 18:56:31 +01:00
										 |  |  | 	ws.Filter(adminAuth). | 
					
						
							|  |  |  | 		HeaderParameter("Authorization", "Admin bearer token") | 
					
						
							| 
									
										
										
										
											2019-02-01 18:28:08 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-15 18:56:31 +01:00
										 |  |  | 	// - configs API | 
					
						
							|  |  |  | 	ws.Route(ws.POST("/configs").To(wsUploadConfig). | 
					
						
							| 
									
										
										
										
											2019-02-04 13:56:43 +11:00
										 |  |  | 		Doc("Upload a new current configuration, archiving the previous one")) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-15 18:56:31 +01:00
										 |  |  | 	// - clusters API | 
					
						
							|  |  |  | 	ws.Route(ws.GET("/clusters").To(wsListClusters). | 
					
						
							| 
									
										
										
										
											2019-02-04 13:56:43 +11:00
										 |  |  | 		Doc("List clusters")) | 
					
						
							| 
									
										
										
										
											2019-02-04 15:46:03 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-15 18:56:31 +01:00
										 |  |  | 	ws.Route(ws.GET("/clusters/{cluster-name}").To(wsCluster). | 
					
						
							| 
									
										
										
										
											2019-02-04 13:56:43 +11:00
										 |  |  | 		Doc("Get cluster details")) | 
					
						
							| 
									
										
										
										
											2019-02-04 15:46:03 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-15 18:56:31 +01:00
										 |  |  | 	ws.Route(ws.GET("/clusters/{cluster-name}/addons").To(wsClusterAddons). | 
					
						
							| 
									
										
										
										
											2019-02-04 15:06:02 +11:00
										 |  |  | 		Produces(mime.YAML). | 
					
						
							| 
									
										
										
										
											2019-02-04 13:56:43 +11:00
										 |  |  | 		Doc("Get cluster addons"). | 
					
						
							|  |  |  | 		Returns(http.StatusOK, "OK", nil). | 
					
						
							|  |  |  | 		Returns(http.StatusNotFound, "The cluster does not exists or does not have addons defined", nil)) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-09 17:45:19 +11:00
										 |  |  | 	ws.Route(ws.GET("/clusters/{cluster-name}/bootstrap-pods").To(wsClusterBootstrapPods). | 
					
						
							|  |  |  | 		Produces(mime.YAML). | 
					
						
							|  |  |  | 		Doc("Get cluster bootstrap pods YAML definitions"). | 
					
						
							|  |  |  | 		Returns(http.StatusOK, "OK", nil). | 
					
						
							|  |  |  | 		Returns(http.StatusNotFound, "The cluster does not exists or does not have bootstrap pods defined", nil)) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-15 18:56:31 +01:00
										 |  |  | 	ws.Route(ws.GET("/clusters/{cluster-name}/passwords").To(wsClusterPasswords). | 
					
						
							| 
									
										
										
										
											2019-04-13 10:36:58 +01:00
										 |  |  | 		Doc("List cluster's passwords")) | 
					
						
							| 
									
										
										
										
											2019-04-15 18:56:31 +01:00
										 |  |  | 	ws.Route(ws.GET("/clusters/{cluster-name}/passwords/{password-name}").To(wsClusterPassword). | 
					
						
							| 
									
										
										
										
											2019-04-13 10:36:58 +01:00
										 |  |  | 		Doc("Get cluster's password")) | 
					
						
							| 
									
										
										
										
											2019-04-15 18:56:31 +01:00
										 |  |  | 	ws.Route(ws.PUT("/clusters/{cluster-name}/passwords/{password-name}").To(wsClusterSetPassword). | 
					
						
							| 
									
										
										
										
											2019-04-13 10:36:58 +01:00
										 |  |  | 		Doc("Set cluster's password")) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-18 18:47:31 +01:00
										 |  |  | 	ws.Route(ws.GET("/hosts").To(wsListHosts). | 
					
						
							|  |  |  | 		Doc("List hosts")) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-15 18:56:31 +01:00
										 |  |  | 	(&wsHost{ | 
					
						
							|  |  |  | 		prefix:  "/hosts/{host-name}", | 
					
						
							|  |  |  | 		hostDoc: "given host", | 
					
						
							|  |  |  | 		getHost: func(req *restful.Request) string { | 
					
						
							|  |  |  | 			return req.PathParameter("host-name") | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2019-04-18 18:47:31 +01:00
										 |  |  | 	}).register(ws, func(rb *restful.RouteBuilder) { | 
					
						
							| 
									
										
										
										
											2019-04-15 18:56:31 +01:00
										 |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-18 18:47:31 +01:00
										 |  |  | 	rest.Add(ws) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-15 18:56:31 +01:00
										 |  |  | 	// Hosts API | 
					
						
							| 
									
										
										
										
											2019-04-18 18:47:31 +01:00
										 |  |  | 	ws = &restful.WebService{} | 
					
						
							|  |  |  | 	ws.Path("/me") | 
					
						
							| 
									
										
										
										
											2019-04-15 18:56:31 +01:00
										 |  |  | 	ws.Filter(hostsAuth). | 
					
						
							|  |  |  | 		HeaderParameter("Authorization", "Host or admin bearer token") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-01 18:28:08 +11:00
										 |  |  | 	(&wsHost{ | 
					
						
							| 
									
										
										
										
											2019-02-04 15:46:03 +11:00
										 |  |  | 		hostDoc: "detected host", | 
					
						
							| 
									
										
										
										
											2019-02-01 18:28:08 +11:00
										 |  |  | 		getHost: detectHost, | 
					
						
							| 
									
										
										
										
											2019-02-04 13:56:43 +11:00
										 |  |  | 	}).register(ws, func(rb *restful.RouteBuilder) { | 
					
						
							|  |  |  | 		rb.Notes("In this case, the host is detected from the remote IP") | 
					
						
							|  |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2019-02-01 18:28:08 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-18 18:47:31 +01:00
										 |  |  | 	rest.Add(ws) | 
					
						
							| 
									
										
										
										
											2019-02-01 18:28:08 +11:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func detectHost(req *restful.Request) string { | 
					
						
							|  |  |  | 	r := req.Request | 
					
						
							|  |  |  | 	remoteAddr := r.RemoteAddr | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if *trustXFF { | 
					
						
							|  |  |  | 		if xff := r.Header.Get("X-Forwarded-For"); xff != "" { | 
					
						
							|  |  |  | 			remoteAddr = strings.Split(xff, ",")[0] | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	hostIP, _, err := net.SplitHostPort(remoteAddr) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		hostIP = remoteAddr | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	cfg, err := readConfig() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return "" | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	host := cfg.HostByIP(hostIP) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if host == nil { | 
					
						
							|  |  |  | 		log.Print("no host found for IP ", hostIP) | 
					
						
							|  |  |  | 		return "" | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return host.Name | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-04 13:56:43 +11:00
										 |  |  | func wsReadConfig(resp *restful.Response) *localconfig.Config { | 
					
						
							|  |  |  | 	cfg, err := readConfig() | 
					
						
							| 
									
										
										
										
											2019-02-01 18:35:50 +11:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2019-02-04 13:56:43 +11:00
										 |  |  | 		log.Print("failed to read config: ", err) | 
					
						
							|  |  |  | 		resp.WriteErrorString(http.StatusServiceUnavailable, "failed to read config") | 
					
						
							|  |  |  | 		return nil | 
					
						
							| 
									
										
										
										
											2019-02-01 18:35:50 +11:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-04 13:56:43 +11:00
										 |  |  | 	return cfg | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-02-01 18:35:50 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-04 13:56:43 +11:00
										 |  |  | func wsNotFound(req *restful.Request, resp *restful.Response) { | 
					
						
							|  |  |  | 	http.NotFound(resp.ResponseWriter, req.Request) | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-02-01 18:35:50 +11:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-04 13:56:43 +11:00
										 |  |  | func wsError(resp *restful.Response, err error) { | 
					
						
							|  |  |  | 	log.Print("request failed: ", err) | 
					
						
							|  |  |  | 	resp.WriteErrorString( | 
					
						
							|  |  |  | 		http.StatusInternalServerError, | 
					
						
							|  |  |  | 		http.StatusText(http.StatusInternalServerError)) | 
					
						
							| 
									
										
										
										
											2019-02-01 18:28:08 +11:00
										 |  |  | } |