Beispiel #1
0
func (h *jobAPI) ResourceCheck(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
	var req host.ResourceCheck
	if err := httphelper.DecodeJSON(r, &req); err != nil {
		httphelper.Error(w, err)
		return
	}
	var conflicts []host.Port
	for _, p := range req.Ports {
		if p.Proto == "" {
			p.Proto = "tcp"
		}
		if !checkPort(p) {
			conflicts = append(conflicts, p)
		}
	}
	if len(conflicts) > 0 {
		resp := host.ResourceCheck{Ports: conflicts}
		detail, err := json.Marshal(resp)
		if err != nil {
			httphelper.Error(w, err)
			return
		}
		httphelper.JSON(w, 409, &httphelper.JSONError{
			Code:    httphelper.ConflictErrorCode,
			Message: "Conflicting resources found",
			Detail:  detail,
		})
		return
	}
	httphelper.JSON(w, 200, struct{}{})
}
Beispiel #2
0
func (p *pgAPI) createDatabase(ctx context.Context, w http.ResponseWriter, req *http.Request) {
	username, password, database := random.Hex(16), random.Hex(16), random.Hex(16)

	if err := p.db.Exec(fmt.Sprintf(`CREATE USER "%s" WITH PASSWORD '%s'`, username, password)); err != nil {
		httphelper.Error(w, err)
		return
	}
	if err := p.db.Exec(fmt.Sprintf(`CREATE DATABASE "%s"`, database)); err != nil {
		p.db.Exec(fmt.Sprintf(`DROP USER "%s"`, username))
		httphelper.Error(w, err)
		return
	}
	if err := p.db.Exec(fmt.Sprintf(`GRANT ALL ON DATABASE "%s" TO "%s"`, database, username)); err != nil {
		p.db.Exec(fmt.Sprintf(`DROP DATABASE "%s"`, database))
		p.db.Exec(fmt.Sprintf(`DROP USER "%s"`, username))
		httphelper.Error(w, err)
		return
	}

	url := fmt.Sprintf("postgres://%s:%s@%s:5432/%s", username, password, serviceHost, database)
	httphelper.JSON(w, 200, resource.Resource{
		ID: fmt.Sprintf("/databases/%s:%s", username, database),
		Env: map[string]string{
			"FLYNN_POSTGRES": serviceName,
			"PGHOST":         serviceHost,
			"PGUSER":         username,
			"PGPASSWORD":     password,
			"PGDATABASE":     database,
			"DATABASE_URL":   url,
		},
	})
}
Beispiel #3
0
func (api *API) GetConfig(ctx context.Context, w http.ResponseWriter, req *http.Request) {
	config := baseConfig

	config.Endpoints["cluster_controller"] = fmt.Sprintf("https://%s", api.conf.ControllerDomain)
	config.Endpoints["cluster_status"] = fmt.Sprintf("https://status.%s", api.conf.DefaultRouteDomain)
	config.Endpoints["cert"] = fmt.Sprintf("http://%s/ca-cert", api.conf.ControllerDomain)
	config.DefaultRouteDomain = api.conf.DefaultRouteDomain
	config.GithubAPIURL = api.conf.GithubAPIURL
	config.GithubTokenURL = api.conf.GithubTokenURL
	config.GithubCloneAuthRequired = api.conf.GithubCloneAuthRequired

	if api.IsAuthenticated(ctx) {
		config.User = &ExpandedUser{}
		config.User.Auths = make(map[string]*OAuthToken)

		if api.conf.GithubToken != "" {
			config.User.Auths["github"] = &OAuthToken{AccessToken: api.conf.GithubToken}
		}

		config.User.ControllerKey = api.conf.ControllerKey
		config.User.StatusKey = api.conf.StatusKey
	}

	httphelper.JSON(w, 200, config)
}
Beispiel #4
0
func (api *API) UpdateRoute(ctx context.Context, w http.ResponseWriter, req *http.Request) {
	log, _ := ctxhelper.LoggerFromContext(ctx)
	params, _ := ctxhelper.ParamsFromContext(ctx)

	var route *router.Route
	if err := json.NewDecoder(req.Body).Decode(&route); err != nil {
		log.Error(err.Error())
		httphelper.Error(w, err)
		return
	}

	route.Type = params.ByName("route_type")
	route.ID = params.ByName("id")

	l := api.router.ListenerFor(route.Type)
	if l == nil {
		httphelper.ValidationError(w, "type", "Invalid route type")
		return
	}

	if err := l.UpdateRoute(route); err != nil {
		if err == ErrNotFound {
			w.WriteHeader(404)
			return
		}
		log.Error(err.Error())
		httphelper.Error(w, err)
		return
	}
	httphelper.JSON(w, 200, route)
}
Beispiel #5
0
func (api *API) CreateCert(ctx context.Context, w http.ResponseWriter, req *http.Request) {
	var cert *router.Certificate
	if err := json.NewDecoder(req.Body).Decode(&cert); err != nil {
		httphelper.Error(w, err)
		return
	}

	l := api.router.HTTP.(*HTTPListener)
	err := l.AddCert(cert)
	if err != nil {
		jsonError := httphelper.JSONError{}
		switch err {
		case ErrConflict:
			jsonError.Code = httphelper.ConflictErrorCode
			jsonError.Message = "Duplicate cert"
		case ErrInvalid:
			jsonError.Code = httphelper.ValidationErrorCode
			jsonError.Message = "Invalid cert"
		default:
			httphelper.Error(w, err)
			return
		}
	}
	httphelper.JSON(w, 200, cert)
}
Beispiel #6
0
func (api *API) GetRoutes(ctx context.Context, w http.ResponseWriter, req *http.Request) {
	log, _ := ctxhelper.LoggerFromContext(ctx)

	routes, err := api.router.HTTP.List()
	if err != nil {
		log.Error(err.Error())
		httphelper.Error(w, err)
		return
	}
	tcpRoutes, err := api.router.TCP.List()
	if err != nil {
		log.Error(err.Error())
		httphelper.Error(w, err)
		return
	}
	routes = append(routes, tcpRoutes...)

	if ref := req.URL.Query().Get("parent_ref"); ref != "" {
		filtered := make([]*router.Route, 0)
		for _, route := range routes {
			if route.ParentRef == ref {
				filtered = append(filtered, route)
			}
		}
		routes = filtered
	}

	sort.Sort(sortedRoutes(routes))
	httphelper.JSON(w, 200, routes)
}
Beispiel #7
0
func (c *controllerAPI) DeleteResource(ctx context.Context, w http.ResponseWriter, req *http.Request) {
	params, _ := ctxhelper.ParamsFromContext(ctx)
	id := params.ByName("resources_id")

	p, err := c.getProvider(ctx)
	if err != nil {
		respondWithError(w, err)
		return
	}

	res, err := c.resourceRepo.Get(id)
	if err != nil {
		respondWithError(w, err)
		return
	}

	if err := resource.Deprovision(p.URL, res.ExternalID); err != nil {
		respondWithError(w, err)
		return
	}

	if err := c.resourceRepo.Remove(res); err != nil {
		respondWithError(w, err)
		return
	}

	httphelper.JSON(w, 200, res)
}
Beispiel #8
0
func (c *controllerAPI) PutResource(ctx context.Context, w http.ResponseWriter, req *http.Request) {
	params, _ := ctxhelper.ParamsFromContext(ctx)

	p, err := c.getProvider(ctx)
	if err != nil {
		respondWithError(w, err)
		return
	}

	var resource ct.Resource
	if err = httphelper.DecodeJSON(req, &resource); err != nil {
		respondWithError(w, err)
		return
	}

	resource.ID = params.ByName("resources_id")
	resource.ProviderID = p.ID

	if err := schema.Validate(resource); err != nil {
		respondWithError(w, err)
		return
	}

	if err := c.resourceRepo.Add(&resource); err != nil {
		respondWithError(w, err)
		return
	}
	httphelper.JSON(w, 200, &resource)
}
Beispiel #9
0
func (h *jobAPI) Update(w http.ResponseWriter, req *http.Request, _ httprouter.Params) {
	log := h.host.log.New("fn", "Update")

	log.Info("decoding command")
	var cmd host.Command
	if err := httphelper.DecodeJSON(req, &cmd); err != nil {
		log.Error("error decoding command", "err", err)
		httphelper.Error(w, err)
		return
	}

	log.Info("updating host")
	err := h.host.Update(&cmd)
	if err != nil {
		httphelper.Error(w, err)
		return
	}

	// send an ok response and then shutdown after 1s to give the response
	// chance to reach the client.
	httphelper.JSON(w, http.StatusOK, cmd)
	log.Info("shutting down in 1s")
	time.AfterFunc(time.Second, func() {
		log.Info("exiting")
		os.Exit(0)
	})
}
Beispiel #10
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)
}
Beispiel #11
0
func (api *HTTPAPI) CreateProvider(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	pspec := &volume.ProviderSpec{}
	if err := httphelper.DecodeJSON(r, &pspec); err != nil {
		httphelper.Error(w, err)
		return
	}
	if pspec.ID == "" {
		pspec.ID = random.UUID()
	}
	if pspec.Kind == "" {
		httphelper.ValidationError(w, "kind", "must not be blank")
		return
	}
	var provider volume.Provider
	provider, err := volumemanager.NewProvider(pspec)
	if err == volume.UnknownProviderKind {
		httphelper.ValidationError(w, "kind", fmt.Sprintf("%q is not known", pspec.Kind))
		return
	}

	if err := api.vman.AddProvider(pspec.ID, provider); err != nil {
		switch err {
		case volumemanager.ErrProviderExists:
			httphelper.ObjectExistsError(w, fmt.Sprintf("provider %q already exists", pspec.ID))
			return
		default:
			httphelper.Error(w, err)
			return
		}
	}

	httphelper.JSON(w, 200, pspec)
}
Beispiel #12
0
func (c *controllerAPI) SetAppRelease(ctx context.Context, w http.ResponseWriter, req *http.Request) {
	var rid releaseID
	if err := httphelper.DecodeJSON(req, &rid); err != nil {
		respondWithError(w, err)
		return
	}

	rel, err := c.releaseRepo.Get(rid.ID)
	if err != nil {
		if err == ErrNotFound {
			err = ct.ValidationError{
				Message: fmt.Sprintf("could not find release with ID %s", rid.ID),
			}
		}
		respondWithError(w, err)
		return
	}
	release := rel.(*ct.Release)

	if err := schema.Validate(release); err != nil {
		respondWithError(w, err)
		return
	}

	app := c.getApp(ctx)
	c.appRepo.SetRelease(app, release.ID)
	httphelper.JSON(w, 200, release)
}
Beispiel #13
0
func (api *httpAPI) GetCloudRegions(w http.ResponseWriter, req *http.Request, _ httprouter.Params) {
	params := req.URL.Query()
	cloud := params.Get("cloud")
	if cloud != "digital_ocean" && cloud != "azure" {
		httphelper.ObjectNotFoundError(w, "")
		return
	}
	credentialID := params.Get("credential_id")
	creds, err := api.Installer.FindCredentials(credentialID)
	if err != nil {
		httphelper.ValidationError(w, "credential_id", "Invalid credential id")
		return
	}
	var res interface{}
	switch cloud {
	case "digital_ocean":
		res, err = api.Installer.ListDigitalOceanRegions(creds)
	case "azure":
		res, err = api.Installer.ListAzureRegions(creds)
	}
	if err != nil {
		httphelper.Error(w, err)
		return
	}
	httphelper.JSON(w, 200, res)
}
Beispiel #14
0
func (c *controllerAPI) UpdateApp(ctx context.Context, rw http.ResponseWriter, req *http.Request) {
	params, _ := ctxhelper.ParamsFromContext(ctx)

	var data appUpdate
	if err := httphelper.DecodeJSON(req, &data); err != nil {
		respondWithError(rw, err)
		return
	}

	if v, ok := data["meta"]; ok && v == nil {
		// handle {"meta": null}
		delete(data, "meta")
	}

	if err := schema.Validate(data); err != nil {
		respondWithError(rw, err)
		return
	}

	app, err := c.appRepo.Update(params.ByName("apps_id"), data)
	if err != nil {
		respondWithError(rw, err)
		return
	}
	httphelper.JSON(rw, 200, app)
}
Beispiel #15
0
func (a *API) createDatabase(ctx context.Context, w http.ResponseWriter, req *http.Request) {
	username, password, database := random.Hex(16), random.Hex(16), random.Hex(16)

	if _, err := a.db.Exec(fmt.Sprintf("CREATE USER '%s'@'%%' IDENTIFIED BY '%s'", username, password)); err != nil {
		httphelper.Error(w, err)
		return
	}
	if _, err := a.db.Exec(fmt.Sprintf("CREATE DATABASE `%s`", database)); err != nil {
		a.db.Exec(fmt.Sprintf("DROP USER '%s'", username))
		httphelper.Error(w, err)
		return
	}
	if _, err := a.db.Exec(fmt.Sprintf("GRANT ALL ON `%s`.* TO '%s'@'%%'", database, username)); err != nil {
		a.db.Exec(fmt.Sprintf("DROP DATABASE `%s`", database))
		a.db.Exec(fmt.Sprintf("DROP USER '%s'", username))
		httphelper.Error(w, err)
		return
	}

	url := fmt.Sprintf("mysql://%s:%s@%s:3306/%s", username, password, serviceHost, database)
	httphelper.JSON(w, 200, resource.Resource{
		ID: fmt.Sprintf("/databases/%s:%s", username, database),
		Env: map[string]string{
			"FLYNN_MYSQL":    serviceName,
			"MYSQL_HOST":     serviceHost,
			"MYSQL_USER":     username,
			"MYSQL_PWD":      password,
			"MYSQL_DATABASE": database,
			"DATABASE_URL":   url,
		},
	})
}
Beispiel #16
0
func (c *controllerAPI) UpdateAppMeta(ctx context.Context, rw http.ResponseWriter, req *http.Request) {
	params, _ := ctxhelper.ParamsFromContext(ctx)

	var data appUpdate
	if err := httphelper.DecodeJSON(req, &data); err != nil {
		respondWithError(rw, err)
		return
	}

	if err := schema.Validate(data); err != nil {
		respondWithError(rw, err)
		return
	}

	if data["meta"] == nil {
		data["meta"] = make(map[string]interface{})
	}

	app, err := c.appRepo.Update(params.ByName("apps_id"), data)
	if err != nil {
		respondWithError(rw, err)
		return
	}
	httphelper.JSON(rw, 200, app)
}
Beispiel #17
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())
}
Beispiel #18
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
	}
}
Beispiel #19
0
func (c *controllerAPI) PutFormation(ctx context.Context, w http.ResponseWriter, req *http.Request) {
	app := c.getApp(ctx)
	release, err := c.getRelease(ctx)
	if err != nil {
		respondWithError(w, err)
		return
	}

	var formation ct.Formation
	if err = httphelper.DecodeJSON(req, &formation); err != nil {
		respondWithError(w, err)
		return
	}

	if release.ArtifactID == "" {
		respondWithError(w, ct.ValidationError{Message: "release is not deployable"})
		return
	}

	formation.AppID = app.ID
	formation.ReleaseID = release.ID

	if err = schema.Validate(formation); err != nil {
		respondWithError(w, err)
		return
	}

	if err = c.formationRepo.Add(&formation); err != nil {
		respondWithError(w, err)
		return
	}
	httphelper.JSON(w, 200, &formation)
}
Beispiel #20
0
// serveGetRaftPeers returns the current raft peers.
func (h *Handler) serveGetRaftPeers(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
	peers, err := h.Store.GetPeers()
	if err != nil {
		hh.Error(w, err)
	}

	hh.JSON(w, 200, peers)
}
Beispiel #21
0
func (c *controllerAPI) ListActiveJobs(ctx context.Context, w http.ResponseWriter, req *http.Request) {
	list, err := c.jobRepo.ListActive()
	if err != nil {
		respondWithError(w, err)
		return
	}
	httphelper.JSON(w, 200, list)
}
Beispiel #22
0
func (api *HTTPAPI) List(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
	vols := api.vman.Volumes()
	volList := make([]*volume.Info, 0, len(vols))
	for _, v := range vols {
		volList = append(volList, v.Info())
	}
	httphelper.JSON(w, 200, volList)
}
Beispiel #23
0
func (c *controllerAPI) GetRouteList(ctx context.Context, w http.ResponseWriter, req *http.Request) {
	routes, err := c.routerc.ListRoutes(routeParentRef(c.getApp(ctx).ID))
	if err != nil {
		respondWithError(w, err)
		return
	}
	httphelper.JSON(w, 200, routes)
}
Beispiel #24
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)
}
Beispiel #25
0
func (c *controllerAPI) GetAppResources(ctx context.Context, w http.ResponseWriter, req *http.Request) {
	res, err := c.resourceRepo.AppList(c.getApp(ctx).ID)
	if err != nil {
		respondWithError(w, err)
		return
	}
	httphelper.JSON(w, 200, res)
}
Beispiel #26
0
func (c *controllerAPI) GetAppRelease(ctx context.Context, w http.ResponseWriter, req *http.Request) {
	release, err := c.appRepo.GetRelease(c.getApp(ctx).ID)
	if err != nil {
		respondWithError(w, err)
		return
	}
	httphelper.JSON(w, 200, release)
}
Beispiel #27
0
func (h *Handler) serveShutdown(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
	h.Shutdown.Store(true)
	targetLogIndex, err := h.Main.Close()
	if err != nil {
		hh.Error(w, err)
		return
	}
	hh.JSON(w, 200, targetLogIndex)
}
Beispiel #28
0
// serveGetRaftLeader returns the current raft leader.
func (h *Handler) serveGetRaftLeader(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
	leader := h.Store.Leader()
	if leader == "" {
		hh.Error(w, ErrNoKnownLeader)
		return
	}

	hh.JSON(w, 200, dt.RaftLeader{Host: h.Store.Leader()})
}
Beispiel #29
0
func (c *controllerAPI) GetJob(ctx context.Context, w http.ResponseWriter, req *http.Request) {
	params, _ := ctxhelper.ParamsFromContext(ctx)
	job, err := c.jobRepo.Get(params.ByName("jobs_id"))
	if err != nil {
		respondWithError(w, err)
		return
	}
	httphelper.JSON(w, 200, job)
}
Beispiel #30
0
func (c *controllerAPI) ListFormations(ctx context.Context, w http.ResponseWriter, req *http.Request) {
	app := c.getApp(ctx)
	list, err := c.formationRepo.List(app.ID)
	if err != nil {
		respondWithError(w, err)
		return
	}
	httphelper.JSON(w, 200, list)
}