func runInfo(cmd *types.Command, args []string) { if infoHelp { cmd.PrintUsage() } if len(args) != 0 { cmd.PrintShortUsage() } // FIXME: fmt.Printf("Servers: %s\n", "quantity") // FIXME: fmt.Printf("Images: %s\n", "quantity") fmt.Printf("Debug mode (client): %v\n", os.Getenv("DEBUG") != "") fmt.Printf("Organization: %s\n", cmd.API.Organization) // FIXME: add partially-masked token fmt.Printf("API Endpoint: %s\n", os.Getenv("scaleway_api_endpoint")) configPath, _ := utils.GetConfigFilePath() fmt.Printf("RC file: %s\n", configPath) fmt.Printf("User: %s\n", os.Getenv("USER")) fmt.Printf("CPUs: %d\n", runtime.NumCPU()) hostname, _ := os.Hostname() fmt.Printf("Hostname: %s\n", hostname) cliPath, _ := osext.Executable() fmt.Printf("CLI Path: %s\n", cliPath) fmt.Printf("Cache: %s\n", cmd.API.Cache.Path) fmt.Printf(" Servers: %d\n", cmd.API.Cache.GetNbServers()) fmt.Printf(" Images: %d\n", cmd.API.Cache.GetNbImages()) fmt.Printf(" Snapshots: %d\n", cmd.API.Cache.GetNbSnapshots()) fmt.Printf(" Volumes: %d\n", cmd.API.Cache.GetNbVolumes()) fmt.Printf(" Bootscripts: %d\n", cmd.API.Cache.GetNbBootscripts()) }
func runCompletion(cmd *types.Command, args []string) { if completionHelp { cmd.PrintUsage() } if len(args) != 1 { cmd.PrintShortUsage() } category := args[0] elements := []string{} switch category { case "servers-all": for identifier, name := range cmd.API.Cache.Servers { elements = append(elements, identifier, wordifyName(name, "server")) } case "servers-names": for _, name := range cmd.API.Cache.Servers { elements = append(elements, wordifyName(name, "server")) } case "images-all": for identifier, name := range cmd.API.Cache.Images { elements = append(elements, identifier, wordifyName(name, "image")) } case "images-names": for _, name := range cmd.API.Cache.Images { elements = append(elements, wordifyName(name, "image")) } case "volumes-all": for identifier, name := range cmd.API.Cache.Volumes { elements = append(elements, identifier, wordifyName(name, "volume")) } case "volumes-names": for _, name := range cmd.API.Cache.Volumes { elements = append(elements, wordifyName(name, "volume")) } case "snapshots-all": for identifier, name := range cmd.API.Cache.Snapshots { elements = append(elements, identifier, wordifyName(name, "snapshot")) } case "snapshots-names": for _, name := range cmd.API.Cache.Snapshots { elements = append(elements, wordifyName(name, "snapshot")) } case "bootscripts-all": for identifier, name := range cmd.API.Cache.Bootscripts { elements = append(elements, identifier, wordifyName(name, "bootscript")) } case "bootscripts-names": for _, name := range cmd.API.Cache.Bootscripts { elements = append(elements, wordifyName(name, "bootscript")) } default: log.Fatalf("Unhandled category of completion: %s", category) } sort.Strings(elements) fmt.Println(strings.Join(utils.RemoveDuplicates(elements), "\n")) }
func runCommit(cmd *types.Command, args []string) { if commitHelp { cmd.PrintUsage() } if len(args) < 1 { cmd.PrintShortUsage() } serverID := cmd.API.GetServerID(args[0]) server, err := cmd.API.GetServer(serverID) if err != nil { log.Fatalf("Cannot fetch server: %v", err) } var volume = server.Volumes[fmt.Sprintf("%d", commitVolume)] var name string if len(args) > 1 { name = args[1] } else { name = volume.Name + "-snapshot" } snapshot, err := cmd.API.PostSnapshot(volume.Identifier, name) if err != nil { log.Fatalf("Cannot create snapshot: %v", err) } fmt.Println(snapshot) }
func runRestart(cmd *types.Command, args []string) { if restartHelp { cmd.PrintUsage() } if len(args) < 1 { cmd.PrintShortUsage() } hasError := false for _, needle := range args { server := cmd.API.GetServerID(needle) err := cmd.API.PostServerAction(server, "reboot") if err != nil { if err.Error() != "server is being stopped or rebooted" { log.Errorf("failed to restart server %s: %s", server, err) hasError = true } } else { fmt.Println(needle) } if hasError { os.Exit(1) } } }
func runRun(cmd *types.Command, args []string) { if runHelpFlag { cmd.PrintUsage() } if len(args) < 1 { cmd.PrintShortUsage() } if runAttachFlag && len(args) > 1 { log.Fatalf("Cannot use '--attach' and 'COMMAND [ARG...]' at the same time. See 'scw run --help'") } // create IMAGE log.Debugf("Creating a new server") serverID, err := api.CreateServer(cmd.API, args[0], runCreateName, runCreateBootscript, runCreateEnv, runCreateVolume) if err != nil { log.Fatalf("Failed to create server: %v", err) } log.Debugf("Created server: %s", serverID) // start SERVER log.Debugf("Starting server") err = api.StartServer(cmd.API, serverID, false) if err != nil { log.Fatalf("Failed to start server %s: %v", serverID, err) } log.Debugf("Server is booting") if runAttachFlag { // Attach to server serial log.Debugf("Attaching to server console") err = utils.AttachToSerial(serverID, cmd.API.Token, true) if err != nil { log.Fatalf("Cannot attach to server serial: %v", err) } } else { // waiting for server to be ready log.Debugf("Waiting for server to be ready") // We wait for 30 seconds, which is the minimal amount of time needed by a server to boot time.Sleep(30 * time.Second) server, err := api.WaitForServerReady(cmd.API, serverID) if err != nil { log.Fatalf("Cannot get access to server %s: %v", serverID, err) } log.Debugf("Server is ready: %s", server.PublicAddress.IP) // exec -w SERVER COMMAND ARGS... log.Debugf("Executing command") if len(args) < 2 { err = utils.SSHExec(server.PublicAddress.IP, []string{"if [ -x /bin/bash ]; then exec /bin/bash; else exec /bin/sh; fi"}, false) } else { err = utils.SSHExec(server.PublicAddress.IP, args[1:], false) } if err != nil { log.Debugf("Command execution failed: %v", err) os.Exit(1) } log.Debugf("Command successfuly executed") } }
func runInspect(cmd *types.Command, args []string) { if inspectHelp { cmd.PrintUsage() } if len(args) < 1 { cmd.PrintShortUsage() } res := "[" nbInspected := 0 ci := make(chan api.ScalewayResolvedIdentifier) cj := make(chan interface{}) go api.ResolveIdentifiers(cmd.API, args, ci) go api.InspectIdentifiers(cmd.API, ci, cj) for { data, open := <-cj if !open { break } if inspectFormat == "" { dataB, err := json.MarshalIndent(data, "", " ") if err == nil { if nbInspected != 0 { res += ",\n" } res += string(dataB) nbInspected++ } } else { tmpl, err := template.New("").Funcs(api.FuncMap).Parse(inspectFormat) if err != nil { log.Fatalf("Format parsing error: %v", err) } err = tmpl.Execute(os.Stdout, data) if err != nil { log.Fatalf("Format execution error: %v", err) } fmt.Fprint(os.Stdout, "\n") nbInspected++ } } res += "]" if inspectFormat == "" { if os.Getenv("SCW_SENSITIVE") != "1" { res = cmd.API.HideApiCredentials(res) } fmt.Println(res) } if len(args) != nbInspected { os.Exit(1) } }
func runLogin(cmd *types.Command, args []string) { if loginHelp { cmd.PrintUsage() } if len(args) != 0 { cmd.PrintShortUsage() } if len(organization) == 0 { fmt.Println("You can get your credentials on https://cloud.scaleway.com/#/credentials") promptUser("Organization (access key): ", &organization, true) } if len(token) == 0 { promptUser("Token: ", &token, false) } cfg := &api.Config{ APIEndPoint: "https://account.scaleway.com/", Organization: strings.Trim(organization, "\n"), Token: strings.Trim(token, "\n"), } api, err := api.NewScalewayAPI(cfg.APIEndPoint, cfg.Organization, cfg.Token) if err != nil { log.Fatalf("Unable to create ScalewayAPI: %s", err) } err = api.CheckCredentials() if err != nil { log.Fatalf("Unable to contact ScalewayAPI: %s", err) } scwrcPath, err := utils.GetConfigFilePath() if err != nil { log.Fatalf("Unable to get scwrc config file path: %s", err) } scwrc, err := os.OpenFile(scwrcPath, os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0600) if err != nil { log.Fatalf("Unable to create scwrc config file: %s", err) } defer scwrc.Close() encoder := json.NewEncoder(scwrc) cfg.APIEndPoint = "https://api.scaleway.com/" err = encoder.Encode(cfg) if err != nil { log.Fatalf("Unable to encode scw config file: %s", err) } }
func runStart(cmd *types.Command, args []string) { if startHelp { cmd.PrintUsage() } if len(args) < 1 { cmd.PrintShortUsage() } hasError := false errChan := make(chan error) successChan := make(chan bool) remainingItems := len(args) for i := range args { needle := args[i] go api.StartServerOnce(cmd.API, needle, startW, successChan, errChan) } if startTimeout > 0 { go func() { time.Sleep(time.Duration(startTimeout*1000) * time.Millisecond) log.Fatalf("Operation timed out") }() } for { select { case _ = <-successChan: remainingItems-- case err := <-errChan: log.Errorf(fmt.Sprintf("%s", err)) remainingItems-- hasError = true } if remainingItems == 0 { break } } if hasError { os.Exit(1) } }
func runTag(cmd *types.Command, args []string) { if tagHelp { cmd.PrintUsage() } if len(args) != 2 { cmd.PrintShortUsage() } snapshotID := cmd.API.GetSnapshotID(args[0]) snapshot, err := cmd.API.GetSnapshot(snapshotID) if err != nil { log.Fatalf("Cannot fetch snapshot: %v", err) } image, err := cmd.API.PostImage(snapshot.Identifier, args[1]) if err != nil { log.Fatalf("Cannot create image: %v", err) } fmt.Println(image) }
func runRename(cmd *types.Command, args []string) { if renameHelp { cmd.PrintUsage() } if len(args) != 2 { cmd.PrintShortUsage() } serverID := cmd.API.GetServerID(args[0]) var server api.ScalewayServerPatchDefinition server.Name = &args[1] err := cmd.API.PatchServer(serverID, server) if err != nil { log.Fatalf("Cannot rename server: %v", err) } else { cmd.API.Cache.InsertServer(serverID, *server.Name) } }
func runPort(cmd *types.Command, args []string) { if portHelp { cmd.PrintUsage() } if len(args) < 1 { cmd.PrintShortUsage() } serverID := cmd.API.GetServerID(args[0]) server, err := cmd.API.GetServer(serverID) if err != nil { log.Fatalf("Failed to get server information for %s: %v", serverID, err) } command := []string{"netstat -lutn 2>/dev/null | grep LISTEN"} err = utils.SSHExec(server.PublicAddress.IP, command, true) if err != nil { log.Fatalf("Command execution failed: %v", err) } }
func runExec(cmd *types.Command, args []string) { if execHelp { cmd.PrintUsage() } if len(args) < 2 { cmd.PrintShortUsage() } serverID := cmd.API.GetServerID(args[0]) var server *api.ScalewayServer var err error if execW { // --wait server, err = api.WaitForServerReady(cmd.API, serverID) if err != nil { log.Fatalf("Failed to wait for server to be ready, %v", err) } } else { // no --wait server, err = cmd.API.GetServer(serverID) if err != nil { log.Fatalf("Failed to get server information for %s: %v", serverID, err) } } if execTimeout > 0 { go func() { time.Sleep(time.Duration(execTimeout*1000) * time.Millisecond) log.Fatalf("Operation timed out") }() } err = utils.SSHExec(server.PublicAddress.IP, args[1:], !execW) if err != nil { log.Fatalf("%v", err) os.Exit(1) } log.Debugf("Command successfuly executed") }
func runPatch(cmd *types.Command, args []string) { if patchHelp { cmd.PrintUsage() } if len(args) != 2 { cmd.PrintShortUsage() } // Parsing FIELD=VALUE updateParts := strings.Split(args[1], "=") if len(updateParts) != 2 { cmd.PrintShortUsage() } fieldName := updateParts[0] newValue := updateParts[1] changes := 0 ident := api.GetIdentifier(cmd.API, args[0]) switch ident.Type { case api.IdentifierServer: currentServer, err := cmd.API.GetServer(ident.Identifier) if err != nil { log.Fatalf("Cannot get server %s: %v", ident.Identifier, err) } var payload api.ScalewayServerPatchDefinition switch fieldName { case "state_detail": log.Debugf("%s=%s => %s=%s", fieldName, currentServer.StateDetail, fieldName, newValue) if currentServer.StateDetail != newValue { changes++ payload.StateDetail = &newValue } case "name": log.Warnf("To rename a server, Use 'scw rename'") log.Debugf("%s=%s => %s=%s", fieldName, currentServer.StateDetail, fieldName, newValue) if currentServer.Name != newValue { changes++ payload.Name = &newValue } default: log.Fatalf("'_patch server %s=' not implemented", fieldName) } if changes > 0 { log.Debugf("updating server: %d change(s)", changes) err = cmd.API.PatchServer(ident.Identifier, payload) } else { log.Debugf("no changes, not updating server") } if err != nil { log.Fatalf("Cannot rename server: %v", err) } default: log.Fatalf("_patch not implemented for this kind of object") } fmt.Println(ident.Identifier) }
func runCp(cmd *types.Command, args []string) { if cpHelp { cmd.PrintUsage() } if len(args) != 2 { cmd.PrintShortUsage() } if strings.Count(args[0], ":") > 1 || strings.Count(args[1], ":") > 1 { log.Fatalf("usage: scw %s", cmd.UsageLine) } sourceStream, err := TarFromSource(cmd.API, args[0]) if err != nil { log.Fatalf("Cannot tar from source '%s': %v", args[0], err) } err = UntarToDest(cmd.API, sourceStream, args[1]) if err != nil { log.Fatalf("Cannot untar to destination '%s': %v", args[1], err) } }
func runLogs(cmd *types.Command, args []string) { if logsHelp { cmd.PrintUsage() } if len(args) != 1 { cmd.PrintShortUsage() } serverID := cmd.API.GetServerID(args[0]) server, err := cmd.API.GetServer(serverID) if err != nil { log.Fatalf("Failed to get server information for %s: %v", serverID, err) } // FIXME: switch to serial history when API is ready command := []string{"dmesg"} err = utils.SSHExec(server.PublicAddress.IP, command, true) if err != nil { log.Fatalf("Command execution failed: %v", err) } }
func runRm(cmd *types.Command, args []string) { if rmHelp { cmd.PrintUsage() } if len(args) < 1 { cmd.PrintShortUsage() } hasError := false for _, needle := range args { server := cmd.API.GetServerID(needle) err := cmd.API.DeleteServer(server) if err != nil { log.Errorf("failed to delete server %s: %s", server, err) hasError = true } else { fmt.Println(needle) } } if hasError { os.Exit(1) } }
func runWait(cmd *types.Command, args []string) { if waitHelp { cmd.PrintUsage() } if len(args) < 1 { cmd.PrintShortUsage() } hasError := false for _, needle := range args { serverIdentifier := cmd.API.GetServerID(needle) _, err := api.WaitForServerStopped(cmd.API, serverIdentifier) if err != nil { log.Errorf("failed to wait for server %s: %v", serverIdentifier, err) hasError = true } } if hasError { os.Exit(1) } }
func runTop(cmd *types.Command, args []string) { if topHelp { cmd.PrintUsage() } if len(args) != 2 { cmd.PrintShortUsage() } serverID := cmd.API.GetServerID(args[0]) command := "ps" server, err := cmd.API.GetServer(serverID) if err != nil { log.Fatalf("Failed to get server information for %s: %v", serverID, err) } execCmd := append(utils.NewSSHExecCmd(server.PublicAddress.IP, true, []string{command})) log.Debugf("Executing: ssh %s", strings.Join(execCmd, " ")) out, err := exec.Command("ssh", execCmd...).CombinedOutput() fmt.Printf("%s", out) if err != nil { log.Fatal(err) } }
func runHistory(cmd *types.Command, args []string) { if historyHelp { cmd.PrintUsage() } if len(args) != 1 { cmd.PrintShortUsage() } imageID := cmd.API.GetImageID(args[0], true) image, err := cmd.API.GetImage(imageID) if err != nil { log.Fatalf("Cannot get image %s: %v", imageID, err) } if imagesQ { fmt.Println(imageID) return } w := tabwriter.NewWriter(os.Stdout, 10, 1, 3, ' ', 0) defer w.Flush() fmt.Fprintf(w, "IMAGE\tCREATED\tCREATED BY\tSIZE\n") identifier := utils.TruncIf(image.Identifier, 8, !historyNoTrunc) creationDate, err := time.Parse("2006-01-02T15:04:05.000000+00:00", image.CreationDate) if err != nil { log.Fatalf("Unable to parse creation date from the Scaleway API: %v", err) } creationDateStr := units.HumanDuration(time.Now().UTC().Sub(creationDate)) volumeName := utils.TruncIf(image.RootVolume.Name, 25, !historyNoTrunc) size := units.HumanSize(float64(image.RootVolume.Size)) fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", identifier, creationDateStr, volumeName, size) }
func runHelp(cmd *types.Command, args []string) { if waitHelp { cmd.PrintUsage() } if len(args) > 1 { cmd.PrintShortUsage() } if len(args) == 1 { name := args[0] for _, command := range Commands { if command.Name() == name { command.PrintUsage() } } log.Fatalf("Unknown help topic `%s`. Run 'scw help'.", name) } else { t := template.New("top") template.Must(t.Parse(helpTemplate)) if err := t.Execute(os.Stdout, Commands); err != nil { panic(err) } } }
func runSearch(cmd *types.Command, args []string) { if searchHelp { cmd.PrintUsage() } if len(args) != 1 { cmd.PrintShortUsage() } w := tabwriter.NewWriter(os.Stdout, 10, 1, 3, ' ', 0) defer w.Flush() fmt.Fprintf(w, "NAME\tDESCRIPTION\tSTARS\tOFFICIAL\tAUTOMATED\n") var entries = []api.ScalewayImageInterface{} images, err := cmd.API.GetImages() if err != nil { log.Fatalf("unable to fetch images from the Scaleway API: %v", err) } for _, val := range *images { entries = append(entries, api.ScalewayImageInterface{ Type: "image", Name: val.Name, Public: val.Public, }) } snapshots, err := cmd.API.GetSnapshots() if err != nil { log.Fatalf("unable to fetch snapshots from the Scaleway API: %v", err) } for _, val := range *snapshots { entries = append(entries, api.ScalewayImageInterface{ Type: "snapshot", Name: val.Name, Public: false, }) } for _, image := range entries { // name field name := utils.TruncIf(utils.Wordify(image.Name), 45, !searchNoTrunc) // description field var description string switch image.Type { case "image": if image.Public { description = "public image" } else { description = "user image" } case "snapshot": description = "user snapshot" } description = utils.TruncIf(utils.Wordify(description), 45, !searchNoTrunc) // official field var official string if image.Public { official = "[OK]" } else { official = "" } fmt.Fprintf(w, "%s\t%s\t%d\t%s\t%s\n", name, description, 0, official, "") } }
func runImages(cmd *types.Command, args []string) { if imagesHelp { cmd.PrintUsage() } if len(args) != 0 { cmd.PrintShortUsage() } wg := sync.WaitGroup{} chEntries := make(chan api.ScalewayImageInterface) var entries = []api.ScalewayImageInterface{} wg.Add(1) go func() { defer wg.Done() images, err := cmd.API.GetImages() if err != nil { log.Fatalf("unable to fetch images from the Scaleway API: %v", err) } for _, val := range *images { creationDate, err := time.Parse("2006-01-02T15:04:05.000000+00:00", val.CreationDate) if err != nil { log.Fatalf("unable to parse creation date from the Scaleway API: %v", err) } chEntries <- api.ScalewayImageInterface{ Type: "image", CreationDate: creationDate, Identifier: val.Identifier, Name: val.Name, Public: val.Public, Tag: "latest", VirtualSize: float64(val.RootVolume.Size), } } }() if imagesA { wg.Add(1) go func() { defer wg.Done() snapshots, err := cmd.API.GetSnapshots() if err != nil { log.Fatalf("unable to fetch snapshots from the Scaleway API: %v", err) } for _, val := range *snapshots { creationDate, err := time.Parse("2006-01-02T15:04:05.000000+00:00", val.CreationDate) if err != nil { log.Fatalf("unable to parse creation date from the Scaleway API: %v", err) } chEntries <- api.ScalewayImageInterface{ Type: "snapshot", CreationDate: creationDate, Identifier: val.Identifier, Name: val.Name, Tag: "<snapshot>", VirtualSize: float64(val.Size), Public: false, } } }() wg.Add(1) go func() { defer wg.Done() bootscripts, err := cmd.API.GetBootscripts() if err != nil { log.Fatalf("unable to fetch bootscripts from the Scaleway API: %v", err) } for _, val := range *bootscripts { chEntries <- api.ScalewayImageInterface{ Type: "bootscript", Identifier: val.Identifier, Name: val.Title, Tag: "<bootscript>", Public: false, } } }() wg.Add(1) go func() { defer wg.Done() volumes, err := cmd.API.GetVolumes() if err != nil { log.Fatalf("unable to fetch volumes from the Scaleway API: %v", err) } for _, val := range *volumes { creationDate, err := time.Parse("2006-01-02T15:04:05.000000+00:00", val.CreationDate) if err != nil { log.Fatalf("unable to parse creation date from the Scaleway API: %v", err) } chEntries <- api.ScalewayImageInterface{ Type: "volume", CreationDate: creationDate, Identifier: val.Identifier, Name: val.Name, Tag: "<volume>", VirtualSize: float64(val.Size), Public: false, } } }() } go func() { wg.Wait() close(chEntries) }() done := false for { select { case entry, ok := <-chEntries: if !ok { done = true break } entries = append(entries, entry) } if done { break } } w := tabwriter.NewWriter(os.Stdout, 20, 1, 3, ' ', 0) defer w.Flush() if !imagesQ { fmt.Fprintf(w, "REPOSITORY\tTAG\tIMAGE ID\tCREATED\tVIRTUAL SIZE\n") } sort.Sort(api.ByCreationDate(entries)) for _, image := range entries { if imagesQ { fmt.Fprintf(w, "%s\n", image.Identifier) } else { tag := image.Tag shortID := utils.TruncIf(image.Identifier, 8, !imagesNoTrunc) name := utils.Wordify(image.Name) if !image.Public && image.Type == "image" { name = "user/" + name } shortName := utils.TruncIf(name, 25, !imagesNoTrunc) var creationDate, virtualSize string if image.CreationDate.IsZero() { creationDate = "n/a" } else { creationDate = units.HumanDuration(time.Now().UTC().Sub(image.CreationDate)) } if image.VirtualSize == 0 { virtualSize = "n/a" } else { virtualSize = units.HumanSize(image.VirtualSize) } fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\n", shortName, tag, shortID, creationDate, virtualSize) } } }