Ejemplo n.º 1
0
func (app *App) handleUserByName(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case "GET":
		vars := mux.Vars(r)
		username := vars["name"]
		// only return all user data if the session user has
		// admin privlages. Need to check the session user against
		// the User table.
		u, ok := app.getUser(r)
		if !ok || (u.Name != username) {
			http.Error(w, "Unauthorized", http.StatusUnauthorized)
			return
		}
		tx, err := app.db.Begin()
		if err != nil {
			app.dbError(w, r, err)
			return
		}
		defer tx.Rollback()
		user, err := db.GetUser(tx, username)
		if err != nil {
			if db.IsNotFound(err) {
				http.Error(w, "User not found", http.StatusNotFound)
			} else {
				app.dbError(w, r, err)
			}
			return
		}
		app.writeJson(w, user)
	default:
		http.Error(w, "I only respond to GETs", http.StatusNotImplemented)
	}
}
Ejemplo n.º 2
0
func (app *App) handleUser(w http.ResponseWriter, r *http.Request) {
	if r.Method != "GET" {
		http.Error(w, "I only respond to GETs", http.StatusNotImplemented)
		return
	}
	u, ok := app.getUser(r)
	if !ok {
		http.Error(w, "Unauthorized", http.StatusUnauthorized)
		return
	}
	tx, err := app.db.Begin()
	if err != nil {
		app.dbError(w, r, err)
		return
	}
	defer tx.Rollback()
	user, err := db.GetUser(tx, u.Name)
	if err != nil {
		if db.IsNotFound(err) {
			http.Error(w, "User not found", http.StatusNotFound)
		} else {
			app.dbError(w, r, err)
		}
		return
	}
	viewUser := struct {
		Name   string
		Email  string
		Admin  bool
		Apikey string
	}{user.Name, user.Email, user.Admin, user.Apikey}
	app.writeJson(w, &viewUser)
}
Ejemplo n.º 3
0
func (app *App) handleModel(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case "GET":
		vars := mux.Vars(r)
		name := vars["name"]
		user, ok := app.getUser(r)
		if !ok {
			http.Error(w, "Unauthorized", http.StatusUnauthorized)
			return
		}

		tx, err := app.db.Begin()
		if err != nil {
			app.dbError(w, r, err)
			return
		}
		defer tx.Rollback()
		model, err := db.GetModel(tx, user.Name, name)
		if err != nil {
			if db.IsNotFound(err) {
				http.Error(w, "Model not found", http.StatusNotFound)
			} else {
				app.dbError(w, r, err)
			}
			return
		}
		v := model.ActiveVersion
		activeVersion, err := db.GetModelVersion(tx, user.Name, name, v)
		if err != nil {
			if db.IsNotFound(err) {
				http.Error(w, "Model not found", http.StatusNotFound)
			} else {
				app.dbError(w, r, err)
			}
			return
		}
		app.writeJson(w, map[string]interface{}{
			"Model":   model,
			"Version": activeVersion,
		})
	default:
		http.Error(w, "I only respond to GETs", http.StatusNotImplemented)
	}
}
Ejemplo n.º 4
0
func (app *App) handleLogin(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case "GET":
		app.serveFile("login.html").ServeHTTP(w, r)
	case "POST":

		username := r.FormValue("username")
		password := r.FormValue("password")
		if username == "" {
			http.Error(w, "No username provided", http.StatusBadRequest)
			return
		}
		if password == "" {
			http.Error(w, "No password provided", http.StatusBadRequest)
			return
		}

		tx, err := app.db.Begin()
		if err != nil {
			app.dbError(w, r, err)
			return
		}
		defer tx.Rollback()

		user, err := db.GetUser(tx, username)
		if err != nil {
			if db.IsNotFound(err) {
				http.Error(w, "User not found", http.StatusNotFound)
			} else {
				app.dbError(w, r, err)
			}
			return
		}
		if phash.Verify(password, user.Password) {
			u := &User{Id: user.Id, Name: user.Name}
			app.setUser(r, w, u)
			w.WriteHeader(http.StatusOK)
		} else {
			http.Error(w, "Invalid username passsword combination.", http.StatusBadRequest)
		}

	default:
		http.Error(w, "I only respond to GET and POSTs", http.StatusNotImplemented)
	}
}
Ejemplo n.º 5
0
func (app *App) handleVerifyPassword(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case "POST":
		// user should already be logged in, we're just validating the password
		password := r.FormValue("password")
		sessionUser, ok := app.getUser(r)

		if !ok {
			http.Error(w, "No user logged in", http.StatusBadRequest)
			return
		}

		tx, err := app.db.Begin()
		if err != nil {
			app.dbError(w, r, err)
			return
		}
		defer tx.Rollback()

		user, err := db.GetUser(tx, sessionUser.Name)
		if err != nil {
			if db.IsNotFound(err) {
				http.Error(w, "User not found", http.StatusNotFound)
			} else {
				app.dbError(w, r, err)
			}
			return
		}

		if password == "" {
			http.Error(w, "No password provided", http.StatusBadRequest)
			return
		}

		if phash.Verify(password, user.Password) {
			w.WriteHeader(http.StatusOK)
		} else {
			http.Error(w, "Invalid username passsword combination.", http.StatusBadRequest)
		}

	default:
		http.Error(w, "I only respond to POSTs", http.StatusNotImplemented)
	}
}
Ejemplo n.º 6
0
// handleOldVerify handles the the /verify route hit by the R and Python
// clients.
func (app *App) handleOldVerify(w http.ResponseWriter, r *http.Request) {
	username, apikey, ok := r.BasicAuth()
	if !ok || username == "" {
		username = r.FormValue("username")
		apikey = r.FormValue("apikey")
	}

	if username == "" {
		http.Error(w, "No auth provided", http.StatusUnauthorized)
		return
	}

	tx, err := app.db.Begin()
	if err != nil {
		app.dbError(w, r, err)
		return
	}
	defer tx.Rollback()

	user, err := db.GetUser(tx, username)
	if err != nil {
		if db.IsNotFound(err) {
			w.WriteHeader(http.StatusNotFound)
			w.Write([]byte("user not found"))
			app.logf("authentication failed %s:%s", username, apikey)
		} else {
			app.dbError(w, r, err)
		}
		return
	}
	if apikey != user.Apikey {
		app.logf("authentication failed %s:%s", username, apikey)
		http.Error(w, "APIKEY did not match", http.StatusUnauthorized)
		return
	}
	w.Header().Set("Content-Type", "application/json")
	w.Write([]byte(`{"success": "true"}`))
}
Ejemplo n.º 7
0
func (app *App) handleModelLogs(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case "GET":
		vars := mux.Vars(r)
		name := vars["name"]
		user, ok := app.getUser(r)
		if !ok {
			http.Error(w, "Unauthorized", http.StatusUnauthorized)
			return
		}

		tx, err := app.db.Begin()
		if err != nil {
			app.dbError(w, r, err)
			return
		}
		defer tx.Rollback()
		model, err := db.GetModel(tx, user.Name, name)
		if err != nil {
			if db.IsNotFound(err) {
				http.Error(w, "Model not found", http.StatusNotFound)
			} else {
				app.dbError(w, r, err)
			}
			return
		}
		logLines, err := alb.ReadDeploymentLogs(app.modelLogsDir,
			user.Name, name, model.LastDeployment)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		app.writeJson(w, logLines)
	default:
		http.Error(w, "I only respond to GETs", http.StatusNotImplemented)
	}
}
Ejemplo n.º 8
0
func (s *storage) Get(user, model string, version int) (*mps.DeployInfo, string, error) {
	tx, err := s.app.db.Begin()
	if err != nil {
		return nil, "", fmt.Errorf("database unavailabled: %v", err)
	}
	defer tx.Rollback()
	modelVersion, err := db.GetModelVersion(tx, user, model, version)
	if err != nil {
		if db.IsNotFound(err) {
			return nil, "", errors.New("model version not found")
		}
		return nil, "", fmt.Errorf("could not query model version: %v", err)
	}

	baseImage, err := db.GetBaseImage(tx, modelVersion.Lang)
	if err != nil && err != sql.ErrNoRows {
		return nil, "", fmt.Errorf("could not query baseImage: %v", err)
	}

	// TODO: Conda channels, CRAN mirror and apt-get sources
	info := &mps.DeployInfo{
		Username:         user,
		Modelname:        model,
		Version:          version,
		Lang:             modelVersion.Lang,
		LanguagePackages: modelVersion.LangPackages,
		UbuntuPackages:   modelVersion.UbuntuPackages,
		BaseImage:        baseImage,
	}
	if modelVersion.BundleFilename == "" {
		return nil, "", fmt.Errorf("no bundle file provided")
	}
	bundlePath := filepath.Join(s.app.bundleDir, modelVersion.BundleFilename)
	log.Println("bundle path is", bundlePath)
	return info, bundlePath, nil
}
Ejemplo n.º 9
0
// handleDeployment listens on the /deployer route and handles requests
// from the R and Python clients.
func (app *App) handleDeployment(w http.ResponseWriter, r *http.Request) {

	// for phone home metrics
	start := time.Now()

	username, apikey, ok := r.BasicAuth()
	if !ok || username == "" {
		username = r.FormValue("username")
		apikey = r.FormValue("apikey")
	}

	if username == "" {
		http.Error(w, "No auth provided", http.StatusUnauthorized)
		return
	}

	tx, err := app.db.Begin()
	if err != nil {
		app.dbError(w, r, err)
		return
	}
	defer tx.Rollback()

	user, err := db.GetUser(tx, username)
	if err != nil {
		if db.IsNotFound(err) {
			w.WriteHeader(http.StatusNotFound)
			w.Write([]byte("user not found"))
		} else {
			app.dbError(w, r, err)
		}
		return
	}
	if apikey != user.Apikey {
		http.Error(w, "APIKEY did not match", http.StatusUnauthorized)
		return
	}

	info, bundle, err := mps.ReadBundle(r)
	if err != nil {
		http.Error(w, "Could not parse upload request "+err.Error(), http.StatusBadRequest)
		return
	}

	modelSize := int64(len(bundle))

	// validate model info
	if !isValidModelName(info.Modelname) {
		http.Error(w, fmt.Sprintf("'%s' is an invalid model name", info.Modelname), http.StatusBadRequest)
		return
	}

	// Write bundle to disk
	timestamp := time.Now().UTC().Format("2006_01_02_15_04_05")
	bundleFilename := user.Name + "_" + info.Modelname + "_" + timestamp + ".json"
	b := filepath.Join(app.bundleDir, bundleFilename)
	log.Println(b)
	if err := ioutil.WriteFile(b, bundle, 0644); err != nil {
		http.Error(w, fmt.Sprintf("could not write model file to disk %v", err), http.StatusInternalServerError)
		return
	}

	// add bundle to database
	p := db.NewVersionParams{
		UserId:         user.Id,
		Model:          info.Modelname,
		Lang:           info.Lang,
		LangPackages:   info.LanguagePackages,
		UbuntuPackages: info.UbuntuPackages,
		SourceCode:     info.SourceCode,
		BundleFilename: bundleFilename,
	}
	versionNum, err := db.NewModelVersion(tx, &p)
	if err != nil {
		http.Error(w, "could not create new model version: "+err.Error(), http.StatusInternalServerError)
		return
	}
	if err := tx.Commit(); err != nil {
		app.dbError(w, r, err)
		return
	}

	clientIP := r.RemoteAddr

	go func(user, model string, version int) {
		app.logf("deployment of %s:%s:%d started", user, model, version)
		err := app.sup.Deploy(user, model, version)
		if err != nil {
			app.logf("deployment of %s:%s:%d failed %v", user, model, version, err)
		} else {
			app.logf("deployment of %s:%s:%d succeeded", user, model, version)
		}

		if app.isdev {
			return
		}

		// Send phone home metrics
		errmsg := ""
		if err != nil {
			errmsg = err.Error()
		}

		d := &events.Deployment{
			StartTime: start.Unix(),
			EndTime:   time.Now().Unix(),
			Username:  user,
			ModelName: model,
			ModelLang: info.Lang,
			ModelVer:  int64(version),
			Service:   app.serviceName,
			ClientIP:  clientIP,
			Error:     errmsg,
			ModelSize: modelSize,
			ModelDeps: packages(info.LanguagePackages).String(),
		}
		data, err := json.Marshal(&d)
		if err != nil {
			app.logf("could not marshal deployment: %v", err)
			return
		}

		resp, err := http.Post(events.Endpoint, "application/json", bytes.NewReader(data))
		if err != nil {
			app.logf("failed to make request: %v", err)
			return
		}
		defer resp.Body.Close()

		if resp.StatusCode != http.StatusOK {
			body, err := ioutil.ReadAll(resp.Body)
			if err != nil {
				app.logf("could not read body: %v", err)
				return
			}
			app.logf("could not send info: %s %v", resp.Status, body)
		}

	}(user.Name, info.Modelname, versionNum)

	// send a JSON response to the user
	resp := struct {
		Status  string `json:"status"`
		Version int    `json:"version"`
	}{"Successfully deployed", versionNum}
	data, err := json.Marshal(&resp)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	w.Header().Set("Content-Type", "application/json")
	w.Write(data)
}