func addNodeForParams(p provision.NodeProvisioner, params provision.AddNodeOptions) (string, map[string]string, error) { response := make(map[string]string) var address string if params.Register { address, _ = params.Metadata["address"] delete(params.Metadata, "address") } else { desc, _ := iaas.Describe(params.Metadata["iaas"]) response["description"] = desc m, err := iaas.CreateMachine(params.Metadata) if err != nil { return address, response, err } address = m.FormatNodeAddress() params.CaCert = m.CaCert params.ClientCert = m.ClientCert params.ClientKey = m.ClientKey } prov, _, err := provision.FindNode(address) if err != provision.ErrNodeNotFound { if err == nil { return "", nil, errors.Errorf("node with address %q already exists in provisioner %q", address, prov.GetName()) } return "", nil, err } err = validateNodeAddress(address) if err != nil { return address, response, err } params.Address = address err = p.AddNode(params) return address, response, err }
// title: list units by node // path: /{provisioner}/node/{address}/containers // method: GET // produce: application/json // responses: // 200: Ok // 204: No content // 401: Unauthorized // 404: Not found func listUnitsByNode(w http.ResponseWriter, r *http.Request, t auth.Token) error { address := r.URL.Query().Get(":address") _, node, err := provision.FindNode(address) if err != nil { if err == provision.ErrNodeNotFound { return &tsuruErrors.HTTP{ Code: http.StatusNotFound, Message: err.Error(), } } return err } hasAccess := permission.Check(t, permission.PermNodeRead, permission.Context(permission.CtxPool, node.Pool())) if !hasAccess { return permission.ErrUnauthorized } units, err := node.Units() if err != nil { return err } if len(units) == 0 { w.WriteHeader(http.StatusNoContent) return nil } w.Header().Set("Content-Type", "application/json") return json.NewEncoder(w).Encode(units) }
// 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(¶ms, 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) }
// title: remove node // path: /{provisioner}/node/{address} // method: DELETE // responses: // 200: Ok // 401: Unauthorized // 404: Not found func removeNodeHandler(w http.ResponseWriter, r *http.Request, t auth.Token) (err error) { r.ParseForm() address := r.URL.Query().Get(":address") if address == "" { return errors.Errorf("Node address is required.") } prov, node, err := provision.FindNode(address) if err != nil { if err == provision.ErrNodeNotFound { return &tsuruErrors.HTTP{ Code: http.StatusNotFound, Message: err.Error(), } } return err } nodeProv := prov.(provision.NodeProvisioner) pool := node.Pool() allowedNodeRemove := permission.Check(t, permission.PermNodeDelete, permission.Context(permission.CtxPool, pool), ) if !allowedNodeRemove { return permission.ErrUnauthorized } removeIaaS, _ := strconv.ParseBool(r.URL.Query().Get("remove-iaas")) if removeIaaS { allowedIaasRemove := permission.Check(t, permission.PermMachineDelete, permission.Context(permission.CtxIaaS, node.Metadata()["iaas"]), ) if !allowedIaasRemove { return permission.ErrUnauthorized } } evt, err := event.New(&event.Opts{ Target: event.Target{Type: event.TargetTypeNode, Value: node.Address()}, Kind: permission.PermNodeDelete, Owner: t, CustomData: event.FormToCustomData(r.Form), Allowed: event.Allowed(permission.PermPoolReadEvents, permission.Context(permission.CtxPool, pool)), }) if err != nil { return err } defer func() { evt.Done(err) }() noRebalance, _ := strconv.ParseBool(r.URL.Query().Get("no-rebalance")) err = nodeProv.RemoveNode(provision.RemoveNodeOptions{ Address: address, Rebalance: !noRebalance, Writer: w, }) if err != nil { return err } if removeIaaS { var m iaas.Machine m, err = iaas.FindMachineByIdOrAddress(node.Metadata()["iaas-id"], net.URLToHost(address)) if err != nil && err != mgo.ErrNotFound { return nil } return m.Destroy() } return nil }