api/node.go
func addNodeHandler(w http.ResponseWriter, r *http.Request, t auth.Token) (err error) {
	var params provision.AddNodeOptions
	err = ParseInput(r, &params)
	if err != nil {
		return err
	}
	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()}
		}
	}
	params.Pool = params.Metadata[provision.PoolMetadataName]
	params.IaaSID = params.Metadata[provision.IaaSIDMetadataName]
	delete(params.Metadata, provision.IaaSIDMetadataName)
	if params.Pool == "" {
		return &tsuruErrors.HTTP{Code: http.StatusBadRequest, Message: "pool is required"}
	}
	if !permission.Check(t, permission.PermNodeCreate, permission.Context(permTypes.CtxPool, params.Pool)) {
		return permission.ErrUnauthorized
	}
	evt, err := event.New(&event.Opts{
		Target:      event.Target{Type: event.TargetTypeNode},
		Kind:        permission.PermNodeCreate,
		Owner:       t,
		CustomData:  event.FormToCustomData(InputFields(r)),
		DisableLock: true,
		Allowed:     event.Allowed(permission.PermPoolReadEvents, permission.Context(permTypes.CtxPool, params.Pool)),
	})
	if err != nil {
		return err
	}
	defer func() { evt.Done(err) }()
	p, err := pool.GetPoolByName(params.Pool)
	if err != nil {
		return err
	}
	prov, err := p.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
}
func addNodeHandler(w http.ResponseWriter, r *http.Request, t auth.Token) (err error) {
	var params provision.AddNodeOptions
	err = ParseInput(r, &params)
	if err != nil {
		return err
	}
	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()}
		}
	}
	params.Pool = params.Metadata[provision.PoolMetadataName]
	params.IaaSID = params.Metadata[provision.IaaSIDMetadataName]
	delete(params.Metadata, provision.IaaSIDMetadataName)
	if params.Pool == "" {
		return &tsuruErrors.HTTP{Code: http.StatusBadRequest, Message: "pool is required"}
	}
	if !permission.Check(t, permission.PermNodeCreate, permission.Context(permTypes.CtxPool, params.Pool)) {
		return permission.ErrUnauthorized
	}
	evt, err := event.New(&event.Opts{
		Target:      event.Target{Type: event.TargetTypeNode},
		Kind:        permission.PermNodeCreate,
		Owner:       t,
		CustomData:  event.FormToCustomData(InputFields(r)),
		DisableLock: true,
		Allowed:     event.Allowed(permission.PermPoolReadEvents, permission.Context(permTypes.CtxPool, params.Pool)),
	})
	if err != nil {
		return err
	}
	defer func() { evt.Done(err) }()
	p, err := pool.GetPoolByName(params.Pool)
	if err != nil {
		return err
	}
	prov, err := p.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
}
// title: add node
// path: /node
// method: POST
// consume: application/x-www-form-urlencoded
// produce: application/x-json-stream
// responses:
//   201: Ok
//   401: Unauthorized
//   404: Not found