github.com/tonto/cli@v0.0.0-20180104210444-aec958fa47db/apps.go (about) 1 package main 2 3 import ( 4 "encoding/json" 5 "errors" 6 "fmt" 7 "os" 8 9 "context" 10 "strings" 11 12 client "github.com/fnproject/cli/client" 13 fnclient "github.com/fnproject/fn_go/client" 14 apiapps "github.com/fnproject/fn_go/client/apps" 15 "github.com/fnproject/fn_go/models" 16 "github.com/jmoiron/jsonq" 17 "github.com/urfave/cli" 18 ) 19 20 type appsCmd struct { 21 client *fnclient.Fn 22 } 23 24 func apps() cli.Command { 25 a := appsCmd{client: client.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 Aliases: []string{"d"}, 93 Usage: "delete an app", 94 Action: a.delete, 95 }, 96 }, 97 } 98 } 99 100 func (a *appsCmd) list(c *cli.Context) error { 101 resp, err := a.client.Apps.GetApps(&apiapps.GetAppsParams{ 102 Context: context.Background(), 103 }) 104 105 if err != nil { 106 switch e := err.(type) { 107 case *apiapps.GetAppsAppNotFound: 108 return fmt.Errorf("%v", e.Payload.Error.Message) 109 case *apiapps.GetAppsAppDefault: 110 return fmt.Errorf("%v", e.Payload.Error.Message) 111 case *apiapps.GetAppsDefault: 112 // this is the one getting called, not sure what the one above is? 113 return fmt.Errorf("%v", e.Payload.Error.Message) 114 default: 115 return fmt.Errorf("%v", err) 116 } 117 } 118 119 if len(resp.Payload.Apps) == 0 { 120 fmt.Println("no apps found") 121 return nil 122 } 123 124 for _, app := range resp.Payload.Apps { 125 fmt.Println(app.Name) 126 } 127 128 return nil 129 } 130 131 func (a *appsCmd) create(c *cli.Context) error { 132 body := &models.AppWrapper{App: &models.App{ 133 Name: c.Args().Get(0), 134 Config: extractEnvConfig(c.StringSlice("config")), 135 }} 136 137 resp, err := a.client.Apps.PostApps(&apiapps.PostAppsParams{ 138 Context: context.Background(), 139 Body: body, 140 }) 141 142 if err != nil { 143 switch e := err.(type) { 144 case *apiapps.PostAppsBadRequest: 145 return fmt.Errorf("%v", e.Payload.Error.Message) 146 case *apiapps.PostAppsConflict: 147 return fmt.Errorf("%v", e.Payload.Error.Message) 148 case *apiapps.PostAppsDefault: 149 return fmt.Errorf("%v", e.Payload.Error.Message) 150 default: 151 return fmt.Errorf("%v", err) 152 } 153 } 154 155 fmt.Println("Successfully created app: ", resp.Payload.App.Name) 156 return nil 157 } 158 159 func (a *appsCmd) update(c *cli.Context) error { 160 appName := c.Args().First() 161 162 patchedApp := &models.App{ 163 Config: extractEnvConfig(c.StringSlice("config")), 164 } 165 166 err := a.patchApp(appName, patchedApp) 167 if err != nil { 168 return err 169 } 170 171 fmt.Println("app", appName, "updated") 172 return nil 173 } 174 175 func (a *appsCmd) configSet(c *cli.Context) error { 176 appName := c.Args().Get(0) 177 key := c.Args().Get(1) 178 value := c.Args().Get(2) 179 180 app := &models.App{ 181 Config: make(map[string]string), 182 } 183 184 app.Config[key] = value 185 186 if err := a.patchApp(appName, app); err != nil { 187 return fmt.Errorf("error updating app configuration: %v", err) 188 } 189 190 fmt.Println(appName, "updated", key, "with", value) 191 return nil 192 } 193 194 func (a *appsCmd) configUnset(c *cli.Context) error { 195 appName := c.Args().Get(0) 196 key := c.Args().Get(1) 197 198 app := &models.App{ 199 Config: make(map[string]string), 200 } 201 202 app.Config[key] = "" 203 204 if err := a.patchApp(appName, app); err != nil { 205 return fmt.Errorf("error updating app configuration: %v", err) 206 } 207 208 fmt.Printf("removed key '%s' from app '%s' \n", key, appName) 209 return nil 210 } 211 212 func (a *appsCmd) patchApp(appName string, app *models.App) error { 213 _, err := a.client.Apps.PatchAppsApp(&apiapps.PatchAppsAppParams{ 214 Context: context.Background(), 215 App: appName, 216 Body: &models.AppWrapper{App: app}, 217 }) 218 219 if err != nil { 220 switch e := err.(type) { 221 case *apiapps.PatchAppsAppBadRequest: 222 return errors.New(e.Payload.Error.Message) 223 case *apiapps.PatchAppsAppNotFound: 224 return errors.New(e.Payload.Error.Message) 225 case *apiapps.PatchAppsAppDefault: 226 return errors.New(e.Payload.Error.Message) 227 default: 228 return fmt.Errorf("%v", err) 229 } 230 } 231 232 return nil 233 } 234 235 func (a *appsCmd) inspect(c *cli.Context) error { 236 if c.Args().Get(0) == "" { 237 return errors.New("missing app name after the inspect command") 238 } 239 240 appName := c.Args().First() 241 prop := c.Args().Get(1) 242 243 resp, err := a.client.Apps.GetAppsApp(&apiapps.GetAppsAppParams{ 244 Context: context.Background(), 245 App: appName, 246 }) 247 248 if err != nil { 249 switch e := err.(type) { 250 case *apiapps.GetAppsAppNotFound: 251 return fmt.Errorf("%v", e.Payload.Error.Message) 252 case *apiapps.GetAppsAppDefault: 253 return fmt.Errorf("%v", e.Payload.Error.Message) 254 default: 255 return fmt.Errorf("%v", err) 256 } 257 } 258 259 enc := json.NewEncoder(os.Stdout) 260 enc.SetIndent("", "\t") 261 262 if prop == "" { 263 enc.Encode(resp.Payload.App) 264 return nil 265 } 266 267 // TODO: we really need to marshal it here just to 268 // unmarshal as map[string]interface{}? 269 data, err := json.Marshal(resp.Payload.App) 270 if err != nil { 271 return fmt.Errorf("could not marshal app: %v", err) 272 } 273 var inspect map[string]interface{} 274 err = json.Unmarshal(data, &inspect) 275 if err != nil { 276 return fmt.Errorf("could not unmarshal data: %v", err) 277 } 278 279 jq := jsonq.NewQuery(inspect) 280 field, err := jq.Interface(strings.Split(prop, ".")...) 281 if err != nil { 282 return fmt.Errorf("failed to inspect field %v", prop) 283 } 284 enc.Encode(field) 285 286 return nil 287 } 288 289 func (a *appsCmd) delete(c *cli.Context) error { 290 appName := c.Args().First() 291 if appName == "" { 292 return errors.New("app name required to delete") 293 } 294 295 _, err := a.client.Apps.DeleteAppsApp(&apiapps.DeleteAppsAppParams{ 296 Context: context.Background(), 297 App: appName, 298 }) 299 300 if err != nil { 301 switch e := err.(type) { 302 case *apiapps.DeleteAppsAppNotFound: 303 return errors.New(e.Payload.Error.Message) 304 case *apiapps.DeleteAppsAppDefault: 305 return errors.New(e.Payload.Error.Message) 306 } 307 return fmt.Errorf("%v", err) 308 } 309 310 fmt.Println("App", appName, "deleted") 311 return nil 312 }