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
2 changes: 1 addition & 1 deletion cmd/humioctl/alerts_show.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func newAlertsShowCmd() *cobra.Command {
{format.String("Is Starred"), format.Bool(alert.IsStarred)},
{format.String("Last Error"), format.StringPtr(alert.LastError)},
{format.String("Throttle Field"), format.StringPtr(alert.ThrottleField)},
{format.String("Time Of Last Trigger"), format.IntPtr(alert.TimeOfLastTrigger)},
{format.String("Time Of Last Trigger"), format.Int64Ptr(alert.TimeOfLastTrigger)},
{format.String("Run As User ID"), format.String(alert.RunAsUserID)},
{format.String("Query Ownership Type"), format.String(alert.QueryOwnershipType)},
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/humioctl/filter_alerts_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func newFilterAlertsListCmd() *cobra.Command {
format.StringPtr(filterAlert.Description),
format.String(strings.Join(filterAlert.ActionNames, ", ")),
format.String(strings.Join(filterAlert.Labels, ", ")),
format.IntPtr(filterAlert.ThrottleTimeSeconds),
format.Int64Ptr(filterAlert.ThrottleTimeSeconds),
format.StringPtr(filterAlert.ThrottleField),
format.String(filterAlert.OwnershipRunAsID),
format.String(filterAlert.QueryOwnershipType),
Expand Down
2 changes: 1 addition & 1 deletion cmd/humioctl/filter_alerts_show.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func newFilterAlertsShowCmd() *cobra.Command {
{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.ActionNames, ", "))},
{format.String("Throttle Time Seconds"), format.IntPtr(filterAlert.ThrottleTimeSeconds)},
{format.String("Throttle Time Seconds"), format.Int64Ptr(filterAlert.ThrottleTimeSeconds)},
{format.String("Throttle Field"), format.StringPtr(filterAlert.ThrottleField)},
{format.String("Run As User ID"), format.String(filterAlert.OwnershipRunAsID)},
{format.String("Query Ownership Type"), format.String(filterAlert.QueryOwnershipType)},
Expand Down
1 change: 1 addition & 0 deletions cmd/humioctl/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ Common Management Commands:
rootCmd.AddCommand(newAlertsCmd())
rootCmd.AddCommand(newFilterAlertsCmd())
rootCmd.AddCommand(newScheduledSearchesCmd())
rootCmd.AddCommand(newScheduledSearchesV2Cmd())
rootCmd.AddCommand(newAggregateAlertsCmd())
rootCmd.AddCommand(newPackagesCmd())
rootCmd.AddCommand(newGroupsCmd())
Expand Down
2 changes: 1 addition & 1 deletion cmd/humioctl/scheduled_searches_install.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ The install command allows you to install scheduled searches from a URL or from

cmd.Flags().StringVar(&filePath, "file", "", "The local file path to the scheduled search to install.")
cmd.Flags().StringVar(&url, "url", "", "A URL to fetch the scheduled search file from.")
cmd.Flags().StringVarP(&name, "name", "n", "", "Install the alert under a specific name, ignoring the `name` attribute in the alert file.")
cmd.Flags().StringVarP(&name, "name", "n", "", "Install the scheduled search under a specific name, ignoring the `name` attribute in the scheduled search file.")
cmd.MarkFlagsMutuallyExclusive("file", "url")
return &cmd
}
35 changes: 35 additions & 0 deletions cmd/humioctl/scheduled_searches_v2.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright © 2025 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 newScheduledSearchesV2Cmd() *cobra.Command {
cmd := &cobra.Command{
Use: "scheduled-searches-v2",
Short: "Manage scheduled searches",
}

cmd.AddCommand(newScheduledSearchesV2ListCmd())
cmd.AddCommand(newScheduledSearchesV2InstallCmd())
cmd.AddCommand(newScheduledSearchesV2ExportCmd())
cmd.AddCommand(newScheduledSearchesV2ExportAllCmd())
cmd.AddCommand(newScheduledSearchesV2RemoveCmd())
cmd.AddCommand(newScheduledSearchesV2ShowCmd())

return cmd
}
106 changes: 106 additions & 0 deletions cmd/humioctl/scheduled_searches_v2_export.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// Copyright © 2025 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 (
"os"

