func waitSSHConnection(ctx CommandContext, args RunArgs, serverID string) (chan notifSSHConnection, string, error) { notif := make(chan notifSSHConnection) // Resolve gateway gateway, err := api.ResolveGateway(ctx.API, args.Gateway) if err != nil { return nil, "", fmt.Errorf("cannot resolve Gateway '%s': %v", args.Gateway, err) } // waiting for server to be ready logrus.Debug("Waiting for server to be ready") // We wait for 30 seconds, which is the minimal amount of time needed by a server to boot go func() { server, err := api.WaitForServerReady(ctx.API, serverID, gateway) if err != nil { notif <- notifSSHConnection{ err: fmt.Errorf("cannot get access to server %s: %v", serverID, err), } return } logrus.Debugf("SSH server is available: %s:22", server.PublicAddress.IP) logrus.Info("Server is ready !") notif <- notifSSHConnection{ server: server, } }() return notif, gateway, nil }
// restartIdentifiers resolves server IDs, restarts, and waits for them to be ready (-w) func restartIdentifiers(ctx CommandContext, wait bool, servers []string, cr chan string) { var wg sync.WaitGroup for _, needle := range servers { wg.Add(1) go func(needle string) { defer wg.Done() server := ctx.API.GetServerID(needle) res := server err := ctx.API.PostServerAction(server, "reboot") if err != nil { if err.Error() != "server is being stopped or rebooted" { logrus.Errorf("failed to restart server %s: %s", server, err) } res = "" } else { if wait { // FIXME: handle gateway api.WaitForServerReady(ctx.API, server, "") } } cr <- res }(needle) } wg.Wait() close(cr) }
func resourceServerCreate(d *schema.ResourceData, m interface{}) error { scaleway := m.(*api.ScalewayAPI) image := d.Get("image").(string) volumes := make(map[string]string) /*for k, v := range d.Get("volumes").(map[string]interface{}) { volumes[k] = v.(string) }*/ var def api.ScalewayServerDefinition def.Name = d.Get("name").(string) def.Image = &image def.Volumes = volumes if bootscriptI, ok := d.GetOk("bootscript"); ok { bootscript := bootscriptI.(string) def.Bootscript = &bootscript } if tags, ok := d.GetOk("tags"); ok { def.Tags = tags.([]string) } id, err := scaleway.PostServer(def) if err != nil { serr := err.(api.ScalewayAPIError) // _, _ := json.Marshal(def) return fmt.Errorf("Error Posting server with image %s. Reason: %s", image, serr.APIMessage) } err = scaleway.PostServerAction(id, "poweron") if err != nil { return err } d.SetId(id) _, err = api.WaitForServerReady(scaleway, id, "") if err != nil { return err } return resourceServerRead(d, m) }
// RunExec is the handler for 'scw exec' func RunExec(ctx CommandContext, args ExecArgs) error { var fingerprints []string done := make(chan struct{}) serverID, err := ctx.API.GetServerID(args.Server) if err != nil { return err } go func() { fingerprints = ctx.API.GetSSHFingerprintFromServer(serverID) close(done) }() // Resolve gateway if args.Gateway == "" { args.Gateway = ctx.Getenv("SCW_GATEWAY") } var gateway string if args.Gateway == serverID || args.Gateway == args.Server { logrus.Debugf("The server and the gateway are the same host, using direct access to the server") gateway = "" } else { gateway, err = api.ResolveGateway(ctx.API, args.Gateway) if err != nil { return fmt.Errorf("Cannot resolve Gateway '%s': %v", args.Gateway, err) } if gateway != "" { logrus.Debugf("The server will be accessed using the gateway '%s' as a SSH relay", gateway) } } var server *api.ScalewayServer if args.Wait { // --wait logrus.Debugf("Waiting for server to be ready") server, err = api.WaitForServerReady(ctx.API, serverID, gateway) if err != nil { return fmt.Errorf("Failed to wait for server to be ready, %v", err) } } else { // no --wait logrus.Debugf("scw won't wait for the server to be ready, if it is not, the command will fail") server, err = ctx.API.GetServer(serverID) if err != nil { rerr := fmt.Errorf("Failed to get server information for %s: %v", serverID, err) if err.Error() == `"`+serverID+`" not found` { return fmt.Errorf("%v\nmaybe try to flush the cache with : scw _flush-cache", rerr) } return rerr } } if server.PublicAddress.IP == "" && gateway == "" { logrus.Warn(`Your host has no public IP address, you should use '--gateway', see 'scw help exec'`) } // --timeout if args.Timeout > 0 { logrus.Debugf("Setting up a global timeout of %d seconds", args.Timeout) // FIXME: avoid use of log.Fatalf here go func() { time.Sleep(time.Duration(args.Timeout*1000) * time.Millisecond) logrus.Fatalf("Operation timed out") }() } <-done if len(fingerprints) > 0 { for i := range fingerprints { fmt.Fprintf(ctx.Stdout, "%s\n", fingerprints[i]) } } logrus.Debugf("PublicDNS %s", serverID+api.URLPublicDNS) logrus.Debugf("PrivateDNS %s", serverID+api.URLPrivateDNS) if err = utils.SSHExec(server.PublicAddress.IP, server.PrivateIP, args.SSHUser, args.SSHPort, args.Command, !args.Wait, gateway); err != nil { return fmt.Errorf("Failed to run the command: %v", err) } logrus.Debugf("Command successfully executed") return nil }
// Run is the handler for 'scw run' func Run(ctx CommandContext, args RunArgs) error { if args.Gateway == "" { args.Gateway = ctx.Getenv("SCW_GATEWAY") } if args.TmpSSHKey { err := AddSSHKeyToTags(ctx, &args.Tags, args.Image) if err != nil { return err } } env := strings.Join(args.Tags, " ") volume := strings.Join(args.Volumes, " ") // create IMAGE logrus.Info("Server creation ...") dynamicIPRequired := args.Gateway == "" serverID, err := api.CreateServer(ctx.API, args.Image, args.Name, args.Bootscript, env, volume, dynamicIPRequired) if err != nil { return fmt.Errorf("failed to create server: %v", err) } logrus.Infof("Server created: %s", serverID) if args.AutoRemove { defer ctx.API.DeleteServerSafe(serverID) } // start SERVER logrus.Info("Server start requested ...") err = api.StartServer(ctx.API, serverID, false) if err != nil { return fmt.Errorf("failed to start server %s: %v", serverID, err) } logrus.Info("Server is starting, this may take up to a minute ...") if args.Detach { fmt.Fprintln(ctx.Stdout, serverID) return nil } else { // Sync cache on disk ctx.API.Sync() } if args.Attach { // Attach to server serial logrus.Info("Attaching to server console ...") err = utils.AttachToSerial(serverID, ctx.API.Token, true) if err != nil { return fmt.Errorf("cannot attach to server serial: %v", err) } } else { // Resolve gateway gateway, err := api.ResolveGateway(ctx.API, args.Gateway) if err != nil { return fmt.Errorf("cannot resolve Gateway '%s': %v", args.Gateway, err) } // waiting for server to be ready logrus.Debug("Waiting for server to be ready") // We wait for 30 seconds, which is the minimal amount of time needed by a server to boot server, err := api.WaitForServerReady(ctx.API, serverID, gateway) if err != nil { return fmt.Errorf("cannot get access to server %s: %v", serverID, err) } logrus.Debugf("SSH server is available: %s:22", server.PublicAddress.IP) logrus.Info("Server is ready !") // exec -w SERVER COMMAND ARGS... if len(args.Command) < 1 { logrus.Info("Connecting to server ...") err = utils.SSHExec(server.PublicAddress.IP, server.PrivateIP, []string{}, false, gateway) } else { logrus.Infof("Executing command: %s ...", args.Command) err = utils.SSHExec(server.PublicAddress.IP, server.PrivateIP, args.Command, false, gateway) } if err != nil { return fmt.Errorf("command execution failed: %v", err) } logrus.Info("Command successfuly executed") } return nil }