github.com/cloud-foundations/dominator@v0.0.0-20221004181915-6e4fee580046/cmd/hyper-control/netbootVm.go (about) 1 package main 2 3 import ( 4 "fmt" 5 6 hyperclient "github.com/Cloud-Foundations/Dominator/hypervisor/client" 7 "github.com/Cloud-Foundations/Dominator/lib/errors" 8 "github.com/Cloud-Foundations/Dominator/lib/log" 9 "github.com/Cloud-Foundations/Dominator/lib/srpc" 10 fm_proto "github.com/Cloud-Foundations/Dominator/proto/fleetmanager" 11 hyper_proto "github.com/Cloud-Foundations/Dominator/proto/hypervisor" 12 ) 13 14 func netbootVmSubcommand(args []string, logger log.DebugLogger) error { 15 err := netbootVm(logger) 16 if err != nil { 17 return fmt.Errorf("Error netbooting VM: %s", err) 18 } 19 return nil 20 } 21 22 func netbootVm(logger log.DebugLogger) error { 23 if len(subnetIDs) < 1 { 24 return errors.New("no subnetIDs specified") 25 } 26 fmCR := srpc.NewClientResource("tcp", 27 fmt.Sprintf("%s:%d", *fleetManagerHostname, *fleetManagerPortNum)) 28 defer fmCR.ScheduleClose() 29 imageClient, err := srpc.DialHTTP("tcp", fmt.Sprintf("%s:%d", 30 *imageServerHostname, *imageServerPortNum), 0) 31 if err != nil { 32 return fmt.Errorf("%s: %s", *imageServerHostname, err) 33 } 34 defer imageClient.Close() 35 var hypervisorAddresses []string 36 if *hypervisorHostname != "" { 37 hypervisorAddresses = append(hypervisorAddresses, 38 fmt.Sprintf("%s:%d", *hypervisorHostname, *hypervisorPortNum)) 39 } else { 40 hypervisorAddresses, err = listConnectedHypervisorsInLocation(fmCR, 41 *location) 42 if err != nil { 43 return err 44 } 45 } 46 if len(hypervisorAddresses) < 1 { 47 return errors.New("no nearby Hypervisors available") 48 } 49 logger.Debugf(0, "Selected %s as boot server on subnet: %s\n", 50 hypervisorAddresses[0], subnetIDs[0]) 51 hyperCR := srpc.NewClientResource("tcp", hypervisorAddresses[0]) 52 defer hyperCR.ScheduleClose() 53 client, err := hyperCR.GetHTTP(nil, 0) 54 if err != nil { 55 return err 56 } 57 defer client.Put() 58 hypervisorSubnets, err := hyperclient.ListSubnets(client, false) 59 if err != nil { 60 return err 61 } 62 subnetTable := make(map[string]hyper_proto.Subnet, len(hypervisorSubnets)) 63 for _, subnet := range hypervisorSubnets { 64 subnetTable[subnet.Id] = subnet 65 } 66 var subnets []*hyper_proto.Subnet 67 for _, subnetId := range subnetIDs { 68 if subnet, ok := subnetTable[subnetId]; !ok { 69 return fmt.Errorf("subnet: %s not available on: %s", 70 subnetId, hypervisorAddresses[0]) 71 } else { 72 subnets = append(subnets, &subnet) 73 } 74 } 75 info := fm_proto.GetMachineInfoResponse{Subnets: subnets} 76 createRequest := hyper_proto.CreateVmRequest{ 77 DhcpTimeout: -1, 78 EnableNetboot: true, 79 MinimumFreeBytes: uint64(volumeSizes[0]), 80 VmInfo: hyper_proto.VmInfo{ 81 ConsoleType: hyper_proto.ConsoleVNC, 82 Hostname: "netboot-test", 83 MemoryInMiB: uint64(memory >> 20), 84 MilliCPUs: 1000, 85 SecondarySubnetIDs: subnetIDs[1:], 86 SubnetId: subnetIDs[0], 87 }, 88 } 89 if createRequest.VmInfo.MemoryInMiB < 1 { 90 createRequest.VmInfo.MemoryInMiB = 1024 91 } 92 for _, size := range volumeSizes[1:] { 93 createRequest.SecondaryVolumes = append(createRequest.SecondaryVolumes, 94 hyper_proto.Volume{Size: uint64(size)}) 95 } 96 var createResponse hyper_proto.CreateVmResponse 97 err = hyperclient.CreateVm(client, createRequest, &createResponse, logger) 98 if err != nil { 99 return err 100 } 101 err = hyperclient.AcknowledgeVm(client, createResponse.IpAddress) 102 if err != nil { 103 return err 104 } 105 logger.Printf("created VM: %s\n", createResponse.IpAddress) 106 vmInfo, err := hyperclient.GetVmInfo(client, createResponse.IpAddress) 107 if err != nil { 108 return err 109 } 110 vncErrChannel := make(chan error, 1) 111 if *vncViewer == "" { 112 vncErrChannel <- nil 113 } else { 114 defer hyperclient.DestroyVm(client, createResponse.IpAddress, nil) 115 client, err := srpc.DialHTTP("tcp", hypervisorAddresses[0], 0) 116 if err != nil { 117 return err 118 } 119 go func() { 120 defer client.Close() 121 vncErrChannel <- hyperclient.ConnectToVmConsole(client, 122 vmInfo.Address.IpAddress, *vncViewer, logger) 123 }() 124 } 125 info.Machine.NetworkEntry = fm_proto.NetworkEntry{ 126 Hostname: vmInfo.Hostname, 127 HostIpAddress: vmInfo.Address.IpAddress, 128 SubnetId: subnetIDs[0], 129 } 130 err = info.Machine.HostMacAddress.UnmarshalText( 131 []byte(vmInfo.Address.MacAddress)) 132 if err != nil { 133 return err 134 } 135 for index, subnetId := range subnetIDs { 136 if index < 1 { 137 continue 138 } 139 address := vmInfo.SecondaryAddresses[index-1] 140 var hwAddr fm_proto.HardwareAddr 141 if err := hwAddr.UnmarshalText([]byte(address.MacAddress)); err != nil { 142 return err 143 } 144 info.Machine.SecondaryNetworkEntries = append( 145 info.Machine.SecondaryNetworkEntries, fm_proto.NetworkEntry{ 146 HostIpAddress: address.IpAddress, 147 HostMacAddress: hwAddr, 148 SubnetId: subnetId, 149 }) 150 } 151 configFiles, err := makeConfigFiles(info, "", getNetworkEntries(info), 152 false) 153 netbootRequest := hyper_proto.NetbootMachineRequest{ 154 Address: vmInfo.Address, 155 Files: configFiles, 156 FilesExpiration: *netbootFilesTimeout, 157 Hostname: vmInfo.Hostname, 158 NumAcknowledgementsToWaitFor: *numAcknowledgementsToWaitFor, 159 OfferExpiration: *offerTimeout, 160 WaitTimeout: *netbootTimeout, 161 } 162 var netbootResponse hyper_proto.NetbootMachineResponse 163 err = client.RequestReply("Hypervisor.NetbootMachine", netbootRequest, 164 &netbootResponse) 165 if err != nil { 166 return err 167 } 168 if err := errors.New(netbootResponse.Error); err != nil { 169 return err 170 } 171 logger.Println("waiting for console exit") 172 return <-vncErrChannel 173 }