"github.com/humio/cli/internal/api"
"github.com/spf13/cobra"
"gopkg.in/yaml.v2"
)

func newScheduledSearchesV2ExportCmd() *cobra.Command {
var outputName string

cmd := cobra.Command{
Use: "export [flags] <view> <scheduled-search>",
Short: "Export a scheduled search <scheduled-search> in <view> to a file.",
Args: cobra.ExactArgs(2),
Run: func(cmd *cobra.Command, args []string) {
view := args[0]
scheduledSearchName := args[1]
client := NewApiClient(cmd)

if outputName == "" {
outputName = scheduledSearchName
}

scheduledSearches, err := client.ScheduledSearchesV2().List(view)
exitOnError(cmd, err, "Could not list scheduled searches")

var scheduledSearch api.ScheduledSearchV2
for _, ss := range scheduledSearches {
if ss.Name == scheduledSearchName {
scheduledSearch = ss
}
}

if scheduledSearch.ID == "" {
exitOnError(cmd, api.ScheduledSearchNotFound(scheduledSearchName), "Could not find scheduled search")
}

yamlData, err := yaml.Marshal(&scheduledSearch)
exitOnError(cmd, err, "Failed to serialize the scheduled search")

outFilePath := outputName + ".yaml"
err = os.WriteFile(outFilePath, yamlData, 0600)
exitOnError(cmd, err, "Error saving the scheduled search file")
},
}

cmd.Flags().StringVarP(&outputName, "output", "o", "", "The file path where the scheduled search should be written. Defaults to ./<scheduled-search-name>.yaml")

return &cmd
}

func newScheduledSearchesV2ExportAllCmd() *cobra.Command {
var outputDirectory string

cmd := cobra.Command{
Use: "export-all <view>",
Short: "Export all scheduled searches",
Long: `Export all scheduled searches to yaml files with naming <sanitized-scheduled-search-name>.yaml.`,
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
view := args[0]
client := NewApiClient(cmd)

var scheduledSearches []api.ScheduledSearchV2
scheduledSearches, err := client.ScheduledSearchesV2().List(view)
exitOnError(cmd, err, "Error fetching scheduled searches")

for i := range scheduledSearches {
yamlData, err := yaml.Marshal(&scheduledSearches[i])
exitOnError(cmd, err, "Failed to serialize the scheduled search")
scheduledSearchFilename := sanitizeTriggerName(scheduledSearches[i].Name) + ".yaml"

var outFilePath string
if outputDirectory != "" {
outFilePath = outputDirectory + "/" + scheduledSearchFilename
} else {
outFilePath = scheduledSearchFilename
}

err = os.WriteFile(outFilePath, yamlData, 0600)
exitOnError(cmd, err, "Error saving the scheduled search to file")
}
},
}

cmd.Flags().StringVarP(&outputDirectory, "outputDirectory", "d", "", "The file path where the scheduled searches should be written. Defaults to current directory.")

return &cmd
}
111 changes: 111 additions & 0 deletions cmd/humioctl/scheduled_searches_v2_install.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
// Copyright © 2025 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 (
"fmt"
"os"

"github.com/humio/cli/internal/api"
"github.com/spf13/cobra"
"gopkg.in/yaml.v2"
)

