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
51 changes: 51 additions & 0 deletions api/handlers/tags.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,57 @@ func (h *HandlersApi) AllTagsHandler(w http.ResponseWriter, r *http.Request) {
h.Inc(metricAPITagsOK)
}

// TagEnvHandler - GET Handler to return one tag for one environment as JSON
func (h *HandlersApi) TagEnvHandler(w http.ResponseWriter, r *http.Request) {
h.Inc(metricAPITagsReq)
utils.DebugHTTPDump(r, h.Settings.DebugHTTP(settings.ServiceAPI, settings.NoEnvironmentID), false)
// Extract environment
envVar := r.PathValue("env")
if envVar == "" {
apiErrorResponse(w, "error getting environment", http.StatusBadRequest, nil)
h.Inc(metricAPITagsErr)
return
}
// Extract tag name
tagVar := r.PathValue("name")
if tagVar == "" {
apiErrorResponse(w, "error getting tag name", http.StatusBadRequest, nil)
h.Inc(metricAPITagsErr)
return
}
// Get environment by UUID
env, err := h.Envs.GetByUUID(envVar)
if err != nil {
if err.Error() == "record not found" {
apiErrorResponse(w, "environment not found", http.StatusNotFound, err)
} else {
apiErrorResponse(w, "error getting environment", http.StatusInternalServerError, err)
}
h.Inc(metricAPIEnvsErr)
return
}
// Get context data and check access
ctx := r.Context().Value(ContextKey(contextAPI)).(ContextValue)
if !h.Users.CheckPermissions(ctx[ctxUser], users.AdminLevel, users.NoEnvironment) {
apiErrorResponse(w, "no access", http.StatusForbidden, fmt.Errorf("attempt to use API by user %s", ctx[ctxUser]))
h.Inc(metricAPITagsErr)
return
}
// Get tag
exist, tag := h.Tags.ExistsGet(tagVar, env.ID)
if !exist {
apiErrorResponse(w, "error getting tag", http.StatusInternalServerError, err)
h.Inc(metricAPITagsErr)
return
}
// Serialize and serve JSON
if h.Settings.DebugService(settings.ServiceAPI) {
log.Debug().Msg("DebugService: Returned tag")
}
utils.HTTPResponse(w, utils.JSONApplicationUTF8, http.StatusOK, tag)
h.Inc(metricAPITagsOK)
}

