예제 #1
0
파일: event.go 프로젝트: tsuru/tsuru
// title: event list
// path: /events
// method: GET
// produce: application/json
// responses:
//   200: OK
//   204: No content
func eventList(w http.ResponseWriter, r *http.Request, t auth.Token) error {
	r.ParseForm()
	filter := &event.Filter{}
	dec := form.NewDecoder(nil)
	dec.IgnoreUnknownKeys(true)
	dec.IgnoreCase(true)
	err := dec.DecodeValues(&filter, r.Form)
	if err != nil {
		return &errors.HTTP{Code: http.StatusBadRequest, Message: fmt.Sprintf("unable to parse event filters: %s", err)}
	}
	filter.PruneUserValues()
	filter.Permissions, err = t.Permissions()
	if err != nil {
		return err
	}
	events, err := event.List(filter)
	if err != nil {
		return err
	}
	if len(events) == 0 {
		w.WriteHeader(http.StatusNoContent)
		return nil
	}
	w.Header().Add("Content-Type", "application/json")
	return json.NewEncoder(w).Encode(events)
}
예제 #2
0
파일: iaas.go 프로젝트: tsuru/tsuru
// title: template create
// path: /iaas/templates
// method: POST
// consume: application/x-www-form-urlencoded
// responses:
//   201: Template created
//   400: Invalid data
//   401: Unauthorized
func templateCreate(w http.ResponseWriter, r *http.Request, token auth.Token) (err error) {
	err = r.ParseForm()
	if err != nil {
		return &errors.HTTP{Code: http.StatusBadRequest, Message: err.Error()}
	}
	var paramTemplate iaas.Template
	dec := form.NewDecoder(nil)
	dec.IgnoreUnknownKeys(true)
	err = dec.DecodeValues(&paramTemplate, r.Form)
	if err != nil {
		return &errors.HTTP{Code: http.StatusBadRequest, Message: err.Error()}
	}
	iaasCtx := permission.Context(permission.CtxIaaS, paramTemplate.IaaSName)
	allowed := permission.Check(token, permission.PermMachineTemplateCreate, iaasCtx)
	if !allowed {
		return permission.ErrUnauthorized
	}
	evt, err := event.New(&event.Opts{
		Target:     event.Target{Type: event.TargetTypeIaas, Value: paramTemplate.IaaSName},
		Kind:       permission.PermMachineTemplateCreate,
		Owner:      token,
		CustomData: event.FormToCustomData(r.Form),
		Allowed:    event.Allowed(permission.PermMachineReadEvents, iaasCtx),
	})
	if err != nil {
		return err
	}
	defer func() { evt.Done(err) }()
	err = paramTemplate.Save()
	if err != nil {
		return err
	}
	w.WriteHeader(http.StatusCreated)
	return nil
}
예제 #3
0
파일: app.go 프로젝트: tsuru/tsuru
// title: set node status
// path: /node/status
// method: POST
// consume: application/x-www-form-urlencoded
// produce: application/json
// responses:
//   200: Ok
//   400: Invalid data
//   401: Unauthorized
//   404: App or unit not found
func setNodeStatus(w http.ResponseWriter, r *http.Request, t auth.Token) error {
	if t.GetAppName() != app.InternalAppName {
		return &errors.HTTP{Code: http.StatusForbidden, Message: "this token is not allowed to execute this action"}
	}
	err := r.ParseForm()
	if err != nil {
		return &errors.HTTP{Code: http.StatusBadRequest, Message: err.Error()}
	}
	var hostInput provision.NodeStatusData
	dec := form.NewDecoder(nil)
	dec.IgnoreUnknownKeys(true)
	err = dec.DecodeValues(&hostInput, r.Form)
	if err != nil {
		return &errors.HTTP{Code: http.StatusBadRequest, Message: err.Error()}
	}
	result, err := app.UpdateNodeStatus(hostInput)
	if err != nil {
		if err == provision.ErrNodeNotFound {
			return &errors.HTTP{Code: http.StatusNotFound, Message: err.Error()}
		}
		return err
	}
	w.Header().Add("Content-Type", "application/json")
	return json.NewEncoder(w).Encode(result)
}
예제 #4
0
파일: admin_test.go 프로젝트: tsuru/tsuru
func (s *S) TestRebalanceContainersRunAskingForConfirmation(c *check.C) {
	var stdout, stderr bytes.Buffer
	context := cmd.Context{
		Stdout: &stdout,
		Stderr: &stderr,
		Stdin:  bytes.NewBufferString("y"),
	}
	msg, _ := json.Marshal(tsuruIo.SimpleJsonMessage{Message: "progress msg"})
	result := string(msg)
	trans := &cmdtest.ConditionalTransport{
		Transport: cmdtest.Transport{Message: result, Status: http.StatusOK},
		CondFunc: func(req *http.Request) bool {
			req.ParseForm()
			var params rebalanceOptions
			dec := form.NewDecoder(nil)
			dec.IgnoreUnknownKeys(true)
			err := dec.DecodeValues(&params, req.Form)
			c.Assert(err, check.IsNil)
			c.Assert(params.Dry, check.Equals, false)
			path := req.URL.Path == "/1.0/docker/containers/rebalance"
			method := req.Method == "POST"
			return path && method
		},
	}
	manager := cmd.NewManager("admin", "0.1", "admin-ver", &stdout, &stderr, nil, nil)
	client := cmd.NewClient(&http.Client{Transport: trans}, nil, manager)
	cmd := rebalanceContainersCmd{}
	err := cmd.Run(&context, client)
	c.Assert(err, check.IsNil)
	c.Assert(stdout.String(), check.Equals, "Are you sure you want to rebalance containers? (y/n) progress msg")
	cmd2 := rebalanceContainersCmd{}
	err = cmd2.Run(&context, client)
	c.Assert(err, check.IsNil)
}
예제 #5
0
파일: handlers.go 프로젝트: tsuru/tsuru
// title: autoscale set rule
// path: /docker/autoscale/rules
// method: POST
// consume: application/x-www-form-urlencoded
// responses:
//   200: Ok
//   400: Invalid data
//   401: Unauthorized
func autoScaleSetRule(w http.ResponseWriter, r *http.Request, t auth.Token) (err error) {
	allowedSetRule := permission.Check(t, permission.PermNodeAutoscaleUpdate)
	if !allowedSetRule {
		return permission.ErrUnauthorized
	}
	err = r.ParseForm()
	if err != nil {
		return &tsuruErrors.HTTP{Code: http.StatusBadRequest, Message: err.Error()}
	}
	var rule autoScaleRule
	dec := form.NewDecoder(nil)
	dec.IgnoreUnknownKeys(true)
	err = dec.DecodeValues(&rule, r.Form)
	if err != nil {
		return &tsuruErrors.HTTP{Code: http.StatusBadRequest, Message: err.Error()}
	}
	var ctxs []permission.PermissionContext
	if rule.MetadataFilter != "" {
		ctxs = append(ctxs, permission.Context(permission.CtxPool, rule.MetadataFilter))
	}
	evt, err := event.New(&event.Opts{
		Target:     event.Target{Type: event.TargetTypePool, Value: rule.MetadataFilter},
		Kind:       permission.PermNodeAutoscaleUpdate,
		Owner:      t,
		CustomData: event.FormToCustomData(r.Form),
		Allowed:    event.Allowed(permission.PermPoolReadEvents, ctxs...),
	})
	if err != nil {
		return err
	}
	defer func() { evt.Done(err) }()
	return rule.update()
}
예제 #6
0
파일: handlers.go 프로젝트: tsuru/tsuru
// title: logs config set
// path: /docker/logs
// method: POST
// consume: application/x-www-form-urlencoded
// produce: application/x-json-stream
// responses:
//   200: Ok
//   400: Invalid data
//   401: Unauthorized
func logsConfigSetHandler(w http.ResponseWriter, r *http.Request, t auth.Token) (err error) {
	err = r.ParseForm()
	if err != nil {
		return &tsuruErrors.HTTP{
			Code:    http.StatusBadRequest,
			Message: fmt.Sprintf("unable to parse form values: %s", err),
		}
	}
	pool := r.FormValue("pool")
	restart, _ := strconv.ParseBool(r.FormValue("restart"))
	delete(r.Form, "pool")
	delete(r.Form, "restart")
	var conf container.DockerLogConfig
	dec := form.NewDecoder(nil)
	dec.IgnoreUnknownKeys(true)
	err = dec.DecodeValues(&conf, r.Form)
	if err != nil {
		return &tsuruErrors.HTTP{
			Code:    http.StatusBadRequest,
			Message: fmt.Sprintf("unable to parse fields in docker log config: %s", err),
		}
	}
	var ctxs []permission.PermissionContext
	if pool != "" {
		ctxs = append(ctxs, permission.Context(permission.CtxPool, pool))
	}
	hasPermission := permission.Check(t, permission.PermPoolUpdateLogs, ctxs...)
	if !hasPermission {
		return permission.ErrUnauthorized
	}
	evt, err := event.New(&event.Opts{
		Target:      event.Target{Type: event.TargetTypePool, Value: pool},
		Kind:        permission.PermPoolUpdateLogs,
		Owner:       t,
		CustomData:  event.FormToCustomData(r.Form),
		DisableLock: true,
		Allowed:     event.Allowed(permission.PermPoolReadEvents, ctxs...),
	})
	if err != nil {
		return err
	}
	defer func() { evt.Done(err) }()
	err = conf.Save(pool)
	if err != nil {
		return err
	}
	w.Header().Set("Content-Type", "application/x-json-stream")
	keepAliveWriter := tsuruIo.NewKeepAliveWriter(w, 15*time.Second, "")
	defer keepAliveWriter.Stop()
	writer := &tsuruIo.SimpleJsonMessageEncoderWriter{Encoder: json.NewEncoder(keepAliveWriter)}
	fmt.Fprintln(writer, "Log config successfully updated.")
	if restart {
		filter := &app.Filter{}
		if pool != "" {
			filter.Pools = []string{pool}
		}
		return tryRestartAppsByFilter(filter, writer)
	}
	return nil
}
예제 #7
0
파일: node.go 프로젝트: tsuru/tsuru
// title: node healing update
// path: /healing/node
// method: POST
// consume: application/x-www-form-urlencoded
// responses:
//   200: Ok
//   401: Unauthorized
func nodeHealingUpdate(w http.ResponseWriter, r *http.Request, t auth.Token) (err error) {
	err = r.ParseForm()
	if err != nil {
		return err
	}
	poolName := r.FormValue("pool")
	var ctxs []permission.PermissionContext
	if poolName != "" {
		ctxs = append(ctxs, permission.Context(permission.CtxPool, poolName))
	}
	if !permission.Check(t, permission.PermHealingUpdate, ctxs...) {
		return permission.ErrUnauthorized
	}
	evt, err := event.New(&event.Opts{
		Target:      event.Target{Type: event.TargetTypePool, Value: poolName},
		Kind:        permission.PermHealingUpdate,
		Owner:       t,
		CustomData:  event.FormToCustomData(r.Form),
		DisableLock: true,
		Allowed:     event.Allowed(permission.PermPoolReadEvents, ctxs...),
	})
	if err != nil {
		return err
	}
	defer func() { evt.Done(err) }()
	var config healer.NodeHealerConfig
	delete(r.Form, "pool")
	dec := form.NewDecoder(nil)
	dec.IgnoreUnknownKeys(true)
	err = dec.DecodeValues(&config, r.Form)
	if err != nil {
		return err
	}
	return healer.UpdateConfig(poolName, config)
}
예제 #8
0
파일: app.go 프로젝트: tsuru/tsuru
// title: set envs
// path: /apps/{app}/env
// method: POST
// consume: application/x-www-form-urlencoded
// produce: application/x-json-stream
// responses:
//   200: Envs updated
//   400: Invalid data
//   401: Unauthorized
//   404: App not found
func setEnv(w http.ResponseWriter, r *http.Request, t auth.Token) (err error) {
	err = r.ParseForm()
	if err != nil {
		return &errors.HTTP{Code: http.StatusBadRequest, Message: err.Error()}
	}
	var e Envs
	dec := form.NewDecoder(nil)
	dec.IgnoreUnknownKeys(true)
	err = dec.DecodeValues(&e, r.Form)
	if err != nil {
		return &errors.HTTP{Code: http.StatusBadRequest, Message: err.Error()}
	}
	if len(e.Envs) == 0 {
		msg := "You must provide the list of environment variables"
		return &errors.HTTP{Code: http.StatusBadRequest, Message: msg}
	}
	appName := r.URL.Query().Get(":app")
	a, err := getAppFromContext(appName, r)
	if err != nil {
		return err
	}
	allowed := permission.Check(t, permission.PermAppUpdateEnvSet,
		contextsForApp(&a)...,
	)
	if !allowed {
		return permission.ErrUnauthorized
	}
	evt, err := event.New(&event.Opts{
		Target:     appTarget(appName),
		Kind:       permission.PermAppUpdateEnvSet,
		Owner:      t,
		CustomData: event.FormToCustomData(r.Form),
		Allowed:    event.Allowed(permission.PermAppReadEvents, contextsForApp(&a)...),
	})
	if err != nil {
		return err
	}
	defer func() { evt.Done(err) }()
	envs := map[string]string{}
	variables := []bind.EnvVar{}
	for _, v := range e.Envs {
		envs[v.Name] = v.Value
		variables = append(variables, bind.EnvVar{Name: v.Name, Value: v.Value, Public: !e.Private})
	}
	w.Header().Set("Content-Type", "application/x-json-stream")
	keepAliveWriter := tsuruIo.NewKeepAliveWriter(w, 30*time.Second, "")
	defer keepAliveWriter.Stop()
	writer := &tsuruIo.SimpleJsonMessageEncoderWriter{Encoder: json.NewEncoder(keepAliveWriter)}
	return a.SetEnvs(
		bind.SetEnvApp{
			Envs:          variables,
			PublicOnly:    true,
			ShouldRestart: !e.NoRestart,
		}, writer,
	)
}
예제 #9
0
파일: pool.go 프로젝트: tsuru/tsuru
// title: pool create
// path: /pools
// method: POST
// consume: application/x-www-form-urlencoded
// responses:
//   201: Pool created
//   400: Invalid data
//   401: Unauthorized
//   409: Pool already exists
func addPoolHandler(w http.ResponseWriter, r *http.Request, t auth.Token) (err error) {
	allowed := permission.Check(t, permission.PermPoolCreate)
	if !allowed {
		return permission.ErrUnauthorized
	}
	dec := form.NewDecoder(nil)
	dec.IgnoreCase(true)
	dec.IgnoreUnknownKeys(true)
	var addOpts provision.AddPoolOptions
	err = r.ParseForm()
	if err == nil {
		err = dec.DecodeValues(&addOpts, r.Form)
	}
	if err != nil {
		return &terrors.HTTP{
			Code:    http.StatusBadRequest,
			Message: err.Error(),
		}
	}
	if addOpts.Name == "" {
		return &terrors.HTTP{
			Code:    http.StatusBadRequest,
			Message: provision.ErrPoolNameIsRequired.Error(),
		}
	}
	evt, err := event.New(&event.Opts{
		Target:     event.Target{Type: event.TargetTypePool, Value: addOpts.Name},
		Kind:       permission.PermPoolCreate,
		Owner:      t,
		CustomData: event.FormToCustomData(r.Form),
		Allowed:    event.Allowed(permission.PermPoolReadEvents, permission.Context(permission.CtxPool, addOpts.Name)),
	})
	if err != nil {
		return err
	}
	defer func() { evt.Done(err) }()
	err = provision.AddPool(addOpts)
	if err == provision.ErrDefaultPoolAlreadyExists {
		return &terrors.HTTP{
			Code:    http.StatusConflict,
			Message: err.Error(),
		}
	}
	if err == provision.ErrPoolNameIsRequired {
		return &terrors.HTTP{
			Code:    http.StatusBadRequest,
			Message: err.Error(),
		}
	}
	if err == nil {
		w.WriteHeader(http.StatusCreated)
	}
	return err
}
예제 #10
0
// title: node container update
// path: /docker/nodecontainers/{name}
// method: POST
// consume: application/x-www-form-urlencoded
// responses:
//   200: Ok
//   400: Invald data
//   401: Unauthorized
//   404: Not found
func nodeContainerUpdate(w http.ResponseWriter, r *http.Request, t auth.Token) (err error) {
	err = r.ParseForm()
	if err != nil {
		return err
	}
	dec := form.NewDecoder(nil)
	dec.IgnoreUnknownKeys(true)
	dec.IgnoreCase(true)
	var config nodecontainer.NodeContainerConfig
	err = dec.DecodeValues(&config, r.Form)
	if err != nil {
		return err
	}
	poolName := r.FormValue("pool")
	var ctxs []permission.PermissionContext
	if poolName != "" {
		ctxs = append(ctxs, permission.Context(permission.CtxPool, poolName))
	}
	if !permission.Check(t, permission.PermNodecontainerUpdate, ctxs...) {
		return permission.ErrUnauthorized
	}
	evt, err := event.New(&event.Opts{
		Target:     event.Target{Type: event.TargetTypeNodeContainer, Value: config.Name},
		Kind:       permission.PermNodecontainerUpdate,
		Owner:      t,
		CustomData: event.FormToCustomData(r.Form),
		Allowed:    event.Allowed(permission.PermPoolReadEvents, ctxs...),
	})
	if err != nil {
		return err
	}
	defer func() { evt.Done(err) }()
	config.Name = r.URL.Query().Get(":name")
	err = nodecontainer.UpdateContainer(poolName, &config)
	if err != nil {
		if err == nodecontainer.ErrNodeContainerNotFound {
			return &tsuruErrors.HTTP{
				Code:    http.StatusNotFound,
				Message: err.Error(),
			}
		}
		if _, ok := err.(nodecontainer.ValidationErr); ok {
			return &tsuruErrors.HTTP{
				Code:    http.StatusBadRequest,
				Message: err.Error(),
			}
		}
		return err
	}
	return nil
}
예제 #11
0
파일: handlers.go 프로젝트: tsuru/tsuru
// title: move container
// path: /docker/container/{id}/move
// method: POST
// consume: application/x-www-form-urlencoded
// produce: application/x-json-stream
// responses:
//   200: Ok
//   400: Invalid data
//   401: Unauthorized
//   404: Not found
func moveContainerHandler(w http.ResponseWriter, r *http.Request, t auth.Token) (err error) {
	err = r.ParseForm()
	if err != nil {
		return &tsuruErrors.HTTP{Code: http.StatusBadRequest, Message: err.Error()}
	}
	params := map[string]string{}
	dec := form.NewDecoder(nil)
	dec.IgnoreUnknownKeys(true)
	err = dec.DecodeValues(&params, r.Form)
	if err != nil {
		return &tsuruErrors.HTTP{Code: http.StatusBadRequest, Message: err.Error()}
	}
	contId := r.URL.Query().Get(":id")
	to := params["to"]
	if to == "" {
		return errors.Errorf("Invalid params: id: %s - to: %s", contId, to)
	}
	cont, err := mainDockerProvisioner.GetContainer(contId)
	if err != nil {
		return &tsuruErrors.HTTP{Code: http.StatusNotFound, Message: err.Error()}
	}
	permContexts, err := moveContainersPermissionContexts(cont.HostAddr, to)
	if err != nil {
		return err
	}
	if !permission.Check(t, permission.PermNodeUpdateMoveContainer, permContexts...) {
		return permission.ErrUnauthorized
	}
	evt, err := event.New(&event.Opts{
		Target:     event.Target{Type: event.TargetTypeContainer, Value: contId},
		Kind:       permission.PermNodeUpdateMoveContainer,
		Owner:      t,
		CustomData: event.FormToCustomData(r.Form),
		Allowed:    event.Allowed(permission.PermPoolReadEvents, permContexts...),
	})
	if err != nil {
		return err
	}
	defer func() { evt.Done(err) }()
	w.Header().Set("Content-Type", "application/x-json-stream")
	keepAliveWriter := tsuruIo.NewKeepAliveWriter(w, 15*time.Second, "")
	defer keepAliveWriter.Stop()
	writer := &tsuruIo.SimpleJsonMessageEncoderWriter{Encoder: json.NewEncoder(keepAliveWriter)}
	_, err = mainDockerProvisioner.moveContainer(contId, to, writer)
	if err != nil {
		return errors.Wrap(err, "Error trying to move container")
	}
	fmt.Fprintf(writer, "Containers moved successfully!\n")
	return nil
}
예제 #12
0
func (r *Response) getForm() map[string]interface{} {
	if r.chain.failed() {
		return nil
	}

	if !r.checkContentType("application/x-www-form-urlencoded", "") {
		return nil
	}

	decoder := form.NewDecoder(bytes.NewReader(r.content))

	var object map[string]interface{}
	if err := decoder.Decode(&object); err != nil {
		r.chain.fail(err.Error())
		return nil
	}

	return object
}
예제 #13
0
파일: handlers.go 프로젝트: tsuru/tsuru
// title: rebalance containers
// path: /docker/containers/rebalance
// method: POST
// consume: application/x-www-form-urlencoded
// produce: application/x-json-stream
// responses:
//   200: Ok
//   204: No content
//   400: Invalid data
//   401: Unauthorized
func rebalanceContainersHandler(w http.ResponseWriter, r *http.Request, t auth.Token) (err error) {
	r.ParseForm()
	var params rebalanceOptions
	dec := form.NewDecoder(nil)
	dec.IgnoreUnknownKeys(true)
	err = dec.DecodeValues(&params, r.Form)
	if err != nil {
		return &tsuruErrors.HTTP{
			Code:    http.StatusBadRequest,
			Message: err.Error(),
		}
	}
	var permContexts []permission.PermissionContext
	pool, ok := params.MetadataFilter["pool"]
	if ok {
		permContexts = append(permContexts, permission.Context(permission.CtxPool, pool))
	}
	if !permission.Check(t, permission.PermNodeUpdateRebalance, permContexts...) {
		return permission.ErrUnauthorized
	}
	evt, err := event.New(&event.Opts{
		Target:      event.Target{Type: event.TargetTypePool, Value: pool},
		Kind:        permission.PermNodeUpdateRebalance,
		Owner:       t,
		CustomData:  event.FormToCustomData(r.Form),
		DisableLock: true,
		Allowed:     event.Allowed(permission.PermPoolReadEvents, permContexts...),
	})
	if err != nil {
		return err
	}
	defer func() { evt.Done(err) }()
	w.Header().Set("Content-Type", "application/x-json-stream")
	keepAliveWriter := tsuruIo.NewKeepAliveWriter(w, 15*time.Second, "")
	defer keepAliveWriter.Stop()
	writer := &tsuruIo.SimpleJsonMessageEncoderWriter{Encoder: json.NewEncoder(keepAliveWriter)}
	_, err = mainDockerProvisioner.rebalanceContainersByFilter(writer, params.AppFilter, params.MetadataFilter, params.Dry)
	if err != nil {
		return errors.Wrap(err, "Error trying to rebalance containers")
	}
	fmt.Fprintf(writer, "Containers successfully rebalanced!\n")
	return nil
}
예제 #14
0
파일: admin_test.go 프로젝트: tsuru/tsuru
func (s *S) TestRebalanceContainersRun(c *check.C) {
	var stdout, stderr bytes.Buffer
	context := cmd.Context{
		Stdout: &stdout,
		Stderr: &stderr,
	}
	msg, _ := json.Marshal(tsuruIo.SimpleJsonMessage{Message: "progress msg"})
	result := string(msg)
	expectedRebalance := rebalanceOptions{
		Dry: true,
	}
	trans := &cmdtest.ConditionalTransport{
		Transport: cmdtest.Transport{Message: result, Status: http.StatusOK},
		CondFunc: func(req *http.Request) bool {
			req.ParseForm()
			var params rebalanceOptions
			dec := form.NewDecoder(nil)
			dec.IgnoreUnknownKeys(true)
			err := dec.DecodeValues(&params, req.Form)
			c.Assert(err, check.IsNil)
			c.Assert(params, check.DeepEquals, expectedRebalance)
			path := req.URL.Path == "/1.0/docker/containers/rebalance"
			method := req.Method == "POST"
			return path && method
		},
	}
	manager := cmd.NewManager("admin", "0.1", "admin-ver", &stdout, &stderr, nil, nil)
	client := cmd.NewClient(&http.Client{Transport: trans}, nil, manager)
	cmd := rebalanceContainersCmd{}
	err := cmd.Flags().Parse(true, []string{"--dry", "-y"})
	c.Assert(err, check.IsNil)
	err = cmd.Run(&context, client)
	c.Assert(err, check.IsNil)
	expected := "progress msg"
	c.Assert(stdout.String(), check.Equals, expected)
	expectedRebalance = rebalanceOptions{
		Dry: false,
	}
	cmd2 := rebalanceContainersCmd{}
	cmd2.Flags().Parse(true, []string{"-y"})
	err = cmd2.Run(&context, client)
	c.Assert(err, check.IsNil)
}
예제 #15
0
파일: pool.go 프로젝트: tsuru/tsuru
// title: pool update
// path: /pools/{name}
// method: PUT
// consume: application/x-www-form-urlencoded
// responses:
//   200: Pool updated
//   401: Unauthorized
//   404: Pool not found
//   409: Default pool already defined
func poolUpdateHandler(w http.ResponseWriter, r *http.Request, t auth.Token) (err error) {
	r.ParseForm()
	allowed := permission.Check(t, permission.PermPoolUpdate)
	if !allowed {
		return permission.ErrUnauthorized
	}
	poolName := r.URL.Query().Get(":name")
	evt, err := event.New(&event.Opts{
		Target:     event.Target{Type: event.TargetTypePool, Value: poolName},
		Kind:       permission.PermPoolUpdate,
		Owner:      t,
		CustomData: event.FormToCustomData(r.Form),
		Allowed:    event.Allowed(permission.PermPoolReadEvents, permission.Context(permission.CtxPool, poolName)),
	})
	if err != nil {
		return err
	}
	defer func() { evt.Done(err) }()
	dec := form.NewDecoder(nil)
	dec.IgnoreCase(true)
	dec.IgnoreUnknownKeys(true)
	var updateOpts provision.UpdatePoolOptions
	err = dec.DecodeValues(&updateOpts, r.Form)
	if err != nil {
		return &terrors.HTTP{
			Code:    http.StatusBadRequest,
			Message: err.Error(),
		}
	}
	err = provision.PoolUpdate(poolName, updateOpts)
	if err == provision.ErrPoolNotFound {
		return &terrors.HTTP{Code: http.StatusNotFound, Message: err.Error()}
	}
	if err == provision.ErrDefaultPoolAlreadyExists {
		return &terrors.HTTP{
			Code:    http.StatusConflict,
			Message: err.Error(),
		}
	}
	return err
}
예제 #16
0
파일: install.go 프로젝트: tsuru/tsuru
// title: add install host
// path: /install/hosts
// method: POST
// consume: application/x-www-form-urlencoded
// produce: application/json
// responses:
//   201: Host added
//   401: Unauthorized
func installHostAdd(w http.ResponseWriter, r *http.Request, t auth.Token) (err error) {
	allowed := permission.Check(t, permission.PermInstallManage)
	if !allowed {
		return permission.ErrUnauthorized
	}
	err = r.ParseForm()
	if err != nil {
		return err
	}
	dec := form.NewDecoder(nil)
	dec.IgnoreUnknownKeys(true)
	dec.IgnoreCase(true)
	var host *install.Host
	err = dec.DecodeValues(&host, r.Form)
	if err != nil {
		return err
	}
	evt, err := event.New(&event.Opts{
		Target:     event.Target{Type: event.TargetTypeInstallHost, Value: host.Name},
		Kind:       permission.PermInstallManage,
		Owner:      t,
		CustomData: event.FormToCustomData(r.Form),
		Allowed:    event.Allowed(permission.PermInstallManage),
	})
	if err != nil {
		return err
	}
	defer func() { evt.Done(err) }()
	var rawDriver map[string]interface{}
	err = json.Unmarshal([]byte(r.Form.Get("driver")), &rawDriver)
	if err != nil {
		return err
	}
	host.Driver = rawDriver
	err = install.AddHost(host)
	if err != nil {
		return err
	}
	w.WriteHeader(http.StatusCreated)
	return nil
}
예제 #17
0
파일: iaas.go 프로젝트: tsuru/tsuru
// title: template update
// path: /iaas/templates/{template_name}
// method: PUT
// consume: application/x-www-form-urlencoded
// responses:
//   200: OK
//   400: Invalid data
//   401: Unauthorized
//   404: Not found
func templateUpdate(w http.ResponseWriter, r *http.Request, token auth.Token) (err error) {
	err = r.ParseForm()
	if err != nil {
		return &errors.HTTP{Code: http.StatusBadRequest, Message: err.Error()}
	}
	var paramTemplate iaas.Template
	dec := form.NewDecoder(nil)
	dec.IgnoreUnknownKeys(true)
	err = dec.DecodeValues(&paramTemplate, r.Form)
	if err != nil {
		return &errors.HTTP{Code: http.StatusBadRequest, Message: err.Error()}
	}
	templateName := r.URL.Query().Get(":template_name")
	dbTpl, err := iaas.FindTemplate(templateName)
	if err != nil {
		if err == mgo.ErrNotFound {
			return &errors.HTTP{Code: http.StatusNotFound, Message: "template not found"}
		}
		return err
	}
	iaasCtx := permission.Context(permission.CtxIaaS, dbTpl.IaaSName)
	allowed := permission.Check(token, permission.PermMachineTemplateUpdate, iaasCtx)
	if !allowed {
		return permission.ErrUnauthorized
	}
	evt, err := event.New(&event.Opts{
		Target:     event.Target{Type: event.TargetTypeIaas, Value: dbTpl.IaaSName},
		Kind:       permission.PermMachineTemplateUpdate,
		Owner:      token,
		CustomData: event.FormToCustomData(r.Form),
		Allowed:    event.Allowed(permission.PermMachineReadEvents, iaasCtx),
	})
	if err != nil {
		return err
	}
	defer func() { evt.Done(err) }()
	return dbTpl.Update(&paramTemplate)
}
예제 #18
0
// NewDecoder returns a form decoder that reads from r.
func NewDecoder(r io.Reader) goa.Decoder {
	return form.NewDecoder(r)
}
예제 #19
0
파일: node.go 프로젝트: tsuru/tsuru
// title: add node
// path: /{provisioner}/node
// method: POST
// consume: application/x-www-form-urlencoded
// produce: application/x-json-stream
// responses:
//   201: Ok
//   401: Unauthorized
//   404: Not found
func addNodeHandler(w http.ResponseWriter, r *http.Request, t auth.Token) (err error) {
	err = r.ParseForm()
	if err != nil {
		return &tsuruErrors.HTTP{Code: http.StatusBadRequest, Message: err.Error()}
	}
	var params provision.AddNodeOptions
	dec := form.NewDecoder(nil)
	dec.IgnoreUnknownKeys(true)
	err = dec.DecodeValues(&params, r.Form)
	if err != nil {
		return &tsuruErrors.HTTP{Code: http.StatusBadRequest, Message: err.Error()}
	}
	if templateName, ok := params.Metadata["template"]; ok {
		params.Metadata, err = iaas.ExpandTemplate(templateName, params.Metadata)
		if err != nil {
			return &tsuruErrors.HTTP{Code: http.StatusBadRequest, Message: err.Error()}
		}
	}
	poolName := params.Metadata["pool"]
	if poolName == "" {
		return &tsuruErrors.HTTP{Code: http.StatusBadRequest, Message: "pool is required"}
	}
	if !permission.Check(t, permission.PermNodeCreate, permission.Context(permission.CtxPool, poolName)) {
		return permission.ErrUnauthorized
	}
	if !params.Register {
		canCreateMachine := permission.Check(t, permission.PermMachineCreate,
			permission.Context(permission.CtxIaaS, params.Metadata["iaas"]))
		if !canCreateMachine {
			return permission.ErrUnauthorized
		}
	}
	evt, err := event.New(&event.Opts{
		Target:      event.Target{Type: event.TargetTypeNode},
		Kind:        permission.PermNodeCreate,
		Owner:       t,
		CustomData:  event.FormToCustomData(r.Form),
		DisableLock: true,
		Allowed:     event.Allowed(permission.PermPoolReadEvents, permission.Context(permission.CtxPool, poolName)),
	})
	if err != nil {
		return err
	}
	defer func() { evt.Done(err) }()
	pool, err := provision.GetPoolByName(poolName)
	if err != nil {
		return err
	}
	prov, err := pool.GetProvisioner()
	if err != nil {
		return err
	}
	nodeProv, ok := prov.(provision.NodeProvisioner)
	if !ok {
		return provision.ProvisionerNotSupported{Prov: prov, Action: "node operations"}
	}
	w.Header().Set("Content-Type", "application/x-json-stream")
	w.WriteHeader(http.StatusCreated)
	keepAliveWriter := tsuruIo.NewKeepAliveWriter(w, 15*time.Second, "")
	defer keepAliveWriter.Stop()
	addr, response, err := addNodeForParams(nodeProv, params)
	evt.Target.Value = addr
	if err != nil {
		if desc := response["description"]; desc != "" {
			return errors.Wrapf(err, "Instructions:\n%s", desc)
		}
		return err
	}
	return nil
}
예제 #20
0
파일: bind.go 프로젝트: andviro/noodle
func formC(r io.Reader) Decoder {
	return form.NewDecoder(r)
}
예제 #21
0
파일: app.go 프로젝트: tsuru/tsuru
// title: app create
// path: /apps
// method: POST
// consume: application/x-www-form-urlencoded
// produce: application/json
// responses:
//   201: App created
//   400: Invalid data
//   401: Unauthorized
//   403: Quota exceeded
//   409: App already exists
func createApp(w http.ResponseWriter, r *http.Request, t auth.Token) (err error) {
	err = r.ParseForm()
	if err != nil {
		return &errors.HTTP{Code: http.StatusBadRequest, Message: err.Error()}
	}
	var ia inputApp
	dec := form.NewDecoder(nil)
	dec.IgnoreCase(true)
	dec.IgnoreUnknownKeys(true)
	dec.DecodeValues(&ia, r.Form)
	a := app.App{
		TeamOwner:   ia.TeamOwner,
		Platform:    ia.Platform,
		Plan:        app.Plan{Name: ia.Plan},
		Name:        ia.Name,
		Description: ia.Description,
		Pool:        ia.Pool,
		RouterOpts:  ia.RouterOpts,
	}
	if a.TeamOwner == "" {
		a.TeamOwner, err = permission.TeamForPermission(t, permission.PermAppCreate)
		if err != nil {
			if err != permission.ErrTooManyTeams {
				return err
			}
			teams, listErr := auth.ListTeams()
			if listErr != nil {
				return listErr
			}
			if len(teams) != 1 {
				return err
			}
			a.TeamOwner = teams[0].Name
		}
	}
	canCreate := permission.Check(t, permission.PermAppCreate,
		permission.Context(permission.CtxTeam, a.TeamOwner),
	)
	if !canCreate {
		return permission.ErrUnauthorized
	}
	u, err := t.User()
	if err != nil {
		return err
	}
	platform, err := app.GetPlatform(a.Platform)
	if err != nil {
		return err
	}
	if platform.Disabled {
		canUsePlat := permission.Check(t, permission.PermPlatformUpdate) ||
			permission.Check(t, permission.PermPlatformCreate)
		if !canUsePlat {
			return &errors.HTTP{Code: http.StatusBadRequest, Message: app.InvalidPlatformError.Error()}
		}
	}
	evt, err := event.New(&event.Opts{
		Target:     appTarget(a.Name),
		Kind:       permission.PermAppCreate,
		Owner:      t,
		CustomData: event.FormToCustomData(r.Form),
		Allowed:    event.Allowed(permission.PermAppReadEvents, contextsForApp(&a)...),
	})
	if err != nil {
		return err
	}
	defer func() { evt.Done(err) }()
	err = app.CreateApp(&a, u)
	if err != nil {
		log.Errorf("Got error while creating app: %s", err)
		if e, ok := err.(*errors.ValidationError); ok {
			return &errors.HTTP{Code: http.StatusBadRequest, Message: e.Message}
		}
		if _, ok := err.(app.NoTeamsError); ok {
			return &errors.HTTP{
				Code:    http.StatusBadRequest,
				Message: "In order to create an app, you should be member of at least one team",
			}
		}
		if e, ok := err.(*app.AppCreationError); ok {
			if e.Err == app.ErrAppAlreadyExists {
				return &errors.HTTP{Code: http.StatusConflict, Message: e.Error()}
			}
			if _, ok := e.Err.(*quota.QuotaExceededError); ok {
				return &errors.HTTP{
					Code:    http.StatusForbidden,
					Message: "Quota exceeded",
				}
			}
		}
		if err == app.InvalidPlatformError {
			return &errors.HTTP{Code: http.StatusBadRequest, Message: err.Error()}
		}
		return err
	}
	repo, err := repository.Manager().GetRepository(a.Name)
	if err != nil {
		return err
	}
	msg := map[string]string{
		"status":         "success",
		"repository_url": repo.ReadWriteURL,
		"ip":             a.Ip,
	}
	jsonMsg, err := json.Marshal(msg)
	if err != nil {
		return err
	}
	w.WriteHeader(http.StatusCreated)
	w.Header().Set("Content-Type", "application/json")
	w.Write(jsonMsg)
	return nil
}
예제 #22
0
파일: node.go 프로젝트: tsuru/tsuru
// title: update nodes
// path: /{provisioner}/node
// method: PUT
// consume: application/x-www-form-urlencoded
// responses:
//   200: Ok
//   400: Invalid data
//   401: Unauthorized
//   404: Not found
func updateNodeHandler(w http.ResponseWriter, r *http.Request, t auth.Token) (err error) {
	err = r.ParseForm()
	if err != nil {
		return &tsuruErrors.HTTP{Code: http.StatusBadRequest, Message: err.Error()}
	}
	var params provision.UpdateNodeOptions
	dec := form.NewDecoder(nil)
	dec.IgnoreUnknownKeys(true)
	err = dec.DecodeValues(&params, r.Form)
	if err != nil {
		return &tsuruErrors.HTTP{Code: http.StatusBadRequest, Message: err.Error()}
	}
	if params.Disable && params.Enable {
		return &tsuruErrors.HTTP{
			Code:    http.StatusBadRequest,
			Message: "A node can't be enabled and disabled simultaneously.",
		}
	}
	if params.Address == "" {
		return &tsuruErrors.HTTP{Code: http.StatusBadRequest, Message: "address is required"}
	}
	prov, node, err := provision.FindNode(params.Address)
	if err != nil {
		if err == provision.ErrNodeNotFound {
			return &tsuruErrors.HTTP{
				Code:    http.StatusNotFound,
				Message: err.Error(),
			}
		}
		return err
	}
	nodeProv := prov.(provision.NodeProvisioner)
	oldPool := node.Pool()
	allowedOldPool := permission.Check(t, permission.PermNodeUpdate,
		permission.Context(permission.CtxPool, oldPool),
	)
	if !allowedOldPool {
		return permission.ErrUnauthorized
	}
	newPool, ok := params.Metadata["pool"]
	if ok {
		allowedNewPool := permission.Check(t, permission.PermNodeUpdate,
			permission.Context(permission.CtxPool, newPool),
		)
		if !allowedNewPool {
			return permission.ErrUnauthorized
		}
	}
	evt, err := event.New(&event.Opts{
		Target:     event.Target{Type: event.TargetTypeNode, Value: node.Address()},
		Kind:       permission.PermNodeUpdate,
		Owner:      t,
		CustomData: event.FormToCustomData(r.Form),
		Allowed: event.Allowed(permission.PermPoolReadEvents,
			permission.Context(permission.CtxPool, oldPool),
			permission.Context(permission.CtxPool, newPool),
		),
	})
	if err != nil {
		return err
	}
	defer func() { evt.Done(err) }()
	return nodeProv.UpdateNode(params)
}