Skip to content

Commit

Permalink
Aggregate alerts
Browse files Browse the repository at this point in the history
  • Loading branch information
fjerlov-cs committed Jul 11, 2024
1 parent b24a1e9 commit 62faeff
Show file tree
Hide file tree
Showing 14 changed files with 695 additions and 4 deletions.
242 changes: 242 additions & 0 deletions api/aggregate-alerts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
package api

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

type AggregateAlert struct {
ID string `graphql:"id" yaml:"-" 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"`
SearchIntervalSeconds int `graphql:"searchIntervalSeconds" yaml:"searchIntervalSeconds" json:"searchIntervalSeconds"`
ActionNames []string `graphql:"actionNames" yaml:"actionNames" json:"actionNames"`
Labels []string `graphql:"labels" yaml:"labels" json:"labels"`
Enabled bool `graphql:"enabled" yaml:"enabled" json:"enabled"`
ThrottleField string `graphql:"throttleField" yaml:"throttleField" json:"throttleField"`
ThrottleTimeSeconds int `graphql:"throttleTimeSeconds" yaml:"throttleTimeSeconds" json:"throttleTimeSeconds"`
QueryOwnershipType string `graphql:"queryOwnership" yaml:"queryOwnershipType" json:"queryOwnershipType"`
TriggerMode string `graphql:"triggerMode" yaml:"triggerMode" json:"triggerMode"`
QueryTimestampType string `graphql:"queryTimestampType" yaml:"queryTimestampType" json:"queryTimestampType"`
RunAsUserID string `graphql:"runAsUserId" yaml:"runAsUserId,omitempty" json:"runAsUserId,omitempty"`
}

type AggregateAlerts struct {
client *Client
}

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

func (a *AggregateAlerts) List(viewName string) ([]AggregateAlert, error) {
var query struct {
SearchDomain struct {
AggregateAlerts []humiographql.AggregateAlert `graphql:"aggregateAlerts"`
} `graphql:"searchDomain(name: $viewName)"`
}

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

err := a.client.Query(&query, variables)
if err != nil {
return nil, err
}

var aggregateAlerts = make([]AggregateAlert, len(query.SearchDomain.AggregateAlerts))
for i := range query.SearchDomain.AggregateAlerts {
aggregateAlerts[i] = mapHumioGraphqlAggregateAlertToAggregateAlert(query.SearchDomain.AggregateAlerts[i])
}

return aggregateAlerts, err
}

func (a *AggregateAlerts) Update(viewName string, updatedAggregateAlert *AggregateAlert) (*AggregateAlert, error) {
if updatedAggregateAlert == nil {
return nil, fmt.Errorf("updatedAggregateAlert must not be nil")
}

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

var mutation struct {
humiographql.AggregateAlert `graphql:"updateAggregateAlert(input: $input)"`
}

actionNames := make([]graphql.String, len(updatedAggregateAlert.ActionNames))
for i, actionName := range updatedAggregateAlert.ActionNames {
actionNames[i] = graphql.String(actionName)
}

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

updateAlert := humiographql.UpdateAggregateAlert{
ViewName: humiographql.RepoOrViewName(viewName),
ID: graphql.String(updatedAggregateAlert.ID),
Name: graphql.String(updatedAggregateAlert.Name),
Description: graphql.String(updatedAggregateAlert.Description),
QueryString: graphql.String(updatedAggregateAlert.QueryString),
SearchIntervalSeconds: humiographql.Long(updatedAggregateAlert.SearchIntervalSeconds),
ActionIdsOrNames: actionNames,
Labels: labels,
Enabled: graphql.Boolean(updatedAggregateAlert.Enabled),
RunAsUserID: graphql.String(updatedAggregateAlert.RunAsUserID),
ThrottleField: graphql.String(updatedAggregateAlert.ThrottleField),
ThrottleTimeSeconds: humiographql.Long(updatedAggregateAlert.ThrottleTimeSeconds),
TriggerMode: humiographql.TriggerMode(updatedAggregateAlert.TriggerMode),
QueryTimestampType: humiographql.QueryTimestampType(updatedAggregateAlert.QueryTimestampType),
QueryOwnershipType: humiographql.QueryOwnershipType(updatedAggregateAlert.QueryOwnershipType),
}

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

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

aggregateAlert := mapHumioGraphqlAggregateAlertToAggregateAlert(mutation.AggregateAlert)

return &aggregateAlert, nil
}