// TagsEnvHandler - GET Handler to return tags for one environment as JSON
func (h *HandlersApi) TagsEnvHandler(w http.ResponseWriter, r *http.Request) {
h.Inc(metricAPITagsReq)
Expand Down
1 change: 1 addition & 0 deletions api/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -604,6 +604,7 @@ func osctrlAPIService() {
// API: tags by environment
muxAPI.Handle("GET "+_apiPath(apiTagsPath), handlerAuthCheck(http.HandlerFunc(handlersApi.AllTagsHandler)))
muxAPI.Handle("GET "+_apiPath(apiTagsPath)+"/{env}", handlerAuthCheck(http.HandlerFunc(handlersApi.TagsEnvHandler)))
muxAPI.Handle("GET "+_apiPath(apiTagsPath)+"/{env}/{name}", handlerAuthCheck(http.HandlerFunc(handlersApi.TagEnvHandler)))
muxAPI.Handle("POST "+_apiPath(apiTagsPath)+"/{env}/{action}", handlerAuthCheck(http.HandlerFunc(handlersApi.TagsActionHandler)))
// API: settings by environment
muxAPI.Handle("GET "+_apiPath(apiSettingsPath), handlerAuthCheck(http.HandlerFunc(handlersApi.SettingsHandler)))
Expand Down
129 changes: 129 additions & 0 deletions cli/api-tag.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package main

import (
"encoding/json"
"fmt"
"strings"

"github.com/jmpsec/osctrl/tags"
"github.com/jmpsec/osctrl/types"
)

// GetAllTags to retrieve all tags from osctrl
func (api *OsctrlAPI) GetAllTags() ([]tags.AdminTag, error) {
var tgs []tags.AdminTag
reqURL := fmt.Sprintf("%s%s%s", api.Configuration.URL, APIPath, APITags)
rawTgs, err := api.GetGeneric(reqURL, nil)
if err != nil {
return tgs, fmt.Errorf("error api request - %v - %s", err, string(rawTgs))
}
if err := json.Unmarshal(rawTgs, &tgs); err != nil {
return tgs, fmt.Errorf("can not parse body - %v", err)
}
return tgs, nil
}

// GetTags to retrieve tags from osctrl by environment
func (api *OsctrlAPI) GetTags(env string) ([]tags.AdminTag, error) {
var tgs []tags.AdminTag
reqURL := fmt.Sprintf("%s%s%s/%s", api.Configuration.URL, APIPath, APITags, env)
rawTgs, err := api.GetGeneric(reqURL, nil)
if err != nil {
return tgs, fmt.Errorf("error api request - %v - %s", err, string(rawTgs))
}
if err := json.Unmarshal(rawTgs, &tgs); err != nil {
return tgs, fmt.Errorf("can not parse body - %v", err)
}
return tgs, nil
}

// GetTag to retrieve a tag from osctrl by environment and name
func (api *OsctrlAPI) GetTag(env, name string) (tags.AdminTag, error) {
var t tags.AdminTag
reqURL := fmt.Sprintf("%s%s%s/%s/%s", api.Configuration.URL, APIPath, APITags, env, name)
rawT, err := api.GetGeneric(reqURL, nil)
if err != nil {
return t, fmt.Errorf("error api request - %v - %s", err, string(rawT))
}
if err := json.Unmarshal(rawT, &t); err != nil {
return t, fmt.Errorf("can not parse body - %v", err)
}
return t, nil
}

// AddTag to add a tag to osctrl
func (api *OsctrlAPI) AddTag(envUUID, name, color, icon, description string, tagType uint) (types.ApiGenericResponse, error) {
var r types.ApiGenericResponse
t := types.ApiTagsRequest{
Name: name,
Description: description,
Color: color,
Icon: icon,
EnvUUID: envUUID,
TagType: tagType,
}
reqURL := fmt.Sprintf("%s%s%s/%s/%s", api.Configuration.URL, APIPath, APITags, envUUID, tags.ActionAdd)
jsonMessage, err := json.Marshal(t)
if err != nil {
return r, fmt.Errorf("error marshaling data - %v", err)
}
jsonParam := strings.NewReader(string(jsonMessage))
rawT, err := api.PostGeneric(reqURL, jsonParam)
if err != nil {
return r, fmt.Errorf("error api request - %v", err)
}
if err := json.Unmarshal(rawT, &r); err != nil {
return r, fmt.Errorf("can not parse body - %v", err)
}
return r, nil
}

// DeleteTag to delete a tag from osctrl
func (api *OsctrlAPI) DeleteTag(envUUID, name string) (types.ApiGenericResponse, error) {
var r types.ApiGenericResponse
t := types.ApiTagsRequest{
Name: name,
EnvUUID: envUUID,
}
reqURL := fmt.Sprintf("%s%s%s/%s/%s", api.Configuration.URL, APIPath, APITags, envUUID, tags.ActionRemove)
jsonMessage, err := json.Marshal(t)
if err != nil {
return r, fmt.Errorf("error marshaling data - %v", err)
}
jsonParam := strings.NewReader(string(jsonMessage))
rawT, err := api.PostGeneric(reqURL, jsonParam)
if err != nil {
return r, fmt.Errorf("error api request - %v", err)
}
if err := json.Unmarshal(rawT, &r); err != nil {
return r, fmt.Errorf("can not parse body - %v", err)
}
return r, nil
}

// EditTag to edit a tag from osctrl
func (api *OsctrlAPI) EditTag(envUUID, name, color, icon, description string, tagType uint) (types.ApiGenericResponse, error) {
var r types.ApiGenericResponse
t := types.ApiTagsRequest{
Name: name,
Description: description,
Color: color,
Icon: icon,
EnvUUID: envUUID,
TagType: tagType,
}
reqURL := fmt.Sprintf("%s%s%s/%s/%s", api.Configuration.URL, APIPath, APITags, envUUID, tags.ActionEdit)
jsonMessage, err := json.Marshal(t)
if err != nil {
return r, fmt.Errorf("error marshaling data - %v", err)
}
jsonParam := strings.NewReader(string(jsonMessage))
rawT, err := api.PostGeneric(reqURL, jsonParam)
if err != nil {
return r, fmt.Errorf("error api request - %v", err)
}
if err := json.Unmarshal(rawT, &r); err != nil {
return r, fmt.Errorf("can not parse body - %v", err)
}
return r, nil
}
2 changes: 2 additions & 0 deletions cli/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ const (
APIUSers = "/users"
// APIEnvironments for the environments path
APIEnvironments = "/environments"
// APITags for the tags path
APITags = "/tags"
// APILogin for the login path
APILogin = "/login"
// JSONApplication for Content-Type headers
Expand Down
90 changes: 64 additions & 26 deletions cli/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -1145,19 +1145,14 @@ func init() {
Usage: "Tag an existing node",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "uuid",
Name: "uuid, u",
Aliases: []string{"u"},
Usage: "Node UUID to be tagged",
},
&cli.StringFlag{
Name: "env",
Aliases: []string{"e"},
Usage: "Environment to be used",
},
&cli.StringFlag{
Name: "tag-value",
Aliases: []string{"T"},
Usage: "Tag value to be used. It will be created if does not exist",
Name: "name",
Aliases: []string{"n"},
Usage: "Tag name to be used. It will be created if does not exist",
},
&cli.StringFlag{
Name: "tag-type",
Expand Down Expand Up @@ -1521,24 +1516,34 @@ func init() {
&cli.StringFlag{
Name: "name",
Aliases: []string{"n"},
Usage: "Tage name to be added",
Usage: "Tage name to be used",
},
&cli.StringFlag{
Name: "env-uuid",
Aliases: []string{"e"},
Usage: "Environment UUID to be used",
},
&cli.StringFlag{
Name: "icon",
Aliases: []string{"i"},
Value: tags.DefaultTagIcon,
Usage: "Fontawesome icon to be used",
},
&cli.StringFlag{
Name: "color",
Aliases: []string{"c"},
Value: "",
Usage: "Tag color to be added",
Usage: "HTML color to be used. If not provided it will be randomly generated",
},
&cli.StringFlag{
Name: "description, d",
Aliases: []string{"d"},
Usage: "Tag description to be added",
Usage: "Tag description to be used",
},
&cli.StringFlag{
Name: "icon, i",
Aliases: []string{"i"},
Value: "",
Usage: "Tag icon to be added",
Name: "tag-type",
Aliases: []string{"t", "type"},
Value: "custom",
Usage: "Tag type to be used. It can be 'env', 'uuid', 'platform', 'localname' and 'custom'",
},
},
Action: cliWrapper(addTag),
Expand All @@ -1551,22 +1556,32 @@ func init() {
&cli.StringFlag{
Name: "name",
Aliases: []string{"n"},
Usage: "Tage name to be edited",
Usage: "Tage name to be used",
},
&cli.StringFlag{
Name: "env-uuid",
Aliases: []string{"e"},
Usage: "Environment UUID to be used",
},
&cli.StringFlag{
Name: "icon",
Aliases: []string{"i"},
Usage: "Fontawesome icon to be used",
},
&cli.StringFlag{
Name: "color",
Aliases: []string{"c"},
Usage: "Tag color to be edited",
Usage: "HTML color to be used. If not provided it will be randomly generated",
},
&cli.StringFlag{
Name: "description",
Name: "description, d",
Aliases: []string{"d"},
Usage: "Tag description to be edited",
Usage: "Tag description to be used",
},
&cli.StringFlag{
Name: "icon",
Aliases: []string{"i"},
Usage: "Tag icon to be edited",
Name: "tag-type",
Aliases: []string{"t", "type"},
Usage: "Tag type to be used. It can be 'env', 'uuid', 'platform', 'localname' and 'custom'",
},
},
Action: cliWrapper(editTag),
Expand All @@ -1581,14 +1596,32 @@ func init() {
Aliases: []string{"n"},
Usage: "Tag name to be deleted",
},
&cli.StringFlag{
Name: "env-uuid",
Aliases: []string{"e"},
Usage: "Environment UUID to be used",
},
},
Action: cliWrapper(deleteTag),
},
{
Name: "list",
Aliases: []string{"l"},
Usage: "List all tags",
Action: cliWrapper(listTags),
Usage: "List all tags by environment",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "env-uuid",
Aliases: []string{"e"},
Usage: "Environment UUID to be used",
},
},
Action: cliWrapper(listTagsByEnv),
},
{
Name: "list-all",
Aliases: []string{"L"},
Usage: "List all tags in osctrl",
Action: cliWrapper(listAllTags),
},
{
Name: "show",
Expand All @@ -1600,6 +1633,11 @@ func init() {
Aliases: []string{"n"},
Usage: "Tag name to be displayed",
},
&cli.StringFlag{
Name: "env-uuid",
Aliases: []string{"e"},
Usage: "Environment UUID to be used",
},
},
Action: cliWrapper(showTag),
},
Expand Down
1 change: 1 addition & 0 deletions cli/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ func nodesToData(nds []nodes.OsqueryNode, header []string) [][]string {
return data
}

// Helper function to convert a node into the data expected for output
func nodeToData(n nodes.OsqueryNode, header []string) [][]string {
var data [][]string
if header != nil {
Expand Down
Loading
Loading