github.com/fastly/cli@v1.7.2-0.20240304164155-9d0f1d77c3bf/pkg/commands/vcl/snippet/update.go (about) 1 package snippet 2 3 import ( 4 "fmt" 5 "io" 6 7 "github.com/fastly/go-fastly/v9/fastly" 8 9 "github.com/fastly/cli/pkg/argparser" 10 fsterr "github.com/fastly/cli/pkg/errors" 11 "github.com/fastly/cli/pkg/global" 12 "github.com/fastly/cli/pkg/text" 13 ) 14 15 // NewUpdateCommand returns a usable command registered under the parent. 16 func NewUpdateCommand(parent argparser.Registerer, g *global.Data) *UpdateCommand { 17 c := UpdateCommand{ 18 Base: argparser.Base{ 19 Globals: g, 20 }, 21 } 22 c.CmdClause = parent.Command("update", "Update a VCL snippet for a particular service and version") 23 24 // Required. 25 c.RegisterFlag(argparser.StringFlagOpts{ 26 Name: argparser.FlagVersionName, 27 Description: argparser.FlagVersionDesc, 28 Dst: &c.serviceVersion.Value, 29 Required: true, 30 }) 31 32 // Optional. 33 c.RegisterAutoCloneFlag(argparser.AutoCloneFlagOpts{ 34 Action: c.autoClone.Set, 35 Dst: &c.autoClone.Value, 36 }) 37 c.CmdClause.Flag("content", "VCL snippet passed as file path or content, e.g. $(< snippet.vcl)").Action(c.content.Set).StringVar(&c.content.Value) 38 c.CmdClause.Flag("dynamic", "Whether the VCL snippet is dynamic or versioned").Action(c.dynamic.Set).BoolVar(&c.dynamic.Value) 39 c.CmdClause.Flag("name", "The name of the VCL snippet to update").StringVar(&c.name) 40 c.CmdClause.Flag("new-name", "New name for the VCL snippet").Action(c.newName.Set).StringVar(&c.newName.Value) 41 c.CmdClause.Flag("priority", "Priority determines execution order. Lower numbers execute first").Short('p').Action(c.priority.Set).IntVar(&c.priority.Value) 42 c.RegisterFlag(argparser.StringFlagOpts{ 43 Name: argparser.FlagServiceIDName, 44 Description: argparser.FlagServiceIDDesc, 45 Dst: &g.Manifest.Flag.ServiceID, 46 Short: 's', 47 }) 48 c.RegisterFlag(argparser.StringFlagOpts{ 49 Action: c.serviceName.Set, 50 Name: argparser.FlagServiceName, 51 Description: argparser.FlagServiceDesc, 52 Dst: &c.serviceName.Value, 53 }) 54 c.CmdClause.Flag("snippet-id", "Alphanumeric string identifying a VCL Snippet").StringVar(&c.snippetID) 55 56 // NOTE: Locations is defined in the same snippet package inside create.go 57 c.CmdClause.Flag("type", "The location in generated VCL where the snippet should be placed").HintOptions(Locations...).Action(c.location.Set).EnumVar(&c.location.Value, Locations...) 58 59 return &c 60 } 61 62 // UpdateCommand calls the Fastly API to update an appropriate resource. 63 type UpdateCommand struct { 64 argparser.Base 65 66 autoClone argparser.OptionalAutoClone 67 content argparser.OptionalString 68 dynamic argparser.OptionalBool 69 location argparser.OptionalString 70 name string 71 newName argparser.OptionalString 72 priority argparser.OptionalInt 73 serviceName argparser.OptionalServiceNameID 74 serviceVersion argparser.OptionalServiceVersion 75 snippetID string 76 } 77 78 // Exec invokes the application logic for the command. 79 func (c *UpdateCommand) Exec(_ io.Reader, out io.Writer) error { 80 serviceID, serviceVersion, err := argparser.ServiceDetails(argparser.ServiceDetailsOpts{ 81 AllowActiveLocked: c.dynamic.WasSet && c.dynamic.Value, 82 AutoCloneFlag: c.autoClone, 83 APIClient: c.Globals.APIClient, 84 Manifest: *c.Globals.Manifest, 85 Out: out, 86 ServiceNameFlag: c.serviceName, 87 ServiceVersionFlag: c.serviceVersion, 88 VerboseMode: c.Globals.Flags.Verbose, 89 }) 90 if err != nil { 91 c.Globals.ErrLog.AddWithContext(err, map[string]any{ 92 "Service ID": serviceID, 93 "Service Version": fsterr.ServiceVersion(serviceVersion), 94 }) 95 return err 96 } 97 98 serviceVersionNumber := fastly.ToValue(serviceVersion.Number) 99 100 if c.dynamic.WasSet { 101 input, err := c.constructDynamicInput(serviceID, serviceVersionNumber) 102 if err != nil { 103 c.Globals.ErrLog.AddWithContext(err, map[string]any{ 104 "Service ID": serviceID, 105 "Service Version": serviceVersionNumber, 106 }) 107 return err 108 } 109 v, err := c.Globals.APIClient.UpdateDynamicSnippet(input) 110 if err != nil { 111 c.Globals.ErrLog.AddWithContext(err, map[string]any{ 112 "Service ID": serviceID, 113 "Service Version": serviceVersionNumber, 114 }) 115 return err 116 } 117 text.Success(out, "Updated dynamic VCL snippet '%s' (service: %s)", fastly.ToValue(v.SnippetID), fastly.ToValue(v.ServiceID)) 118 return nil 119 } 120 121 input, err := c.constructInput(serviceID, serviceVersionNumber) 122 if err != nil { 123 c.Globals.ErrLog.AddWithContext(err, map[string]any{ 124 "Service ID": serviceID, 125 "Service Version": serviceVersionNumber, 126 }) 127 return err 128 } 129 v, err := c.Globals.APIClient.UpdateSnippet(input) 130 if err != nil { 131 c.Globals.ErrLog.AddWithContext(err, map[string]any{ 132 "Service ID": serviceID, 133 "Service Version": serviceVersionNumber, 134 }) 135 return err 136 } 137 text.Success(out, 138 "Updated VCL snippet '%s' (previously: '%s', service: %s, version: %d, type: %v, priority: %d)", 139 fastly.ToValue(v.Name), 140 input.Name, 141 fastly.ToValue(v.ServiceID), 142 fastly.ToValue(v.ServiceVersion), 143 fastly.ToValue(v.Type), 144 fastly.ToValue(v.Priority), 145 ) 146 return nil 147 } 148 149 // constructDynamicInput transforms values parsed from CLI flags into an object to be used by the API client library. 150 func (c *UpdateCommand) constructDynamicInput(serviceID string, _ int) (*fastly.UpdateDynamicSnippetInput, error) { 151 var input fastly.UpdateDynamicSnippetInput 152 153 input.SnippetID = c.snippetID 154 input.ServiceID = serviceID 155 156 if c.newName.WasSet { 157 return nil, fmt.Errorf("error parsing arguments: --new-name is not supported when updating a dynamic VCL snippet") 158 } 159 if c.snippetID == "" { 160 return nil, fmt.Errorf("error parsing arguments: must provide --snippet-id to update a dynamic VCL snippet") 161 } 162 if c.content.WasSet { 163 input.Content = fastly.ToPointer(argparser.Content(c.content.Value)) 164 } 165 166 return &input, nil 167 } 168 169 // constructInput transforms values parsed from CLI flags into an object to be used by the API client library. 170 func (c *UpdateCommand) constructInput(serviceID string, serviceVersion int) (*fastly.UpdateSnippetInput, error) { 171 var input fastly.UpdateSnippetInput 172 173 input.Name = c.name 174 input.ServiceID = serviceID 175 input.ServiceVersion = serviceVersion 176 177 if c.snippetID != "" { 178 return nil, fmt.Errorf("error parsing arguments: --snippet-id is not supported when updating a versioned VCL snippet") 179 } 180 if c.name == "" { 181 return nil, fmt.Errorf("error parsing arguments: must provide --name to update a versioned VCL snippet") 182 } 183 if c.newName.WasSet { 184 input.NewName = &c.newName.Value 185 } 186 if c.priority.WasSet { 187 input.Priority = &c.priority.Value 188 } 189 if c.content.WasSet { 190 input.Content = fastly.ToPointer(argparser.Content(c.content.Value)) 191 } 192 if c.location.WasSet { 193 location := fastly.SnippetType(c.location.Value) 194 input.Type = &location 195 } 196 197 return &input, nil 198 }