Beispiel #1
0
func EnvironmentDelete(rw http.ResponseWriter, r *http.Request) *httperr.Error {
	vars := mux.Vars(r)
	app := vars["app"]
	name := vars["name"]

	env, err := models.GetEnvironment(app)

	if awsError(err) == "ValidationError" {
		return httperr.Errorf(404, "no such app: %s", app)
	}

	if err != nil {
		return httperr.Server(err)
	}

	delete(env, name)

	releaseId, err := models.PutEnvironment(app, env)

	if err != nil {
		return httperr.Server(err)
	}

	rw.Header().Set("Release-Id", releaseId)

	env, err = models.GetEnvironment(app)

	if err != nil {
		return httperr.Server(err)
	}

	return RenderJson(rw, env)
}
Beispiel #2
0
func AppDelete(rw http.ResponseWriter, r *http.Request) *httperr.Error {
	name := mux.Vars(r)["app"]

	app, err := models.GetApp(name)

	if awsError(err) == "ValidationError" {
		return httperr.Errorf(404, "no such app: %s", name)
	}

	if err != nil {
		return httperr.Server(err)
	}

	if app.Tags["Type"] != "app" || app.Tags["System"] != "convox" || app.Tags["Rack"] != os.Getenv("RACK") {
		return httperr.Errorf(404, "invalid app: %s", name)
	}

	err = app.Delete()

	if err != nil {
		return httperr.Server(err)
	}

	return RenderSuccess(rw)
}
Beispiel #3
0
func EnvironmentSet(rw http.ResponseWriter, r *http.Request) *httperr.Error {
	vars := mux.Vars(r)

	app := vars["app"]

	_, err := models.GetEnvironment(app)

	if awsError(err) == "ValidationError" {
		return httperr.Errorf(404, "no such app: %s", app)
	}

	body, err := ioutil.ReadAll(r.Body)

	if err != nil {
		return httperr.Server(err)
	}

	releaseId, err := models.PutEnvironment(app, models.LoadEnvironment(body))

	if err != nil {
		return httperr.Server(err)
	}

	rw.Header().Set("Release-Id", releaseId)

	env, err := models.GetEnvironment(app)

	if err != nil {
		return httperr.Server(err)
	}

	return RenderJson(rw, env)
}
Beispiel #4
0
func IndexUpload(rw http.ResponseWriter, r *http.Request) *httperr.Error {
	err := r.ParseMultipartForm(10 * 1024 * 1024)

	hash := mux.Vars(r)["hash"]

	if err != nil {
		return httperr.Server(err)
	}

	file, _, err := r.FormFile("data")

	if err != nil {
		return httperr.Server(err)
	}

	data, err := ioutil.ReadAll(file)

	if err != nil {
		return httperr.Server(err)
	}

	sum := sha256.Sum256(data)

	if hash != hex.EncodeToString(sum[:]) {
		return httperr.New(403, fmt.Errorf("invalid hash"))
	}

	err = models.IndexUpload(hash, data)

	if err != nil {
		return httperr.Server(err)
	}

	return RenderSuccess(rw)
}
Beispiel #5
0
func SSLDelete(rw http.ResponseWriter, r *http.Request) *httperr.Error {
	vars := mux.Vars(r)
	app := vars["app"]
	process := vars["process"]
	port := vars["port"]

	if process == "" {
		return httperr.Errorf(403, "must specify a process")
	}

	portn, err := strconv.Atoi(port)

	if err != nil {
		return httperr.Errorf(403, "port must be numeric")
	}

	ssl, err := models.DeleteSSL(app, process, portn)

	if awsError(err) == "ValidationError" {
		return httperr.Errorf(404, "no such app: %s", app)
	}

	if err != nil {
		return httperr.Server(err)
	}

	return RenderJson(rw, ssl)
}
Beispiel #6
0
func SSLCreate(rw http.ResponseWriter, r *http.Request) *httperr.Error {
	a := mux.Vars(r)["app"]
	process := GetForm(r, "process")
	port := GetForm(r, "port")
	body := GetForm(r, "body")
	key := GetForm(r, "key")
	secure := GetForm(r, "secure")

	if process == "" {
		return httperr.Errorf(403, "must specify a process")
	}

	portn, err := strconv.Atoi(port)

	if err != nil {
		return httperr.Errorf(403, "port must be numeric")
	}

	ssl, err := models.CreateSSL(a, process, portn, body, key, (secure == "true"))

	if awsError(err) == "ValidationError" {
		return httperr.Errorf(404, "%s", err)
	}

	if err != nil {
		return httperr.Server(err)
	}

	return RenderJson(rw, ssl)
}
Beispiel #7
0
func ServiceDelete(rw http.ResponseWriter, r *http.Request) *httperr.Error {
	service := mux.Vars(r)["service"]

	s, err := models.GetService(service)

	if awsError(err) == "ValidationError" {
		return httperr.Errorf(404, "no such service: %s", service)
	}

	if err != nil {
		return httperr.Server(err)
	}

	err = s.Delete()

	if err != nil {
		return httperr.Server(err)
	}

	s, err = models.GetService(service)

	if err != nil {
		return httperr.Server(err)
	}

	return RenderJson(rw, s)
}
Beispiel #8
0
func FormationSet(rw http.ResponseWriter, r *http.Request) *httperr.Error {
	vars := mux.Vars(r)
	app := vars["app"]
	process := vars["process"]
	count := GetForm(r, "count")
	memory := GetForm(r, "memory")

	_, err := models.GetApp(app)

	if awsError(err) == "ValidationError" {
		return httperr.Errorf(404, "no such app: %s", app)
	}

	err = models.SetFormation(app, process, count, memory)

	if ae, ok := err.(awserr.Error); ok {
		if ae.Code() == "ValidationError" {
			switch {
			case strings.Index(ae.Error(), "No updates are to be performed") > -1:
				return httperr.Errorf(403, "no updates are to be performed: %s", app)
			case strings.Index(ae.Error(), "can not be updated") > -1:
				return httperr.Errorf(403, "app is already updating: %s", app)
			}
		}
	}

	if err != nil {
		return httperr.Server(err)
	}

	return RenderSuccess(rw)
}
Beispiel #9
0
func ProcessShow(rw http.ResponseWriter, r *http.Request) *httperr.Error {
	vars := mux.Vars(r)
	app := vars["app"]
	process := vars["process"]

	_, err := models.GetApp(app)

	if awsError(err) == "ValidationError" {
		return httperr.Errorf(404, "no such app: %s", app)
	}

	p, err := models.GetProcess(app, process)

	if err != nil {
		return httperr.Server(err)
	}

	err = p.FetchStats()

	if err != nil {
		return httperr.Server(err)
	}

	return RenderJson(rw, p)
}
Beispiel #10
0
func ParametersSet(rw http.ResponseWriter, r *http.Request) *httperr.Error {
	app := mux.Vars(r)["app"]

	a, err := models.GetApp(app)

	if awsError(err) == "ValidationError" {
		return httperr.Errorf(404, "no such app: %s", app)
	}

	if err != nil {
		return httperr.Server(err)
	}

	r.ParseMultipartForm(2048)

	params := map[string]string{}

	for key, values := range r.Form {
		params[key] = values[0]
	}

	err = a.UpdateParams(params)

	if err != nil {
		return httperr.Server(err)
	}

	return RenderSuccess(rw)
}
Beispiel #11
0
func ReleasePromote(rw http.ResponseWriter, r *http.Request) *httperr.Error {
	vars := mux.Vars(r)
	app := vars["app"]
	release := vars["release"]

	_, err := models.GetApp(app)

	if awsError(err) == "ValidationError" {
		return httperr.Errorf(404, "no such app: %s", app)
	}

	rr, err := models.GetRelease(app, release)

	if err != nil && strings.HasPrefix(err.Error(), "no such release") {
		return httperr.Errorf(404, "no such release: %s", release)
	}

	if err != nil {
		return httperr.Server(err)
	}

	err = rr.Promote()

	if awsError(err) == "ValidationError" {
		message := err.(awserr.Error).Message()
		return httperr.Errorf(403, message)
	}

	if err != nil {
		return httperr.Server(err)
	}

	return RenderJson(rw, rr)
}
Beispiel #12
0
func ReleaseShow(rw http.ResponseWriter, r *http.Request) *httperr.Error {
	vars := mux.Vars(r)
	app := vars["app"]
	release := vars["release"]

	_, err := models.GetApp(app)

	if awsError(err) == "ValidationError" {
		return httperr.Errorf(404, "no such app: %s", app)
	}

	rr, err := models.GetRelease(app, release)

	if err != nil && strings.HasPrefix(err.Error(), "no such release") {
		return httperr.Errorf(404, "no such release: %s", release)
	}

	fmt.Printf("err %+v\n", err)

	if err != nil {
		return httperr.Server(err)
	}

	return RenderJson(rw, rr)
}
Beispiel #13
0
func AppLogs(ws *websocket.Conn) *httperr.Error {
	app := mux.Vars(ws.Request())["app"]

	a, err := models.GetApp(app)

	if awsError(err) == "ValidationError" {
		return httperr.Errorf(404, "no such app: %s", app)
	}

	if err != nil {
		return httperr.Server(err)
	}

	logs := make(chan []byte)
	done := make(chan bool)

	a.SubscribeLogs(logs, done)

	go signalWsClose(ws, done)

	for data := range logs {
		ws.Write(data)
	}

	return nil
}
Beispiel #14
0
func AppShow(rw http.ResponseWriter, r *http.Request) *httperr.Error {
	app := mux.Vars(r)["app"]

	a, err := models.GetApp(mux.Vars(r)["app"])

	if awsError(err) == "ValidationError" {
		return httperr.Errorf(404, "no such app: %s", app)
	}

	if err != nil && strings.HasPrefix(err.Error(), "no such app") {
		return httperr.Errorf(404, "no such app: %s", app)
	}

	if err != nil {
		return httperr.Server(err)
	}

	return RenderJson(rw, a)
}
Beispiel #15
0
func LinkDelete(rw http.ResponseWriter, r *http.Request) *httperr.Error {
	app := mux.Vars(r)["app"]
	service := mux.Vars(r)["service"]

	s, err := models.GetService(service)

	if awsError(err) == "ValidationError" {
		return httperr.Errorf(404, "no such service: %s", service)
	}

	if err != nil {
		return httperr.Server(err)
	}

	if s.Status != "running" {
		return httperr.Errorf(403, "can not unlink service with status: %s", s.Status)
	}

	if s.Type != "papertrail" {
		return httperr.Errorf(403, "unlinking is not yet implemented for service type: %s", s.Type)
	}

	a, err := models.GetApp(app)

	if awsError(err) == "ValidationError" {
		return httperr.Errorf(404, "no such app: %s", app)
	}

	if err != nil {
		return httperr.Server(err)
	}

	err = s.UnlinkPapertrail(*a)

	if err != nil {
		return httperr.Server(err)
	}

	return RenderJson(rw, s)
}
Beispiel #16
0
func FormationSet(rw http.ResponseWriter, r *http.Request) *httperr.Error {
	vars := mux.Vars(r)
	app := vars["app"]
	process := vars["process"]

	_, err := models.GetApp(app)

	if awsError(err) == "ValidationError" {
		return httperr.Errorf(404, "no such app: %s", app)
	}

	// initialize to invalid values that indicate no change
	var count, memory int64 = -1, -1

	// update based on form input
	if cc := GetForm(r, "count"); cc != "" {
		if c, err := strconv.ParseInt(cc, 10, 64); err != nil {
			return httperr.Errorf(403, "count must be numeric")
		} else {
			count = c
		}
	}

	if mm := GetForm(r, "memory"); mm != "" {
		if m, err := strconv.ParseInt(mm, 10, 64); err != nil {
			return httperr.Errorf(403, "memory must be numeric")
		} else {
			memory = m
		}
	}

	err = models.SetFormation(app, process, count, memory)

	if ae, ok := err.(awserr.Error); ok {
		if ae.Code() == "ValidationError" {
			switch {
			case strings.Index(ae.Error(), "No updates are to be performed") > -1:
				return httperr.Errorf(403, "no updates are to be performed: %s", app)
			case strings.Index(ae.Error(), "can not be updated") > -1:
				return httperr.Errorf(403, "app is already updating: %s", app)
			}
		}
	}

	if err != nil {
		return httperr.Server(err)
	}

	return RenderSuccess(rw)
}
Beispiel #17
0
func EnvironmentList(rw http.ResponseWriter, r *http.Request) *httperr.Error {
	app := mux.Vars(r)["app"]

	env, err := models.GetEnvironment(app)

	if awsError(err) == "ValidationError" {
		return httperr.Errorf(404, "no such app: %s", app)
	}

	if err != nil {
		return httperr.Server(err)
	}

	return RenderJson(rw, env)
}
Beispiel #18
0
func ParametersList(rw http.ResponseWriter, r *http.Request) *httperr.Error {
	app := mux.Vars(r)["app"]

	a, err := models.GetApp(app)

	if awsError(err) == "ValidationError" {
		return httperr.Errorf(404, "no such app: %s", app)
	}

	if err != nil {
		return httperr.Server(err)
	}

	return RenderJson(rw, a.Parameters)
}
Beispiel #19
0
func SSLList(rw http.ResponseWriter, r *http.Request) *httperr.Error {
	a := mux.Vars(r)["app"]

	ssls, err := models.ListSSLs(a)

	if awsError(err) == "ValidationError" {
		return httperr.Errorf(404, "no such app: %s", a)
	}

	if err != nil {
		return httperr.Server(err)
	}

	return RenderJson(rw, ssls)
}
Beispiel #20
0
func ProcessList(rw http.ResponseWriter, r *http.Request) *httperr.Error {
	app := mux.Vars(r)["app"]
	stats := r.URL.Query().Get("stats") == "true"

	_, err := models.GetApp(app)

	if awsError(err) == "ValidationError" {
		return httperr.Errorf(404, "no such app: %s", app)
	}

	processes, err := models.ListProcesses(app)

	if err != nil {
		return httperr.Server(err)
	}

	if stats {
		w := new(sync.WaitGroup)
		erch := make(chan error, len(processes))

		for _, p := range processes {
			w.Add(1)

			go func(p *models.Process, w *sync.WaitGroup, erch chan error) {
				err := p.FetchStats()

				w.Done()

				if err != nil {
					erch <- err
				}
			}(p, w, erch)
		}

		w.Wait()

		select {
		case err := <-erch:
			return httperr.Server(err)
		default:
			// noop
		}
	}

	sort.Sort(models.Processes(processes))

	return RenderJson(rw, processes)
}
Beispiel #21
0
func BuildLogs(ws *websocket.Conn) *httperr.Error {
	vars := mux.Vars(ws.Request())
	app := vars["app"]
	build := vars["build"]

	_, err := models.GetApp(app)

	if awsError(err) == "ValidationError" {
		return httperr.Errorf(404, "no such app: %s", app)
	}

	_, err = models.GetBuild(app, build)

	if err != nil {
		return httperr.Server(err)
	}

	// proxy to docker container logs
	// https://docs.docker.com/reference/api/docker_remote_api_v1.19/#get-container-logs
	client, err := docker.NewClient("unix:///var/run/docker.sock")

	if err != nil {
		return httperr.Server(err)
	}

	r, w := io.Pipe()

	quit := make(chan bool)

	go scanLines(r, ws)
	go keepAlive(ws, quit)

	err = client.Logs(docker.LogsOptions{
		Container:    fmt.Sprintf("build-%s", build),
		Follow:       true,
		Stdout:       true,
		Stderr:       true,
		Tail:         "all",
		RawTerminal:  false,
		OutputStream: w,
		ErrorStream:  w,
	})

	quit <- true

	return httperr.Server(err)
}
Beispiel #22
0
func FormationList(rw http.ResponseWriter, r *http.Request) *httperr.Error {
	app := mux.Vars(r)["app"]

	_, err := models.GetApp(app)

	if awsError(err) == "ValidationError" {
		return httperr.Errorf(404, "no such app: %s", app)
	}

	formation, err := models.ListFormation(app)

	if err != nil {
		return httperr.Server(err)
	}

	return RenderJson(rw, formation)
}
Beispiel #23
0
func ServiceUpdate(rw http.ResponseWriter, r *http.Request) *httperr.Error {
	service := mux.Vars(r)["service"]

	s, err := models.GetService(service)

	if awsError(err) == "ValidationError" {
		return httperr.Errorf(404, "no such service: %s", service)
	}

	if err != nil {
		return httperr.Server(err)
	}

	err = r.ParseForm()
	if err != nil {
		return httperr.Server(err)
	}

	// get the last set value for all form values
	// ie:  foo=1&foo=2  sets foo to "2"
	params := make(map[string]string)
	for key, values := range r.Form {
		val := values[len(values)-1]
		params[key] = val
	}

	err = s.Update(models.CFParams(params))

	if err != nil && awsError(err) == "ValidationError" {
		e := err.(awserr.Error)
		return httperr.Errorf(403, convoxifyCloudformationError(e.Message()))
	}

	if err != nil {
		return httperr.Server(err)
	}

	s, err = models.GetService(service)

	if err != nil {
		return httperr.Server(err)
	}

	return RenderJson(rw, s)
}
Beispiel #24
0
func ProcessExecAttached(ws *websocket.Conn) *httperr.Error {
	vars := mux.Vars(ws.Request())
	app := vars["app"]
	pid := vars["pid"]
	command := ws.Request().Header.Get("Command")

	a, err := models.GetApp(app)

	if awsError(err) == "ValidationError" {
		return httperr.Errorf(404, "no such app: %s", app)
	}

	if err != nil {
		return httperr.Server(err)
	}

	return httperr.Server(a.ExecAttached(pid, command, ws))
}
Beispiel #25
0
func ProcessList(rw http.ResponseWriter, r *http.Request) *httperr.Error {
	app := mux.Vars(r)["app"]

	_, err := models.GetApp(app)

	if awsError(err) == "ValidationError" {
		return httperr.Errorf(404, "no such app: %s", app)
	}

	processes, err := models.ListProcesses(app)

	if err != nil {
		return httperr.Server(err)
	}

	final := models.Processes{}

	if r.URL.Query().Get("stats") != "false" {
		psch := make(chan models.Process)
		errch := make(chan error)

		for _, p := range processes {
			p := p
			go p.FetchStatsAsync(psch, errch)
		}

		for _, _ = range processes {
			err := <-errch

			if err != nil {
				return httperr.Server(err)
			}

			final = append(final, <-psch)
		}
	} else {
		final = processes
	}

	sort.Sort(final)

	return RenderJson(rw, final)
}
Beispiel #26
0
func ProcessRunDetached(rw http.ResponseWriter, r *http.Request) *httperr.Error {
	vars := mux.Vars(r)
	app := vars["app"]
	process := vars["process"]
	command := GetForm(r, "command")

	a, err := models.GetApp(app)

	if awsError(err) == "ValidationError" {
		return httperr.Errorf(404, "no such app: %s", app)
	}

	err = a.RunDetached(process, command)

	if err != nil {
		return httperr.Server(err)
	}

	return RenderSuccess(rw)
}
Beispiel #27
0
func BuildList(rw http.ResponseWriter, r *http.Request) *httperr.Error {
	app := mux.Vars(r)["app"]

	builds, err := models.ListBuilds(app)

	if err != nil {
		return httperr.Server(err)
	}

	_, err = models.GetApp(app)

	if awsError(err) == "ValidationError" {
		return httperr.Errorf(404, "no such app: %s", app)
	}

	if err != nil {
		return httperr.Server(err)
	}

	return RenderJson(rw, builds)
}
Beispiel #28
0
func AppDelete(rw http.ResponseWriter, r *http.Request) *httperr.Error {
	name := mux.Vars(r)["app"]

	app, err := models.GetApp(name)

	if awsError(err) == "ValidationError" {
		return httperr.Errorf(404, "no such app: %s", name)
	}

	if err != nil {
		return httperr.Server(err)
	}

	err = app.Delete()

	if err != nil {
		return httperr.Server(err)
	}

	return RenderSuccess(rw)
}
Beispiel #29
0
func ServiceLogs(ws *websocket.Conn) *httperr.Error {
	service := mux.Vars(ws.Request())["service"]

	s, err := models.GetService(service)

	if err != nil {
		return httperr.Server(err)
	}

	logs := make(chan []byte)
	done := make(chan bool)

	s.SubscribeLogs(logs, done)

	go signalWsClose(ws, done)

	for data := range logs {
		ws.Write(data)
	}

	return nil
}
Beispiel #30
0
func ProcessRunAttached(ws *websocket.Conn) *httperr.Error {
	vars := mux.Vars(ws.Request())
	header := ws.Request().Header

	app := vars["app"]
	process := vars["process"]
	command := header.Get("Command")
	height, _ := strconv.Atoi(header.Get("Height"))
	width, _ := strconv.Atoi(header.Get("Width"))

	a, err := models.GetApp(app)

	if awsError(err) == "ValidationError" {
		return httperr.Errorf(404, "no such app: %s", app)
	}

	if err != nil {
		return httperr.Server(err)
	}

	return httperr.Server(a.RunAttached(process, command, height, width, ws))
}