func sshCreate(ctx *cli.Context) { if len(ctx.Args()) != 2 { log.Fatal("Must provide name and public key file.") } tokenSource := &TokenSource{ AccessToken: APIKey, } oauthClient := oauth2.NewClient(oauth2.NoContext, tokenSource) client := godo.NewClient(oauthClient) file, err := os.Open(ctx.Args()[1]) if err != nil { log.Fatalf("Error opening key file: %s.", err) } keyData, err := ioutil.ReadAll(file) if err != nil { log.Fatalf("Error reading key file: %s.", err) } createRequest := &godo.KeyCreateRequest{ Name: ctx.Args().First(), PublicKey: string(keyData), } key, _, err := client.Keys.Create(createRequest) if err != nil { log.Fatal(err) } WriteOutput(key) }
func TestApp_RunAsSubcommandParseFlags(t *testing.T) { var context *cli.Context a := cli.NewApp() a.Commands = []cli.Command{ { Name: "foo", Action: func(c *cli.Context) { context = c }, Flags: []cli.Flag{ cli.StringFlag{ Name: "lang", Value: "english", Usage: "language for the greeting", }, }, Before: func(_ *cli.Context) error { return nil }, }, } a.Run([]string{"", "foo", "--lang", "spanish", "abcd"}) expect(t, context.Args().Get(0), "abcd") expect(t, context.String("lang"), "spanish") }
func dropletActionUpgrade(ctx *cli.Context) { if ctx.Int("id") == 0 && len(ctx.Args()) != 1 { log.Fatal("Error: Must provide ID or name for Droplet to resize.") } tokenSource := &TokenSource{ AccessToken: APIKey, } oauthClient := oauth2.NewClient(oauth2.NoContext, tokenSource) client := godo.NewClient(oauthClient) id := ctx.Int("id") if id == 0 { droplet, err := FindDropletByName(client, ctx.Args()[0]) if err != nil { log.Fatal(err) } else { id = droplet.ID } } droplet, _, err := client.Droplets.Get(id) if err != nil { log.Fatal("Unable to find Droplet: %s.", err) } action, _, err := client.DropletActions.Upgrade(droplet.ID) if err != nil { log.Fatal(err) } WriteOutput(action) }
func dropletDestroy(ctx *cli.Context) { if ctx.Int("id") == 0 && len(ctx.Args()) != 1 { log.Fatal("Error: Must provide ID or name for Droplet to destroy.") } tokenSource := &TokenSource{ AccessToken: APIKey, } oauthClient := oauth2.NewClient(oauth2.NoContext, tokenSource) client := godo.NewClient(oauthClient) id := ctx.Int("id") if id == 0 { droplet, err := FindDropletByName(client, ctx.Args()[0]) if err != nil { log.Fatal(err) } else { id = droplet.ID } } droplet, _, err := client.Droplets.Get(id) if err != nil { log.Fatalf("Unable to find Droplet: %s.", err) } _, err = client.Droplets.Delete(id) if err != nil { log.Fatalf("Unable to destroy Droplet: %s.", err) } log.Fatalf("Droplet %s destroyed.", droplet.Name) }
func domainRecordList(ctx *cli.Context) { if len(ctx.Args()) != 1 { fmt.Printf("Error: Must provide a domain name for which to list records.\n") os.Exit(64) } tokenSource := &TokenSource{ AccessToken: APIKey, } oauthClient := oauth2.NewClient(oauth2.NoContext, tokenSource) client := godo.NewClient(oauthClient) domainName := ctx.Args().First() opt := &godo.ListOptions{ Page: ctx.Int("page"), PerPage: ctx.Int("page-size"), } domainDecords, _, err := client.Domains.Records(domainName, opt) if err != nil { fmt.Printf("%s\n", err) os.Exit(1) } WriteOutput(domainDecords) }
func sshDestroy(ctx *cli.Context) { if ctx.Int("id") == 0 && ctx.String("fingerprint") == "" && len(ctx.Args()) < 1 { fmt.Printf("Error: Must provide ID, fingerprint or name for SSH Key to destroy.\n") os.Exit(1) } tokenSource := &TokenSource{ AccessToken: APIKey, } oauthClient := oauth2.NewClient(oauth2.NoContext, tokenSource) client := godo.NewClient(oauthClient) id := ctx.Int("id") fingerprint := ctx.String("fingerprint") var key godo.Key if id == 0 && fingerprint == "" { key, err := FindKeyByName(client, ctx.Args().First()) if err != nil { fmt.Printf("%s\n", err) os.Exit(64) } else { id = key.ID } } else if id != 0 { key, _, err := client.Keys.GetByID(id) if err != nil { fmt.Printf("Unable to find SSH Key: %s\n", err) os.Exit(1) } else { id = key.ID } } else { key, _, err := client.Keys.GetByFingerprint(fingerprint) if err != nil { fmt.Printf("Unable to find SSH Key: %s\n", err) os.Exit(1) } else { id = key.ID } } _, err := client.Keys.DeleteByID(id) if err != nil { fmt.Printf("Unable to destroy SSH Key: %s\n", err) os.Exit(1) } fmt.Printf("Key %s destroyed.\n", key.Name) }
func domainShow(ctx *cli.Context) { if len(ctx.Args()) != 1 { log.Fatal("Error: Must provide name for Domain.") } name := ctx.Args().First() tokenSource := &TokenSource{ AccessToken: APIKey, } oauthClient := oauth2.NewClient(oauth2.NoContext, tokenSource) client := godo.NewClient(oauthClient) domain, _, err := client.Domains.Get(name) if err != nil { log.Fatal(err) } WriteOutput(domain) }
func domainDestroy(ctx *cli.Context) { if len(ctx.Args()) != 1 { log.Fatal("Error: Must provide a name for the domain to destroy.") } name := ctx.Args().First() tokenSource := &TokenSource{ AccessToken: APIKey, } oauthClient := oauth2.NewClient(oauth2.NoContext, tokenSource) client := godo.NewClient(oauthClient) _, err := client.Domains.Delete(name) if err != nil { log.Fatalf("Unable to destroy domain: %s.", err) } log.Printf("Domain %s destroyed", name) }
func sshFind(ctx *cli.Context) { if len(ctx.Args()) != 1 { log.Fatal("Error: Must provide name for Key.") } name := ctx.Args().First() tokenSource := &TokenSource{ AccessToken: APIKey, } oauthClient := oauth2.NewClient(oauth2.NoContext, tokenSource) client := godo.NewClient(oauthClient) key, err := FindKeyByName(client, name) if err != nil { log.Fatal(err) } WriteOutput(key) }
func domainCreate(ctx *cli.Context) { if len(ctx.Args()) != 2 { log.Fatal("Must provide domain name and Droplet name.") } tokenSource := &TokenSource{ AccessToken: APIKey, } oauthClient := oauth2.NewClient(oauth2.NoContext, tokenSource) client := godo.NewClient(oauthClient) droplet, err := FindDropletByName(client, ctx.Args()[1]) if err != nil { log.Fatal(err) } createRequest := &godo.DomainCreateRequest{ Name: ctx.Args().First(), IPAddress: PublicIPForDroplet(droplet), } domain, _, err := client.Domains.Create(createRequest) if err != nil { log.Fatal(err) } WriteOutput(domain) }
func dropletActionResize(ctx *cli.Context) { if ctx.Int("id") == 0 && len(ctx.Args()) != 1 { fmt.Printf("Error: Must provide ID or name for Droplet to destroy.\n") os.Exit(1) } size := ctx.String("size") disk := ctx.Bool("disk") tokenSource := &TokenSource{ AccessToken: APIKey, } oauthClient := oauth2.NewClient(oauth2.NoContext, tokenSource) client := godo.NewClient(oauthClient) id := ctx.Int("id") if id == 0 { droplet, err := FindDropletByName(client, ctx.Args()[0]) if err != nil { fmt.Printf("%s\n", err) os.Exit(64) } else { id = droplet.ID } } droplet, _, err := client.Droplets.Get(id) if err != nil { fmt.Printf("Unable to find Droplet: %s\n", err) os.Exit(1) } action, _, err := client.DropletActions.Resize(droplet.ID, size, disk) if err != nil { fmt.Println(err) os.Exit(1) } WriteOutput(action) }
func domainRecordDestroy(ctx *cli.Context) { if len(ctx.Args()) != 2 { fmt.Printf("Error: Must provide domain name and domain record id.\n") os.Exit(1) } domainName := ctx.Args().First() recordID, err := strconv.Atoi(ctx.Args()[1]) if err != nil { fmt.Printf("%s\n", err) os.Exit(1) } tokenSource := &TokenSource{ AccessToken: APIKey, } oauthClient := oauth2.NewClient(oauth2.NoContext, tokenSource) client := godo.NewClient(oauthClient) _, err = client.Domains.DeleteRecord(domainName, recordID) if err != nil { fmt.Printf("Unable to destroy domain record: %s\n", err) os.Exit(1) } fmt.Printf("Domain record %d destroyed.\n", recordID) }
func domainRecordShow(ctx *cli.Context) { if len(ctx.Args()) == 2 { fmt.Printf("Error: Must provide domain name and domain record id.\n") os.Exit(64) } tokenSource := &TokenSource{ AccessToken: APIKey, } oauthClient := oauth2.NewClient(oauth2.NoContext, tokenSource) client := godo.NewClient(oauthClient) domainName := ctx.Args().First() recordID, err := strconv.Atoi(ctx.Args()[1]) if err != nil { fmt.Printf("%s\n", err) os.Exit(1) } domainDecord, _, err := client.Domains.Record(domainName, recordID) if err != nil { fmt.Printf("%s\n", err) os.Exit(1) } WriteOutput(domainDecord) }
func sshFind(ctx *cli.Context) { if len(ctx.Args()) != 1 { fmt.Printf("Error: Must provide name for Key.\n") os.Exit(1) } name := ctx.Args().First() tokenSource := &TokenSource{ AccessToken: APIKey, } oauthClient := oauth2.NewClient(oauth2.NoContext, tokenSource) client := godo.NewClient(oauthClient) key, err := FindKeyByName(client, name) if err != nil { fmt.Printf("%s\n", err) os.Exit(64) } WriteOutput(key) }
func domainShow(ctx *cli.Context) { if len(ctx.Args()) != 1 { fmt.Printf("Error: Must provide name for Domain.\n") os.Exit(64) } name := ctx.Args().First() tokenSource := &TokenSource{ AccessToken: APIKey, } oauthClient := oauth2.NewClient(oauth2.NoContext, tokenSource) client := godo.NewClient(oauthClient) domain, _, err := client.Domains.Get(name) if err != nil { fmt.Printf("%s\n", err) os.Exit(1) } WriteOutput(domain) }
func domainRecordCreate(ctx *cli.Context) { if len(ctx.Args()) != 1 { cli.ShowAppHelp(ctx) fmt.Printf("Must specify a domain name to add a record to.\n") os.Exit(1) } domainName := ctx.Args().First() tokenSource := &TokenSource{ AccessToken: APIKey, } oauthClient := oauth2.NewClient(oauth2.NoContext, tokenSource) client := godo.NewClient(oauthClient) createRequest := &godo.DomainRecordEditRequest{ Type: strings.ToUpper(ctx.String("type")), Name: ctx.String("name"), Data: ctx.String("data"), } if createRequest.Type == "MX" || createRequest.Type == "SRV" { createRequest.Priority = ctx.Int("priority") } if createRequest.Type == "SRV" { createRequest.Port = ctx.Int("port") createRequest.Weight = ctx.Int("weight") } domainRecord, _, err := client.Domains.CreateRecord(domainName, createRequest) if err != nil { fmt.Printf("%s\n", err) os.Exit(1) } WriteOutput(domainRecord) }
func dropletFind(ctx *cli.Context) { if len(ctx.Args()) == 0 || len(ctx.Args()) > 1 { log.Fatal("Error: Must provide one name for a Droplet search.") } name := ctx.Args().First() tokenSource := &TokenSource{ AccessToken: APIKey, } oauthClient := oauth2.NewClient(oauth2.NoContext, tokenSource) client := godo.NewClient(oauthClient) droplet, err := FindDropletByName(client, name) if err != nil { log.Fatal(err) } WriteOutput(droplet) }
func actionShow(ctx *cli.Context) { if len(ctx.Args()) == 0 || len(ctx.Args()) > 1 { log.Fatal("Error: Must provide exactly one id of an Action to show.") } id, _ := strconv.ParseInt(ctx.Args().First(), 10, 0) tokenSource := &TokenSource{ AccessToken: APIKey, } oauthClient := oauth2.NewClient(oauth2.NoContext, tokenSource) client := godo.NewClient(oauthClient) action, _, err := client.Actions.Get(int(id)) if err != nil { log.Fatal(err) } WriteOutput(action) }
func dropletActionKernels(ctx *cli.Context) { if ctx.Int("id") == 0 && len(ctx.Args()) != 1 { log.Fatal("Error: Must provide ID or name for Droplet to list available kernels.") } tokenSource := &TokenSource{ AccessToken: APIKey, } oauthClient := oauth2.NewClient(oauth2.NoContext, tokenSource) client := godo.NewClient(oauthClient) id := ctx.Int("id") if id == 0 { droplet, err := FindDropletByName(client, ctx.Args()[0]) if err != nil { log.Fatal(err) } else { id = droplet.ID } } droplet, _, err := client.Droplets.Get(id) if err != nil { log.Fatal("Unable to find Droplet: %s.", err) } opt := &godo.ListOptions{} kernelList := []godo.Kernel{} for { // TODO make all optional kernelsPage, resp, err := client.Droplets.Kernels(droplet.ID, opt) if err != nil { log.Fatalf("Unable to list Droplet kernels: %s.", err) } // append the current page's droplets to our list for _, k := range kernelsPage { kernelList = append(kernelList, k) } // if we are at the last page, break out the for loop if resp.Links == nil || resp.Links.IsLastPage() { break } page, err := resp.Links.CurrentPage() if err != nil { log.Fatalf("Unable to get pagination: %s.", err) } // set the page we want for the next request opt.Page = page + 1 } cliOut := NewCLIOutput() defer cliOut.Flush() cliOut.Header("ID", "Name", "Version") for _, kernel := range kernelList { cliOut.Writeln("%d\t%s\t%s\n", kernel.ID, kernel.Name, kernel.Version) } }
func dropletCreate(ctx *cli.Context) { if len(ctx.Args()) != 1 { log.Fatal("Error: Must provide name for Droplet.") } tokenSource := &TokenSource{ AccessToken: APIKey, } oauthClient := oauth2.NewClient(oauth2.NoContext, tokenSource) client := godo.NewClient(oauthClient) // Add domain to end if available. dropletName := ctx.Args().First() if ctx.Bool("add-region") { dropletName = fmt.Sprintf("%s.%s", dropletName, ctx.String("region")) } if ctx.String("domain") != "" { dropletName = fmt.Sprintf("%s.%s", dropletName, ctx.String("domain")) } // Loop through the SSH Keys and add by name. DO API should have handled // this case as well. var sshKeys []godo.DropletCreateSSHKey keyNames := ctx.String("ssh-keys") if keyNames != "" { for _, keyName := range strings.Split(keyNames, ",") { sshKey, err := FindKeyByName(client, keyName) if sshKey != nil && err == nil { sshKeys = append(sshKeys, godo.DropletCreateSSHKey{ID: sshKey.ID}) } else { log.Fatalf("Warning: Could not find key: %q.", keyName) } } } userData := "" userDataPath := ctx.String("user-data-file") if userDataPath != "" { file, err := os.Open(userDataPath) if err != nil { log.Fatalf("Error opening user data file: %s.", err) } userDataFile, err := ioutil.ReadAll(file) if err != nil { log.Fatalf("Error reading user data file: %s.", err) } userData = string(userDataFile) } else { userData = ctx.String("user-data") } createRequest := &godo.DropletCreateRequest{ Name: dropletName, Region: ctx.String("region"), Size: ctx.String("size"), Image: godo.DropletCreateImage{ Slug: ctx.String("image"), }, SSHKeys: sshKeys, Backups: ctx.Bool("backups"), IPv6: ctx.Bool("ipv6"), PrivateNetworking: ctx.Bool("private-networking"), UserData: userData, } droplet, resp, err := client.Droplets.Create(createRequest) if err != nil { log.Fatalf("Unable to create Droplet: %s.", err) } if ctx.Bool("wait-for-active") { util.WaitForActive(client, resp.Links.Actions[0].HREF) } WriteOutput(droplet) }
func connect(ctx *cli.Context) { if len(ctx.Args()) != 1 { log.Fatal("Error: Must provide name of droplet.") } name := ctx.Args().First() tokenSource := &TokenSource{ AccessToken: APIKey, } oauthClient := oauth2.NewClient(oauth2.NoContext, tokenSource) client := godo.NewClient(oauthClient) droplet, err := FindDropletByName(client, name) if err != nil { log.Fatal(err) } var ip string for _, n := range droplet.Networks.V4 { if n.Type == "public" { ip = n.IPAddress } } endpoint := fmt.Sprintf("%s:%d", ip, 22) methods, err := authMethods(ctx) if err != nil { log.Fatal(err) } user := "******" if strings.Contains(droplet.Image.Slug, "coreos") { user = "******" } c := &ssh.ClientConfig{ User: user, Auth: methods, } conn, err := ssh.Dial("tcp", endpoint, c) if err != nil { log.Fatal("Unable to connect.", err.Error()) } session, err := conn.NewSession() if err != nil { log.Fatal(err.Error()) } session.Stdout = os.Stdout session.Stderr = os.Stderr session.Stdin = os.Stdin defer session.Close() modes := ssh.TerminalModes{ ssh.ECHO: 1, } fd := os.Stdin.Fd() var ( termWidth, termHeight int ) if term.IsTerminal(fd) { oldState, err := term.MakeRaw(fd) if err != nil { log.Fatal(err) } defer term.RestoreTerminal(fd, oldState) winsize, err := term.GetWinsize(fd) if err != nil { termWidth = 80 termHeight = 24 } else { termWidth = int(winsize.Width) termHeight = int(winsize.Height) } } if err := session.RequestPty("xterm", termWidth, termHeight, modes); err != nil { session.Close() log.Fatalf("request for pseudo terminal failed: %s", err) } if err == nil { err = session.Shell() } if err != nil { log.Fatal(err) } err = session.Wait() if err != nil && err != io.EOF { // Ignore the error if it's an ExitError with an empty message, // this occurs when you do CTRL+c and then run exit cmd which isn't an // actual error. waitMsg, ok := err.(*ssh.ExitError) if ok && waitMsg.Msg() == "" { return } log.Fatal(err) } }