diff --git a/api/actions.go b/api/actions.go index cf80a8d..95c7129 100644 --- a/api/actions.go +++ b/api/actions.go @@ -832,7 +832,7 @@ func (n *Actions) Delete(viewName, actionName string) error { } } if actionID == "" { - return fmt.Errorf("unable to find action") + return ActionNotFound(actionID) } var mutation struct { diff --git a/api/error.go b/api/error.go index a33c2ba..9a78cb3 100644 --- a/api/error.go +++ b/api/error.go @@ -7,6 +7,10 @@ import ( type EntityType string const ( + EntityTypeSearchDomain EntityType = "search-domain" + EntityTypeRepository EntityType = "repository" + EntityTypeView EntityType = "view" + EntityTypeIngestToken EntityType = "ingest-token" EntityTypeParser EntityType = "parser" EntityTypeAction EntityType = "action" EntityTypeAlert EntityType = "alert" @@ -36,6 +40,34 @@ func (e EntityNotFound) Error() string { return fmt.Sprintf("%s %q not found", e.entityType.String(), e.key) } +func SearchDomainNotFound(name string) error { + return EntityNotFound{ + entityType: EntityTypeSearchDomain, + key: name, + } +} + +func RepositoryNotFound(name string) error { + return EntityNotFound{ + entityType: EntityTypeRepository, + key: name, + } +} + +func ViewNotFound(name string) error { + return EntityNotFound{ + entityType: EntityTypeView, + key: name, + } +} + +func IngestTokenNotFound(name string) error { + return EntityNotFound{ + entityType: EntityTypeIngestToken, + key: name, + } +} + func ParserNotFound(name string) error { return EntityNotFound{ entityType: EntityTypeParser, diff --git a/api/ingest-tokens.go b/api/ingest-tokens.go index 470db50..28da72a 100644 --- a/api/ingest-tokens.go +++ b/api/ingest-tokens.go @@ -1,7 +1,6 @@ package api import ( - "fmt" graphql "github.com/cli/shurcooL-graphql" ) @@ -61,7 +60,7 @@ func (i *IngestTokens) Get(repoName, tokenName string) (*IngestToken, error) { } } - return nil, fmt.Errorf("could not find an ingest token with name '%s' in repo '%s'", tokenName, repoName) + return nil, IngestTokenNotFound(tokenName) } func toIngestToken(data ingestTokenData) *IngestToken { diff --git a/api/internal/humiographql/searchdomains.go b/api/internal/humiographql/searchdomains.go new file mode 100644 index 0000000..a0dc9b9 --- /dev/null +++ b/api/internal/humiographql/searchdomains.go @@ -0,0 +1,7 @@ +package humiographql + +import graphql "github.com/cli/shurcooL-graphql" + +const ( + SearchDomainTypeView graphql.String = "View" +) diff --git a/api/repositories.go b/api/repositories.go index a37b70d..753107b 100644 --- a/api/repositories.go +++ b/api/repositories.go @@ -38,8 +38,7 @@ func (r *Repositories) Get(name string) (Repository, error) { err := r.client.Query(&query, variables) if err != nil { - // The graphql error message is vague if the repo already exists, so add a hint. - return query.Repository, fmt.Errorf("%w. Does the repo already exist?", err) + return query.Repository, RepositoryNotFound(name) } return query.Repository, nil @@ -81,6 +80,11 @@ func (r *Repositories) Create(name string) error { } func (r *Repositories) Delete(name, reason string, allowDataDeletion bool) error { + _, err := r.Get(name) + if err != nil { + return err + } + if !allowDataDeletion { return fmt.Errorf("repository may contain data and data deletion not enabled") } @@ -232,6 +236,11 @@ func (r *Repositories) UpdateIngestBasedRetention(name string, ingestInGB float6 } func (r *Repositories) UpdateDescription(name, description string) error { + _, err := r.Get(name) + if err != nil { + return err + } + var mutation struct { UpdateDescription struct { // We have to make a selection, so just take __typename @@ -332,6 +341,11 @@ func (r *Repositories) UpdateS3ArchivingConfiguration(name string, bucket string } func (r *Repositories) UpdateAutomaticSearch(name string, automaticSearch bool) error { + _, err := r.Get(name) + if err != nil { + return err + } + var mutation struct { SetAutomaticSearching struct { // We have to make a selection, so just take __typename diff --git a/api/searchdomains.go b/api/searchdomains.go new file mode 100644 index 0000000..2dcb8e1 --- /dev/null +++ b/api/searchdomains.go @@ -0,0 +1,70 @@ +package api + +import ( + "sort" + "strings" + + graphql "github.com/cli/shurcooL-graphql" +) + +type SearchDomains struct { + client *Client +} + +type SearchDomainsQueryData struct { + Name string + Description string + AutomaticSearch bool + Typename graphql.String `graphql:"__typename"` +} + +type SearchDomain struct { + Name string + Description string + AutomaticSearch bool +} + +func (s *Client) SearchDomains() *SearchDomains { return &SearchDomains{client: s} } + +func (s *SearchDomains) Get(name string) (*SearchDomain, error) { + var query struct { + Result SearchDomainsQueryData `graphql:"searchDomain(name: $name)"` + } + + variables := map[string]interface{}{ + "name": graphql.String(name), + } + + err := s.client.Query(&query, variables) + if err != nil { + return nil, SearchDomainNotFound(name) + } + + searchDomain := SearchDomain{ + Name: query.Result.Name, + Description: query.Result.Description, + AutomaticSearch: query.Result.AutomaticSearch, + } + + return &searchDomain, nil +} + +type SearchDomainListItem struct { + Name string + Typename string `graphql:"__typename"` + AutomaticSearch bool +} + +func (s *SearchDomains) List() ([]SearchDomainListItem, error) { + var query struct { + SearchDomain []SearchDomainListItem `graphql:"searchDomains"` + } + + err := s.client.Query(&query, nil) + + sort.Slice(query.SearchDomain, func(i, j int) bool { + return strings.ToLower(query.SearchDomain[i].Name) < strings.ToLower(query.SearchDomain[j].Name) + }) + + return query.SearchDomain, err +} diff --git a/api/views.go b/api/views.go index 7f058b9..6a9c5ed 100644 --- a/api/views.go +++ b/api/views.go @@ -1,6 +1,7 @@ package api import ( + "github.com/humio/cli/api/internal/humiographql" "sort" "strings" @@ -26,6 +27,7 @@ type ViewQueryData struct { Filter string } } `graphql:"... on View"` + Typename graphql.String `graphql:"__typename"` } type View struct { @@ -48,7 +50,10 @@ func (c *Views) Get(name string) (*View, error) { err := c.client.Query(&query, variables) if err != nil { - return nil, err + return nil, ViewNotFound(name) + } + if query.Result.Typename != "View" { + return nil, ViewNotFound("name") } connections := make([]ViewConnection, len(query.Result.ViewInfo.Connections)) @@ -82,11 +87,18 @@ func (c *Views) List() ([]ViewListItem, error) { err := c.client.Query(&query, nil) - sort.Slice(query.View, func(i, j int) bool { - return strings.ToLower(query.View[i].Name) < strings.ToLower(query.View[j].Name) + viewsList := []ViewListItem{} + for k, v := range query.View { + if v.Typename == string(humiographql.SearchDomainTypeView) { + viewsList = append(viewsList, query.View[k]) + } + } + + sort.Slice(viewsList, func(i, j int) bool { + return strings.ToLower(viewsList[i].Name) < strings.ToLower(viewsList[j].Name) }) - return query.View, err + return viewsList, err } type ViewConnectionInput struct { @@ -112,6 +124,11 @@ func (c *Views) Create(name, description string, connections []ViewConnectionInp } func (c *Views) Delete(name, reason string) error { + _, err := c.Get(name) + if err != nil { + return err + } + var mutation struct { DeleteSearchDomain struct { // We have to make a selection, so just take __typename @@ -142,6 +159,11 @@ func (c *Views) UpdateConnections(name string, connections []ViewConnectionInput } func (c *Views) UpdateDescription(name string, description string) error { + _, err := c.Get(name) + if err != nil { + return err + } + var mutation struct { UpdateDescriptionMutation struct { // We have to make a selection, so just take __typename @@ -158,6 +180,11 @@ func (c *Views) UpdateDescription(name string, description string) error { } func (c *Views) UpdateAutomaticSearch(name string, automaticSearch bool) error { + _, err := c.Get(name) + if err != nil { + return err + } + var mutation struct { SetAutomaticSearching struct { // We have to make a selection, so just take __typename