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 }