From 6faf24aad88d5353309e531078962d22b51c49c7 Mon Sep 17 00:00:00 2001 From: Maksim An Date: Tue, 13 May 2025 14:25:51 -0700 Subject: [PATCH 1/3] add support for resource partitions Adds annotation for resource partition id, when present, set the corresponding field on HCS doc (no-op for now), the rest will be handled by HCS. Signed-off-by: Maksim An --- internal/oci/uvm.go | 1 + internal/tools/uvmboot/main.go | 8 ++++++++ internal/uvm/create.go | 4 ++++ internal/uvm/create_lcow.go | 5 +++++ internal/uvm/create_wcow.go | 5 +++++ pkg/annotations/annotations.go | 3 +++ 6 files changed, 26 insertions(+) diff --git a/internal/oci/uvm.go b/internal/oci/uvm.go index f0d9402e1d..1d5f9af0e3 100644 --- a/internal/oci/uvm.go +++ b/internal/oci/uvm.go @@ -264,6 +264,7 @@ func specToUVMCreateOptionsCommon(ctx context.Context, opts *uvm.Options, s *spe opts.StorageQoSBandwidthMaximum = ParseAnnotationsStorageBps(ctx, s, annotations.StorageQoSBandwidthMaximum, opts.StorageQoSBandwidthMaximum) opts.StorageQoSIopsMaximum = ParseAnnotationsStorageIops(ctx, s, annotations.StorageQoSIopsMaximum, opts.StorageQoSIopsMaximum) opts.CPUGroupID = ParseAnnotationsString(s.Annotations, annotations.CPUGroupID, opts.CPUGroupID) + opts.ResourcePoolID = ParseAnnotationsString(s.Annotations, annotations.ResourcePoolID, opts.ResourcePoolID) opts.NetworkConfigProxy = ParseAnnotationsString(s.Annotations, annotations.NetworkConfigProxy, opts.NetworkConfigProxy) opts.ProcessDumpLocation = ParseAnnotationsString(s.Annotations, annotations.ContainerProcessDumpLocation, opts.ProcessDumpLocation) opts.NoWritableFileShares = ParseAnnotationsBool(ctx, s.Annotations, annotations.DisableWritableFileShares, opts.NoWritableFileShares) diff --git a/internal/tools/uvmboot/main.go b/internal/tools/uvmboot/main.go index 8756162872..5e44d6596d 100644 --- a/internal/tools/uvmboot/main.go +++ b/internal/tools/uvmboot/main.go @@ -24,6 +24,7 @@ const ( measureArgName = "measure" parallelArgName = "parallel" countArgName = "count" + resourcePoolArgName = "resource-pool" execCommandLineArgName = "exec" uvmConsolePipe = "\\\\.\\pipe\\uvmpipe" @@ -82,6 +83,10 @@ func main() { Usage: "Launch the GCS and perform requested operations via its RPC interface", Destination: &useGCS, }, + cli.StringFlag{ + Name: resourcePoolArgName, + Usage: "Resource pool GUID to assign UVM to", + }, } app.Commands = []cli.Command{ @@ -125,6 +130,9 @@ func setGlobalOptions(c *cli.Context, options *uvm.Options) { if c.GlobalIsSet(enableDeferredCommitArgName) { options.EnableDeferredCommit = c.GlobalBool(enableDeferredCommitArgName) } + if c.GlobalIsSet(resourcePoolArgName) { + options.ResourcePoolID = c.GlobalString(resourcePoolArgName) + } // Always set the console pipe in uvmboot, it helps with testing/debugging options.ConsolePipe = uvmConsolePipe } diff --git a/internal/uvm/create.go b/internal/uvm/create.go index c736133494..f1ae771f80 100644 --- a/internal/uvm/create.go +++ b/internal/uvm/create.go @@ -84,6 +84,10 @@ type Options struct { // CPUGroupID set the ID of a CPUGroup on the host that the UVM should be added to on start. // Defaults to an empty string which indicates the UVM should not be added to any CPUGroup. CPUGroupID string + + // ResourcePoolID holds the resource pool ID the UVM should be assigned to. + ResourcePoolID string + // NetworkConfigProxy holds the address of the network config proxy service. // This != "" determines whether to start the ComputeAgent TTRPC service // that receives the UVMs set of NICs from this proxy instead of enumerating diff --git a/internal/uvm/create_lcow.go b/internal/uvm/create_lcow.go index 3b3c364734..0f68a28a52 100644 --- a/internal/uvm/create_lcow.go +++ b/internal/uvm/create_lcow.go @@ -657,6 +657,11 @@ func makeLCOWDoc(ctx context.Context, opts *OptionsLCOW, uvm *UtilityVM) (_ *hcs doc.VirtualMachine.ComputeTopology.Memory.SlitType = &firmwareFallbackMeasured } + if opts.ResourcePoolID != "" { + // TODO (maksiman): assign pod to resource pool and potentially do an OS version check before that + log.G(ctx).WithField("resource-pool-id", opts.ResourcePoolID).Debug("setting resource pool ID") + } + // Add optional devices that were specified on the UVM spec if len(opts.AssignedDevices) > 0 { if doc.VirtualMachine.Devices.VirtualPci == nil { diff --git a/internal/uvm/create_wcow.go b/internal/uvm/create_wcow.go index b1dbfdd138..37a56e5ca0 100644 --- a/internal/uvm/create_wcow.go +++ b/internal/uvm/create_wcow.go @@ -231,6 +231,11 @@ func prepareCommonConfigDoc(ctx context.Context, uvm *UtilityVM, opts *OptionsWC doc.VirtualMachine.ComputeTopology.Memory.SlitType = &firmwareFallbackMeasured } + if opts.ResourcePoolID != "" { + // TODO (maksiman): assign pod to resource pool and potentially do an OS version check before that + log.G(ctx).WithField("resource-pool-id", opts.ResourcePoolID).Debug("setting resource pool ID") + } + maps.Copy(doc.VirtualMachine.Devices.HvSocket.HvSocketConfig.ServiceTable, opts.AdditionalHyperVConfig) // Handle StorageQoS if set diff --git a/pkg/annotations/annotations.go b/pkg/annotations/annotations.go index 31406fa1b9..e757faf96a 100644 --- a/pkg/annotations/annotations.go +++ b/pkg/annotations/annotations.go @@ -312,6 +312,9 @@ const ( // number of memory blocks at slice index 1, etc. // This should be used for explicit vNUMA topology. NumaCountOfMemoryBlocks = "io.microsoft.virtualmachine.computetopology.numa.count-of-memory-blocks" + + // ResourcePoolID is a GUID string representing a resource pool ID the UVM should be associated with. + ResourcePoolID = "io.microsoft.virtualmachine.resource-pool-id" ) // uVM storage (Quality of Service) annotations. From 83348b7b0a55b4d9da7e023d81c322f3c5fee102 Mon Sep 17 00:00:00 2001 From: Maksim An Date: Fri, 18 Jul 2025 15:40:12 -0700 Subject: [PATCH 2/3] pr feedback: add logic to parse GUID annotations Signed-off-by: Maksim An --- internal/oci/annotations.go | 13 +++++++++++++ internal/oci/uvm.go | 18 ++++++++++++++---- internal/tools/uvmboot/main.go | 7 ++++++- internal/uvm/create.go | 4 ++-- internal/uvm/create_lcow.go | 4 ++-- internal/uvm/create_wcow.go | 4 ++-- 6 files changed, 39 insertions(+), 11 deletions(-) diff --git a/internal/oci/annotations.go b/internal/oci/annotations.go index 64a194c760..5c88dd9e60 100644 --- a/internal/oci/annotations.go +++ b/internal/oci/annotations.go @@ -377,6 +377,19 @@ func ParseAnnotationCommaSeparated(key string, a map[string]string) []string { return results } +// ParseAnnotationsGUID searches `a` for `key`. If `key` is found, tries to parse it as guid.GUID, otherwise +// returns `def`. +func ParseAnnotationsGUID(a map[string]string, key string, def *guid.GUID) (*guid.GUID, error) { + if v, ok := a[key]; ok { + g, err := guid.FromString(v) + if err != nil { + return nil, err + } + return &g, nil + } + return def, nil +} + func logAnnotationValueParseError(ctx context.Context, k, v, et string, err error) { entry := log.G(ctx).WithFields(logrus.Fields{ logfields.OCIAnnotation: k, diff --git a/internal/oci/uvm.go b/internal/oci/uvm.go index 1d5f9af0e3..fd1c89491d 100644 --- a/internal/oci/uvm.go +++ b/internal/oci/uvm.go @@ -251,7 +251,7 @@ func parseDevices(ctx context.Context, specWindows *specs.Windows) []uvm.VPCIDev } // sets options common to both WCOW and LCOW from annotations. -func specToUVMCreateOptionsCommon(ctx context.Context, opts *uvm.Options, s *specs.Spec) { +func specToUVMCreateOptionsCommon(ctx context.Context, opts *uvm.Options, s *specs.Spec) (err error) { opts.MemorySizeInMB = ParseAnnotationsMemory(ctx, s, annotations.MemorySizeInMB, opts.MemorySizeInMB) opts.LowMMIOGapInMB = ParseAnnotationsUint64(ctx, s.Annotations, annotations.MemoryLowMMIOGapInMB, opts.LowMMIOGapInMB) opts.HighMMIOBaseInMB = ParseAnnotationsUint64(ctx, s.Annotations, annotations.MemoryHighMMIOBaseInMB, opts.HighMMIOBaseInMB) @@ -264,7 +264,6 @@ func specToUVMCreateOptionsCommon(ctx context.Context, opts *uvm.Options, s *spe opts.StorageQoSBandwidthMaximum = ParseAnnotationsStorageBps(ctx, s, annotations.StorageQoSBandwidthMaximum, opts.StorageQoSBandwidthMaximum) opts.StorageQoSIopsMaximum = ParseAnnotationsStorageIops(ctx, s, annotations.StorageQoSIopsMaximum, opts.StorageQoSIopsMaximum) opts.CPUGroupID = ParseAnnotationsString(s.Annotations, annotations.CPUGroupID, opts.CPUGroupID) - opts.ResourcePoolID = ParseAnnotationsString(s.Annotations, annotations.ResourcePoolID, opts.ResourcePoolID) opts.NetworkConfigProxy = ParseAnnotationsString(s.Annotations, annotations.NetworkConfigProxy, opts.NetworkConfigProxy) opts.ProcessDumpLocation = ParseAnnotationsString(s.Annotations, annotations.ContainerProcessDumpLocation, opts.ProcessDumpLocation) opts.NoWritableFileShares = ParseAnnotationsBool(ctx, s.Annotations, annotations.DisableWritableFileShares, opts.NoWritableFileShares) @@ -283,6 +282,13 @@ func specToUVMCreateOptionsCommon(ctx context.Context, opts *uvm.Options, s *spe opts.NumaMemoryBlocksCounts) maps.Copy(opts.AdditionalHyperVConfig, parseHVSocketServiceTable(ctx, s.Annotations)) + + // parse error yielding annotations + opts.ResourcePoolID, err = ParseAnnotationsGUID(s.Annotations, annotations.ResourcePoolID, opts.ResourcePoolID) + if err != nil { + return err + } + return nil } // SpecToUVMCreateOpts parses `s` and returns either `*uvm.OptionsLCOW` or @@ -293,7 +299,9 @@ func SpecToUVMCreateOpts(ctx context.Context, s *specs.Spec, id, owner string) ( } if IsLCOW(s) { lopts := uvm.NewDefaultOptionsLCOW(id, owner) - specToUVMCreateOptionsCommon(ctx, lopts.Options, s) + if err := specToUVMCreateOptionsCommon(ctx, lopts.Options, s); err != nil { + return nil, err + } /* WARNING!!!!!!!!!! @@ -340,7 +348,9 @@ func SpecToUVMCreateOpts(ctx context.Context, s *specs.Spec, id, owner string) ( return lopts, nil } else if IsWCOW(s) { wopts := uvm.NewDefaultOptionsWCOW(id, owner) - specToUVMCreateOptionsCommon(ctx, wopts.Options, s) + if err := specToUVMCreateOptionsCommon(ctx, wopts.Options, s); err != nil { + return nil, err + } wopts.DisableCompartmentNamespace = ParseAnnotationsBool(ctx, s.Annotations, annotations.DisableCompartmentNamespace, wopts.DisableCompartmentNamespace) wopts.NoDirectMap = ParseAnnotationsBool(ctx, s.Annotations, annotations.VSMBNoDirectMap, wopts.NoDirectMap) diff --git a/internal/tools/uvmboot/main.go b/internal/tools/uvmboot/main.go index 5e44d6596d..57f63365c4 100644 --- a/internal/tools/uvmboot/main.go +++ b/internal/tools/uvmboot/main.go @@ -9,6 +9,7 @@ import ( "sync" "time" + "github.com/Microsoft/go-winio/pkg/guid" "github.com/sirupsen/logrus" "github.com/urfave/cli" @@ -131,7 +132,11 @@ func setGlobalOptions(c *cli.Context, options *uvm.Options) { options.EnableDeferredCommit = c.GlobalBool(enableDeferredCommitArgName) } if c.GlobalIsSet(resourcePoolArgName) { - options.ResourcePoolID = c.GlobalString(resourcePoolArgName) + rpID, err := guid.FromString(c.GlobalString(resourcePoolArgName)) + if err != nil { + logrus.Fatalf("Failed to parse resource pool GUID: %v", err) + } + options.ResourcePoolID = &rpID } // Always set the console pipe in uvmboot, it helps with testing/debugging options.ConsolePipe = uvmConsolePipe diff --git a/internal/uvm/create.go b/internal/uvm/create.go index f1ae771f80..94ec04f494 100644 --- a/internal/uvm/create.go +++ b/internal/uvm/create.go @@ -85,8 +85,8 @@ type Options struct { // Defaults to an empty string which indicates the UVM should not be added to any CPUGroup. CPUGroupID string - // ResourcePoolID holds the resource pool ID the UVM should be assigned to. - ResourcePoolID string + // ResourcePoolID holds the resource pool guid.GUID the UVM should be assigned to. + ResourcePoolID *guid.GUID // NetworkConfigProxy holds the address of the network config proxy service. // This != "" determines whether to start the ComputeAgent TTRPC service diff --git a/internal/uvm/create_lcow.go b/internal/uvm/create_lcow.go index 0f68a28a52..6005532cfb 100644 --- a/internal/uvm/create_lcow.go +++ b/internal/uvm/create_lcow.go @@ -657,9 +657,9 @@ func makeLCOWDoc(ctx context.Context, opts *OptionsLCOW, uvm *UtilityVM) (_ *hcs doc.VirtualMachine.ComputeTopology.Memory.SlitType = &firmwareFallbackMeasured } - if opts.ResourcePoolID != "" { + if opts.ResourcePoolID != nil { // TODO (maksiman): assign pod to resource pool and potentially do an OS version check before that - log.G(ctx).WithField("resource-pool-id", opts.ResourcePoolID).Debug("setting resource pool ID") + log.G(ctx).WithField("resource-pool-id", opts.ResourcePoolID.String()).Debug("setting resource pool ID") } // Add optional devices that were specified on the UVM spec diff --git a/internal/uvm/create_wcow.go b/internal/uvm/create_wcow.go index 37a56e5ca0..ed1744038b 100644 --- a/internal/uvm/create_wcow.go +++ b/internal/uvm/create_wcow.go @@ -231,9 +231,9 @@ func prepareCommonConfigDoc(ctx context.Context, uvm *UtilityVM, opts *OptionsWC doc.VirtualMachine.ComputeTopology.Memory.SlitType = &firmwareFallbackMeasured } - if opts.ResourcePoolID != "" { + if opts.ResourcePoolID != nil { // TODO (maksiman): assign pod to resource pool and potentially do an OS version check before that - log.G(ctx).WithField("resource-pool-id", opts.ResourcePoolID).Debug("setting resource pool ID") + log.G(ctx).WithField("resource-pool-id", opts.ResourcePoolID.String()).Debug("setting resource pool ID") } maps.Copy(doc.VirtualMachine.Devices.HvSocket.HvSocketConfig.ServiceTable, opts.AdditionalHyperVConfig) From f6b9597f6d55472e7d86da33025ef9ed80069655 Mon Sep 17 00:00:00 2001 From: Maksim An Date: Mon, 4 Aug 2025 18:30:15 -0700 Subject: [PATCH 3/3] pr feedback - better error messages - update doc strings - rename from pool to partition - add validation for resource partitions Signed-off-by: Maksim An --- internal/oci/annotations.go | 2 +- internal/oci/uvm.go | 5 +++-- internal/tools/uvmboot/main.go | 14 +++++++------- internal/uvm/create.go | 14 ++++++++++++-- internal/uvm/create_lcow.go | 6 +++--- internal/uvm/create_wcow.go | 6 +++--- pkg/annotations/annotations.go | 7 +++++-- 7 files changed, 34 insertions(+), 20 deletions(-) diff --git a/internal/oci/annotations.go b/internal/oci/annotations.go index 5c88dd9e60..7463bc9dfe 100644 --- a/internal/oci/annotations.go +++ b/internal/oci/annotations.go @@ -383,7 +383,7 @@ func ParseAnnotationsGUID(a map[string]string, key string, def *guid.GUID) (*gui if v, ok := a[key]; ok { g, err := guid.FromString(v) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to parse annotation %q with value %q as GUID: %w", key, v, err) } return &g, nil } diff --git a/internal/oci/uvm.go b/internal/oci/uvm.go index fd1c89491d..b45e6176a0 100644 --- a/internal/oci/uvm.go +++ b/internal/oci/uvm.go @@ -251,7 +251,7 @@ func parseDevices(ctx context.Context, specWindows *specs.Windows) []uvm.VPCIDev } // sets options common to both WCOW and LCOW from annotations. -func specToUVMCreateOptionsCommon(ctx context.Context, opts *uvm.Options, s *specs.Spec) (err error) { +func specToUVMCreateOptionsCommon(ctx context.Context, opts *uvm.Options, s *specs.Spec) error { opts.MemorySizeInMB = ParseAnnotationsMemory(ctx, s, annotations.MemorySizeInMB, opts.MemorySizeInMB) opts.LowMMIOGapInMB = ParseAnnotationsUint64(ctx, s.Annotations, annotations.MemoryLowMMIOGapInMB, opts.LowMMIOGapInMB) opts.HighMMIOBaseInMB = ParseAnnotationsUint64(ctx, s.Annotations, annotations.MemoryHighMMIOBaseInMB, opts.HighMMIOBaseInMB) @@ -284,7 +284,8 @@ func specToUVMCreateOptionsCommon(ctx context.Context, opts *uvm.Options, s *spe maps.Copy(opts.AdditionalHyperVConfig, parseHVSocketServiceTable(ctx, s.Annotations)) // parse error yielding annotations - opts.ResourcePoolID, err = ParseAnnotationsGUID(s.Annotations, annotations.ResourcePoolID, opts.ResourcePoolID) + var err error + opts.ResourcePartitionID, err = ParseAnnotationsGUID(s.Annotations, annotations.ResourcePartitionID, opts.ResourcePartitionID) if err != nil { return err } diff --git a/internal/tools/uvmboot/main.go b/internal/tools/uvmboot/main.go index 57f63365c4..0a631f7bc8 100644 --- a/internal/tools/uvmboot/main.go +++ b/internal/tools/uvmboot/main.go @@ -25,7 +25,7 @@ const ( measureArgName = "measure" parallelArgName = "parallel" countArgName = "count" - resourcePoolArgName = "resource-pool" + resourcePartitionArgName = "resource-partition" execCommandLineArgName = "exec" uvmConsolePipe = "\\\\.\\pipe\\uvmpipe" @@ -85,8 +85,8 @@ func main() { Destination: &useGCS, }, cli.StringFlag{ - Name: resourcePoolArgName, - Usage: "Resource pool GUID to assign UVM to", + Name: resourcePartitionArgName, + Usage: "Resource partition GUID to assign UVM to", }, } @@ -131,12 +131,12 @@ func setGlobalOptions(c *cli.Context, options *uvm.Options) { if c.GlobalIsSet(enableDeferredCommitArgName) { options.EnableDeferredCommit = c.GlobalBool(enableDeferredCommitArgName) } - if c.GlobalIsSet(resourcePoolArgName) { - rpID, err := guid.FromString(c.GlobalString(resourcePoolArgName)) + if c.GlobalIsSet(resourcePartitionArgName) { + rpID, err := guid.FromString(c.GlobalString(resourcePartitionArgName)) if err != nil { - logrus.Fatalf("Failed to parse resource pool GUID: %v", err) + logrus.Fatalf("Failed to parse resource partition GUID: %v", err) } - options.ResourcePoolID = &rpID + options.ResourcePartitionID = &rpID } // Always set the console pipe in uvmboot, it helps with testing/debugging options.ConsolePipe = uvmConsolePipe diff --git a/internal/uvm/create.go b/internal/uvm/create.go index 94ec04f494..ddd8993e36 100644 --- a/internal/uvm/create.go +++ b/internal/uvm/create.go @@ -85,8 +85,8 @@ type Options struct { // Defaults to an empty string which indicates the UVM should not be added to any CPUGroup. CPUGroupID string - // ResourcePoolID holds the resource pool guid.GUID the UVM should be assigned to. - ResourcePoolID *guid.GUID + // ResourcePartitionID holds the resource partition guid.GUID the UVM should be assigned to. + ResourcePartitionID *guid.GUID // NetworkConfigProxy holds the address of the network config proxy service. // This != "" determines whether to start the ComputeAgent TTRPC service @@ -175,6 +175,11 @@ func verifyOptions(_ context.Context, options interface{}) error { if opts.EnableColdDiscardHint && osversion.Build() < 18967 { return errors.New("EnableColdDiscardHint is not supported on builds older than 18967") } + if opts.ResourcePartitionID != nil { + if opts.CPUGroupID != "" { + return errors.New("resource partition ID and CPU group ID cannot be set at the same time") + } + } case *OptionsWCOW: if opts.EnableDeferredCommit && !opts.AllowOvercommit { return errors.New("EnableDeferredCommit is not supported on physically backed VMs") @@ -188,6 +193,11 @@ func verifyOptions(_ context.Context, options interface{}) error { if opts.SecurityPolicyEnabled && opts.GuestStateFilePath == "" { return fmt.Errorf("GuestStateFilePath must be provided when enabling security policy") } + if opts.ResourcePartitionID != nil { + if opts.CPUGroupID != "" { + return errors.New("resource partition ID and CPU group ID cannot be set at the same time") + } + } } return nil } diff --git a/internal/uvm/create_lcow.go b/internal/uvm/create_lcow.go index 6005532cfb..d6d9b4f2d3 100644 --- a/internal/uvm/create_lcow.go +++ b/internal/uvm/create_lcow.go @@ -657,9 +657,9 @@ func makeLCOWDoc(ctx context.Context, opts *OptionsLCOW, uvm *UtilityVM) (_ *hcs doc.VirtualMachine.ComputeTopology.Memory.SlitType = &firmwareFallbackMeasured } - if opts.ResourcePoolID != nil { - // TODO (maksiman): assign pod to resource pool and potentially do an OS version check before that - log.G(ctx).WithField("resource-pool-id", opts.ResourcePoolID.String()).Debug("setting resource pool ID") + if opts.ResourcePartitionID != nil { + // TODO (maksiman): assign pod to resource partition and potentially do an OS version check before that + log.G(ctx).WithField("resource-partition-id", opts.ResourcePartitionID.String()).Debug("setting resource partition ID") } // Add optional devices that were specified on the UVM spec diff --git a/internal/uvm/create_wcow.go b/internal/uvm/create_wcow.go index ed1744038b..9441a72e67 100644 --- a/internal/uvm/create_wcow.go +++ b/internal/uvm/create_wcow.go @@ -231,9 +231,9 @@ func prepareCommonConfigDoc(ctx context.Context, uvm *UtilityVM, opts *OptionsWC doc.VirtualMachine.ComputeTopology.Memory.SlitType = &firmwareFallbackMeasured } - if opts.ResourcePoolID != nil { - // TODO (maksiman): assign pod to resource pool and potentially do an OS version check before that - log.G(ctx).WithField("resource-pool-id", opts.ResourcePoolID.String()).Debug("setting resource pool ID") + if opts.ResourcePartitionID != nil { + // TODO (maksiman): assign pod to resource partition and potentially do an OS version check before that + log.G(ctx).WithField("resource-partition-id", opts.ResourcePartitionID.String()).Debug("setting resource partition ID") } maps.Copy(doc.VirtualMachine.Devices.HvSocket.HvSocketConfig.ServiceTable, opts.AdditionalHyperVConfig) diff --git a/pkg/annotations/annotations.go b/pkg/annotations/annotations.go index e757faf96a..38653ec233 100644 --- a/pkg/annotations/annotations.go +++ b/pkg/annotations/annotations.go @@ -217,6 +217,7 @@ const ( // uVM CPU annotations. const ( // CPUGroupID specifies the cpugroup ID that a UVM should be assigned to, if any. + // Passing this annotation together with ResourcePartitionID will result in an error. CPUGroupID = "io.microsoft.virtualmachine.cpugroup.id" // ProcessorCount overrides the hypervisor isolated vCPU count set @@ -313,8 +314,10 @@ const ( // This should be used for explicit vNUMA topology. NumaCountOfMemoryBlocks = "io.microsoft.virtualmachine.computetopology.numa.count-of-memory-blocks" - // ResourcePoolID is a GUID string representing a resource pool ID the UVM should be associated with. - ResourcePoolID = "io.microsoft.virtualmachine.resource-pool-id" + // ResourcePartitionID is a GUID string representing a resource partition ID the UVM should be associated with. + // Resource partition will have its own CPU group, as a result this annotation cannot be used together with + // CPUGroupID and will yield an error. + ResourcePartitionID = "io.microsoft.virtualmachine.resource-partition-id" ) // uVM storage (Quality of Service) annotations.