func (a *AggregateAlerts) Create(viewName string, newAggregateAlert *AggregateAlert) (*AggregateAlert, error) {
if newAggregateAlert == nil {
return nil, fmt.Errorf("newAggregateAlert must not be nil")
}

var mutation struct {
humiographql.AggregateAlert `graphql:"createAggregateAlert(input: $input)"`
}

actionNames := make([]graphql.String, len(newAggregateAlert.ActionNames))
for i, actionName := range newAggregateAlert.ActionNames {
actionNames[i] = graphql.String(actionName)
}

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

createAggregateAlert := humiographql.CreateAggregateAlert{
ViewName: humiographql.RepoOrViewName(viewName),
Name: graphql.String(newAggregateAlert.Name),
Description: graphql.String(newAggregateAlert.Description),
QueryString: graphql.String(newAggregateAlert.QueryString),
SearchIntervalSeconds: humiographql.Long(newAggregateAlert.SearchIntervalSeconds),
ActionIdsOrNames: actionNames,
Labels: labels,
Enabled: graphql.Boolean(newAggregateAlert.Enabled),
ThrottleField: graphql.String(newAggregateAlert.ThrottleField),
ThrottleTimeSeconds: humiographql.Long(newAggregateAlert.ThrottleTimeSeconds),
RunAsUserID: graphql.String(newAggregateAlert.RunAsUserID),
TriggerMode: humiographql.TriggerMode(newAggregateAlert.TriggerMode),
QueryTimestampType: humiographql.QueryTimestampType(newAggregateAlert.QueryTimestampType),
QueryOwnershipType: humiographql.QueryOwnershipType(newAggregateAlert.QueryOwnershipType),
}

variables := map[string]any{
"input": createAggregateAlert,
}

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

aggregateAlert := mapHumioGraphqlAggregateAlertToAggregateAlert(mutation.AggregateAlert)

return &aggregateAlert, nil
}

func (a *AggregateAlerts) Delete(viewName, aggregateAlertID string) error {
if aggregateAlertID == "" {
return fmt.Errorf("aggregateAlertID is empty")
}

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

variables := map[string]any{
"viewName": humiographql.RepoOrViewName(viewName),
"id": graphql.String(aggregateAlertID),
}

err := a.client.Mutate(&mutation, variables)

if !mutation.DidDelete {
return fmt.Errorf("unable to remove aggregate alert in repo/view '%s' with id '%s'", viewName, aggregateAlertID)
}

return err
}

func (a *AggregateAlerts) Get(viewName string, aggregateAlertID string) (*AggregateAlert, error) {
var query struct {
SearchDomain struct {
AggregateAlert humiographql.AggregateAlert `graphql:"aggregateAlert(id: $aggregateAlertId)"`
} `graphql:"searchDomain(name: $viewName) "`
}

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

err := a.client.Query(&query, variables)
if err != nil {
return nil, err
}

aggregateAlert := mapHumioGraphqlAggregateAlertToAggregateAlert(query.SearchDomain.AggregateAlert)

return &aggregateAlert, nil
}

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

var actionNames = make([]string, len(input.Actions))
for i := range input.Actions {
actionNames[i] = string(input.Actions[i].Name)
}

var labels = make([]string, len(input.Labels))
for i := range input.Labels {
labels[i] = string(input.Labels[i])
}

return AggregateAlert{
ID: string(input.ID),
Name: string(input.Name),
Description: string(input.Description),
QueryString: string(input.QueryString),
SearchIntervalSeconds: int(input.SearchIntervalSeconds),
ActionNames: actionNames,
Labels: labels,
Enabled: bool(input.Enabled),
ThrottleField: string(input.ThrottleField),
ThrottleTimeSeconds: int(input.ThrottleTimeSeconds),
QueryOwnershipType: queryOwnershipType,
TriggerMode: string(input.TriggerMode),
QueryTimestampType: string(input.QueryTimestampType),
RunAsUserID: runAsUserID,
}
}
8 changes: 8 additions & 0 deletions api/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const (
EntityTypeAlert EntityType = "alert"
EntityTypeFilterAlert EntityType = "filter-alert"
EntityTypeScheduledSearch EntityType = "scheduled-search"
EntityTypeAggregateAlert EntityType = "aggregate-alert"
)

