github.com/fastly/cli@v1.7.2-0.20240304164155-9d0f1d77c3bf/pkg/commands/products/root.go (about)

     1  package products
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"io"
     7  
     8  	"github.com/fastly/go-fastly/v9/fastly"
     9  
    10  	"github.com/fastly/cli/pkg/argparser"
    11  	fsterr "github.com/fastly/cli/pkg/errors"
    12  	"github.com/fastly/cli/pkg/global"
    13  	"github.com/fastly/cli/pkg/text"
    14  )
    15  
    16  // RootCommand is the parent command for all subcommands in this package.
    17  // It should be installed under the primary root command.
    18  type RootCommand struct {
    19  	argparser.Base
    20  	argparser.JSONOutput
    21  
    22  	disableProduct string
    23  	enableProduct  string
    24  	serviceName    argparser.OptionalServiceNameID
    25  }
    26  
    27  // ProductEnablementOptions is a list of products that can be enabled/disabled.
    28  var ProductEnablementOptions = []string{
    29  	"brotli_compression",
    30  	"domain_inspector",
    31  	"fanout",
    32  	"image_optimizer",
    33  	"origin_inspector",
    34  	"websockets",
    35  }
    36  
    37  // NewRootCommand returns a new command registered in the parent.
    38  func NewRootCommand(parent argparser.Registerer, g *global.Data) *RootCommand {
    39  	var c RootCommand
    40  	c.Globals = g
    41  	c.CmdClause = parent.Command("products", "Enable, disable, and check the enablement status of products")
    42  
    43  	// Optional.
    44  	c.CmdClause.Flag("disable", "Disable product").HintOptions(ProductEnablementOptions...).EnumVar(&c.disableProduct, ProductEnablementOptions...)
    45  	c.CmdClause.Flag("enable", "Enable product").HintOptions(ProductEnablementOptions...).EnumVar(&c.enableProduct, ProductEnablementOptions...)
    46  	c.RegisterFlagBool(c.JSONFlag()) // --json
    47  	c.RegisterFlag(argparser.StringFlagOpts{
    48  		Name:        argparser.FlagServiceIDName,
    49  		Description: argparser.FlagServiceIDDesc,
    50  		Dst:         &g.Manifest.Flag.ServiceID,
    51  		Short:       's',
    52  	})
    53  	c.RegisterFlag(argparser.StringFlagOpts{
    54  		Action:      c.serviceName.Set,
    55  		Name:        argparser.FlagServiceName,
    56  		Description: argparser.FlagServiceDesc,
    57  		Dst:         &c.serviceName.Value,
    58  	})
    59  	return &c
    60  }
    61  
    62  // Exec implements the command interface.
    63  func (c *RootCommand) Exec(_ io.Reader, out io.Writer) error {
    64  	ac := c.Globals.APIClient
    65  
    66  	if c.enableProduct != "" && c.disableProduct != "" {
    67  		return fsterr.ErrInvalidEnableDisableFlagCombo
    68  	}
    69  
    70  	if c.Globals.Verbose() && c.JSONOutput.Enabled {
    71  		return fsterr.ErrInvalidVerboseJSONCombo
    72  	}
    73  
    74  	serviceID, _, _, err := argparser.ServiceID(c.serviceName, *c.Globals.Manifest, c.Globals.APIClient, c.Globals.ErrLog)
    75  	if err != nil {
    76  		return fmt.Errorf("failed to identify Service ID: %w", err)
    77  	}
    78  
    79  	if c.enableProduct != "" {
    80  		p := identifyProduct(c.enableProduct)
    81  		if p == fastly.ProductUndefined {
    82  			return errors.New("unrecognised product")
    83  		}
    84  		if _, err := ac.EnableProduct(&fastly.ProductEnablementInput{
    85  			ProductID: p,
    86  			ServiceID: serviceID,
    87  		}); err != nil {
    88  			return fmt.Errorf("failed to enable product '%s': %w", c.enableProduct, err)
    89  		}
    90  		text.Success(out, "Successfully enabled product '%s'", c.enableProduct)
    91  		return nil
    92  	}
    93  
    94  	if c.disableProduct != "" {
    95  		p := identifyProduct(c.disableProduct)
    96  		if p == fastly.ProductUndefined {
    97  			return errors.New("unrecognised product")
    98  		}
    99  		if err := ac.DisableProduct(&fastly.ProductEnablementInput{
   100  			ProductID: p,
   101  			ServiceID: serviceID,
   102  		}); err != nil {
   103  			return fmt.Errorf("failed to disable product '%s': %w", c.disableProduct, err)
   104  		}
   105  		text.Success(out, "Successfully disabled product '%s'", c.disableProduct)
   106  		return nil
   107  	}
   108  
   109  	ps := ProductStatus{}
   110  
   111  	if _, err = ac.GetProduct(&fastly.ProductEnablementInput{
   112  		ProductID: fastly.ProductBrotliCompression,
   113  		ServiceID: serviceID,
   114  	}); err == nil {
   115  		ps.BrotliCompression = true
   116  	}
   117  	if _, err = ac.GetProduct(&fastly.ProductEnablementInput{
   118  		ProductID: fastly.ProductDomainInspector,
   119  		ServiceID: serviceID,
   120  	}); err == nil {
   121  		ps.DomainInspector = true
   122  	}
   123  	if _, err = ac.GetProduct(&fastly.ProductEnablementInput{
   124  		ProductID: fastly.ProductFanout,
   125  		ServiceID: serviceID,
   126  	}); err == nil {
   127  		ps.Fanout = true
   128  	}
   129  	if _, err = ac.GetProduct(&fastly.ProductEnablementInput{
   130  		ProductID: fastly.ProductImageOptimizer,
   131  		ServiceID: serviceID,
   132  	}); err == nil {
   133  		ps.ImageOptimizer = true
   134  	}
   135  	if _, err = ac.GetProduct(&fastly.ProductEnablementInput{
   136  		ProductID: fastly.ProductOriginInspector,
   137  		ServiceID: serviceID,
   138  	}); err == nil {
   139  		ps.OriginInspector = true
   140  	}
   141  	if _, err = ac.GetProduct(&fastly.ProductEnablementInput{
   142  		ProductID: fastly.ProductWebSockets,
   143  		ServiceID: serviceID,
   144  	}); err == nil {
   145  		ps.WebSockets = true
   146  	}
   147  
   148  	if ok, err := c.WriteJSON(out, ps); ok {
   149  		return err
   150  	}
   151  
   152  	t := text.NewTable(out)
   153  	t.AddHeader("PRODUCT", "ENABLED")
   154  	t.AddLine("Brotli Compression", ps.BrotliCompression)
   155  	t.AddLine("Domain Inspector", ps.DomainInspector)
   156  	t.AddLine("Fanout", ps.Fanout)
   157  	t.AddLine("Image Optimizer", ps.ImageOptimizer)
   158  	t.AddLine("Origin Inspector", ps.OriginInspector)
   159  	t.AddLine("Web Sockets", ps.WebSockets)
   160  	t.Print()
   161  	return nil
   162  }
   163  
   164  func identifyProduct(product string) fastly.Product {
   165  	switch product {
   166  	case "brotli_compression":
   167  		return fastly.ProductBrotliCompression
   168  	case "domain_inspector":
   169  		return fastly.ProductDomainInspector
   170  	case "fanout":
   171  		return fastly.ProductFanout
   172  	case "image_optimizer":
   173  		return fastly.ProductImageOptimizer
   174  	case "origin_inspector":
   175  		return fastly.ProductOriginInspector
   176  	case "websockets":
   177  		return fastly.ProductWebSockets
   178  	default:
   179  		return fastly.ProductUndefined
   180  	}
   181  }
   182  
   183  // ProductStatus indicates the status for each product.
   184  type ProductStatus struct {
   185  	BrotliCompression bool `json:"brotli_compression"`
   186  	DomainInspector   bool `json:"domain_inspector"`
   187  	Fanout            bool `json:"fanout"`
   188  	ImageOptimizer    bool `json:"image_optimizer"`
   189  	OriginInspector   bool `json:"origin_inspector"`
   190  	WebSockets        bool `json:"websockets"`
   191  }