From 468a5df48aa84da8eb4cf029b52c3bedd19ccf58 Mon Sep 17 00:00:00 2001 From: fjerlov-cs <158591046+fjerlov-cs@users.noreply.github.com> Date: Tue, 5 Mar 2024 13:05:22 +0100 Subject: [PATCH] Filter alerts (#147) * Filter alerts * Move byte getters to util --- api/error.go | 14 +- api/filter-alerts.go | 228 ++++++++++++++++++++ api/internal/humiographql/alerts.go | 26 +-- api/internal/humiographql/filter-alerts.go | 49 +++++ api/internal/humiographql/queryownership.go | 22 ++ api/internal/humiographql/scalars.go | 5 + cmd/humioctl/alerts_install.go | 4 +- cmd/humioctl/filter_alerts.go | 34 +++ cmd/humioctl/filter_alerts_export.go | 55 +++++ cmd/humioctl/filter_alerts_install.go | 86 ++++++++ cmd/humioctl/filter_alerts_list.go | 63 ++++++ cmd/humioctl/filter_alerts_remove.go | 42 ++++ cmd/humioctl/filter_alerts_show.go | 57 +++++ cmd/humioctl/root.go | 1 + cmd/humioctl/util.go | 21 ++ 15 files changed, 678 insertions(+), 29 deletions(-) create mode 100644 api/filter-alerts.go create mode 100644 api/internal/humiographql/filter-alerts.go create mode 100644 api/internal/humiographql/queryownership.go create mode 100644 api/internal/humiographql/scalars.go create mode 100644 cmd/humioctl/filter_alerts.go create mode 100644 cmd/humioctl/filter_alerts_export.go create mode 100644 cmd/humioctl/filter_alerts_install.go create mode 100644 cmd/humioctl/filter_alerts_list.go create mode 100644 cmd/humioctl/filter_alerts_remove.go create mode 100644 cmd/humioctl/filter_alerts_show.go diff --git a/api/error.go b/api/error.go index 09ff5d7..90fdefe 100644 --- a/api/error.go +++ b/api/error.go @@ -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 { @@ -51,3 +52,10 @@ func AlertNotFound(name string) error { key: name, } } + +func FilterAlertNotFound(name string) error { + return EntityNotFound{ + entityType: EntityTypeFilterAlert, + key: name, + } +} diff --git a/api/filter-alerts.go b/api/filter-alerts.go new file mode 100644 index 0000000..883e274 --- /dev/null +++ b/api/filter-alerts.go @@ -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, + } +} diff --git a/api/internal/humiographql/alerts.go b/api/internal/humiographql/alerts.go index 0612896..52eb6da 100644 --- a/api/internal/humiographql/alerts.go +++ b/api/internal/humiographql/alerts.go @@ -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"` @@ -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" -) diff --git a/api/internal/humiographql/filter-alerts.go b/api/internal/humiographql/filter-alerts.go new file mode 100644 index 0000000..1932997 --- /dev/null +++ b/api/internal/humiographql/filter-alerts.go @@ -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"` +} diff --git a/api/internal/humiographql/queryownership.go b/api/internal/humiographql/queryownership.go new file mode 100644 index 0000000..0bfd6bb --- /dev/null +++ b/api/internal/humiographql/queryownership.go @@ -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"` +} diff --git a/api/internal/humiographql/scalars.go b/api/internal/humiographql/scalars.go new file mode 100644 index 0000000..7411074 --- /dev/null +++ b/api/internal/humiographql/scalars.go @@ -0,0 +1,5 @@ +package humiographql + +type RepoOrViewName string + +type Long int64 diff --git a/cmd/humioctl/alerts_install.go b/cmd/humioctl/alerts_install.go index dab15e9..bda83c5 100644 --- a/cmd/humioctl/alerts_install.go +++ b/cmd/humioctl/alerts_install.go @@ -52,9 +52,9 @@ The install command allows you to install alerts from a URL or from a local file // if we only got 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) diff --git a/cmd/humioctl/filter_alerts.go b/cmd/humioctl/filter_alerts.go new file mode 100644 index 0000000..a4c7bbc --- /dev/null +++ b/cmd/humioctl/filter_alerts.go @@ -0,0 +1,34 @@ +// Copyright © 2020 Humio Ltd. +// +// 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 newFilterAlertsCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "filter-alerts", + Short: "Manage filter alerts", + } + + cmd.AddCommand(newFilterAlertsListCmd()) + cmd.AddCommand(newFilterAlertsInstallCmd()) + cmd.AddCommand(newFilterAlertsExportCmd()) + cmd.AddCommand(newFilterAlertsRemoveCmd()) + cmd.AddCommand(newFilterAlertsShowCmd()) + + return cmd +} diff --git a/cmd/humioctl/filter_alerts_export.go b/cmd/humioctl/filter_alerts_export.go new file mode 100644 index 0000000..19ed3bc --- /dev/null +++ b/cmd/humioctl/filter_alerts_export.go @@ -0,0 +1,55 @@ +// Copyright © 2020 Humio Ltd. +// +// 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 ( + "os" + + "github.com/spf13/cobra" + "gopkg.in/yaml.v2" +) + +func newFilterAlertsExportCmd() *cobra.Command { + var outputName string + + cmd := cobra.Command{ + Use: "export [flags] ", + Short: "Export an filter alert in to a file.", + Args: cobra.ExactArgs(2), + Run: func(cmd *cobra.Command, args []string) { + view := args[0] + filterAlertName := args[1] + client := NewApiClient(cmd) + + if outputName == "" { + outputName = filterAlertName + } + + filterAlert, err := client.FilterAlerts().Get(view, filterAlertName) + exitOnError(cmd, err, "Error fetching filter alert") + + yamlData, err := yaml.Marshal(&filterAlert) + exitOnError(cmd, err, "Failed to serialize the filter alert") + + outFilePath := outputName + ".yaml" + err = os.WriteFile(outFilePath, yamlData, 0600) + exitOnError(cmd, err, "Error saving the filter alert file") + }, + } + + cmd.Flags().StringVarP(&outputName, "output", "o", "", "The file path where the filter alert should be written. Defaults to ./.yaml") + + return &cmd +} diff --git a/cmd/humioctl/filter_alerts_install.go b/cmd/humioctl/filter_alerts_install.go new file mode 100644 index 0000000..58d9c49 --- /dev/null +++ b/cmd/humioctl/filter_alerts_install.go @@ -0,0 +1,86 @@ +// Copyright © 2020 Humio Ltd. +// +// 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 ( + "fmt" + "os" + + "github.com/humio/cli/api" + "github.com/spf13/cobra" + "gopkg.in/yaml.v2" +) + +func newFilterAlertsInstallCmd() *cobra.Command { + var ( + filePath, url, name string + ) + + cmd := cobra.Command{ + Use: "install [flags] ", + Short: "Installs an filter alert in a view", + Long: `Install an filter alert from a URL or from a local file. + +The install command allows you to install filter alerts from a URL or from a local file, e.g. + + $ humioctl filter-alerts install viewName --name filterAlertName --url=https://example.com/acme/filter-alert.yaml + + $ humioctl filter-alerts install viewName --name filterAlertName --file=./filter-alert.yaml + + $ humioctl filter-alerts install viewName --file=./filter-alert.yaml +`, + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + var content []byte + var err error + + // Check that we got the right number of argument + // if we only got you must supply --file or --url. + if l := len(args); l == 1 { + if filePath != "" { + content, err = getBytesFromFile(filePath) + } else if url != "" { + content, err = getBytesFromURL(url) + } else { + cmd.Printf("You must specify a path using --file or --url\n") + os.Exit(1) + } + } + exitOnError(cmd, err, "Failed to load the filter alert") + + client := NewApiClient(cmd) + viewName := args[0] + + var filterAlert api.FilterAlert + err = yaml.Unmarshal(content, &filterAlert) + exitOnError(cmd, err, "Filter alert format is invalid") + + if name != "" { + filterAlert.Name = name + } + + _, err = client.FilterAlerts().Add(viewName, &filterAlert) + exitOnError(cmd, err, "Error creating filter alert") + + fmt.Fprintln(cmd.OutOrStdout(), "Filter alert created") + }, + } + + cmd.Flags().StringVar(&filePath, "file", "", "The local file path to the filter alert to install.") + cmd.Flags().StringVar(&url, "url", "", "A URL to fetch the filter alert file from.") + cmd.Flags().StringVarP(&name, "name", "n", "", "Install the filter alert under a specific name, ignoring the `name` attribute in the filter alert file.") + + return &cmd +} diff --git a/cmd/humioctl/filter_alerts_list.go b/cmd/humioctl/filter_alerts_list.go new file mode 100644 index 0000000..171f4a2 --- /dev/null +++ b/cmd/humioctl/filter_alerts_list.go @@ -0,0 +1,63 @@ +// Copyright © 2020 Humio Ltd. +// +// 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 ( + "strings" + + "github.com/humio/cli/cmd/internal/format" + "github.com/spf13/cobra" +) + +func newFilterAlertsListCmd() *cobra.Command { + cmd := cobra.Command{ + Use: "list [flags] ", + Short: "List all filter alerts in a view.", + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + view := args[0] + client := NewApiClient(cmd) + + filterAlerts, err := client.FilterAlerts().List(view) + exitOnError(cmd, err, "Error fetching filter alerts") + + actions, err := client.Actions().List(view) + exitOnError(cmd, err, "Unable to fetch notifier details") + + var notifierMap = map[string]string{} + for _, action := range actions { + notifierMap[action.ID] = action.Name + } + + var rows [][]format.Value + for i := 0; i < len(filterAlerts); i++ { + filterAlert := filterAlerts[i] + var notifierNames []string + for _, notifierID := range filterAlert.Actions { + notifierNames = append(notifierNames, notifierMap[notifierID]) + } + rows = append(rows, []format.Value{ + format.String(filterAlert.Name), + format.Bool(filterAlert.Enabled), + format.String(filterAlert.Description), + format.String(strings.Join(notifierNames, ", "))}) + } + + printOverviewTable(cmd, []string{"Name", "Enabled", "Description", "Actions"}, rows) + }, + } + + return &cmd +} diff --git a/cmd/humioctl/filter_alerts_remove.go b/cmd/humioctl/filter_alerts_remove.go new file mode 100644 index 0000000..52ee3e3 --- /dev/null +++ b/cmd/humioctl/filter_alerts_remove.go @@ -0,0 +1,42 @@ +// Copyright © 2020 Humio Ltd. +// +// 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 ( + "fmt" + + "github.com/spf13/cobra" +) + +func newFilterAlertsRemoveCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "remove [flags] ", + Short: "Removes an filter alert.", + Long: `Removes the filter alert with name '' in the view with name ''.`, + Args: cobra.ExactArgs(2), + Run: func(cmd *cobra.Command, args []string) { + viewName := args[0] + filterAlertName := args[1] + client := NewApiClient(cmd) + + err := client.FilterAlerts().Delete(viewName, filterAlertName) + exitOnError(cmd, err, "Error removing alert") + + fmt.Fprintf(cmd.OutOrStdout(), "Successfully removed filter alert %q from view %q\n", filterAlertName, viewName) + }, + } + + return cmd +} diff --git a/cmd/humioctl/filter_alerts_show.go b/cmd/humioctl/filter_alerts_show.go new file mode 100644 index 0000000..21ee5c6 --- /dev/null +++ b/cmd/humioctl/filter_alerts_show.go @@ -0,0 +1,57 @@ +// Copyright © 2020 Humio Ltd. +// +// 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 ( + "strings" + + "github.com/humio/cli/cmd/internal/format" + "github.com/spf13/cobra" +) + +func newFilterAlertsShowCmd() *cobra.Command { + cmd := cobra.Command{ + Use: "show ", + Short: "Show details about an filter alert in a repository or view.", + Args: cobra.ExactArgs(2), + Run: func(cmd *cobra.Command, args []string) { + repoOrViewName := args[0] + name := args[1] + client := NewApiClient(cmd) + + filterAlert, err := client.FilterAlerts().Get(repoOrViewName, name) + exitOnError(cmd, err, "Error fetching filter alert") + + details := [][]format.Value{ + {format.String("ID"), format.String(filterAlert.ID)}, + {format.String("Name"), format.String(filterAlert.Name)}, + {format.String("Enabled"), format.Bool(filterAlert.Enabled)}, + {format.String("Description"), format.String(filterAlert.Description)}, + {format.String("Query String"), format.String(filterAlert.QueryString)}, + {format.String("Labels"), format.String(strings.Join(filterAlert.Labels, ", "))}, + {format.String("Actions"), format.String(strings.Join(filterAlert.Actions, ", "))}, + {format.String("Last Error"), format.String(filterAlert.LastError)}, + {format.String("Last Error Time"), format.Int(filterAlert.LastErrorTime)}, + {format.String("Last Error"), format.String(filterAlert.LastError)}, + {format.String("Run As User ID"), format.String(filterAlert.RunAsUserID)}, + {format.String("Query Ownership Type"), format.String(filterAlert.QueryOwnershipType)}, + } + + printDetailsTable(cmd, details) + }, + } + + return &cmd +} diff --git a/cmd/humioctl/root.go b/cmd/humioctl/root.go index efe8ac0..5598f98 100644 --- a/cmd/humioctl/root.go +++ b/cmd/humioctl/root.go @@ -121,6 +121,7 @@ Common Management Commands: rootCmd.AddCommand(newClusterCmd()) rootCmd.AddCommand(newActionsCmd()) rootCmd.AddCommand(newAlertsCmd()) + rootCmd.AddCommand(newFilterAlertsCmd()) rootCmd.AddCommand(newPackagesCmd()) rootCmd.AddCommand(newGroupsCmd()) rootCmd.AddCommand(newFilesCmd()) diff --git a/cmd/humioctl/util.go b/cmd/humioctl/util.go index d765cc2..319bf48 100644 --- a/cmd/humioctl/util.go +++ b/cmd/humioctl/util.go @@ -3,6 +3,8 @@ package main import ( "errors" "fmt" + "io" + "net/http" "net/url" "os" "strconv" @@ -137,3 +139,22 @@ func printDetailsTable(cmd *cobra.Command, data [][]format.Value) { func printOverviewTable(cmd *cobra.Command, header []string, data [][]format.Value) { format.FormatterFromCommand(cmd).Table(header, data) } + +func getBytesFromFile(filePath string) ([]byte, error) { + // #nosec G304 + return os.ReadFile(filePath) +} + +func getBytesFromURL(url string) ([]byte, error) { + // #nosec G107 + response, err := http.Get(url) + + if err != nil { + return nil, err + } + + defer func() { + _ = response.Body.Close() + }() + return io.ReadAll(response.Body) +}