Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions cmd/api/handlers/nodes.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,55 @@ func (h *HandlersApi) DeleteNodeHandler(w http.ResponseWriter, r *http.Request)
utils.HTTPResponse(w, utils.JSONApplicationUTF8, http.StatusOK, types.ApiGenericResponse{Message: "node deleted"})
}

// TagNodeHandler - POST Handler to tag a node
func (h *HandlersApi) TagNodeHandler(w http.ResponseWriter, r *http.Request) {
// Debug HTTP if enabled
if h.DebugHTTPConfig.Enabled {
utils.DebugHTTPDump(h.DebugHTTP, r, h.DebugHTTPConfig.ShowBody)
}
// Extract environment
envVar := r.PathValue("env")
if envVar == "" {
apiErrorResponse(w, "error with environment", http.StatusBadRequest, nil)
return
}
// Get environment
env, err := h.Envs.GetByUUID(envVar)
if err != nil {
apiErrorResponse(w, "error getting environment", http.StatusInternalServerError, nil)
return
}
// Get context data and check access
ctx := r.Context().Value(ContextKey(contextAPI)).(ContextValue)
if !h.Users.CheckPermissions(ctx[ctxUser], users.AdminLevel, env.UUID) {
apiErrorResponse(w, "no access", http.StatusForbidden, fmt.Errorf("attempt to use API by user %s", ctx[ctxUser]))
return
}
var t types.ApiNodeTagRequest
// Parse request JSON body
if err := json.NewDecoder(r.Body).Decode(&t); err != nil {
apiErrorResponse(w, "error parsing POST body", http.StatusInternalServerError, err)
return
}
// Get node by UUID
n, err := h.Nodes.GetByUUIDEnv(t.UUID, env.ID)
if err != nil {
if err.Error() == "record not found" {
apiErrorResponse(w, "node not found", http.StatusNotFound, err)
} else {
apiErrorResponse(w, "error getting node", http.StatusInternalServerError, err)
}
return
}
if err := h.Tags.TagNode(t.Tag, n, ctx[ctxUser], false, t.Type); err != nil {
apiErrorResponse(w, "error tagging node", http.StatusInternalServerError, err)
return
}
// Serialize and serve JSON
log.Debug().Msgf("Tagged node %s with %s", n.UUID, t.Tag)
utils.HTTPResponse(w, utils.JSONApplicationUTF8, http.StatusOK, types.ApiGenericResponse{Message: "node tagged"})
}

// LookupNodeHandler - POST Handler to lookup a node by identifier
func (h *HandlersApi) LookupNodeHandler(w http.ResponseWriter, r *http.Request) {
// Debug HTTP if enabled
Expand Down
3 changes: 3 additions & 0 deletions cmd/api/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,9 @@ func osctrlAPIService() {
muxAPI.Handle(
"POST "+_apiPath(apiNodesPath)+"/{env}/delete",
handlerAuthCheck(http.HandlerFunc(handlersApi.DeleteNodeHandler), flagParams.ConfigValues.Auth, flagParams.JWTConfigValues.JWTSecret))
muxAPI.Handle(
"POST "+_apiPath(apiNodesPath)+"/{env}/tag",
handlerAuthCheck(http.HandlerFunc(handlersApi.TagNodeHandler), flagParams.ConfigValues.Auth, flagParams.JWTConfigValues.JWTSecret))
muxAPI.Handle(
"POST "+_apiPath(apiNodesPath)+"/lookup",
handlerAuthCheck(http.HandlerFunc(handlersApi.LookupNodeHandler), flagParams.ConfigValues.Auth, flagParams.JWTConfigValues.JWTSecret))
Expand Down
21 changes: 20 additions & 1 deletion cmd/cli/api-node.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,26 @@ func (api *OsctrlAPI) DeleteNode(env, identifier string) error {
}

// TagNode to tag node in osctrl
func (api *OsctrlAPI) TagNode(env, identifier, tag string) error {
func (api *OsctrlAPI) TagNode(env, identifier, tag string, tagType uint) error {
t := types.ApiNodeTagRequest{
UUID: identifier,
Tag: tag,
Type: tagType,
}
var r types.ApiGenericResponse
reqURL := path.Join(api.Configuration.URL, APIPath, APINodes, env, "tag")
jsonMessage, err := json.Marshal(t)
if err != nil {
return fmt.Errorf("error marshaling data - %w", err)
}
jsonParam := bytes.NewReader(jsonMessage)
rawN, err := api.PostGeneric(reqURL, jsonParam)
if err != nil {
return fmt.Errorf("error api request - %w - %s", err, string(rawN))
}
if err := json.Unmarshal(rawN, &r); err != nil {
return fmt.Errorf("can not parse body - %w", err)
}
return nil
}

Expand Down
2 changes: 1 addition & 1 deletion cmd/cli/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ func tagNode(c *cli.Context) error {
return fmt.Errorf("error tagging - %w", err)
}
} else if apiFlag {
if err := osctrlAPI.TagNode(env, uuid, tag); err != nil {
if err := osctrlAPI.TagNode(env, uuid, tag, tagTypeInt); err != nil {
return fmt.Errorf("error tagging node - %w", err)
}
}
Expand Down
63 changes: 63 additions & 0 deletions osctrl-api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,59 @@ paths:
security:
- Authorization:
- admin
/nodes/{env}/tag:
post:
tags:
- nodes
summary: Tags node
description: Tags an existing node by identifier (UUID, hostname or localname)
operationId: TagNodeHandler
parameters:
- name: env
in: path
description: Name or UUID of the requested osctrl environment
required: true
schema:
type: string
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/ApiNodeTagRequest"
responses:
200:
description: successful operation
content:
application/json:
schema:
$ref: "#/components/schemas/ApiGenericResponse"
400:
description: bad request
content:
application/json:
schema:
$ref: "#/components/schemas/ApiErrorResponse"
403:
description: no access
content:
application/json:
schema:
$ref: "#/components/schemas/ApiErrorResponse"
404:
description: no nodes
content:
application/json:
schema:
$ref: "#/components/schemas/ApiErrorResponse"
500:
description: error tagging node
content:
application/json:
schema:
$ref: "#/components/schemas/ApiErrorResponse"
security:
- Authorization:
- admin
/nodes/lookup:
post:
tags:
Expand Down Expand Up @@ -2081,6 +2134,16 @@ components:
properties:
uuid:
type: string
ApiNodeTagRequest:
type: object
properties:
uuid:
type: string
tag:
type: string
type:
type: integer
format: int32
DistributedQuery:
type: object
properties:
Expand Down
4 changes: 4 additions & 0 deletions pkg/tags/tags.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ const (
ActionEdit string = "edit"
// ActionRemove as action to remove a tag
ActionRemove string = "remove"
// ActionTag as action to tag a node
ActionTag string = "tag"
// ActionUntag as action to untag a node
ActionUntag string = "untag"
)

// AdminTag to hold all tags
Expand Down
7 changes: 7 additions & 0 deletions pkg/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,13 @@ type ApiNodeGenericRequest struct {
UUID string `json:"uuid"`
}

// ApiNodeTagRequest to receive tag node requests
type ApiNodeTagRequest struct {
UUID string `json:"uuid"`
Tag string `json:"tag"`
Type uint `json:"type"`
}

// ApiLoginRequest to receive login requests
type ApiLoginRequest struct {
Username string `json:"username"`
Expand Down
Loading