Exemple #1
0
// servePutInstance adds an instance to a service.
func (h *Handler) servePutInstance(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
	// Read path parameter.
	service := params.ByName("service")

	// Read instance from request.
	inst := &discoverd.Instance{}
	if err := json.NewDecoder(r.Body).Decode(inst); err != nil {
		hh.Error(w, err)
		return
	}

	// Ensure instance is valid.
	if err := inst.Valid(); err != nil {
		hh.ValidationError(w, "", err.Error())
		return
	}

	// Add instance to service in the store.
	if err := h.Store.AddInstance(service, inst); err == ErrNotLeader {
		h.redirectToLeader(w, r)
		return
	} else if IsNotFound(err) {
		hh.ObjectNotFoundError(w, err.Error())
		return
	} else if err != nil {
		hh.Error(w, err)
		return
	}
}
Exemple #2
0
func (api *httpAPI) ServeTemplate(w http.ResponseWriter, req *http.Request, params httprouter.Params) {
	if req.Header.Get("Accept") == "application/json" {
		s, err := api.Installer.FindBaseCluster(params.ByName("id"))
		if err != nil {
			httphelper.ObjectNotFoundError(w, err.Error())
			return
		}
		httphelper.JSON(w, 200, s)
		return
	}

	manifest, err := api.AssetManifest()
	if err != nil {
		httphelper.Error(w, err)
		api.logger.Debug(err.Error())
		return
	}

	w.Header().Add("Content-Type", "text/html; charset=utf-8")
	w.Header().Add("Cache-Control", "max-age=0")

	err = htmlTemplate.Execute(w, &htmlTemplateData{
		ApplicationJSPath:  manifest.Assets["application.js"],
		ApplicationCSSPath: manifest.Assets["application.css"],
		ReactJSPath:        manifest.Assets["react.js"],
	})
	if err != nil {
		httphelper.Error(w, err)
		api.logger.Debug(err.Error())
		return
	}
}
Exemple #3
0
// servePutService creates a service.
func (h *Handler) servePutService(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
	// Retrieve the path parameter.
	service := params.ByName("service")
	if err := ValidServiceName(service); err != nil {
		hh.ValidationError(w, "", err.Error())
		return
	}

	// Read config from the request.
	config := &discoverd.ServiceConfig{}
	if err := hh.DecodeJSON(r, config); err != nil {
		hh.Error(w, err)
		return
	}

	// Add the service to the store.
	if err := h.Store.AddService(service, config); err == ErrNotLeader {
		h.redirectToLeader(w, r)
		return
	} else if IsServiceExists(err) {
		hh.ObjectExistsError(w, err.Error())
		return
	} else if err != nil {
		hh.Error(w, err)
		return
	}
}
Exemple #4
0
// servePutLeader sets the leader for a service.
func (h *Handler) servePutLeader(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
	// Retrieve path parameters.
	service := params.ByName("service")

	// Check if the service allows manual leader election.
	config := h.Store.Config(service)
	if config == nil || config.LeaderType != discoverd.LeaderTypeManual {
		hh.ValidationError(w, "", "service leader election type is not manual")
		return
	}

	// Read instance from the request.
	inst := &discoverd.Instance{}
	if err := hh.DecodeJSON(r, inst); err != nil {
		hh.Error(w, err)
		return
	}

	// Manually set the leader on the service.
	if err := h.Store.SetServiceLeader(service, inst.ID); err == ErrNotLeader {
		h.redirectToLeader(w, r)
		return
	} else if err != nil {
		hh.Error(w, err)
		return
	}
}
Exemple #5
0
func (r *Runner) getBuildLog(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
	id := ps.ByName("build")
	b := &Build{}
	if err := r.db.View(func(tx *bolt.Tx) error {
		v := tx.Bucket(dbBucket).Get([]byte(id))
		if err := json.Unmarshal(v, b); err != nil {
			return fmt.Errorf("could not decode build %s: %s", v, err)
		}
		return nil
	}); err != nil {
		http.Error(w, err.Error(), 500)
		return
	}

	// if it's a V1 build, redirect to the log in S3
	if b.Version == BuildVersion1 {
		http.Redirect(w, req, b.LogURL, http.StatusMovedPermanently)
		return
	}

	// if it's a browser, serve the build-log.html template
	if strings.Contains(req.Header.Get("Accept"), "text/html") {
		tpl, err := template.ParseFiles(path.Join(args.AssetsDir, "build-log.html"))
		if err != nil {
			http.Error(w, err.Error(), 500)
			return
		}
		w.Header().Set("Content-Type", "text/html; charset=utf-8")
		if err := tpl.Execute(w, b); err != nil {
			log.Printf("error executing build-log template: %s", err)
		}
		return
	}

	// serve the build log as either an SSE or plain text stream
	ch := make(chan string)
	stream, err := getBuildLogStream(b, ch)
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}
	if cn, ok := w.(http.CloseNotifier); ok {
		go func() {
			<-cn.CloseNotify()
			stream.Close()
		}()
	} else {
		defer stream.Close()
	}

	if strings.Contains(req.Header.Get("Accept"), "text/event-stream") {
		sse.ServeStream(w, ch, nil)
	} else {
		servePlainStream(w, ch)
	}

	if err := stream.Err(); err != nil {
		log.Println("error serving build log stream:", err)
	}
}
Exemple #6
0
func (api *HTTPAPI) Pull(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	volumeID := ps.ByName("volume_id")

	pull := &volume.PullCoordinate{}
	if err := httphelper.DecodeJSON(r, &pull); err != nil {
		httphelper.Error(w, err)
		return
	}

	hostClient, err := api.cluster.Host(pull.HostID)
	if err != nil {
		httphelper.Error(w, err)
		return
	}

	haves, err := api.vman.ListHaves(volumeID)
	if err != nil {
		httphelper.Error(w, err)
		return
	}

	reader, err := hostClient.SendSnapshot(pull.SnapshotID, haves)
	if err != nil {
		httphelper.Error(w, err)
		return
	}

	snap, err := api.vman.ReceiveSnapshot(volumeID, reader)
	if err != nil {
		httphelper.Error(w, err)
		return
	}

	httphelper.JSON(w, 200, snap.Info())
}
Exemple #7
0
func (api *HTTPAPI) Send(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	volumeID := ps.ByName("volume_id")

	if !strings.Contains(r.Header.Get("Accept"), snapshotContentType) {
		httphelper.ValidationError(w, "", fmt.Sprintf("must be prepared to accept a content type of %q", snapshotContentType))
		return
	}
	w.Header().Set("Content-Type", snapshotContentType)

	var haves []json.RawMessage
	if err := httphelper.DecodeJSON(r, &haves); err != nil {
		httphelper.Error(w, err)
		return
	}

	err := api.vman.SendSnapshot(volumeID, haves, w)
	if err != nil {
		switch err {
		case volumemanager.NoSuchVolume:
			httphelper.ObjectNotFoundError(w, fmt.Sprintf("no volume with id %q", volumeID))
			return
		default:
			httphelper.Error(w, err)
			return
		}
	}
}
Exemple #8
0
func (api *httpAPI) ServeApplicationJS(w http.ResponseWriter, req *http.Request, params httprouter.Params) {
	path := filepath.Join("app", "build", params.ByName("assetPath"))
	data, err := api.Asset(path)
	if err != nil {
		fmt.Println(err)
		w.WriteHeader(500)
		return
	}

	var jsConf bytes.Buffer
	jsConf.Write([]byte("window.InstallerConfig = "))
	json.NewEncoder(&jsConf).Encode(installerJSConfig{
		Endpoints: map[string]string{
			"install": "/install",
			"events":  "/events/:id",
			"prompt":  "/prompt/:id",
		},
		HasAWSEnvCredentials: api.AWSEnvCreds != nil,
	})
	jsConf.Write([]byte(";\n"))

	r := ioutil.NewMultiReadSeeker(bytes.NewReader(jsConf.Bytes()), data)

	http.ServeContent(w, req, path, time.Now(), r)
}
Exemple #9
0
func (api *httpAPI) EventsHandler(w http.ResponseWriter, req *http.Request, params httprouter.Params) {
	api.InstallerStackMtx.Lock()
	s := api.InstallerStacks[params.ByName("id")]
	api.InstallerStackMtx.Unlock()
	if s == nil {
		httphelper.ObjectNotFoundError(w, "install instance not found")
		return
	}

	eventChan := make(chan *httpEvent)
	doneChan, errChan := s.Subscribe(eventChan)

	stream := sse.NewStream(w, eventChan, s.logger)
	stream.Serve()

	s.logger.Info(fmt.Sprintf("streaming events for %s", s.ID))

	go func() {
		for {
			select {
			case err := <-errChan:
				s.logger.Info(err.Error())
				stream.Error(err)
			case <-doneChan:
				stream.Close()
				return
			}
		}
	}()

	stream.Wait()
}
Exemple #10
0
func (api *httpAPI) DeleteCredential(w http.ResponseWriter, req *http.Request, params httprouter.Params) {
	if err := api.Installer.DeleteCredentials(params.ByName("id")); err != nil {
		httphelper.Error(w, err)
		return
	}
	w.WriteHeader(200)
}
Exemple #11
0
// serveGetLeader returns the current leader for a service.
func (h *Handler) serveGetLeader(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
	// Process as a stream if that's what the client wants.
	if strings.Contains(r.Header.Get("Accept"), "text/event-stream") {
		if !h.Store.IsLeader() {
			h.redirectToLeader(w, r)
			return
		}
		h.serveStream(w, params, discoverd.EventKindLeader)
		return
	}

	// Otherwise retrieve the current leader.
	service := params.ByName("service")
	leader, err := h.Store.ServiceLeader(service)
	if err != nil {
		hh.Error(w, err)
		return
	} else if leader == nil {
		hh.ObjectNotFoundError(w, "no leader found")
		return
	}

	// Write leader to the response.
	hh.JSON(w, 200, leader)
}
Exemple #12
0
func (r *Runner) getBuildLog(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
	id := ps.ByName("build")
	b := &Build{}
	if err := r.db.View(func(tx *bolt.Tx) error {
		v := tx.Bucket(dbBucket).Get([]byte(id))
		if err := json.Unmarshal(v, b); err != nil {
			return fmt.Errorf("could not decode build %s: %s", v, err)
		}
		return nil
	}); err != nil {
		http.Error(w, err.Error(), 500)
		return
	}
	if b.Finished() {
		if b.Version == BuildVersion1 {
			http.Redirect(w, req, b.LogURL, http.StatusMovedPermanently)
			return
		}
		if strings.Contains(req.Header.Get("Accept"), "text/event-stream") {
			if err := serveBuildLogStream(b, w); err != nil {
				http.Error(w, err.Error(), 500)
			}
			return
		}
		http.ServeFile(w, req, path.Join(args.AssetsDir, "build-log.html"))
		return
	}
	t, err := tail.TailFile(b.LogFile, tail.Config{Follow: true, MustExist: true})
	if err != nil {
		http.Error(w, err.Error(), 500)
		return
	}
	if cn, ok := w.(http.CloseNotifier); ok {
		go func() {
			<-cn.CloseNotify()
			t.Stop()
		}()
	} else {
		defer t.Stop()
	}
	flush := func() {
		if fw, ok := w.(http.Flusher); ok {
			fw.Flush()
		}
	}
	w.Header().Set("Content-Type", textPlain)
	w.WriteHeader(http.StatusOK)
	flush()
	for line := range t.Lines {
		if _, err := io.WriteString(w, line.Text+"\n"); err != nil {
			log.Printf("serveBuildLog write error: %s\n", err)
			return
		}
		flush()
		if strings.HasPrefix(line.Text, "build finished") {
			return
		}
	}
}
Exemple #13
0
func (h *httpAPI) GetServiceMeta(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
	meta := h.Store.GetServiceMeta(params.ByName("service"))
	if meta == nil {
		hh.ObjectNotFoundError(w, "service meta not found")
		return
	}
	hh.JSON(w, 200, meta)
}
Exemple #14
0
func (r *Runner) removeHost(c *cluster.Cluster, w http.ResponseWriter, q url.Values, ps httprouter.Params) error {
	hostID := ps.ByName("host")
	if err := c.RemoveHost(hostID); err != nil {
		return err
	}
	w.WriteHeader(200)
	return nil
}
Exemple #15
0
func (h *jobAPI) StopJob(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	id := ps.ByName("id")
	if err := h.host.StopJob(id); err != nil {
		httphelper.Error(w, err)
		return
	}
	w.WriteHeader(200)
}
Exemple #16
0
// serveDeleteRaftNodes removes a peer to the store cluster.
func (h *Handler) serveDeleteRaftPeer(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
	peer := params.ByName("peer")
	if err := h.Store.RemovePeer(peer); err == ErrNotLeader {
		h.redirectToLeader(w, r)
		return
	} else if err != nil {
		hh.Error(w, err)
		return
	}
}
Exemple #17
0
func (api *HTTPAPI) Inspect(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	volumeID := ps.ByName("volume_id")
	vol := api.vman.GetVolume(volumeID)
	if vol == nil {
		httphelper.ObjectNotFoundError(w, fmt.Sprintf("no volume with id %q", volumeID))
		return
	}

	httphelper.JSON(w, 200, vol.Info())
}
Exemple #18
0
func (api *httpAPI) GetCert(w http.ResponseWriter, req *http.Request, params httprouter.Params) {
	cluster, err := api.Installer.FindBaseCluster(params.ByName("id"))
	if err != nil {
		httphelper.ObjectNotFoundError(w, err.Error())
		return
	}
	w.Header().Set("Content-Type", "application/x-x509-ca-cert")
	w.Header().Set("Content-Disposition", `attachment; filename="flynn-ca.cer"`)
	w.Write([]byte(cluster.CACert))
}
Exemple #19
0
func (h *httpAPI) RemoveInstance(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
	if err := h.Store.RemoveInstance(params.ByName("service"), params.ByName("instance_id")); err != nil {
		if IsNotFound(err) {
			hh.ObjectNotFoundError(w, err.Error())
		} else {
			hh.Error(w, err)
		}
		return
	}
}
Exemple #20
0
func (api *HTTPAPI) Create(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	providerID := ps.ByName("provider_id")

	vol, err := api.vman.NewVolumeFromProvider(providerID)
	if err == volumemanager.NoSuchProvider {
		httphelper.ObjectNotFoundError(w, fmt.Sprintf("no volume provider with id %q", providerID))
		return
	}

	httphelper.JSON(w, 200, vol.Info())
}
Exemple #21
0
func (h *httpAPI) handleStream(w http.ResponseWriter, params httprouter.Params, kind discoverd.EventKind) {
	ch := make(chan *discoverd.Event, 64) // TODO: figure out how big this buffer should be
	stream := h.Store.Subscribe(params.ByName("service"), true, kind, ch)
	s := sse.NewStream(w, ch, nil)
	s.Serve()
	s.Wait()
	stream.Close()
	if err := stream.Err(); err != nil {
		s.CloseWithError(err)
	}
}
Exemple #22
0
func (api *httpAPI) DeleteCluster(w http.ResponseWriter, req *http.Request, params httprouter.Params) {
	if err := api.Installer.DeleteCluster(params.ByName("id")); err != nil {
		if err == ClusterNotFoundError {
			httphelper.ObjectNotFoundError(w, err.Error())
			return
		}
		httphelper.Error(w, err)
		return
	}
	w.WriteHeader(200)
}
Exemple #23
0
func (h *jobAPI) GetJob(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	id := ps.ByName("id")

	if strings.Contains(r.Header.Get("Accept"), "text/event-stream") {
		if err := h.host.streamEvents(id, w); err != nil {
			httphelper.Error(w, err)
		}
		return
	}
	job := h.host.state.GetJob(id)
	httphelper.JSON(w, 200, job)
}
Exemple #24
0
func (api *httpAPI) ServeAsset(w http.ResponseWriter, req *http.Request, params httprouter.Params) {
	if strings.HasPrefix(params.ByName("assetPath"), "/application-") && strings.HasSuffix(params.ByName("assetPath"), ".js") {
		api.ServeApplicationJS(w, req, params)
	} else {
		path := filepath.Join("app", "build", params.ByName("assetPath"))
		data, err := api.Asset(path)
		if err != nil {
			httphelper.Error(w, err)
			return
		}
		http.ServeContent(w, req, path, time.Now(), data)
	}
}
Exemple #25
0
func (h *httpAPI) GetInstances(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
	if strings.Contains(r.Header.Get("Accept"), "text/event-stream") {
		h.handleStream(w, params, discoverd.EventKindUp|discoverd.EventKindUpdate|discoverd.EventKindDown)
		return
	}

	instances := h.Store.Get(params.ByName("service"))
	if instances == nil {
		hh.ObjectNotFoundError(w, "service not found")
		return
	}
	hh.JSON(w, 200, instances)
}
Exemple #26
0
func (h *httpAPI) GetLeader(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
	if strings.Contains(r.Header.Get("Accept"), "text/event-stream") {
		h.handleStream(w, params, discoverd.EventKindLeader)
		return
	}

	leader := h.Store.GetLeader(params.ByName("service"))
	if leader == nil {
		hh.ObjectNotFoundError(w, "no leader found")
		return
	}
	hh.JSON(w, 200, leader)
}
Exemple #27
0
// servePutRaftNodes joins a peer to the store cluster.
func (h *Handler) servePutRaftPeer(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
	peer := params.ByName("peer")
	if err := h.Store.AddPeer(peer); err == ErrNotLeader {
		h.redirectToLeader(w, r)
		return
	} else if err != nil {
		hh.Error(w, err)
		return
	}
	var targetLogIndex dt.TargetLogIndex
	targetLogIndex.LastIndex = h.Store.LastIndex()
	hh.JSON(w, 200, targetLogIndex)
}
Exemple #28
0
// serveGetServiceMeta returns the metadata for a service.
func (h *Handler) serveGetServiceMeta(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
	// Read path parameter.
	service := params.ByName("service")

	// Read meta from the store.
	meta := h.Store.ServiceMeta(service)
	if meta == nil {
		hh.ObjectNotFoundError(w, "service meta not found")
		return
	}

	// Write meta to the response.
	hh.JSON(w, 200, meta)
}
Exemple #29
0
func (h *httpAPI) RemoveService(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
	service := params.ByName("service")
	if err := ValidServiceName(service); err != nil {
		hh.ValidationError(w, "", err.Error())
		return
	}
	if err := h.Store.RemoveService(params.ByName("service")); err != nil {
		if IsNotFound(err) {
			hh.ObjectNotFoundError(w, err.Error())
		} else {
			hh.Error(w, err)
		}
		return
	}
}
Exemple #30
0
func (api *HTTPAPI) Snapshot(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	volumeID := ps.ByName("volume_id")
	snap, err := api.vman.CreateSnapshot(volumeID)
	if err != nil {
		switch err {
		case volumemanager.NoSuchVolume:
			httphelper.ObjectNotFoundError(w, fmt.Sprintf("no volume with id %q", volumeID))
			return
		default:
			httphelper.Error(w, err)
			return
		}
	}

	httphelper.JSON(w, 200, snap.Info())
}