github.com/fastly/cli@v1.7.2-0.20240304164155-9d0f1d77c3bf/pkg/commands/logging/kinesis/create.go (about) 1 package kinesis 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 "github.com/fastly/cli/pkg/commands/logging/common" 11 "github.com/fastly/cli/pkg/errors" 12 "github.com/fastly/cli/pkg/global" 13 "github.com/fastly/cli/pkg/manifest" 14 "github.com/fastly/cli/pkg/text" 15 ) 16 17 // CreateCommand calls the Fastly API to create an Amazon Kinesis logging endpoint. 18 type CreateCommand struct { 19 argparser.Base 20 Manifest manifest.Data 21 22 // Required. 23 ServiceName argparser.OptionalServiceNameID 24 ServiceVersion argparser.OptionalServiceVersion 25 26 // mutual exclusions 27 // AccessKey + SecretKey or IAMRole must be provided 28 AccessKey argparser.OptionalString 29 SecretKey argparser.OptionalString 30 IAMRole argparser.OptionalString 31 32 // Optional. 33 AutoClone argparser.OptionalAutoClone 34 EndpointName argparser.OptionalString // Can't shadow argparser.Base method Name(). 35 Format argparser.OptionalString 36 FormatVersion argparser.OptionalInt 37 Placement argparser.OptionalString 38 Region argparser.OptionalString 39 ResponseCondition argparser.OptionalString 40 StreamName argparser.OptionalString 41 } 42 43 // NewCreateCommand returns a usable command registered under the parent. 44 func NewCreateCommand(parent argparser.Registerer, g *global.Data) *CreateCommand { 45 c := CreateCommand{ 46 Base: argparser.Base{ 47 Globals: g, 48 }, 49 } 50 c.CmdClause = parent.Command("create", "Create an Amazon Kinesis logging endpoint on a Fastly service version").Alias("add") 51 52 // Required. 53 c.CmdClause.Flag("name", "The name of the Kinesis logging object. Used as a primary key for API access").Short('n').Action(c.EndpointName.Set).StringVar(&c.EndpointName.Value) 54 c.RegisterFlag(argparser.StringFlagOpts{ 55 Name: argparser.FlagVersionName, 56 Description: argparser.FlagVersionDesc, 57 Dst: &c.ServiceVersion.Value, 58 Required: true, 59 }) 60 61 // required, but mutually exclusive 62 c.CmdClause.Flag("access-key", "The access key associated with the target Amazon Kinesis stream").Action(c.AccessKey.Set).StringVar(&c.AccessKey.Value) 63 c.CmdClause.Flag("secret-key", "The secret key associated with the target Amazon Kinesis stream").Action(c.SecretKey.Set).StringVar(&c.SecretKey.Value) 64 c.CmdClause.Flag("iam-role", "The IAM role ARN for logging").Action(c.IAMRole.Set).StringVar(&c.IAMRole.Value) 65 66 // Optional. 67 c.RegisterAutoCloneFlag(argparser.AutoCloneFlagOpts{ 68 Action: c.AutoClone.Set, 69 Dst: &c.AutoClone.Value, 70 }) 71 common.Format(c.CmdClause, &c.Format) 72 common.FormatVersion(c.CmdClause, &c.FormatVersion) 73 c.CmdClause.Flag("region", "The AWS region where the Kinesis stream exists").Action(c.Region.Set).StringVar(&c.Region.Value) 74 common.ResponseCondition(c.CmdClause, &c.ResponseCondition) 75 common.Placement(c.CmdClause, &c.Placement) 76 c.CmdClause.Flag("stream-name", "The Amazon Kinesis stream to send logs to").Action(c.StreamName.Set).StringVar(&c.StreamName.Value) 77 c.RegisterFlag(argparser.StringFlagOpts{ 78 Name: argparser.FlagServiceIDName, 79 Description: argparser.FlagServiceIDDesc, 80 Dst: &g.Manifest.Flag.ServiceID, 81 Short: 's', 82 }) 83 c.RegisterFlag(argparser.StringFlagOpts{ 84 Action: c.ServiceName.Set, 85 Name: argparser.FlagServiceName, 86 Description: argparser.FlagServiceDesc, 87 Dst: &c.ServiceName.Value, 88 }) 89 90 return &c 91 } 92 93 // ConstructInput transforms values parsed from CLI flags into an object to be used by the API client library. 94 func (c *CreateCommand) ConstructInput(serviceID string, serviceVersion int) (*fastly.CreateKinesisInput, error) { 95 var input fastly.CreateKinesisInput 96 97 input.ServiceID = serviceID 98 if c.EndpointName.WasSet { 99 input.Name = &c.EndpointName.Value 100 } 101 if c.StreamName.WasSet { 102 input.StreamName = &c.StreamName.Value 103 } 104 if c.Region.WasSet { 105 input.Region = &c.Region.Value 106 } 107 input.ServiceVersion = serviceVersion 108 109 // The following block checks for invalid permutations of the ways in 110 // which the AccessKey + SecretKey and IAMRole flags can be 111 // provided. This is necessary because either the AccessKey and 112 // SecretKey or the IAMRole is required, but they are mutually 113 // exclusive. The kingpin library lacks a way to express this constraint 114 // via the flag specification API so we enforce it manually here. 115 switch { 116 case !c.AccessKey.WasSet && !c.SecretKey.WasSet && !c.IAMRole.WasSet: 117 return nil, fmt.Errorf("error parsing arguments: the --access-key and --secret-key flags or the --iam-role flag must be provided") 118 case (c.AccessKey.WasSet || c.SecretKey.WasSet) && c.IAMRole.WasSet: 119 // Enforce mutual exclusion 120 return nil, fmt.Errorf("error parsing arguments: the --access-key and --secret-key flags are mutually exclusive with the --iam-role flag") 121 case c.AccessKey.WasSet && !c.SecretKey.WasSet: 122 return nil, fmt.Errorf("error parsing arguments: required flag --secret-key not provided") 123 case !c.AccessKey.WasSet && c.SecretKey.WasSet: 124 return nil, fmt.Errorf("error parsing arguments: required flag --access-key not provided") 125 } 126 127 if c.AccessKey.WasSet { 128 input.AccessKey = &c.AccessKey.Value 129 } 130 131 if c.SecretKey.WasSet { 132 input.SecretKey = &c.SecretKey.Value 133 } 134 135 if c.IAMRole.WasSet { 136 input.IAMRole = &c.IAMRole.Value 137 } 138 139 if c.Format.WasSet { 140 input.Format = &c.Format.Value 141 } 142 143 if c.FormatVersion.WasSet { 144 input.FormatVersion = &c.FormatVersion.Value 145 } 146 147 if c.ResponseCondition.WasSet { 148 input.ResponseCondition = &c.ResponseCondition.Value 149 } 150 151 if c.Placement.WasSet { 152 input.Placement = &c.Placement.Value 153 } 154 155 return &input, nil 156 } 157 158 // Exec invokes the application logic for the command. 159 func (c *CreateCommand) Exec(_ io.Reader, out io.Writer) error { 160 serviceID, serviceVersion, err := argparser.ServiceDetails(argparser.ServiceDetailsOpts{ 161 AutoCloneFlag: c.AutoClone, 162 APIClient: c.Globals.APIClient, 163 Manifest: *c.Globals.Manifest, 164 Out: out, 165 ServiceNameFlag: c.ServiceName, 166 ServiceVersionFlag: c.ServiceVersion, 167 VerboseMode: c.Globals.Flags.Verbose, 168 }) 169 if err != nil { 170 c.Globals.ErrLog.AddWithContext(err, map[string]any{ 171 "Service ID": serviceID, 172 "Service Version": errors.ServiceVersion(serviceVersion), 173 }) 174 return err 175 } 176 177 input, err := c.ConstructInput(serviceID, fastly.ToValue(serviceVersion.Number)) 178 if err != nil { 179 c.Globals.ErrLog.Add(err) 180 return err 181 } 182 183 d, err := c.Globals.APIClient.CreateKinesis(input) 184 if err != nil { 185 c.Globals.ErrLog.Add(err) 186 return err 187 } 188 189 text.Success(out, 190 "Created Kinesis logging endpoint %s (service %s version %d)", 191 fastly.ToValue(d.Name), 192 fastly.ToValue(d.ServiceID), 193 fastly.ToValue(d.ServiceVersion), 194 ) 195 return nil 196 }