github.com/cloud-foundations/dominator@v0.0.0-20221004181915-6e4fee580046/cmd/vm-control/replaceVmImage.go (about) 1 package main 2 3 import ( 4 "bufio" 5 "errors" 6 "fmt" 7 "io" 8 "net" 9 10 "github.com/Cloud-Foundations/Dominator/lib/log" 11 "github.com/Cloud-Foundations/Dominator/lib/srpc" 12 proto "github.com/Cloud-Foundations/Dominator/proto/hypervisor" 13 ) 14 15 func replaceVmImageSubcommand(args []string, logger log.DebugLogger) error { 16 if err := replaceVmImage(args[0], logger); err != nil { 17 return fmt.Errorf("Error replacing VM image: %s", err) 18 } 19 return nil 20 } 21 22 func callReplaceVmImage(client *srpc.Client, 23 request proto.ReplaceVmImageRequest, reply *proto.ReplaceVmImageResponse, 24 imageReader io.Reader, logger log.DebugLogger) error { 25 conn, err := client.Call("Hypervisor.ReplaceVmImage") 26 if err != nil { 27 return err 28 } 29 defer conn.Close() 30 if err := conn.Encode(request); err != nil { 31 return err 32 } 33 // Stream any required data. 34 if imageReader != nil { 35 logger.Debugln(0, "uploading image") 36 if _, err := io.Copy(conn, imageReader); err != nil { 37 return err 38 } 39 } 40 if err := conn.Flush(); err != nil { 41 return err 42 } 43 for { 44 var response proto.ReplaceVmImageResponse 45 if err := conn.Decode(&response); err != nil { 46 return err 47 } 48 if response.Error != "" { 49 return errors.New(response.Error) 50 } 51 if response.ProgressMessage != "" { 52 logger.Debugln(0, response.ProgressMessage) 53 } 54 if response.Final { 55 *reply = response 56 return nil 57 } 58 } 59 } 60 61 func replaceVmImage(vmHostname string, logger log.DebugLogger) error { 62 if vmIP, hypervisor, err := lookupVmAndHypervisor(vmHostname); err != nil { 63 return err 64 } else { 65 return replaceVmImageOnHypervisor(hypervisor, vmIP, logger) 66 } 67 } 68 69 func replaceVmImageOnHypervisor(hypervisor string, ipAddr net.IP, 70 logger log.DebugLogger) error { 71 request := proto.ReplaceVmImageRequest{ 72 DhcpTimeout: *dhcpTimeout, 73 IpAddress: ipAddr, 74 MinimumFreeBytes: uint64(minFreeBytes), 75 RoundupPower: *roundupPower, 76 } 77 var imageReader io.Reader 78 if *imageName != "" { 79 request.ImageName = *imageName 80 request.ImageTimeout = *imageTimeout 81 request.SkipBootloader = *skipBootloader 82 } else if *imageURL != "" { 83 request.ImageURL = *imageURL 84 } else if *imageFile != "" { 85 file, size, err := getReader(*imageFile) 86 if err != nil { 87 return err 88 } else { 89 defer file.Close() 90 request.ImageDataSize = uint64(size) 91 imageReader = bufio.NewReader(io.LimitReader(file, size)) 92 } 93 } else { 94 return errors.New("no image specified") 95 } 96 client, err := dialHypervisor(hypervisor) 97 if err != nil { 98 return err 99 } 100 defer client.Close() 101 var reply proto.ReplaceVmImageResponse 102 err = callReplaceVmImage(client, request, &reply, imageReader, logger) 103 if err != nil { 104 return err 105 } 106 return nil 107 }