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
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
### Breaking:

### Bug Fixes:
- fix(stats): `stats historical` now returns write errors instead of silently swallowing them. [#1678](https://github.com/fastly/cli/pull/1678)
- fix(stats): `stats historical` now returns write errors instead of silently swallowing them [#1678](https://github.com/fastly/cli/pull/1678)

### Enhancements:
- feat(stats): add `--field` flag to `stats historical` to filter to a single stats field. [#1678](https://github.com/fastly/cli/pull/1678)
Expand All @@ -15,6 +15,7 @@
- feat(stats): add `stats origin-inspector` subcommand for origin-level metrics. [#1678](https://github.com/fastly/cli/pull/1678)
- feat(apisecurity/discoveredoperations): add support for 'list' and 'update' support for 'API discovery'. [#1689](https://github.com/fastly/cli/pull/1689)
- feat(apisecurity/operations): add CRUD support for 'API Inventory' operations. [#1689](https://github.com/fastly/cli/pull/1689)
- feat(apisecurity/tags): add API Security Operations tag support ([#1688](https://github.com/fastly/cli/pull/1688))

### Dependencies:
- build(deps): `golang.org/x/net` from 0.50.0 to 0.51.0 ([#1674](https://github.com/fastly/cli/pull/1674))
Expand Down
105 changes: 105 additions & 0 deletions pkg/commands/apisecurity/tags/create.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package tags

import (
"context"
"errors"
"io"

"github.com/fastly/go-fastly/v13/fastly"
"github.com/fastly/go-fastly/v13/fastly/apisecurity/operations"

"github.com/fastly/cli/pkg/argparser"
fsterr "github.com/fastly/cli/pkg/errors"
"github.com/fastly/cli/pkg/global"
"github.com/fastly/cli/pkg/text"
)

// CreateCommand calls the Fastly API to create an operation tag.
type CreateCommand struct {
argparser.Base
argparser.JSONOutput

// Required.
name string
serviceName argparser.OptionalServiceNameID

// Optional.
description argparser.OptionalString
}

// NewCreateCommand returns a usable command registered under the parent.
func NewCreateCommand(parent argparser.Registerer, g *global.Data) *CreateCommand {
c := CreateCommand{
Base: argparser.Base{
Globals: g,
},
}

c.CmdClause = parent.Command("create", "Create an operation tag")

// Required.
c.CmdClause.Flag("name", "Name of the operation tag").Required().StringVar(&c.name)

// Optional.
c.RegisterFlag(argparser.StringFlagOpts{
Name: argparser.FlagServiceIDName,
Description: argparser.FlagServiceIDDesc,
Dst: &g.Manifest.Flag.ServiceID,
})
c.RegisterFlag(argparser.StringFlagOpts{
Action: c.serviceName.Set,
Name: argparser.FlagServiceName,
Description: argparser.FlagServiceNameDesc,
Dst: &c.serviceName.Value,
})
c.CmdClause.Flag("description", "Description of the operation tag").Action(c.description.Set).StringVar(&c.description.Value)
c.RegisterFlagBool(c.JSONFlag())

return &c
}

// Exec invokes the application logic for the command.
func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error {
if c.Globals.Verbose() && c.JSONOutput.Enabled {
return fsterr.ErrInvalidVerboseJSONCombo
}

serviceID, source, flag, err := argparser.ServiceID(c.serviceName, *c.Globals.Manifest, c.Globals.APIClient, c.Globals.ErrLog)
if err != nil {
return err
}
if c.Globals.Verbose() {
argparser.DisplayServiceID(serviceID, flag, source, out)
}

if serviceID == "" {
return errors.New("service-id is required")
}

fc, ok := c.Globals.APIClient.(*fastly.Client)
if !ok {
return errors.New("failed to convert interface to a fastly client")
}

input := &operations.CreateTagInput{
ServiceID: &serviceID,
Name: &c.name,
}

if c.description.WasSet {
input.Description = &c.description.Value
}

tag, err := operations.CreateTag(context.TODO(), fc, input)
if err != nil {
c.Globals.ErrLog.Add(err)
return err
}

if ok, err := c.WriteJSON(out, tag); ok {
return err
}

text.Success(out, "Created operation tag '%s' (id: %s)", tag.Name, tag.ID)
return nil
}
105 changes: 105 additions & 0 deletions pkg/commands/apisecurity/tags/delete.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package tags

import (
"context"
"errors"
"io"

"github.com/fastly/go-fastly/v13/fastly"
"github.com/fastly/go-fastly/v13/fastly/apisecurity/operations"

"github.com/fastly/cli/pkg/argparser"
fsterr "github.com/fastly/cli/pkg/errors"
"github.com/fastly/cli/pkg/global"
"github.com/fastly/cli/pkg/text"
)

// DeleteCommand calls the Fastly API to delete an operation tag.
type DeleteCommand struct {
argparser.Base
argparser.JSONOutput

// Required.
tagID string
serviceName argparser.OptionalServiceNameID
}

// NewDeleteCommand returns a usable command registered under the parent.
func NewDeleteCommand(parent argparser.Registerer, g *global.Data) *DeleteCommand {
c := DeleteCommand{
Base: argparser.Base{
Globals: g,
},
}

c.CmdClause = parent.Command("delete", "Delete an operation tag")

// Required.
c.CmdClause.Flag("tag-id", "Tag ID").Required().StringVar(&c.tagID)

// Optional.
c.RegisterFlag(argparser.StringFlagOpts{
Name: argparser.FlagServiceIDName,
Description: argparser.FlagServiceIDDesc,
Dst: &g.Manifest.Flag.ServiceID,
})
c.RegisterFlag(argparser.StringFlagOpts{
Action: c.serviceName.Set,
Name: argparser.FlagServiceName,
Description: argparser.FlagServiceNameDesc,
Dst: &c.serviceName.Value,
})
c.RegisterFlagBool(c.JSONFlag())

return &c
}

// Exec invokes the application logic for the command.
func (c *DeleteCommand) Exec(_ io.Reader, out io.Writer) error {
if c.Globals.Verbose() && c.JSONOutput.Enabled {
return fsterr.ErrInvalidVerboseJSONCombo
}

serviceID, source, flag, err := argparser.ServiceID(c.serviceName, *c.Globals.Manifest, c.Globals.APIClient, c.Globals.ErrLog)
if err != nil {
return err
}
if c.Globals.Verbose() {
argparser.DisplayServiceID(serviceID, flag, source, out)
}

if serviceID == "" {
return errors.New("service-id is required")
}

fc, ok := c.Globals.APIClient.(*fastly.Client)
if !ok {
return errors.New("failed to convert interface to a fastly client")
}

err = operations.DeleteTag(context.TODO(), fc, &operations.DeleteTagInput{
ServiceID: &serviceID,
TagID: &c.tagID,
})
if err != nil {
c.Globals.ErrLog.Add(err)
return err
}

if c.JSONOutput.Enabled {
o := struct {
ServiceID string `json:"service_id"`
TagID string `json:"tag_id"`
Deleted bool `json:"deleted"`
}{
serviceID,
c.tagID,
true,
}
_, err := c.WriteJSON(out, o)
return err
}

text.Success(out, "Deleted operation tag (id: %s)", c.tagID)
return nil
}
2 changes: 2 additions & 0 deletions pkg/commands/apisecurity/tags/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Package tags contains commands to manipulate Fastly API Security operation tags.
package tags
95 changes: 95 additions & 0 deletions pkg/commands/apisecurity/tags/get.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package tags

import (
"context"
"errors"
"io"

"github.com/fastly/go-fastly/v13/fastly"
"github.com/fastly/go-fastly/v13/fastly/apisecurity/operations"

"github.com/fastly/cli/pkg/argparser"
fsterr "github.com/fastly/cli/pkg/errors"
"github.com/fastly/cli/pkg/global"
"github.com/fastly/cli/pkg/text"
)

// GetCommand calls the Fastly API to get an operation tag.
type GetCommand struct {
argparser.Base
argparser.JSONOutput

// Required.
tagID string
serviceName argparser.OptionalServiceNameID
}

// NewGetCommand returns a usable command registered under the parent.
func NewGetCommand(parent argparser.Registerer, g *global.Data) *GetCommand {
c := GetCommand{
Base: argparser.Base{
Globals: g,
},
}

c.CmdClause = parent.Command("get", "Get an operation tag")

// Required.
c.CmdClause.Flag("tag-id", "Tag ID").Required().StringVar(&c.tagID)

// Optional.
c.RegisterFlag(argparser.StringFlagOpts{
Name: argparser.FlagServiceIDName,
Description: argparser.FlagServiceIDDesc,
Dst: &g.Manifest.Flag.ServiceID,
})
c.RegisterFlag(argparser.StringFlagOpts{
Action: c.serviceName.Set,
Name: argparser.FlagServiceName,
Description: argparser.FlagServiceNameDesc,
Dst: &c.serviceName.Value,
})
c.RegisterFlagBool(c.JSONFlag())

return &c
}

// Exec invokes the application logic for the command.
func (c *GetCommand) Exec(_ io.Reader, out io.Writer) error {
if c.Globals.Verbose() && c.JSONOutput.Enabled {
return fsterr.ErrInvalidVerboseJSONCombo
}

serviceID, source, flag, err := argparser.ServiceID(c.serviceName, *c.Globals.Manifest, c.Globals.APIClient, c.Globals.ErrLog)
if err != nil {
return err
}
if c.Globals.Verbose() {
argparser.DisplayServiceID(serviceID, flag, source, out)
}

if serviceID == "" {
return errors.New("service-id is required")
}

fc, ok := c.Globals.APIClient.(*fastly.Client)
if !ok {
return errors.New("failed to convert interface to a fastly client")
}

tag, err := operations.DescribeTag(context.TODO(), fc, &operations.DescribeTagInput{
ServiceID: &serviceID,
TagID: &c.tagID,
})
if err != nil {
c.Globals.ErrLog.Add(err)
return err
}

if ok, err := c.WriteJSON(out, tag); ok {
return err
}

text.PrintOperationTag(out, tag)
return nil
}
Loading
Loading