func (e EntityType) String() string {
Expand Down Expand Up @@ -68,4 +69,11 @@ func ScheduledSearchNotFound(name string) error {
entityType: EntityTypeScheduledSearch,
key: name,
}
}

func AggregateAlertNotFound(name string) error {
return EntityNotFound{
entityType: EntityTypeAggregateAlert,
key: name,
}
}
7 changes: 7 additions & 0 deletions api/internal/humiographql/action.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package humiographql

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

type Action struct {
Name graphql.String `graphql:"name"`
}
54 changes: 54 additions & 0 deletions api/internal/humiographql/aggregate-alerts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package humiographql

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

type AggregateAlert struct {
ID graphql.String `json:"id"`
Name graphql.String `json:"name"`
Description graphql.String `json:"description,omitempty"`
QueryString graphql.String `json:"queryString"`
SearchIntervalSeconds Long `json:"searchIntervalSeconds"`
ThrottleTimeSeconds Long `json:"throttleTimeSeconds"`
ThrottleField graphql.String `json:"throttleField,omitempty"`
Actions []Action `json:"actionIdsOrNames"`
Labels []graphql.String `json:"labels"`
Enabled graphql.Boolean `json:"enabled"`
QueryOwnership QueryOwnership `json:"queryOwnershipType"`
TriggerMode TriggerMode `json:"triggerMode"`
QueryTimestampType QueryTimestampType `json:"queryTimestampType"`
}

type CreateAggregateAlert struct {
ViewName RepoOrViewName `json:"viewName"`
Name graphql.String `json:"name"`
Description graphql.String `json:"description,omitempty"`
QueryString graphql.String `json:"queryString"`
SearchIntervalSeconds Long `json:"searchIntervalSeconds"`
ThrottleTimeSeconds Long `json:"throttleTimeSeconds"`
ThrottleField graphql.String `json:"throttleField,omitempty"`
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"`
TriggerMode TriggerMode `json:"triggerMode,omitempty"`
QueryTimestampType QueryTimestampType `json:"queryTimestampType"`
}

type UpdateAggregateAlert 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"`
SearchIntervalSeconds Long `json:"searchIntervalSeconds"`
ThrottleTimeSeconds Long `json:"throttleTimeSeconds"`
ThrottleField graphql.String `json:"throttleField,omitempty"`
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"`
TriggerMode TriggerMode `json:"triggerMode"`
QueryTimestampType QueryTimestampType `json:"queryTimestampType"`
}
4 changes: 0 additions & 4 deletions api/internal/humiographql/filter-alerts.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,6 @@ type FilterAlert struct {
QueryOwnership QueryOwnership `graphql:"queryOwnership"`
}

type Action struct {
Name graphql.String `graphql:"name"`
}

type CreateFilterAlert struct {
ViewName RepoOrViewName `json:"viewName"`
Name graphql.String `json:"name"`
Expand Down
8 changes: 8 additions & 0 deletions api/internal/humiographql/query-timestamp-type.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package humiographql

type QueryTimestampType string

const (
QueryTimestampTypeIngestTimestamp QueryTimestampType = "IngestTimestamp"
QueryTimestampTypeEventTimestamp QueryTimestampType = "EventTimestamp"
)
8 changes: 8 additions & 0 deletions api/internal/humiographql/trigger-mode.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package humiographql

type TriggerMode string

const (
TriggerModeCompleteMode TriggerMode = "CompleteMode"
TriggerModeImmediateMode TriggerMode = "ImmediateMode"
)
34 changes: 34 additions & 0 deletions cmd/humioctl/aggregate_alerts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright © 2024 CrowdStrike
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
"github.com/spf13/cobra"
)

func newAggregateAlertsCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "aggregate-alerts",
Short: "Manage aggregate alerts",
}

cmd.AddCommand(newAggregateAlertsListCmd())
cmd.AddCommand(newAggregateAlertsInstallCmd())
cmd.AddCommand(newAggregateAlertsExportCmd())
cmd.AddCommand(newAggregateAlertsRemoveCmd())
cmd.AddCommand(newAggregateAlertsShowCmd())

return cmd
}
Loading

0 comments on commit 62faeff

Please sign in to comment.