diff --git a/src/cloud-api-adaptor/cmd/cloud-api-adaptor/main.go b/src/cloud-api-adaptor/cmd/cloud-api-adaptor/main.go index 5f9e17635..60503c1e7 100644 --- a/src/cloud-api-adaptor/cmd/cloud-api-adaptor/main.go +++ b/src/cloud-api-adaptor/cmd/cloud-api-adaptor/main.go @@ -125,6 +125,7 @@ func (cfg *daemonConfig) Setup() (cmd.Starter, error) { flags.StringVar(&cfg.serverConfig.Initdata, "initdata", "", "Default initdata for all Pods") flags.BoolVar(&cfg.serverConfig.EnableCloudConfigVerify, "cloud-config-verify", false, "Enable cloud config verify - should use it for production") flags.IntVar(&cfg.serverConfig.PeerPodsLimitPerNode, "peerpods-limit-per-node", 10, "peer pods limit per node (default=10)") + flags.Uint64Var(&cfg.serverConfig.DiskSize, "disk-size", 0, "Disk size in GB. Default is 0, which implies the default image disk size") cloud.ParseCmd(flags) }) diff --git a/src/cloud-api-adaptor/entrypoint.sh b/src/cloud-api-adaptor/entrypoint.sh index 6f32c4917..86dca57d5 100755 --- a/src/cloud-api-adaptor/entrypoint.sh +++ b/src/cloud-api-adaptor/entrypoint.sh @@ -30,6 +30,7 @@ optionals+="" [[ "${SECURE_COMMS_PP_OUTBOUNDS}" ]] && optionals+="-secure-comms-pp-outbounds ${SECURE_COMMS_PP_OUTBOUNDS} " [[ "${SECURE_COMMS_KBS_ADDR}" ]] && optionals+="-secure-comms-kbs ${SECURE_COMMS_KBS_ADDR} " [[ "${PEERPODS_LIMIT_PER_NODE}" ]] && optionals+="-peerpods-limit-per-node ${PEERPODS_LIMIT_PER_NODE} " +[[ "${DISK_SIZE}" ]] && optionals+="-disk-size ${DISK_SIZE} " test_vars() { for i in "$@"; do diff --git a/src/cloud-api-adaptor/pkg/adaptor/cloud/cloud.go b/src/cloud-api-adaptor/pkg/adaptor/cloud/cloud.go index b956f8284..8241a1f0d 100644 --- a/src/cloud-api-adaptor/pkg/adaptor/cloud/cloud.go +++ b/src/cloud-api-adaptor/pkg/adaptor/cloud/cloud.go @@ -64,6 +64,8 @@ type ServerConfig struct { SecureCommsPpOutbounds string SecureCommsKbsAddress string PeerPodsLimitPerNode int + UseEncryptedDisk bool + DiskSize uint64 } var logger = log.New(log.Writer(), "[adaptor/cloud] ", log.LstdFlags|log.Lmsgprefix) @@ -222,7 +224,12 @@ func (s *cloudService) CreateVM(ctx context.Context, req *pb.CreateVMRequest) (r instanceType := util.GetInstanceTypeFromAnnotation(req.Annotations) // Get Pod VM cpu and memory from annotations - vcpus, memory, gpus := util.GetPodvmResourcesFromAnnotation(req.Annotations) + resources := util.GetPodVMResourcesFromAnnotation(req.Annotations) + + // Add disk size to resources if set + if s.serverConfig.DiskSize > 0 { + resources.Storage = int64(s.serverConfig.DiskSize) + } // Get Pod VM image from annotations image := util.GetImageFromAnnotation(req.Annotations) @@ -230,9 +237,7 @@ func (s *cloudService) CreateVM(ctx context.Context, req *pb.CreateVMRequest) (r // Pod VM spec vmSpec := provider.InstanceTypeSpec{ InstanceType: instanceType, - VCPUs: vcpus, - Memory: memory, - GPUs: gpus, + Resources: resources, Image: image, } @@ -332,6 +337,14 @@ func (s *cloudService) CreateVM(ctx context.Context, req *pb.CreateVMRequest) (r }, } + if s.serverConfig.DiskSize > 0 { + // Write an empty file to indicate that we want to use available space as sandbox storage + cloudConfig.WriteFiles = append(cloudConfig.WriteFiles, cloudinit.WriteFile{ + Path: UseScratchPath, + Content: "", + }) + } + if authJSON != nil { if len(authJSON) > cloudinit.DefaultAuthfileLimit { logger.Printf("Credentials file is too large to be included in cloud-config") diff --git a/src/cloud-api-adaptor/pkg/paths/paths.go b/src/cloud-api-adaptor/pkg/paths/paths.go index e5b76414b..4b09a7218 100644 --- a/src/cloud-api-adaptor/pkg/paths/paths.go +++ b/src/cloud-api-adaptor/pkg/paths/paths.go @@ -8,4 +8,5 @@ const ( AgentCfgPath = "/run/peerpod/agent-config.toml" ForwarderCfgPath = "/run/peerpod/daemon.json" UserDataPath = "/run/media/cidata/user-data" + UseScratchPath = "/run/peerpod/mount-scratch" ) diff --git a/src/cloud-api-adaptor/pkg/userdata/provision.go b/src/cloud-api-adaptor/pkg/userdata/provision.go index 830d99740..4adbd440f 100644 --- a/src/cloud-api-adaptor/pkg/userdata/provision.go +++ b/src/cloud-api-adaptor/pkg/userdata/provision.go @@ -37,7 +37,7 @@ const ( ) var logger = log.New(log.Writer(), "[userdata/provision] ", log.LstdFlags|log.Lmsgprefix) -var WriteFilesList = []string{AACfgPath, CDHCfgPath, AgentCfgPath, ForwarderCfgPath, AuthFilePath, InitDataPath} +var WriteFilesList = []string{AACfgPath, CDHCfgPath, AgentCfgPath, ForwarderCfgPath, AuthFilePath, InitDataPath, UseScratchPath} var InitdDataFilesList = []string{AACfgPath, CDHCfgPath, PolicyPath} type Config struct { diff --git a/src/cloud-api-adaptor/pkg/util/cloud.go b/src/cloud-api-adaptor/pkg/util/cloud.go index 9c0dfda81..859eec5fe 100644 --- a/src/cloud-api-adaptor/pkg/util/cloud.go +++ b/src/cloud-api-adaptor/pkg/util/cloud.go @@ -5,6 +5,7 @@ import ( "strconv" "strings" + provider "github.com/confidential-containers/cloud-api-adaptor/src/cloud-providers" cri "github.com/containerd/containerd/pkg/cri/annotations" hypannotations "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/pkg/annotations" ) @@ -44,48 +45,48 @@ func GetImageFromAnnotation(annotations map[string]string) string { } // Method to get vCPU, memory and gpus from annotations -func GetPodvmResourcesFromAnnotation(annotations map[string]string) (int64, int64, int64) { - - var vcpuInt, memoryInt, gpuInt int64 +func GetPodVMResourcesFromAnnotation(annotations map[string]string) provider.PodVMResources { + var vcpus, gpus, memory int64 var err error vcpu, ok := annotations[hypannotations.DefaultVCPUs] if ok { - vcpuInt, err = strconv.ParseInt(vcpu, 10, 64) + vcpus, err = strconv.ParseInt(vcpu, 10, 64) if err != nil { fmt.Printf("Error converting vcpu to int64. Defaulting to 0: %v\n", err) - vcpuInt = 0 + vcpus = 0 } } else { - vcpuInt = 0 + vcpus = 0 } - memory, ok := annotations[hypannotations.DefaultMemory] + mem, ok := annotations[hypannotations.DefaultMemory] if ok { // Use strconv.ParseInt to convert string to int64 - memoryInt, err = strconv.ParseInt(memory, 10, 64) + memory, err = strconv.ParseInt(mem, 10, 64) if err != nil { fmt.Printf("Error converting memory to int64. Defaulting to 0: %v\n", err) - memoryInt = 0 + memory = 0 } } else { - memoryInt = 0 + memory = 0 } gpu, ok := annotations[hypannotations.DefaultGPUs] if ok { - gpuInt, err = strconv.ParseInt(gpu, 10, 64) + gpus, err = strconv.ParseInt(gpu, 10, 64) if err != nil { fmt.Printf("Error converting gpu to int64. Defaulting to 0: %v\n", err) - gpuInt = 0 + gpus = 0 } } else { - gpuInt = 0 + gpus = 0 } - // Return vCPU, memory and GPU - return vcpuInt, memoryInt, gpuInt + storage := int64(0) + + return provider.PodVMResources{VCPUs: vcpus, Memory: memory, GPUs: gpus, Storage: storage} } // Method to get initdata from annotation diff --git a/src/cloud-api-adaptor/pkg/util/cloud_test.go b/src/cloud-api-adaptor/pkg/util/cloud_test.go index 3e1a2c859..dc152a421 100644 --- a/src/cloud-api-adaptor/pkg/util/cloud_test.go +++ b/src/cloud-api-adaptor/pkg/util/cloud_test.go @@ -98,7 +98,8 @@ func TestGetPodvmResourcesFromAnnotation(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, got1, got2 := GetPodvmResourcesFromAnnotation(tt.args.annotations) + r := GetPodVMResourcesFromAnnotation(tt.args.annotations) + got, got1, got2 := r.VCPUs, r.Memory, r.GPUs if got != tt.want { t.Errorf("GetPodvmResourcesFromAnnotation() got = %v, want %v", got, tt.want) } diff --git a/src/cloud-providers/aws/provider.go b/src/cloud-providers/aws/provider.go index d47ba7f74..b47300144 100644 --- a/src/cloud-providers/aws/provider.go +++ b/src/cloud-providers/aws/provider.go @@ -370,8 +370,10 @@ func (p *awsProvider) updateInstanceTypeSpecList() error { if err != nil { return err } + resources := provider.NewPodVMResources(vcpus, memory) + resources.GPUs = gpuCount instanceTypeSpecList = append(instanceTypeSpecList, - provider.InstanceTypeSpec{InstanceType: instanceType, VCPUs: vcpus, Memory: memory, GPUs: gpuCount}) + provider.InstanceTypeSpec{InstanceType: instanceType, Resources: resources}) } // Sort the instanceTypeSpecList and update the serviceConfig diff --git a/src/cloud-providers/azure/provider.go b/src/cloud-providers/azure/provider.go index 4e4488a98..50c2536ad 100644 --- a/src/cloud-providers/azure/provider.go +++ b/src/cloud-providers/azure/provider.go @@ -11,7 +11,6 @@ import ( "log" "net/netip" "os" - "path/filepath" "regexp" "strings" @@ -35,24 +34,44 @@ const ( type azureProvider struct { azureClient azcore.TokenCredential serviceConfig *Config + sshKey armcompute.SSHPublicKey } func NewProvider(config *Config) (provider.Provider, error) { logger.Printf("azure config %+v", config.Redact()) - // Clean the config.SSHKeyPath to avoid bad paths - config.SSHKeyPath = filepath.Clean(config.SSHKeyPath) - azureClient, err := NewAzureClient(*config) if err != nil { logger.Printf("creating azure client: %v", err) return nil, err } + // The podvm disk doesn't support sshd logins. keys can be baked + // into a debug-image. The ARM api mandates a pubkey, though. + sshPublicKeyPath := os.ExpandEnv(config.SSHKeyPath) + var pubkeyBytes []byte + if _, err := os.Stat(sshPublicKeyPath); err == nil { + pubkeyBytes, err = os.ReadFile(sshPublicKeyPath) + if err != nil { + err = fmt.Errorf("reading ssh public key file: %w", err) + logger.Printf("%v", err) + return nil, err + } + } else { + err = fmt.Errorf("ssh public key: %w", err) + logger.Printf("%v", err) + return nil, err + } + dummySSHKey := armcompute.SSHPublicKey{ + Path: to.Ptr(fmt.Sprintf("/home/%s/.ssh/authorized_keys", config.SSHUserName)), + KeyData: to.Ptr(string(pubkeyBytes)), + } + provider := &azureProvider{ azureClient: azureClient, serviceConfig: config, + sshKey: dummySSHKey, } if err = provider.updateInstanceSizeSpecList(); err != nil { @@ -218,28 +237,12 @@ func (p *azureProvider) CreateInstance(ctx context.Context, podName, sandboxID s diskName := fmt.Sprintf("%s-disk", instanceName) nicName := fmt.Sprintf("%s-net", instanceName) - // require ssh key for authentication on linux - sshPublicKeyPath := os.ExpandEnv(p.serviceConfig.SSHKeyPath) - var sshBytes []byte - if _, err := os.Stat(sshPublicKeyPath); err == nil { - sshBytes, err = os.ReadFile(sshPublicKeyPath) - if err != nil { - err = fmt.Errorf("reading ssh public key file: %w", err) - logger.Printf("%v", err) - return nil, err - } - } else { - err = fmt.Errorf("ssh public key: %w", err) - logger.Printf("%v", err) - return nil, err - } - if spec.Image != "" { logger.Printf("Choosing %s from annotation as the Azure Image for the PodVM image", spec.Image) p.serviceConfig.ImageId = spec.Image } - vmParameters, err := p.getVMParameters(instanceSize, diskName, cloudConfigData, sshBytes, instanceName, nicName) + vmParameters, err := p.getVMParameters(instanceSize, diskName, cloudConfigData, instanceName, nicName, spec.Resources.Storage) if err != nil { return nil, err } @@ -350,7 +353,10 @@ func (p *azureProvider) updateInstanceSizeSpecList() error { } for _, vmSize := range nextResult.VirtualMachineSizeListResult.Value { if util.Contains(instanceSizes, *vmSize.Name) { - instanceSizeSpecList = append(instanceSizeSpecList, provider.InstanceTypeSpec{InstanceType: *vmSize.Name, VCPUs: int64(*vmSize.NumberOfCores), Memory: int64(*vmSize.MemoryInMB)}) + vcpus, memory := int64(*vmSize.NumberOfCores), int64(*vmSize.MemoryInMB) + resources := provider.NewPodVMResources(vcpus, memory) + instanceSizeSpec := provider.InstanceTypeSpec{InstanceType: *vmSize.Name, Resources: resources} + instanceSizeSpecList = append(instanceSizeSpecList, instanceSizeSpec) } } } @@ -371,7 +377,7 @@ func (p *azureProvider) getResourceTags() map[string]*string { return tags } -func (p *azureProvider) getVMParameters(instanceSize, diskName, cloudConfig string, sshBytes []byte, instanceName, nicName string) (*armcompute.VirtualMachine, error) { +func (p *azureProvider) getVMParameters(instanceSize, diskName, cloudConfig, instanceName, nicName string, diskSize int64) (*armcompute.VirtualMachine, error) { userDataB64 := base64.StdEncoding.EncodeToString([]byte(cloudConfig)) // Azure limits the base64 encrypted userData to 64KB. @@ -416,6 +422,18 @@ func (p *azureProvider) getVMParameters(instanceSize, diskName, cloudConfig stri networkConfig := p.buildNetworkConfig(nicName) + osDisk := armcompute.OSDisk{ + Name: to.Ptr(diskName), + CreateOption: to.Ptr(armcompute.DiskCreateOptionTypesFromImage), + Caching: to.Ptr(armcompute.CachingTypesReadWrite), + DeleteOption: to.Ptr(armcompute.DiskDeleteOptionTypesDelete), + ManagedDisk: managedDiskParams, + } + + if diskSize > 0 { + osDisk.DiskSizeGB = to.Ptr(int32(diskSize)) + } + vmParameters := armcompute.VirtualMachine{ Location: to.Ptr(p.serviceConfig.Region), Properties: &armcompute.VirtualMachineProperties{ @@ -424,25 +442,15 @@ func (p *azureProvider) getVMParameters(instanceSize, diskName, cloudConfig stri }, StorageProfile: &armcompute.StorageProfile{ ImageReference: imgRef, - OSDisk: &armcompute.OSDisk{ - Name: to.Ptr(diskName), - CreateOption: to.Ptr(armcompute.DiskCreateOptionTypesFromImage), - Caching: to.Ptr(armcompute.CachingTypesReadWrite), - DeleteOption: to.Ptr(armcompute.DiskDeleteOptionTypesDelete), - ManagedDisk: managedDiskParams, - }, + OSDisk: &osDisk, }, OSProfile: &armcompute.OSProfile{ AdminUsername: to.Ptr(p.serviceConfig.SSHUserName), ComputerName: to.Ptr(instanceName), LinuxConfiguration: &armcompute.LinuxConfiguration{ DisablePasswordAuthentication: to.Ptr(true), - //TBD: replace with a suitable mechanism to use precreated SSH key SSH: &armcompute.SSHConfiguration{ - PublicKeys: []*armcompute.SSHPublicKey{{ - Path: to.Ptr(fmt.Sprintf("/home/%s/.ssh/authorized_keys", p.serviceConfig.SSHUserName)), - KeyData: to.Ptr(string(sshBytes)), - }}, + PublicKeys: []*armcompute.SSHPublicKey{&p.sshKey}, }, }, }, diff --git a/src/cloud-providers/ibmcloud/provider.go b/src/cloud-providers/ibmcloud/provider.go index 1be306405..0dcee2d1d 100644 --- a/src/cloud-providers/ibmcloud/provider.go +++ b/src/cloud-providers/ibmcloud/provider.go @@ -332,7 +332,8 @@ func (p *ibmcloudVPCProvider) updateInstanceProfileSpecList() error { if err != nil { return err } - instanceProfileSpecList = append(instanceProfileSpecList, provider.InstanceTypeSpec{InstanceType: profileType, VCPUs: vcpus, Memory: memory, Arch: arch}) + resources := provider.NewPodVMResources(vcpus, memory) + instanceProfileSpecList = append(instanceProfileSpecList, provider.InstanceTypeSpec{InstanceType: profileType, Resources: resources, Arch: arch}) } // Sort the instanceProfileSpecList and update the serviceConfig diff --git a/src/cloud-providers/types.go b/src/cloud-providers/types.go index 82ea5b0c7..d1a093225 100644 --- a/src/cloud-providers/types.go +++ b/src/cloud-providers/types.go @@ -60,11 +60,25 @@ type Instance struct { IPs []netip.Addr } +type PodVMResources struct { + VCPUs int64 + Memory int64 + GPUs int64 + Storage int64 +} + +func NewPodVMResources(vcpus, memory int64) PodVMResources { + return PodVMResources{ + VCPUs: vcpus, + Memory: memory, + GPUs: 0, + Storage: 0, + } +} + type InstanceTypeSpec struct { InstanceType string - VCPUs int64 - Memory int64 + Resources PodVMResources Arch string - GPUs int64 Image string } diff --git a/src/cloud-providers/util.go b/src/cloud-providers/util.go index e8b3f6309..40268dd1d 100644 --- a/src/cloud-providers/util.go +++ b/src/cloud-providers/util.go @@ -44,16 +44,17 @@ func VerifyCloudInstanceType(instanceType string, validInstanceTypes []string, d // Method to sort InstanceTypeSpec into ascending order based on gpu, then memory, followed by cpu func SortInstanceTypesOnResources(instanceTypeSpecList []InstanceTypeSpec) []InstanceTypeSpec { sort.Slice(instanceTypeSpecList, func(i, j int) bool { + resI, resJ := instanceTypeSpecList[i].Resources, instanceTypeSpecList[j].Resources // First, sort by GPU count - if instanceTypeSpecList[i].GPUs != instanceTypeSpecList[j].GPUs { - return instanceTypeSpecList[i].GPUs < instanceTypeSpecList[j].GPUs + if resI.GPUs != resJ.GPUs { + return resI.GPUs < resJ.GPUs } // If GPU count is the same, sort by memory - if instanceTypeSpecList[i].Memory != instanceTypeSpecList[j].Memory { - return instanceTypeSpecList[i].Memory < instanceTypeSpecList[j].Memory + if resI.Memory != resJ.Memory { + return resI.Memory < resJ.Memory } // If memory is the same, sort by vCPUs - return instanceTypeSpecList[i].VCPUs < instanceTypeSpecList[j].VCPUs + return resI.VCPUs < resJ.VCPUs }) return instanceTypeSpecList @@ -64,16 +65,17 @@ func SelectInstanceTypeToUse(spec InstanceTypeSpec, specList []InstanceTypeSpec, var instanceType string var err error + gpus, vcpus, memory := spec.Resources.GPUs, spec.Resources.VCPUs, spec.Resources.Memory // GPU gets the highest priority - if spec.GPUs > 0 { - instanceType, err = GetBestFitInstanceTypeWithGPU(specList, spec.GPUs, spec.VCPUs, spec.Memory) + if gpus > 0 { + instanceType, err = GetBestFitInstanceTypeWithGPU(specList, gpus, vcpus, memory) if err != nil { return "", fmt.Errorf("failed to get instance type based on GPU, vCPU, and memory annotations: %w", err) } logger.Printf("Instance type selected by the cloud provider based on GPU annotation: %s", instanceType) - } else if spec.VCPUs != 0 && spec.Memory != 0 { + } else if vcpus != 0 && memory != 0 { // If no GPU is required, fall back to vCPU and memory selection - instanceType, err = GetBestFitInstanceType(specList, spec.VCPUs, spec.Memory) + instanceType, err = GetBestFitInstanceType(specList, vcpus, memory) if err != nil { return "", fmt.Errorf("failed to get instance type based on vCPU and memory annotations: %w", err) } @@ -104,7 +106,8 @@ func GetBestFitInstanceType(sortedInstanceTypeSpecList []InstanceTypeSpec, vcpus // Use sort.Search to find the index of the first element in the sortedMachineTypeList slice // that is greater than or equal to the given memory and vcpus index := sort.Search(len(sortedInstanceTypeSpecList), func(i int) bool { - return sortedInstanceTypeSpecList[i].Memory >= memory && sortedInstanceTypeSpecList[i].VCPUs >= vcpus + res := sortedInstanceTypeSpecList[i].Resources + return res.Memory >= memory && res.VCPUs >= vcpus }) // If binary search fails to find a match, return error @@ -121,7 +124,7 @@ func GetBestFitInstanceType(sortedInstanceTypeSpecList []InstanceTypeSpec, vcpus func FilterOutGPUInstances(instanceTypeSpecList []InstanceTypeSpec) []InstanceTypeSpec { var filteredList []InstanceTypeSpec for _, spec := range instanceTypeSpecList { - if spec.GPUs == 0 { + if spec.Resources.GPUs == 0 { filteredList = append(filteredList, spec) } } @@ -132,9 +135,8 @@ func FilterOutGPUInstances(instanceTypeSpecList []InstanceTypeSpec) []InstanceTy // TBD: Incorporate GPU model based selection as well func GetBestFitInstanceTypeWithGPU(sortedInstanceTypeSpecList []InstanceTypeSpec, gpus, vcpus, memory int64) (string, error) { index := sort.Search(len(sortedInstanceTypeSpecList), func(i int) bool { - return sortedInstanceTypeSpecList[i].GPUs >= gpus && - sortedInstanceTypeSpecList[i].VCPUs >= vcpus && - sortedInstanceTypeSpecList[i].Memory >= memory + res := sortedInstanceTypeSpecList[i].Resources + return res.GPUs >= gpus && res.VCPUs >= vcpus && res.Memory >= memory }) if index == len(sortedInstanceTypeSpecList) { diff --git a/src/cloud-providers/util_test.go b/src/cloud-providers/util_test.go index 83aa0845a..c1525f333 100644 --- a/src/cloud-providers/util_test.go +++ b/src/cloud-providers/util_test.go @@ -109,36 +109,48 @@ func TestSortInstanceTypesOnResources(t *testing.T) { instanceTypeSpecList: []InstanceTypeSpec{ { InstanceType: "t2.small", - VCPUs: 2, - Memory: 6, + Resources: PodVMResources{ + VCPUs: 2, + Memory: 6, + }, }, { InstanceType: "t2.medium", - VCPUs: 4, - Memory: 8, + Resources: PodVMResources{ + VCPUs: 4, + Memory: 8, + }, }, { InstanceType: "t2.large", - VCPUs: 8, - Memory: 16, + Resources: PodVMResources{ + VCPUs: 8, + Memory: 16, + }, }, }, }, want: []InstanceTypeSpec{ { InstanceType: "t2.small", - VCPUs: 2, - Memory: 6, + Resources: PodVMResources{ + VCPUs: 2, + Memory: 6, + }, }, { InstanceType: "t2.medium", - VCPUs: 4, - Memory: 8, + Resources: PodVMResources{ + VCPUs: 4, + Memory: 8, + }, }, { InstanceType: "t2.large", - VCPUs: 8, - Memory: 16, + Resources: PodVMResources{ + VCPUs: 8, + Memory: 16, + }, }, }, }, @@ -149,36 +161,48 @@ func TestSortInstanceTypesOnResources(t *testing.T) { instanceTypeSpecList: []InstanceTypeSpec{ { InstanceType: "t2.small", - VCPUs: 2, - Memory: 6, + Resources: PodVMResources{ + VCPUs: 2, + Memory: 6, + }, }, { InstanceType: "t2.large", - VCPUs: 8, - Memory: 16, + Resources: PodVMResources{ + VCPUs: 8, + Memory: 16, + }, }, { InstanceType: "t2.medium", - VCPUs: 4, - Memory: 8, + Resources: PodVMResources{ + VCPUs: 4, + Memory: 8, + }, }, }, }, want: []InstanceTypeSpec{ { InstanceType: "t2.small", - VCPUs: 2, - Memory: 6, + Resources: PodVMResources{ + VCPUs: 2, + Memory: 6, + }, }, { InstanceType: "t2.medium", - VCPUs: 4, - Memory: 8, + Resources: PodVMResources{ + VCPUs: 4, + Memory: 8, + }, }, { InstanceType: "t2.large", - VCPUs: 8, - Memory: 16, + Resources: PodVMResources{ + VCPUs: 8, + Memory: 16, + }, }, }, }, @@ -189,36 +213,48 @@ func TestSortInstanceTypesOnResources(t *testing.T) { instanceTypeSpecList: []InstanceTypeSpec{ { InstanceType: "t2.medium", - VCPUs: 4, - Memory: 8, + Resources: PodVMResources{ + VCPUs: 4, + Memory: 8, + }, }, { InstanceType: "t2.small", - VCPUs: 2, - Memory: 6, + Resources: PodVMResources{ + VCPUs: 2, + Memory: 6, + }, }, { InstanceType: "t2.large", - VCPUs: 8, - Memory: 16, + Resources: PodVMResources{ + VCPUs: 8, + Memory: 16, + }, }, }, }, want: []InstanceTypeSpec{ { InstanceType: "t2.small", - VCPUs: 2, - Memory: 6, + Resources: PodVMResources{ + VCPUs: 2, + Memory: 6, + }, }, { InstanceType: "t2.medium", - VCPUs: 4, - Memory: 8, + Resources: PodVMResources{ + VCPUs: 4, + Memory: 8, + }, }, { InstanceType: "t2.large", - VCPUs: 8, - Memory: 16, + Resources: PodVMResources{ + VCPUs: 8, + Memory: 16, + }, }, }, }, @@ -230,42 +266,54 @@ func TestSortInstanceTypesOnResources(t *testing.T) { instanceTypeSpecList: []InstanceTypeSpec{ { InstanceType: "p2.medium", - VCPUs: 4, - Memory: 8, - GPUs: 2, + Resources: PodVMResources{ + VCPUs: 4, + Memory: 8, + GPUs: 2, + }, }, { InstanceType: "p2.small", - VCPUs: 2, - Memory: 6, - GPUs: 1, + Resources: PodVMResources{ + VCPUs: 2, + Memory: 6, + GPUs: 1, + }, }, { InstanceType: "p2.large", - VCPUs: 8, - Memory: 16, - GPUs: 4, + Resources: PodVMResources{ + VCPUs: 8, + Memory: 16, + GPUs: 4, + }, }, }, }, want: []InstanceTypeSpec{ { InstanceType: "p2.small", - VCPUs: 2, - Memory: 6, - GPUs: 1, + Resources: PodVMResources{ + VCPUs: 2, + Memory: 6, + GPUs: 1, + }, }, { InstanceType: "p2.medium", - VCPUs: 4, - Memory: 8, - GPUs: 2, + Resources: PodVMResources{ + VCPUs: 4, + Memory: 8, + GPUs: 2, + }, }, { InstanceType: "p2.large", - VCPUs: 8, - Memory: 16, - GPUs: 4, + Resources: PodVMResources{ + VCPUs: 8, + Memory: 16, + GPUs: 4, + }, }, }, }, @@ -302,18 +350,24 @@ func TestGetBestFitInstanceType(t *testing.T) { sortedInstanceTypeSpecList: []InstanceTypeSpec{ { InstanceType: "t2.small", - VCPUs: 2, - Memory: 6, + Resources: PodVMResources{ + VCPUs: 2, + Memory: 6, + }, }, { InstanceType: "t2.medium", - VCPUs: 4, - Memory: 8, + Resources: PodVMResources{ + VCPUs: 4, + Memory: 8, + }, }, { InstanceType: "t2.large", - VCPUs: 8, - Memory: 16, + Resources: PodVMResources{ + VCPUs: 8, + Memory: 16, + }, }, }, vcpus: 2, @@ -329,18 +383,24 @@ func TestGetBestFitInstanceType(t *testing.T) { sortedInstanceTypeSpecList: []InstanceTypeSpec{ { InstanceType: "t2.small", - VCPUs: 2, - Memory: 6, + Resources: PodVMResources{ + VCPUs: 2, + Memory: 6, + }, }, { InstanceType: "t2.medium", - VCPUs: 4, - Memory: 8, + Resources: PodVMResources{ + VCPUs: 4, + Memory: 8, + }, }, { InstanceType: "t2.large", - VCPUs: 8, - Memory: 16, + Resources: PodVMResources{ + VCPUs: 8, + Memory: 16, + }, }, }, vcpus: 4, @@ -356,18 +416,24 @@ func TestGetBestFitInstanceType(t *testing.T) { sortedInstanceTypeSpecList: []InstanceTypeSpec{ { InstanceType: "t2.small", - VCPUs: 2, - Memory: 6, + Resources: PodVMResources{ + VCPUs: 2, + Memory: 6, + }, }, { InstanceType: "t2.medium", - VCPUs: 4, - Memory: 8, + Resources: PodVMResources{ + VCPUs: 4, + Memory: 8, + }, }, { InstanceType: "t2.large", - VCPUs: 8, - Memory: 16, + Resources: PodVMResources{ + VCPUs: 8, + Memory: 16, + }, }, }, vcpus: 4, @@ -383,19 +449,25 @@ func TestGetBestFitInstanceType(t *testing.T) { sortedInstanceTypeSpecList: []InstanceTypeSpec{ { InstanceType: "t2.small", - VCPUs: 2, - Memory: 6, + Resources: PodVMResources{ + VCPUs: 2, + Memory: 6, + }, }, { InstanceType: "p2.medium", - VCPUs: 4, - Memory: 8, - GPUs: 2, + Resources: PodVMResources{ + VCPUs: 4, + Memory: 8, + GPUs: 2, + }, }, { InstanceType: "t2.large", - VCPUs: 8, - Memory: 16, + Resources: PodVMResources{ + VCPUs: 8, + Memory: 16, + }, }, }, vcpus: 4, @@ -412,18 +484,24 @@ func TestGetBestFitInstanceType(t *testing.T) { sortedInstanceTypeSpecList: []InstanceTypeSpec{ { InstanceType: "t2.small", - VCPUs: 2, - Memory: 6, + Resources: PodVMResources{ + VCPUs: 2, + Memory: 6, + }, }, { InstanceType: "t2.medium", - VCPUs: 4, - Memory: 8, + Resources: PodVMResources{ + VCPUs: 4, + Memory: 8, + }, }, { InstanceType: "t2.large", - VCPUs: 8, - Memory: 16, + Resources: PodVMResources{ + VCPUs: 8, + Memory: 16, + }, }, }, vcpus: 4, @@ -547,8 +625,8 @@ func TestGetBestFitInstanceTypeWithGPU(t *testing.T) { { name: "exact match", specList: []InstanceTypeSpec{ - {InstanceType: "small-gpu", GPUs: 1, VCPUs: 2, Memory: 4096}, - {InstanceType: "medium-gpu", GPUs: 2, VCPUs: 4, Memory: 8192}, + {InstanceType: "small-gpu", Resources: PodVMResources{GPUs: 1, VCPUs: 2, Memory: 4096}}, + {InstanceType: "medium-gpu", Resources: PodVMResources{GPUs: 2, VCPUs: 4, Memory: 8192}}, }, gpus: 1, vcpus: 2, @@ -559,8 +637,8 @@ func TestGetBestFitInstanceTypeWithGPU(t *testing.T) { { name: "next best fit", specList: []InstanceTypeSpec{ - {InstanceType: "small-gpu", GPUs: 1, VCPUs: 2, Memory: 4096}, - {InstanceType: "medium-gpu", GPUs: 2, VCPUs: 4, Memory: 8192}, + {InstanceType: "small-gpu", Resources: PodVMResources{GPUs: 1, VCPUs: 2, Memory: 4096}}, + {InstanceType: "medium-gpu", Resources: PodVMResources{GPUs: 2, VCPUs: 4, Memory: 8192}}, }, gpus: 1, vcpus: 3, @@ -571,8 +649,8 @@ func TestGetBestFitInstanceTypeWithGPU(t *testing.T) { { name: "no match found", specList: []InstanceTypeSpec{ - {InstanceType: "small-gpu", GPUs: 1, VCPUs: 2, Memory: 4096}, - {InstanceType: "medium-gpu", GPUs: 2, VCPUs: 4, Memory: 8192}, + {InstanceType: "small-gpu", Resources: PodVMResources{GPUs: 1, VCPUs: 2, Memory: 4096}}, + {InstanceType: "medium-gpu", Resources: PodVMResources{GPUs: 2, VCPUs: 4, Memory: 8192}}, }, gpus: 4, vcpus: 8,