github.com/devcamcar/cli@v0.0.0-20181107134215-706a05759d18/objects/trigger/triggers.go (about) 1 package trigger 2 3 import ( 4 "context" 5 "encoding/json" 6 "errors" 7 "fmt" 8 "os" 9 "strings" 10 "text/tabwriter" 11 12 "github.com/fnproject/fn_go/clientv2/fns" 13 14 "github.com/jmoiron/jsonq" 15 16 "github.com/fnproject/cli/common" 17 "github.com/fnproject/cli/objects/app" 18 "github.com/fnproject/cli/objects/fn" 19 "github.com/fnproject/fn_go/clientv2" 20 apiTriggers "github.com/fnproject/fn_go/clientv2/triggers" 21 models "github.com/fnproject/fn_go/modelsv2" 22 "github.com/fnproject/fn_go/provider" 23 "github.com/urfave/cli" 24 ) 25 26 type triggersCmd struct { 27 provider provider.Provider 28 client *clientv2.Fn 29 } 30 31 // TriggerFlags used to create/update triggers 32 var TriggerFlags = []cli.Flag{ 33 cli.StringFlag{ 34 Name: "source,s", 35 Usage: "trigger source", 36 }, 37 cli.StringFlag{ 38 Name: "type, t", 39 Usage: "Todo", 40 }, 41 cli.StringSliceFlag{ 42 Name: "annotation", 43 Usage: "fn annotation (can be specified multiple times)", 44 }, 45 } 46 47 func (t *triggersCmd) create(c *cli.Context) error { 48 appName := c.Args().Get(0) 49 fnName := c.Args().Get(1) 50 triggerName := c.Args().Get(2) 51 52 app, err := app.GetAppByName(t.client, appName) 53 if err != nil { 54 return err 55 } 56 57 fn, err := fn.GetFnByName(t.client, app.ID, fnName) 58 if err != nil { 59 return err 60 } 61 62 trigger := &models.Trigger{ 63 AppID: app.ID, 64 FnID: fn.ID, 65 } 66 67 trigger.Name = triggerName 68 69 if triggerType := c.String("type"); triggerType != "" { 70 trigger.Type = triggerType 71 } 72 73 if triggerSource := c.String("source"); triggerSource != "" { 74 trigger.Source = validateTriggerSource(triggerSource) 75 } 76 77 WithFlags(c, trigger) 78 79 if trigger.Name == "" { 80 return errors.New("triggerName path is missing") 81 } 82 83 return CreateTrigger(t.client, trigger) 84 } 85 86 func validateTriggerSource(ts string) string { 87 if !strings.HasPrefix(ts, "/") { 88 ts = "/" + ts 89 } 90 return ts 91 } 92 93 // CreateTrigger request 94 func CreateTrigger(client *clientv2.Fn, trigger *models.Trigger) error { 95 resp, err := client.Triggers.CreateTrigger(&apiTriggers.CreateTriggerParams{ 96 Context: context.Background(), 97 Body: trigger, 98 }) 99 100 if err != nil { 101 switch e := err.(type) { 102 case *apiTriggers.CreateTriggerBadRequest: 103 fmt.Println(e) 104 return fmt.Errorf("%s", e.Payload.Message) 105 case *apiTriggers.CreateTriggerConflict: 106 return fmt.Errorf("%s", e.Payload.Message) 107 default: 108 return err 109 } 110 } 111 112 fmt.Println("Successfully created trigger:", resp.Payload.Name) 113 endpoint := resp.Payload.Annotations["fnproject.io/trigger/httpEndpoint"] 114 fmt.Println("Trigger Endpoint:", endpoint) 115 116 return nil 117 } 118 119 func (t *triggersCmd) list(c *cli.Context) error { 120 appName := c.Args().Get(0) 121 fnName := c.Args().Get(1) 122 var params *apiTriggers.ListTriggersParams 123 124 app, err := app.GetAppByName(t.client, appName) 125 if err != nil { 126 return err 127 } 128 129 if len(fnName) == 0 { 130 params = &apiTriggers.ListTriggersParams{ 131 Context: context.Background(), 132 AppID: &app.ID, 133 } 134 135 } else { 136 137 fn, err := fn.GetFnByName(t.client, app.ID, fnName) 138 if err != nil { 139 return err 140 } 141 params = &apiTriggers.ListTriggersParams{ 142 Context: context.Background(), 143 AppID: &app.ID, 144 FnID: &fn.ID, 145 } 146 } 147 148 var resTriggers []*models.Trigger 149 for { 150 151 resp, err := t.client.Triggers.ListTriggers(params) 152 if err != nil { 153 return err 154 } 155 n := c.Int64("n") 156 if n < 0 { 157 return errors.New("number of calls: negative value not allowed") 158 } 159 160 resTriggers = append(resTriggers, resp.Payload.Items...) 161 howManyMore := n - int64(len(resTriggers)+len(resp.Payload.Items)) 162 if howManyMore <= 0 || resp.Payload.NextCursor == "" { 163 break 164 } 165 166 params.Cursor = &resp.Payload.NextCursor 167 } 168 169 if len(resTriggers) == 0 { 170 if len(fnName) == 0 { 171 fmt.Fprintf(os.Stderr, "No triggers found for app: %s\n", appName) 172 } else { 173 fmt.Fprintf(os.Stderr, "No triggers found for function: %s\n", fnName) 174 } 175 return nil 176 } 177 178 w := tabwriter.NewWriter(os.Stdout, 0, 8, 1, '\t', 0) 179 if len(fnName) != 0 { 180 181 fmt.Fprint(w, "NAME", "\t", "ID", "\t", "TYPE", "\t", "SOURCE", "\t", "ENDPOINT", "\n") 182 for _, trigger := range resTriggers { 183 endpoint := trigger.Annotations["fnproject.io/trigger/httpEndpoint"] 184 fmt.Fprint(w, trigger.Name, "\t", trigger.ID, "\t", trigger.Type, "\t", trigger.Source, "\t", endpoint, "\n") 185 } 186 } else { 187 fmt.Fprint(w, "FUNCTION", "\t", "NAME", "\t", "ID", "\t", "TYPE", "\t", "SOURCE", "\t", "ENDPOINT", "\n") 188 for _, trigger := range resTriggers { 189 endpoint := trigger.Annotations["fnproject.io/trigger/httpEndpoint"] 190 191 resp, err := t.client.Fns.GetFn(&fns.GetFnParams{ 192 FnID: trigger.FnID, 193 Context: context.Background(), 194 }) 195 if err != nil { 196 return err 197 } 198 fnName = resp.Payload.Name 199 fmt.Fprint(w, fnName, "\t", trigger.Name, "\t", trigger.ID, "\t", trigger.Type, "\t", trigger.Source, "\t", endpoint, "\n") 200 } 201 } 202 w.Flush() 203 return nil 204 } 205 206 func (t *triggersCmd) update(c *cli.Context) error { 207 appName := c.Args().Get(0) 208 fnName := c.Args().Get(1) 209 triggerName := c.Args().Get(2) 210 211 trigger, err := GetTrigger(t.client, appName, fnName, triggerName) 212 if err != nil { 213 return err 214 } 215 216 WithFlags(c, trigger) 217 218 err = PutTrigger(t.client, trigger) 219 if err != nil { 220 return err 221 } 222 223 fmt.Println(appName, fnName, triggerName, "updated") 224 return nil 225 } 226 227 // PutTrigger updates the provided trigger with new values 228 func PutTrigger(t *clientv2.Fn, trigger *models.Trigger) error { 229 _, err := t.Triggers.UpdateTrigger(&apiTriggers.UpdateTriggerParams{ 230 Context: context.Background(), 231 TriggerID: trigger.ID, 232 Body: trigger, 233 }) 234 235 if err != nil { 236 switch e := err.(type) { 237 case *apiTriggers.UpdateTriggerBadRequest: 238 return fmt.Errorf("%s", e.Payload.Message) 239 default: 240 return err 241 } 242 } 243 244 return nil 245 } 246 247 func (t *triggersCmd) inspect(c *cli.Context) error { 248 appName := c.Args().Get(0) 249 fnName := c.Args().Get(1) 250 triggerName := c.Args().Get(2) 251 prop := c.Args().Get(3) 252 253 trigger, err := GetTrigger(t.client, appName, fnName, triggerName) 254 if err != nil { 255 return err 256 } 257 258 if c.Bool("endpoint") { 259 endpoint, ok := trigger.Annotations["fnproject.io/trigger/httpEndpoint"].(string) 260 if !ok { 261 return errors.New("missing or invalid http endpoint on trigger") 262 } 263 fmt.Println(endpoint) 264 return nil 265 } 266 267 enc := json.NewEncoder(os.Stdout) 268 enc.SetIndent("", "\t") 269 270 if prop == "" { 271 enc.Encode(trigger) 272 return nil 273 } 274 275 data, err := json.Marshal(trigger) 276 if err != nil { 277 return fmt.Errorf("failed to inspect %s: %s", triggerName, err) 278 } 279 280 var inspect map[string]interface{} 281 err = json.Unmarshal(data, &inspect) 282 if err != nil { 283 return fmt.Errorf("failed to inspect %s: %s", triggerName, err) 284 } 285 286 jq := jsonq.NewQuery(inspect) 287 field, err := jq.Interface(strings.Split(prop, ".")...) 288 if err != nil { 289 return errors.New("failed to inspect %s field names") 290 } 291 enc.Encode(field) 292 293 return nil 294 } 295 296 func (t *triggersCmd) delete(c *cli.Context) error { 297 appName := c.Args().Get(0) 298 fnName := c.Args().Get(1) 299 triggerName := c.Args().Get(2) 300 301 trigger, err := GetTrigger(t.client, appName, fnName, triggerName) 302 if err != nil { 303 return err 304 } 305 306 params := apiTriggers.NewDeleteTriggerParams() 307 params.TriggerID = trigger.ID 308 309 _, err = t.client.Triggers.DeleteTrigger(params) 310 if err != nil { 311 return err 312 } 313 314 fmt.Println(appName, fnName, triggerName, "deleted") 315 return nil 316 } 317 318 // GetTrigger looks up a trigger using the provided client by app, function and trigger name 319 func GetTrigger(client *clientv2.Fn, appName, fnName, triggerName string) (*models.Trigger, error) { 320 app, err := app.GetAppByName(client, appName) 321 if err != nil { 322 return nil, err 323 } 324 325 fn, err := fn.GetFnByName(client, app.ID, fnName) 326 if err != nil { 327 return nil, err 328 } 329 330 trigger, err := GetTriggerByName(client, app.ID, fn.ID, triggerName) 331 if err != nil { 332 return nil, err 333 } 334 335 return trigger, nil 336 } 337 338 // GetTriggerByName looks up a trigger using the provided client by app and function ID and trigger name 339 func GetTriggerByName(client *clientv2.Fn, appID string, fnID string, triggerName string) (*models.Trigger, error) { 340 triggerList, err := client.Triggers.ListTriggers(&apiTriggers.ListTriggersParams{ 341 Context: context.Background(), 342 AppID: &appID, 343 FnID: &fnID, 344 Name: &triggerName, 345 }) 346 347 if err != nil { 348 return nil, err 349 } 350 if len(triggerList.Payload.Items) == 0 { 351 return nil, fmt.Errorf("Trigger %s not found", triggerName) 352 } 353 354 return triggerList.Payload.Items[0], nil 355 } 356 357 // WithFlags returns a trigger with the specified flags 358 func WithFlags(c *cli.Context, t *models.Trigger) { 359 if len(c.StringSlice("annotation")) > 0 { 360 t.Annotations = common.ExtractAnnotations(c) 361 } 362 }