github.com/iron-io/functions@v0.0.0-20180820112432-d59d7d1c40b2/fn/commands/apps.go (about) 1 package commands 2 3 import ( 4 "context" 5 "encoding/json" 6 "errors" 7 "fmt" 8 "os" 9 "strings" 10 11 "github.com/iron-io/functions/fn/common" 12 "github.com/iron-io/functions_go" 13 fnclient "github.com/iron-io/functions_go/client" 14 apiapps "github.com/iron-io/functions_go/client/apps" 15 "github.com/iron-io/functions_go/models" 16 "github.com/jmoiron/jsonq" 17 "github.com/urfave/cli" 18 ) 19 20 type appsCmd struct { 21 client *fnclient.Functions 22 } 23 24 func Apps() cli.Command { 25 a := appsCmd{client: common.ApiClient()} 26 27 return cli.Command{ 28 Name: "apps", 29 Usage: "manage applications", 30 Subcommands: []cli.Command{ 31 { 32 Name: "create", 33 Aliases: []string{"c"}, 34 Usage: "create a new app", 35 ArgsUsage: "<app>", 36 Action: a.create, 37 Flags: []cli.Flag{ 38 cli.StringSliceFlag{ 39 Name: "config", 40 Usage: "application configuration", 41 }, 42 }, 43 }, 44 { 45 Name: "inspect", 46 Aliases: []string{"i"}, 47 Usage: "retrieve one or all apps properties", 48 ArgsUsage: "<app> [property.[key]]", 49 Action: a.inspect, 50 }, 51 { 52 Name: "update", 53 Aliases: []string{"u"}, 54 Usage: "update an `app`", 55 ArgsUsage: "<app>", 56 Action: a.update, 57 Flags: []cli.Flag{ 58 cli.StringSliceFlag{ 59 Name: "config,c", 60 Usage: "route configuration", 61 }, 62 }, 63 }, 64 { 65 Name: "config", 66 Usage: "manage your apps's function configs", 67 Subcommands: []cli.Command{ 68 { 69 Name: "set", 70 Aliases: []string{"s"}, 71 Usage: "store a configuration key for this application", 72 ArgsUsage: "<app> <key> <value>", 73 Action: a.configSet, 74 }, 75 { 76 Name: "unset", 77 Aliases: []string{"u"}, 78 Usage: "remove a configuration key for this application", 79 ArgsUsage: "<app> <key>", 80 Action: a.configUnset, 81 }, 82 }, 83 }, 84 { 85 Name: "list", 86 Aliases: []string{"l"}, 87 Usage: "list all apps", 88 Action: a.list, 89 }, 90 { 91 Name: "delete", 92 Usage: "delete an app", 93 Action: a.delete, 94 }, 95 }, 96 } 97 } 98 99 func (a *appsCmd) list(c *cli.Context) error { 100 resp, err := a.client.Apps.GetApps(&apiapps.GetAppsParams{ 101 Context: context.Background(), 102 }) 103 104 if err != nil { 105 switch err.(type) { 106 case *apiapps.GetAppsAppNotFound: 107 return fmt.Errorf("error: %v", err.(*apiapps.GetAppsAppNotFound).Payload.Error.Message) 108 case *apiapps.GetAppsAppDefault: 109 return fmt.Errorf("unexpected error: %v", err.(*apiapps.GetAppsAppDefault).Payload.Error.Message) 110 } 111 return fmt.Errorf("unexpected error: %v", err) 112 } 113 114 if len(resp.Payload.Apps) == 0 { 115 fmt.Println("no apps found") 116 return nil 117 } 118 119 for _, app := range resp.Payload.Apps { 120 fmt.Println(app.Name) 121 } 122 123 return nil 124 } 125 126 func (a *appsCmd) create(c *cli.Context) error { 127 body := &models.AppWrapper{App: &models.App{ 128 Name: c.Args().Get(0), 129 Config: common.ExtractEnvConfig(c.StringSlice("config")), 130 }} 131 132 resp, err := a.client.Apps.PostApps(&apiapps.PostAppsParams{ 133 Context: context.Background(), 134 Body: body, 135 }) 136 137 if err != nil { 138 switch err.(type) { 139 case *apiapps.PostAppsBadRequest: 140 return fmt.Errorf("error: %v", err.(*apiapps.PostAppsBadRequest).Payload.Error.Message) 141 case *apiapps.PostAppsConflict: 142 return fmt.Errorf("error: %v", err.(*apiapps.PostAppsConflict).Payload.Error.Message) 143 case *apiapps.PostAppsDefault: 144 return fmt.Errorf("unexpected error: %v", err.(*apiapps.PostAppsDefault).Payload.Error.Message) 145 } 146 return fmt.Errorf("unexpected error: %v", err) 147 } 148 149 fmt.Println(resp.Payload.App.Name, "created") 150 return nil 151 } 152 153 func (a *appsCmd) update(c *cli.Context) error { 154 appName := c.Args().First() 155 156 patchedApp := &functions.App{ 157 Config: common.ExtractEnvConfig(c.StringSlice("config")), 158 } 159 160 err := a.patchApp(appName, patchedApp) 161 if err != nil { 162 return err 163 } 164 165 fmt.Println("app", appName, "updated") 166 return nil 167 } 168 169 func (a *appsCmd) configSet(c *cli.Context) error { 170 appName := c.Args().Get(0) 171 key := c.Args().Get(1) 172 value := c.Args().Get(2) 173 174 app := &functions.App{ 175 Config: make(map[string]string), 176 } 177 178 app.Config[key] = value 179 180 if err := a.patchApp(appName, app); err != nil { 181 return fmt.Errorf("error updating app configuration: %v", err) 182 } 183 184 fmt.Println(appName, "updated", key, "with", value) 185 return nil 186 } 187 188 func (a *appsCmd) configUnset(c *cli.Context) error { 189 appName := c.Args().Get(0) 190 key := c.Args().Get(1) 191 192 app := &functions.App{ 193 Config: make(map[string]string), 194 } 195 196 app.Config["-"+key] = "" 197 198 if err := a.patchApp(appName, app); err != nil { 199 return fmt.Errorf("error updating app configuration: %v", err) 200 } 201 202 fmt.Printf("removed key '%s' from app '%s' \n", key, appName) 203 return nil 204 } 205 206 func (a *appsCmd) patchApp(appName string, app *functions.App) error { 207 resp, err := a.client.Apps.GetAppsApp(&apiapps.GetAppsAppParams{ 208 Context: context.Background(), 209 App: appName, 210 }) 211 212 if err != nil { 213 switch err.(type) { 214 case *apiapps.GetAppsAppNotFound: 215 return fmt.Errorf("error: %v", err.(*apiapps.GetAppsAppNotFound).Payload.Error.Message) 216 case *apiapps.GetAppsAppDefault: 217 return fmt.Errorf("unexpected error: %v", err.(*apiapps.GetAppsAppDefault).Payload.Error.Message) 218 } 219 return fmt.Errorf("unexpected error: %v", err) 220 } 221 222 if resp.Payload.App.Config == nil { 223 resp.Payload.App.Config = map[string]string{} 224 } 225 226 resp.Payload.App.Name = "" 227 if app != nil { 228 if app.Config != nil { 229 for k, v := range app.Config { 230 if string(k[0]) == "-" { 231 delete(resp.Payload.App.Config, string(k[1:])) 232 continue 233 } 234 resp.Payload.App.Config[k] = v 235 } 236 } 237 } 238 239 body := &models.AppWrapper{App: resp.Payload.App} 240 241 _, err = a.client.Apps.PatchAppsApp(&apiapps.PatchAppsAppParams{ 242 Context: context.Background(), 243 App: appName, 244 Body: body, 245 }) 246 247 if err != nil { 248 switch err.(type) { 249 case *apiapps.PatchAppsAppBadRequest: 250 return errors.New(err.(*apiapps.PatchAppsAppBadRequest).Payload.Error.Message) 251 case *apiapps.PatchAppsAppNotFound: 252 return errors.New(err.(*apiapps.PatchAppsAppNotFound).Payload.Error.Message) 253 case *apiapps.PatchAppsAppDefault: 254 return errors.New(err.(*apiapps.PatchAppsAppDefault).Payload.Error.Message) 255 } 256 return fmt.Errorf("unexpected error: %v", err) 257 } 258 259 return nil 260 } 261 262 func (a *appsCmd) inspect(c *cli.Context) error { 263 if c.Args().Get(0) == "" { 264 return errors.New("error: missing app name after the inspect command") 265 } 266 267 appName := c.Args().First() 268 prop := c.Args().Get(1) 269 270 resp, err := a.client.Apps.GetAppsApp(&apiapps.GetAppsAppParams{ 271 Context: context.Background(), 272 App: appName, 273 }) 274 275 if err != nil { 276 switch err.(type) { 277 case *apiapps.GetAppsAppNotFound: 278 return fmt.Errorf("error: %v", err.(*apiapps.GetAppsAppNotFound).Payload.Error.Message) 279 case *apiapps.GetAppsAppDefault: 280 return fmt.Errorf("unexpected error: %v", err.(*apiapps.GetAppsAppDefault).Payload.Error.Message) 281 } 282 return fmt.Errorf("unexpected error: %v", err) 283 } 284 285 enc := json.NewEncoder(os.Stdout) 286 enc.SetIndent("", "\t") 287 288 if prop == "" { 289 enc.Encode(resp.Payload.App) 290 return nil 291 } 292 293 // TODO: we really need to marshal it here just to 294 // unmarshal as map[string]interface{}? 295 data, err := json.Marshal(resp.Payload.App) 296 if err != nil { 297 return fmt.Errorf("error inspect app: %v", err) 298 } 299 var inspect map[string]interface{} 300 err = json.Unmarshal(data, &inspect) 301 if err != nil { 302 return fmt.Errorf("error inspect app: %v", err) 303 } 304 305 jq := jsonq.NewQuery(inspect) 306 field, err := jq.Interface(strings.Split(prop, ".")...) 307 if err != nil { 308 return errors.New("failed to inspect that apps's field") 309 } 310 enc.Encode(field) 311 312 return nil 313 } 314 315 func (a *appsCmd) delete(c *cli.Context) error { 316 appName := c.Args().First() 317 if appName == "" { 318 return errors.New("error: deleting an app takes one argument, an app name") 319 } 320 321 _, err := a.client.Apps.DeleteAppsApp(&apiapps.DeleteAppsAppParams{ 322 Context: context.Background(), 323 App: appName, 324 }) 325 326 if err != nil { 327 switch err.(type) { 328 case *apiapps.DeleteAppsAppNotFound: 329 return errors.New(err.(*apiapps.DeleteAppsAppNotFound).Payload.Error.Message) 330 case *apiapps.DeleteAppsAppDefault: 331 return errors.New(err.(*apiapps.DeleteAppsAppDefault).Payload.Error.Message) 332 } 333 return fmt.Errorf("unexpected error: %v", err) 334 } 335 336 fmt.Println("app", appName, "deleted") 337 return nil 338 }