Skip to content

Commit

Permalink
Filter alerts (#147)
Browse files Browse the repository at this point in the history
* Filter alerts

* Move byte getters to util
  • Loading branch information
fjerlov-cs authored Mar 5, 2024
1 parent 1d7631a commit 468a5df
Show file tree
Hide file tree
Showing 15 changed files with 678 additions and 29 deletions.
14 changes: 11 additions & 3 deletions api/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ import "fmt"
type EntityType string

const (
EntityTypeParser EntityType = "parser"
EntityTypeAction EntityType = "action"
EntityTypeAlert EntityType = "alert"
EntityTypeParser EntityType = "parser"
EntityTypeAction EntityType = "action"
EntityTypeAlert EntityType = "alert"
EntityTypeFilterAlert EntityType = "filter-alert"
)

func (e EntityType) String() string {
Expand Down Expand Up @@ -51,3 +52,10 @@ func AlertNotFound(name string) error {
key: name,
}
}

func FilterAlertNotFound(name string) error {
return EntityNotFound{
entityType: EntityTypeFilterAlert,
key: name,
}
}
228 changes: 228 additions & 0 deletions api/filter-alerts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
package api

import (
"fmt"
graphql "github.com/cli/shurcooL-graphql"
"github.com/humio/cli/api/internal/humiographql"
)

type FilterAlert struct {
ID string `graphql:"id" yaml:"id" json:"id"`
Name string `graphql:"name" yaml:"name" json:"name"`
Description string `graphql:"description" yaml:"description,omitempty" json:"description,omitempty"`
QueryString string `graphql:"queryString" yaml:"queryString" json:"queryString"`
Actions []string `graphql:"actions" yaml:"actions" json:"actions"`
Labels []string `graphql:"labels" yaml:"labels" json:"labels"`
Enabled bool `graphql:"enabled" yaml:"enabled" json:"enabled"`
LastTriggered int `graphql:"lastTriggered" yaml:"lastTriggered,omitempty" json:"lastTriggered,omitempty"`
LastErrorTime int `graphql:"lastErrorTime" yaml:"lastErrorTime,omitempty" json:"lastErrorTime,omitempty"`
LastError string `graphql:"lastError" yaml:"lastError,omitempty" json:"lastError,omitempty"`
LastWarnings []string `graphql:"lastWarnings" yaml:"lastWarnings" json:"lastWarnings"`
QueryOwnershipType string `graphql:"queryOwnership" yaml:"queryOwnershipType" json:"queryOwnershipType"`
RunAsUserID string `graphql:"runAsUserID" yaml:"runAsUserID,omitempty" json:"runAsUserID,omitempty"`
}

type FilterAlerts struct {
client *Client
}

func (c *Client) FilterAlerts() *FilterAlerts { return &FilterAlerts{client: c} }

func (fa *FilterAlerts) List(viewName string) ([]FilterAlert, error) {
var query struct {
SearchDomain struct {
FilterAlerts []humiographql.FilterAlert `graphql:"filterAlerts"`
} `graphql:"searchDomain(name: $viewName)"`
}

variables := map[string]interface{}{
"viewName": graphql.String(viewName),
}

err := fa.client.Query(&query, variables)

var filterAlerts []FilterAlert
for _, humioGraphqlFilterAlert := range query.SearchDomain.FilterAlerts {
filterAlerts = append(filterAlerts, mapHumioGraphqlFilterAlertToFilterAlert(humioGraphqlFilterAlert))
}
return filterAlerts, err
}

func (fa *FilterAlerts) Update(viewName string, newFilterAlert *FilterAlert) (*FilterAlert, error) {
if newFilterAlert == nil {
return nil, fmt.Errorf("newFilterAlert must not be nil")
}

if newFilterAlert.ID == "" {
return nil, fmt.Errorf("newFilterAlert must have non-empty newFilterAlert id")
}

var mutation struct {
humiographql.FilterAlert `graphql:"updateFilterAlert(input: $input)"`
}

actionsIdsOrNames := make([]graphql.String, len(newFilterAlert.Actions))
for i, actionIdOrName := range newFilterAlert.Actions {
actionsIdsOrNames[i] = graphql.String(actionIdOrName)
}

labels := make([]graphql.String, len(newFilterAlert.Labels))
for i, label := range newFilterAlert.Labels {
labels[i] = graphql.String(label)
}

updateAlert := humiographql.UpdateFilterAlert{
ViewName: humiographql.RepoOrViewName(viewName),
ID: graphql.String(newFilterAlert.ID),
Name: graphql.String(newFilterAlert.Name),
Description: graphql.String(newFilterAlert.Description),
QueryString: graphql.String(newFilterAlert.QueryString),
ActionIdsOrNames: actionsIdsOrNames,
Labels: labels,
Enabled: graphql.Boolean(newFilterAlert.Enabled),
RunAsUserID: graphql.String(newFilterAlert.RunAsUserID),
QueryOwnershipType: humiographql.QueryOwnershipType(newFilterAlert.QueryOwnershipType),
}

variables := map[string]interface{}{
"input": updateAlert,
}

err := fa.client.Mutate(&mutation, variables)
if err != nil {
return nil, err
}

filterAlert := mapHumioGraphqlFilterAlertToFilterAlert(mutation.FilterAlert)

return &filterAlert, nil
}

func (fa *FilterAlerts) Add(viewName string, newFilterAlert *FilterAlert) (*FilterAlert, error) {
if newFilterAlert == nil {
return nil, fmt.Errorf("newFilterAlert must not be nil")
}

var mutation struct {
humiographql.FilterAlert `graphql:"createFilterAlert(input: $input)"`
}

actionsIdsOrNames := make([]graphql.String, len(newFilterAlert.Actions))
for i, actionIdOrName := range newFilterAlert.Actions {
actionsIdsOrNames[i] = graphql.String(actionIdOrName)
}

labels := make([]graphql.String, len(newFilterAlert.Labels))
for i, label := range newFilterAlert.Labels {
labels[i] = graphql.String(label)
}

createFilterAlert := humiographql.CreateFilterAlert{
ViewName: humiographql.RepoOrViewName(viewName),
Name: graphql.String(newFilterAlert.Name),
Description: graphql.String(newFilterAlert.Description),
QueryString: graphql.String(newFilterAlert.QueryString),
ActionIdsOrNames: actionsIdsOrNames,
Labels: labels,
Enabled: graphql.Boolean(newFilterAlert.Enabled),
RunAsUserID: graphql.String(newFilterAlert.RunAsUserID),
QueryOwnershipType: humiographql.QueryOwnershipType(newFilterAlert.QueryOwnershipType),
}

variables := map[string]interface{}{
"input": createFilterAlert,
}

err := fa.client.Mutate(&mutation, variables)
if err != nil {
return nil, err
}

filterAlert := mapHumioGraphqlFilterAlertToFilterAlert(mutation.FilterAlert)

return &filterAlert, nil
}

func (fa *FilterAlerts) Get(viewName, filterAlertName string) (*FilterAlert, error) {
filterAlerts, err := fa.List(viewName)
if err != nil {
return nil, fmt.Errorf("unable to list filter alerts: %w", err)
}
for _, filterAlert := range filterAlerts {
if filterAlert.Name == filterAlertName {
return &filterAlert, nil
}
}

return nil, FilterAlertNotFound(filterAlertName)
}

func (fa *FilterAlerts) Delete(viewName, filterAlertName string) error {
filterAlerts, err := fa.List(viewName)
if err != nil {
return fmt.Errorf("unable to list filter alerts: %w", err)
}
var filterAlertID string
for _, filterAlert := range filterAlerts {
if filterAlert.Name == filterAlertName {
filterAlertID = filterAlert.ID
break
}
}
if filterAlertID == "" {
return fmt.Errorf("unable to find filter alert")
}

var mutation struct {
DeleteAction bool `graphql:"deleteFilterAlert(input: { viewName: $viewName, id: $id })"`
}

variables := map[string]interface{}{
"viewName": graphql.String(viewName),
"id": graphql.String(filterAlertID),
}

return fa.client.Mutate(&mutation, variables)
}

func mapHumioGraphqlFilterAlertToFilterAlert(input humiographql.FilterAlert) FilterAlert {
var queryOwnershipType, runAsUserID string
switch input.QueryOwnership.QueryOwnershipTypeName {
case humiographql.QueryOwnershipTypeNameOrganization:
queryOwnershipType = QueryOwnershipTypeOrganization
case humiographql.QueryOwnershipTypeNameUser:
queryOwnershipType = QueryOwnershipTypeUser
runAsUserID = string(input.QueryOwnership.ID)
}

var actions []string
for _, action := range input.Actions {
actions = append(actions, string(action.ID))
}

var labels []string
for _, label := range input.Labels {
labels = append(labels, string(label))
}

var lastWarnings []string
for _, warning := range input.LastWarnings {
lastWarnings = append(lastWarnings, string(warning))
}

return FilterAlert{
ID: string(input.ID),
Name: string(input.Name),
Description: string(input.Description),
QueryString: string(input.QueryString),
Actions: actions,
Labels: labels,
Enabled: bool(input.Enabled),
LastTriggered: int(input.LastTriggered),
LastErrorTime: int(input.LastErrorTime),
LastError: string(input.LastError),
LastWarnings: lastWarnings,
QueryOwnershipType: queryOwnershipType,
RunAsUserID: runAsUserID,
}
}
26 changes: 2 additions & 24 deletions api/internal/humiographql/alerts.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,12 @@ type Alert struct {
Actions []graphql.String `graphql:"actions"`
Labels []graphql.String `graphql:"labels"`
LastError graphql.String `graphql:"lastError"`
QueryOwnership struct {
ID graphql.String `graphql:"id"`
QueryOwnershipTypeName QueryOwnershipTypeName `graphql:"__typename"`
} `graphql:"queryOwnership"`
RunAsUser struct {
QueryOwnership QueryOwnership `graphql:"queryOwnership"`
RunAsUser struct {
ID graphql.String `graphql:"id"`
} `graphql:"runAsUser"`
}

type QueryOwnership struct {
}

type CreateAlert struct {
ViewName graphql.String `json:"viewName"`
Name graphql.String `json:"name"`
Expand Down Expand Up @@ -58,19 +52,3 @@ type UpdateAlert struct {
Labels []graphql.String `json:"labels"`
QueryOwnershipType QueryOwnershipType `json:"queryOwnershipType,omitempty"`
}

type Long int64

type QueryOwnershipTypeName string

const (
QueryOwnershipTypeNameOrganization QueryOwnershipTypeName = "OrganizationOwnership"
QueryOwnershipTypeNameUser QueryOwnershipTypeName = "UserOwnership"
)

type QueryOwnershipType string

const (
QueryOwnershipTypeUser QueryOwnershipType = "User"
QueryOwnershipTypeOrganization QueryOwnershipType = "Organization"
)
49 changes: 49 additions & 0 deletions api/internal/humiographql/filter-alerts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package humiographql

import graphql "github.com/cli/shurcooL-graphql"

type FilterAlert struct {
ID graphql.String `graphql:"id"`
Name graphql.String `graphql:"name"`
Description graphql.String `graphql:"description"`
QueryString graphql.String `graphql:"queryString"`
Actions []Action `graphql:"actions"`
Labels []graphql.String `graphql:"labels"`
Enabled graphql.Boolean `graphql:"enabled"`
LastTriggered Long `graphql:"lastTriggered"`
LastErrorTime Long `graphql:"lastErrorTime"`
LastError graphql.String `graphql:"lastError"`
LastWarnings []graphql.String `graphql:"lastWarnings"`
QueryOwnership QueryOwnership `graphql:"queryOwnership"`
}

type Action struct {
Name graphql.String `graphql:"name"`
DisplayName graphql.String `graphql:"displayName"`
ID graphql.String `graphql:"id"`
}

type CreateFilterAlert struct {
ViewName RepoOrViewName `json:"viewName"`
Name graphql.String `json:"name"`
Description graphql.String `json:"description,omitempty"`
QueryString graphql.String `json:"queryString"`
ActionIdsOrNames []graphql.String `json:"actionIdsOrNames"`
Labels []graphql.String `json:"labels"`
Enabled graphql.Boolean `json:"enabled"`
RunAsUserID graphql.String `json:"runAsUserID,omitempty"`
QueryOwnershipType QueryOwnershipType `json:"queryOwnershipType"`
}

type UpdateFilterAlert struct {
ViewName RepoOrViewName `json:"viewName"`
ID graphql.String `json:"id"`
Name graphql.String `json:"name"`
Description graphql.String `json:"description,omitempty"`
QueryString graphql.String `json:"queryString"`
ActionIdsOrNames []graphql.String `json:"actionIdsOrNames"`
Labels []graphql.String `json:"labels"`
Enabled graphql.Boolean `json:"enabled"`
RunAsUserID graphql.String `json:"runAsUserID,omitempty"`
QueryOwnershipType QueryOwnershipType `json:"queryOwnershipType"`
}
22 changes: 22 additions & 0 deletions api/internal/humiographql/queryownership.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package humiographql

import graphql "github.com/cli/shurcooL-graphql"

type QueryOwnershipTypeName string

const (
QueryOwnershipTypeNameOrganization QueryOwnershipTypeName = "OrganizationOwnership"
QueryOwnershipTypeNameUser QueryOwnershipTypeName = "UserOwnership"
)

type QueryOwnershipType string

const (
QueryOwnershipTypeUser QueryOwnershipType = "User"
QueryOwnershipTypeOrganization QueryOwnershipType = "Organization"
)

type QueryOwnership struct {
ID graphql.String `graphql:"id"`
QueryOwnershipTypeName QueryOwnershipTypeName `graphql:"__typename"`
}
5 changes: 5 additions & 0 deletions api/internal/humiographql/scalars.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package humiographql

type RepoOrViewName string

type Long int64
4 changes: 2 additions & 2 deletions cmd/humioctl/alerts_install.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@ The install command allows you to install alerts from a URL or from a local file
// if we only got <view> you must supply --file or --url.
if l := len(args); l == 1 {
if filePath != "" {
content, err = getAlertFromFile(filePath)
content, err = getBytesFromFile(filePath)
} else if url != "" {
content, err = getURLAlert(url)
content, err = getBytesFromURL(url)
} else {
cmd.Printf("You must specify a path using --file or --url\n")
os.Exit(1)
Expand Down
Loading

0 comments on commit 468a5df

Please sign in to comment.