func postBackend(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) body, err := ioutil.ReadAll(r.Body) if err != nil { log.Errorln(err) http.Error(w, err.Error(), http.StatusInternalServerError) return } defer r.Body.Close() backendName := vars["backend"] serviceName := vars["service"] backendCfg := client.BackendConfig{Name: backendName} err = json.Unmarshal(body, &backendCfg) if err != nil { log.Errorln(err) http.Error(w, err.Error(), http.StatusInternalServerError) return } if err := Registry.AddBackend(serviceName, backendCfg); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } go writeStateConfig() w.Write(marshal(Registry.Config())) }
// Update the global config func postConfig(w http.ResponseWriter, r *http.Request) { cfg := client.Config{} body, err := ioutil.ReadAll(r.Body) if err != nil { log.Errorln(err) http.Error(w, err.Error(), http.StatusInternalServerError) return } defer r.Body.Close() err = json.Unmarshal(body, &cfg) if err != nil { log.Errorln(err) http.Error(w, err.Error(), http.StatusInternalServerError) return } if err := Registry.UpdateConfig(cfg); err != nil { log.Errorln(err) // TODO: differentiate between ServerError and BadRequest http.Error(w, err.Error(), http.StatusInternalServerError) return } }
// Update a service and/or backends. func postService(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) body, err := ioutil.ReadAll(r.Body) if err != nil { log.Errorln(err) http.Error(w, err.Error(), http.StatusInternalServerError) return } defer r.Body.Close() svcCfg := client.ServiceConfig{Name: vars["service"]} err = json.Unmarshal(body, &svcCfg) if err != nil { log.Errorln(err) http.Error(w, err.Error(), http.StatusInternalServerError) return } // don't let someone update the wrong service if svcCfg.Name != vars["service"] { errMsg := "Mismatched service name in API call" log.Error(errMsg) http.Error(w, errMsg, http.StatusBadRequest) return } cfg := client.Config{ Services: []client.ServiceConfig{svcCfg}, } err = Registry.UpdateConfig(cfg) //FIXME: this doesn't return an error for an empty or broken service if err != nil { log.Error(err) http.Error(w, err.Error(), http.StatusBadRequest) return } w.Write(marshal(Registry.Config())) }
// Update the global config state, including services and backends. // This does not remove any Services, but will add or update any provided in // the config. func (s *ServiceRegistry) UpdateConfig(cfg client.Config) error { // Set globals // TODO: we might need to unset something // TODO: this should remove services and backends to match the submitted config if cfg.Balance != "" { s.cfg.Balance = cfg.Balance } if cfg.CheckInterval != 0 { s.cfg.CheckInterval = cfg.CheckInterval } if cfg.Fall != 0 { s.cfg.Fall = cfg.Fall } if cfg.Rise != 0 { s.cfg.Rise = cfg.Rise } if cfg.ClientTimeout != 0 { s.cfg.ClientTimeout = cfg.ClientTimeout } if cfg.ServerTimeout != 0 { s.cfg.ServerTimeout = cfg.ServerTimeout } if cfg.DialTimeout != 0 { s.cfg.DialTimeout = cfg.DialTimeout } // apply the https rediect flag if httpsRedirect { s.cfg.HTTPSRedirect = true } invalidPorts := []string{ // FIXME: lookup bound addresses some other way. We may have multiple // http listeners, as well as all listening Services. // listenAddr[strings.Index(listenAddr, ":")+1:], adminListenAddr[strings.Index(adminListenAddr, ":")+1:], } errors := &multiError{} for _, svc := range cfg.Services { for _, port := range invalidPorts { if strings.HasSuffix(svc.Addr, port) { // TODO: report conflicts between service listeners errors.Add(fmt.Errorf("Port conflict: %s port %s already bound by shuttle", svc.Name, port)) continue } } // Add a new service, or update an existing one. if Registry.GetService(svc.Name) == nil { if err := Registry.AddService(svc); err != nil { log.Errorln("Unable to add service %s: %s", svc.Name, err.Error()) errors.Add(err) continue } } else if err := Registry.UpdateService(svc); err != nil { log.Errorln("Unable to update service %s: %s", svc.Name, err.Error()) errors.Add(err) continue } } go writeStateConfig() if errors.Len() == 0 { return nil } return errors }