func runUploadManifestYaml(c *cli.Context, stackUid string) { manifestYamlFile := c.Args().First() if manifestYamlFile == "" { printFatal("manifest_yaml file path is required") } else { manifestYamlFile = expandPath(manifestYamlFile) } manifestYamlBytes, err := ioutil.ReadFile(manifestYamlFile) must(err) manifestYaml := string(manifestYamlBytes) comments := c.String("comments") if comments == "" { fmt.Println("\nComments can't be blank, Please add one:") if term.IsTerminal(os.Stdin) { fmt.Printf("> ") } reader := bufio.NewReader(os.Stdin) if comments, err = reader.ReadString('\n'); err != nil { printFatal(err.Error()) } } _, err = client.CreateManifestYaml(stackUid, manifestYaml, comments) must(err) }
func runBackups(c *cli.Context) { var dbType = c.String("dbtype") w := tabwriter.NewWriter(os.Stdout, 1, 2, 2, ' ', 0) defer w.Flush() stack := mustStack(c) backups, err := client.ManagedBackups(stack.Uid) must(err) var dbTypeGroup = map[string][]cloud66.ManagedBackup{} if c.Bool("latest") { for _, i := range backups { if dbTypeGroup[i.DbType] == nil { // it's a new one dbTypeGroup[i.DbType] = []cloud66.ManagedBackup{i} } else { dbTypeGroup[i.DbType] = append(dbTypeGroup[i.DbType], i) } } // now sort each group topResults := []cloud66.ManagedBackup{} for _, v := range dbTypeGroup { sort.Sort(backupsByDate(v)) topResults = append(topResults, v[0]) } printBackupList(w, topResults, dbType) } else { printBackupList(w, backups, dbType) } }
func runContainers(c *cli.Context) { stack := mustStack(c) w := tabwriter.NewWriter(os.Stdout, 1, 2, 2, ' ', 0) defer w.Flush() flagServer := c.String("server") flagServiceName := c.String("service") flagTruncate := c.Bool("trunc") var serverUid *string if flagServer == "" { serverUid = nil } else { servers, err := client.Servers(stack.Uid) if err != nil { printFatal(err.Error()) } server, err := findServer(servers, flagServer) if err != nil { printFatal(err.Error()) } if server == nil { printFatal("Server '" + flagServer + "' not found") } fmt.Printf("Server: %s\n", server.Name) serverUid = &server.Uid } containers, err := client.GetContainers(stack.Uid, serverUid, &flagServiceName) must(err) printContainerList(w, containers, flagTruncate) }
func runContainerExec(c *cli.Context) { if len(c.Args()) != 2 { cli.ShowSubcommandHelp(c) os.Exit(2) } fmt.Println("Running exec on container...") stack := mustStack(c) w := tabwriter.NewWriter(os.Stdout, 1, 2, 2, ' ', 0) defer w.Flush() containerUid := c.Args()[0] command := c.Args()[1] container, err := client.GetContainer(stack.Uid, containerUid) must(err) if container == nil { printFatal("Container with Id '" + containerUid + "' not found") } server, err := client.GetServer(stack.Uid, container.ServerUid, 0) must(err) dockerFlags := c.String("docker-flags") userCommand := fmt.Sprintf("sudo docker exec %s %s %s", dockerFlags, container.Uid, command) err = SshToServerForCommand(*server, userCommand, true) if err != nil { printFatal(err.Error()) } }
func runServerSettings(c *cli.Context) { stack := mustStack(c) // get the server serverName := c.String("server") if len(serverName) == 0 { cli.ShowSubcommandHelp(c) os.Exit(2) } servers, err := client.Servers(stack.Uid) if err != nil { printFatal(err.Error()) } server, err := findServer(servers, serverName) if err != nil { printFatal(err.Error()) } if server == nil { printFatal("Server '" + serverName + "' not found") } fmt.Printf("Server: %s\n", server.Name) getServerSettings(*stack, *server, c.Args()) }
func runServerReboot(c *cli.Context) { stack := mustStack(c) if len(c.Args()) != 0 { cli.ShowSubcommandHelp(c) os.Exit(2) } serverName := c.String("server") servers, err := client.Servers(stack.Uid) if err != nil { printFatal(err.Error()) } server, err := findServer(servers, serverName) if err != nil { printFatal(err.Error()) } if server == nil { printFatal("Server '" + serverName + "' not found") } fmt.Printf("Server: %s\n", server.Name) // confirmation is needed if the stack is production if !c.Bool("y") { mustConfirm("This operation will reboot your server during which time your server will not be available. Proceed with reboot? [yes/N]", "yes") } executeServerReboot(*stack, *server) }
func runRun(c *cli.Context) { if runtime.GOOS == "windows" { printFatal("Not supported on Windows") os.Exit(2) } stack := mustStack(c) if c.String("service") != "" && stack.Framework != "docker" { printFatal("The service option only applies to docker stacks") os.Exit(2) } serverName := c.String("server") if !c.IsSet("service") { if len(c.Args()) != 1 { cli.ShowCommandHelp(c, "run") os.Exit(2) } } userCommand := "" if len(c.Args()) == 1 { userCommand = c.Args()[0] } servers, err := client.Servers(stack.Uid) if err != nil { printFatal(err.Error()) } server, err := findServer(servers, serverName) if err != nil { printFatal(err.Error()) } if server == nil { printFatal("Server '" + serverName + "' not found") } if c.String("service") != "" { // fetch service information for existing server/command service, err := client.GetService(stack.Uid, c.String("service"), &server.Uid, &userCommand) must(err) userCommand = service.WrapCommand } includeTty := c.String("service") != "" err = SshToServerForCommand(*server, userCommand, includeTty) if err != nil { printFatal(err.Error()) } }
func runUpload(c *cli.Context) { if runtime.GOOS == "windows" { printFatal("Not supported on Windows") os.Exit(2) } stack := mustStack(c) // args start after stack name // and check if user specified target directory var targetDirectory string = "" if len(c.Args()) < 1 { cli.ShowCommandHelp(c, "upload") os.Exit(2) } else if len(c.Args()) == 2 { targetDirectory = c.Args()[1] } // get the server serverName := c.String("server") // get the file path filePath := c.Args()[0] servers, err := client.Servers(stack.Uid) if err != nil { printFatal(err.Error()) } server, err := findServer(servers, serverName) if err != nil { printError("server not found, please ensure correct server is specified in command.") os.Exit(2) } if server == nil { printFatal("Server '" + serverName + "' not found") } fmt.Printf("Server: %s\n", server.Name) if targetDirectory == "" { err = sshToServerToUpload(*server, filePath) } else { err = sshToServerToUpload(*server, filePath, targetDirectory) } if err != nil { printFatal(err.Error()) } }
func runJobs(c *cli.Context) { flagServer := c.String("server") flagServiceName := c.String("service") stack := mustStack(c) w := tabwriter.NewWriter(os.Stdout, 1, 2, 2, ' ', 0) defer w.Flush() var serverUid *string if flagServer == "" { serverUid = nil } else { servers, err := client.Servers(stack.Uid) if err != nil { printFatal(err.Error()) } server, err := findServer(servers, flagServer) if err != nil { printFatal(err.Error()) } if server == nil { printFatal("Server '" + flagServer + "' not found") } if !server.HasRole("docker") { printFatal("Server '" + flagServer + "' can not host containers") } fmt.Printf("Server: %s\n", server.Name) serverUid = &server.Uid } var ( jobs []cloud66.Job err error ) if flagServiceName == "" { jobs, err = client.GetJobs(stack.Uid, serverUid) must(err) } // else { // service, err := client.GetService(stack.Uid, flagServiceName, serverUid, nil) // must(err) // if service == nil { // printFatal("Service '" + flagServiceName + "' not found on specified stack") // } else { // services = make([]cloud66.Service, 1) // services[0] = *service // } // } printJobsList(w, jobs, flagServer) }
func runLease(c *cli.Context) { stack := mustStack(c) from := c.String("from") tto := c.Int("tto") port := c.Int("port") fmt.Printf("Attempting to lease from %s to port %d for %d minutes...\n", from, port, tto) genericRes, err := client.LeaseSync(stack.Uid, &from, &tto, &port, nil) if err != nil { printFatal(err.Error()) } printGenericResponse(*genericRes) }
func runUpdate(c *cli.Context) { debugMode = c.GlobalBool("debug") flagForcedVersion = c.String("force") if debugMode { fmt.Printf("Current version is %s\n", VERSION) if flagForcedVersion == "" { fmt.Println("No forced version") } else { fmt.Printf("Forced version is %s\n", flagForcedVersion) } } updateIt, err := needUpdate() if err != nil { if debugMode { fmt.Printf("Cannot verify need for update %v\n", err) } return } if !updateIt { if debugMode { fmt.Println("No need for update") } return } // houston we have an update. which one do we need? download, err := getVersionManifest(flagForcedVersion) if err != nil { if debugMode { fmt.Printf("Error fetching manifest %v\n", err) } } if download == nil { if debugMode { fmt.Println("Found no matching download for the current OS and ARCH") } return } err = download.update() if err != nil { if debugMode { fmt.Printf("Failed to update: %v\n", err) } return } }
func runDownloadManifestYaml(c *cli.Context, stackUid string) { version := c.String("version") if version == "" { version = "latest" } manifestYaml, err := client.ManifestYamlInfo(stackUid, version) must(err) output := c.String("output") if output != "" { err := writeFile(output, manifestYaml.Body) must(err) } else { fmt.Println(manifestYaml.Body) } }
func runStacks(c *cli.Context) { w := tabwriter.NewWriter(os.Stdout, 1, 2, 2, ' ', 0) defer w.Flush() var stacks []cloud66.Stack names := c.Args() flagForcedEnvironment := c.String("environment") if len(names) == 0 { var err error stacks, err = client.StackListWithFilter(func(item interface{}) bool { if flagForcedEnvironment == "" { return true } return strings.HasPrefix(strings.ToLower(item.(cloud66.Stack).Environment), strings.ToLower(flagForcedEnvironment)) }) must(err) } else { stackch := make(chan *cloud66.Stack, len(names)) errch := make(chan error, len(names)) for _, name := range names { if name == "" { stackch <- nil } else { go func(stackname string) { if stack, err := client.StackInfoWithEnvironment(stackname, flagForcedEnvironment); err != nil { errch <- err } else { stackch <- stack } }(name) } } for _ = range names { select { case err := <-errch: printFatal(err.Error()) case stack := <-stackch: if stack != nil { stacks = append(stacks, *stack) } } } } printStackList(w, stacks) }
func runServiceStop(c *cli.Context) { if len(c.Args()) != 1 { cli.ShowSubcommandHelp(c) os.Exit(2) } stack := mustStack(c) serviceName := c.Args()[0] flagServer := c.String("server") var serverUid *string if flagServer == "" { serverUid = nil } else { servers, err := client.Servers(stack.Uid) if err != nil { printFatal(err.Error()) } server, err := findServer(servers, flagServer) if err != nil { printFatal(err.Error()) } if server == nil { printFatal("Server '" + flagServer + "' not found") } if !server.HasRole("docker") { printFatal("Server '" + flagServer + "' can not host containers") } fmt.Printf("Server: %s\n", server.Name) serverUid = &server.Uid } asyncId, err := startServiceStop(stack.Uid, serviceName, serverUid) if err != nil { printFatal(err.Error()) } genericRes, err := endServiceStop(*asyncId, stack.Uid) if err != nil { printFatal(err.Error()) } printGenericResponse(*genericRes) return }
func runServerSet(c *cli.Context) { fmt.Println(c.Args()) stack := mustStack(c) if len(c.Args()) != 1 { cli.ShowSubcommandHelp(c) os.Exit(2) } // get the server args := c.Args() serverName := c.String("server") // filter out the server name kvs := args[0] kva := strings.Split(kvs, "=") if len(kva) != 2 { cli.ShowSubcommandHelp(c) os.Exit(2) } key := kva[0] value := kva[1] servers, err := client.Servers(stack.Uid) if err != nil { printFatal(err.Error()) } server, err := findServer(servers, serverName) if err != nil { printFatal(err.Error()) } if server == nil { printFatal("Server '" + serverName + "' not found") } fmt.Printf("Server: %s\n", server.Name) executeServerSet(*stack, *server, c, key, value) }
func runServiceInfo(c *cli.Context) { if len(c.Args()) != 1 { cli.ShowSubcommandHelp(c) os.Exit(2) } w := tabwriter.NewWriter(os.Stdout, 1, 2, 2, ' ', 0) defer w.Flush() stack := mustStack(c) serviceName := c.Args()[0] flagServer := c.String("server") var serverUid *string if flagServer == "" { serverUid = nil } else { servers, err := client.Servers(stack.Uid) if err != nil { printFatal(err.Error()) } server, err := findServer(servers, flagServer) if err != nil { printFatal(err.Error()) } if server == nil { printFatal("Server '" + flagServer + "' not found") } if !server.HasRole("docker") { printFatal("Server '" + flagServer + "' is not a docker server") } fmt.Printf("Server: %s\n", server.Name) serverUid = &server.Uid } service, err := client.GetService(stack.Uid, serviceName, serverUid, nil) must(err) printServiceInfoList(w, service) return }
func runSlaveResync(c *cli.Context) { stack := mustStack(c) if len(c.Args()) < 1 { cli.ShowSubcommandHelp(c) os.Exit(2) } // get the server serverName := c.Args()[0] flagDbType := c.String("dbtype") servers, err := client.Servers(stack.Uid) if err != nil { printFatal(err.Error()) } server, err := findServer(servers, serverName) if err != nil { printFatal(err.Error()) } if server == nil { printFatal("Server '" + serverName + "' not found") } fmt.Printf("Server: %s\n", server.Name) currenttime := time.Now().Local() fmt.Printf("Started: %s\n", currenttime.Format("2006-01-02 15:04:05")) asyncId, err := startSlaveResync(stack.Uid, server.Uid, &flagDbType) if err != nil { printFatal(err.Error()) } genericRes, err := endSlaveResync(*asyncId, stack.Uid) if err != nil { printFatal(err.Error()) } printGenericResponse(*genericRes) }
func runRedeploy(c *cli.Context) { stack := mustStack(c) // confirmation is needed if the stack is production if stack.Environment == "production" && !c.Bool("y") { mustConfirm("This is a production stack. Proceed with deployment? [yes/N]", "yes") } if len(c.StringSlice("service")) > 0 { fmt.Printf("Deploying service(s): ") for i, service := range c.StringSlice("service") { if i > 0 { fmt.Printf(", ") } fmt.Printf(service) } fmt.Printf("\n") } result, err := client.RedeployStack(stack.Uid, c.String("git-ref"), c.StringSlice("service")) must(err) if !c.Bool("listen") || result.Queued { // its queued - just message and exit fmt.Println(result.Message) } else { // tail the logs go StartListen(stack) stack, err = WaitStackBuild(stack.Uid, false) must(err) if stack.HealthCode == 2 || stack.HealthCode == 4 || stack.StatusCode == 2 || stack.StatusCode == 7 { fmt.Println("Completed with some errors!") } else { fmt.Println("Completed successfully!") } } }
func runNewBackup(c *cli.Context) { stack := mustStack(c) var flagDbTypes *string if c.IsSet("dbtypes") { flagDbTypes = new(string) *flagDbTypes = c.String("dbtypes") } var flagFrequency *string if c.IsSet("frequency") { flagFrequency = new(string) *flagFrequency = c.String("frequency") } var flagKeep *int if c.IsSet("keep") { flagKeep = new(int) *flagKeep = c.Int("keep") } var flagGzip *bool if c.IsSet("gzip") { flagGzip = new(bool) *flagGzip = c.Bool("gzip") } var flagExcludetables *string if c.IsSet("exclude-tables") { flagExcludetables = new(string) *flagExcludetables = c.String("exclude-tables") } var flagRunonreplica *bool if c.IsSet("run-on-replica") { flagRunonreplica = new(bool) *flagRunonreplica = c.Bool("run-on-replica") } err := client.NewBackup(stack.Uid, flagDbTypes, flagFrequency, flagKeep, flagGzip, flagExcludetables, flagRunonreplica) if err != nil { printFatal("Error during backup creation: " + err.Error()) return } fmt.Println("queued for creation") }
func mustFile(c *cli.Context) ConfigureFile { var file ConfigureFile switch c.String("file") { case "service.yml": file = ConfigureFile{ Name: c.String("file"), ListFunc: runServiceYamlList, DownloadFunc: runDownloadServiceYaml, UploadFunc: runUploadServiceYaml} case "manifest.yml": file = ConfigureFile{ Name: c.String("file"), ListFunc: runManifestYamlList, DownloadFunc: runDownloadManifestYaml, UploadFunc: runUploadManifestYaml} default: printFatal("No file type specified or file type is not supported. Use --file flag to choose file type. supported values are: service.yml , manifest.yml") } return file }
func runServiceScale(c *cli.Context) { if len(c.Args()) != 2 { cli.ShowSubcommandHelp(c) os.Exit(2) } stack := mustStack(c) serviceName := c.Args()[0] count := c.Args()[1] flagServer := c.String("server") flagGroup := c.String("group") // fetch servers info servers, err := client.Servers(stack.Uid) must(err) if flagServer != "" { server, err := findServer(servers, flagServer) must(err) if server == nil { printFatal("Server '" + flagServer + "' not found") } if !server.HasRole("docker") { printFatal("Server '" + flagServer + "' can not host containers") } fmt.Printf("Server: %s\n", server.Name) // filter servers collection down servers = make([]cloud66.Server, 1) servers[0] = *server } if flagGroup != "" { if flagGroup != "web" { printFatal("Only web group is supported at the moment") } } // param for api call serverCountDesired := make(map[string]int) var absoluteCount int if strings.ContainsAny(count, "+ & -") { // fetch service information for existing counts service, err := client.GetService(stack.Uid, serviceName, nil, nil) must(err) serverCountCurrent := service.ServerContainerCountMap() relativeCount, _ := strconv.Atoi(count) for _, server := range servers { if _, present := serverCountCurrent[server.Name]; present { serverCountDesired[server.Uid] = relativeCount + serverCountCurrent[server.Name] } else { serverCountDesired[server.Uid] = relativeCount } } } else { absoluteCount, _ = strconv.Atoi(count) for _, server := range servers { serverCountDesired[server.Uid] = absoluteCount } } // validate non < 0 for serverUid, count := range serverCountDesired { if count < 0 { serverCountDesired[serverUid] = 0 } } fmt.Println("Scaling your '" + serviceName + "' service") var asyncId *int if flagGroup != "" { var groupMap = make(map[string]int) groupMap["web"] = absoluteCount asyncId, err = startServiceScaleByGroup(stack.Uid, serviceName, groupMap) } else { asyncId, err = startServiceScale(stack.Uid, serviceName, serverCountDesired) } must(err) genericRes, err := endServiceScale(*asyncId, stack.Uid) must(err) printGenericResponse(*genericRes) return }
func runCreateStack(c *cli.Context) { name := c.String("name") environment := c.String("environment") serviceYamlFile := c.String("service_yaml") manifestYamlFile := c.String("manifest_yaml") manifestYaml := "" if len(name) < 5 { printFatal("name is required and must be at least 5 characters long") } if environment == "" { printFatal("environment is required") } // handle service yaml file if serviceYamlFile == "" { printFatal("service_yaml file path is required") } else { serviceYamlFile = expandPath(serviceYamlFile) } serviceYamlBytes, err := ioutil.ReadFile(serviceYamlFile) must(err) serviceYaml := string(serviceYamlBytes) accountInfo, err := currentAccountInfo() must(err) fmt.Printf("Using account: %s\n", accountInfo.Owner) targetOptions := make(map[string]string) if manifestYamlFile != "" { fmt.Println("Using supplied manifest file") manifestYamlFile = expandPath(manifestYamlFile) manifestYamlBytes, err := ioutil.ReadFile(manifestYamlFile) must(err) manifestYaml = string(manifestYamlBytes) } else { fmt.Println("Note: No manifest provided; for additional options you can provide your own manifest with this command") targetCloud, err := askForCloud(*accountInfo) must(err) targetOptions["cloud"] = targetCloud.Id targetOptions["key_name"] = targetCloud.KeyName targetRegion, targetSize, err := askForSizeAndRegion(*targetCloud) must(err) targetOptions["region"] = targetRegion targetOptions["size"] = targetSize targetBuildType, err := askForBuildType() must(err) targetOptions["build_type"] = targetBuildType } asyncId, err := startCreateStack(name, environment, serviceYaml, manifestYaml, targetOptions) must(err) // now we fetch the corresponding stack stack, err := client.StackInfoWithEnvironment(name, environment) must(err) // wait for the stack analysis to complete _, err = endCreateStack(*asyncId, stack.Uid) must(err) fmt.Printf("\nStack created; Build starting...\n\n") err = initiateStackBuild(stack.Uid) must(err) // logging output go StartListen(stack) stack, err = WaitStackBuild(stack.Uid, false) must(err) fmt.Println("Stack build completed successfully!") }
func stack(c *cli.Context) (*cloud66.Stack, error) { if flagStack != nil { return flagStack, nil } if c.String("environment") != "" { flagEnvironment = c.String("environment") } var err error if c.String("stack") != "" { stacks, err := client.StackListWithFilter(filterByEnvironmentExact) if err != nil { return nil, err } var stackNames []string for _, stack := range stacks { stackNames = append(stackNames, stack.Name) } idx, err := fuzzyFind(stackNames, c.String("stack"), false) if err != nil { // try fuzzy env match stacks, err = client.StackListWithFilter(filterByEnvironmentFuzzy) if err != nil { return nil, err } var stackFuzzNames []string for _, stack := range stacks { stackFuzzNames = append(stackFuzzNames, stack.Name) } idx, err = fuzzyFind(stackFuzzNames, c.String("stack"), false) if err != nil { return nil, err } } flagStack = &stacks[idx] // toSdout is of type []bool. Take first value if c.String("environment") != "" { fmt.Printf("(%s)\n", flagStack.Environment) } return flagStack, err } if stack := c.String("cxstack"); stack != "" { // the environment variable should be exact match flagStack, err = client.StackInfo(stack) return flagStack, err } return stackFromGitRemote(remoteGitUrl(), localGitBranch()) }
func runDownloadBackup(c *cli.Context) { if len(c.Args()) == 0 { //cmd.printUsage() os.Exit(2) } stack := mustStack(c) backupId, err := strconv.Atoi(c.Args()[0]) if err != nil { //cmd.printUsage() os.Exit(2) } segmentIndeces, err := client.GetBackupSegmentIndeces(stack.Uid, backupId) must(err) if len(segmentIndeces) < 1 { printFatal("Cannot find file segments associated with this backup") } flagDownloadDir := c.String("directory") mainDir := filepath.Join(homePath(), "cx_backups") if flagDownloadDir != "" { mainDir = flagDownloadDir } // create a download tmp folder dir := filepath.Join(mainDir, "tmp", c.Args()[0]) err = os.MkdirAll(dir, 0777) must(err) var files = []string{} for _, segmentIndex := range segmentIndeces { segment, err := client.GetBackupSegment(stack.Uid, backupId, segmentIndex.Extension) must(err) fmt.Printf("Downloading %s to %s\n", segmentIndex.Filename, dir) // this should be moved to go routines toFile := filepath.Join(dir, segmentIndex.Filename) err = downloadFile(segment.Url, toFile) must(err) files = append(files, toFile) } toFile := filepath.Join(mainDir, "backup_"+c.Args()[0]+".tar") fmt.Printf("Concatenating files to %s\n", toFile) err = appendFiles(files, toFile) if err != nil { printFatal("Error during concatenation: " + err.Error()) return } // remove the temp if !debugMode { os.RemoveAll(dir) fmt.Printf("Deleting %s\n", dir) } fmt.Println("Done") }