func newScheduledSearchesV2InstallCmd() *cobra.Command {
var filePath, url, name string

cmd := cobra.Command{
Use: "install [flags] <view>",
Short: "Installs a scheduled search in a view",
Long: `Install a scheduled search from a URL or from a local file.

The install command allows you to install scheduled searches from a URL or from a local file, e.g.

$ humioctl scheduled-searches-v2 install viewName --url=https://example.com/acme/scheduled-search-v2.yaml

$ humioctl scheduled-searches-v2 install viewName --file=./scheduled-searches-v2.yaml

$ humioctl scheduled-searches-v2 install viewName --file=./scheduled-search-v1.yaml
This will install the legacy scheduled search with the CreateScheduledSearch mutation (deprecated for removal in 1.231).
`,
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 <view> 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, "Could to load the scheduled search")

client := NewApiClient(cmd)
viewName := args[0]

var scheduledSearchV2 api.ScheduledSearchV2
scheduledSearchV2, parseErr := tryParseScheduledSearchV2(content)
if parseErr != nil {
_, _ = fmt.Fprintf(cmd.OutOrStdout(), "Yaml file could not be parsed as scheduled search v2, err='%s'. Attempting to parse as scheduled search v1 and create using deprecated CreateScheduledSearch mutation.\n", parseErr)
var scheduledSearchV1 api.ScheduledSearch
err = yaml.UnmarshalStrict(content, &scheduledSearchV1)

exitOnError(cmd, err, "Could not unmarshal the scheduled search as a scheduled search v1.")

if name != "" {
scheduledSearchV1.Name = name
}

_, err = client.ScheduledSearches().Create(viewName, &scheduledSearchV1)
exitOnError(cmd, err, "Could not create the scheduled search using deprecated CreateScheduledSearch mutation.")

_, _ = fmt.Fprintln(cmd.OutOrStdout(), "Scheduled search v1 created using deprecated CreateScheduledSearch mutation.")
} else {
if name != "" {
scheduledSearchV2.Name = name
}

_, err = client.ScheduledSearchesV2().Create(viewName, &scheduledSearchV2)
exitOnError(cmd, err, "Could not create the scheduled search")

_, _ = fmt.Fprintln(cmd.OutOrStdout(), "Scheduled search created")
os.Exit(1)
}
},
}

cmd.Flags().StringVar(&filePath, "file", "", "The local file path to the scheduled search to install.")
cmd.Flags().StringVar(&url, "url", "", "A URL to fetch the scheduled search file from.")
cmd.Flags().StringVarP(&name, "name", "n", "", "Install the scheduled search under a specific name, ignoring the `name` attribute in the scheduled search file.")
cmd.MarkFlagsMutuallyExclusive("file", "url")
return &cmd
}

func tryParseScheduledSearchV2(content []byte) (api.ScheduledSearchV2, error) {
var scheduledSearchV2 api.ScheduledSearchV2
err := yaml.UnmarshalStrict(content, &scheduledSearchV2)
if err != nil {
return api.ScheduledSearchV2{}, err
} else {
return scheduledSearchV2, nil
}
}
81 changes: 81 additions & 0 deletions cmd/humioctl/scheduled_searches_v2_list.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// Copyright © 2025 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 (
"strconv"
"strings"

"github.com/humio/cli/internal/format"
"github.com/spf13/cobra"
)

func newScheduledSearchesV2ListCmd() *cobra.Command {
cmd := cobra.Command{
Use: "list <view>",
Short: "List all scheduled searches in a view.",
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
view := args[0]
client := NewApiClient(cmd)

scheduledSearches, err := client.ScheduledSearchesV2().List(view)
exitOnError(cmd, err, "Error fetching scheduled searches")

var rows = make([][]format.Value, len(scheduledSearches))
for i := range scheduledSearches {
scheduledSearch := scheduledSearches[i]

rows[i] = []format.Value{
format.String(scheduledSearch.ID),
format.String(scheduledSearch.Name),
format.StringPtr(scheduledSearch.Description),
format.String(strconv.FormatInt(scheduledSearch.SearchIntervalSeconds, 10)),
format.Int64Ptr(scheduledSearch.SearchIntervalOffsetSeconds),
format.String(scheduledSearch.QueryTimestampType),
format.Int64Ptr(scheduledSearch.MaxWaitTimeSeconds),
format.IntPtr(scheduledSearch.BackfillLimitV2),
format.String(scheduledSearch.TimeZone),
format.String(scheduledSearch.Schedule),
format.String(strings.Join(scheduledSearch.ActionNames, ", ")),
format.String(strings.Join(scheduledSearch.Labels, ", ")),
format.Bool(scheduledSearch.Enabled),
format.String(scheduledSearch.OwnershipRunAsID),
format.String(scheduledSearch.QueryOwnershipType),
}
}

printOverviewTable(cmd, []string{
"ID",
"Name",
"Description",
"Search Interval Seconds",
"Search Interval Offset Seconds",
"Query Timestamp Type",
"Max Wait Time",
"Backfill Limit",
"Time Zone",
"Schedule",
"Action Names",
"Labels",
"Enabled",
"Run As User ID",
"Query Ownership Type",
}, rows)
},
}

return &cmd
}
Loading
Loading