From 7b2dada57475f255ededc19ddf80fe10d2f13c55 Mon Sep 17 00:00:00 2001 From: Gal-Zaidman Date: Mon, 19 Apr 2021 13:26:35 +0300 Subject: [PATCH] oVirt: update ovirt terraform provider anf cluster-api-provider-ovirt Updates the oVirt terraform and cluster api providers to get ovirt affinity group abilities --- go.mod | 4 +- go.sum | 9 +- pkg/terraform/exec/plugins/ovirt.go | 2 +- .../pkg/apis/ovirtprovider/v1beta1/types.go | 7 +- .../ovirt/provider.go | 49 ++++++++- .../ovirt/resource_ovirt_affinity_group.go | 26 +++-- .../ovirt/resource_ovirt_vm.go | 103 +++++++++++++++++- .../terraform-provider-ovirt/ovirt/utils.go | 16 +++ vendor/modules.txt | 4 +- 9 files changed, 193 insertions(+), 27 deletions(-) diff --git a/go.mod b/go.mod index c868976e16..dd89b47ccd 100644 --- a/go.mod +++ b/go.mod @@ -61,12 +61,12 @@ require ( github.com/openshift/cluster-api-provider-gcp v0.0.1-0.20201203141909-4dc702fd57a5 github.com/openshift/cluster-api-provider-kubevirt v0.0.0-20201214114543-e5aed9c73f1f github.com/openshift/cluster-api-provider-libvirt v0.2.1-0.20191219173431-2336783d4603 - github.com/openshift/cluster-api-provider-ovirt v0.1.1-0.20210315122142-893a4db3909a + github.com/openshift/cluster-api-provider-ovirt v0.1.1-0.20210406154451-1ea59ab6b543 github.com/openshift/library-go v0.0.0-20201215165635-4ee79b1caed5 github.com/openshift/machine-api-operator v0.2.1-0.20210104142355-8e6ae0acdfcf github.com/openshift/machine-config-operator v0.0.0 github.com/ovirt/go-ovirt v0.0.0-20210308100159-ac0bcbc88d7c - github.com/ovirt/terraform-provider-ovirt v0.99.1-0.20210326142716-4545f80e61cd + github.com/ovirt/terraform-provider-ovirt v0.99.1-0.20210419101841-5d3f6567ce90 github.com/packer-community/winrmcp v0.0.0-20180921211025-c76d91c1e7db // indirect github.com/pborman/uuid v1.2.0 github.com/pkg/errors v0.9.1 diff --git a/go.sum b/go.sum index dc43cb7349..6d5ba1432f 100644 --- a/go.sum +++ b/go.sum @@ -1237,8 +1237,8 @@ github.com/openshift/cluster-api-provider-libvirt v0.2.1-0.20191219173431-233678 github.com/openshift/cluster-api-provider-libvirt v0.2.1-0.20191219173431-2336783d4603/go.mod h1:7pQ9Bzha+ug/5zd+0ufbDEcnn2OnNlPwRwYrzhXk4NM= github.com/openshift/cluster-api-provider-openstack v0.0.0-20210302164104-8498241fa4bd h1:5mq9/JftiO9u/RknQ5iR9Nkd09R1XFfUPS1nO11Wth0= github.com/openshift/cluster-api-provider-openstack v0.0.0-20210302164104-8498241fa4bd/go.mod h1:ONl4R7ziQtgnsBjR59fcZbOLjBEPVeZ69C1TPKevynw= -github.com/openshift/cluster-api-provider-ovirt v0.1.1-0.20210315122142-893a4db3909a h1:ZVGkVxyKM00gzdJRC7LYEBGgL4CfK8W50uOjj0fX1/E= -github.com/openshift/cluster-api-provider-ovirt v0.1.1-0.20210315122142-893a4db3909a/go.mod h1:pqKflzzmag/YrCHzJw5rpjk9o+rArgPn9qEVEe4ULP8= +github.com/openshift/cluster-api-provider-ovirt v0.1.1-0.20210406154451-1ea59ab6b543 h1:rzPiPUccXtMbXuOlgIXU8Qhhn9zQpTLeuyDcOfZc2MA= +github.com/openshift/cluster-api-provider-ovirt v0.1.1-0.20210406154451-1ea59ab6b543/go.mod h1:PDoRQIKJb/XT14ebzBoNH0I6ZV2yA7G+jJCk1gCsXB0= github.com/openshift/cluster-autoscaler-operator v0.0.0-20190521201101-62768a6ba480/go.mod h1:/XmV44Fh28Vo3Ye93qFrxAbcFJ/Uy+7LPD+jGjmfJYc= github.com/openshift/custom-resource-status v0.0.0-20190822192428-e62f2f3b79f3 h1:XuAys09+XqT5/FjdR23G/UtbBLII89dFe9XIi73EKIQ= github.com/openshift/custom-resource-status v0.0.0-20190822192428-e62f2f3b79f3/go.mod h1:GDjWl0tX6FNIj82vIxeudWeSx2Ff6nDZ8uJn0ohUFvo= @@ -1278,11 +1278,10 @@ github.com/operator-framework/operator-sdk v0.5.1-0.20190301204940-c2efe6f74e7b/ github.com/oracle/oci-go-sdk v7.0.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888= github.com/ory/dockertest v3.3.4+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= github.com/ostreedev/ostree-go v0.0.0-20190702140239-759a8c1ac913/go.mod h1:J6OG6YJVEWopen4avK3VNQSnALmmjvniMmni/YFYAwc= -github.com/ovirt/go-ovirt v0.0.0-20210112072624-e4d3b104de71/go.mod h1:fLDxPk1Sf64DBYtwIYxrnx3gPZ1q0xPdWdI1y9vxUaw= github.com/ovirt/go-ovirt v0.0.0-20210308100159-ac0bcbc88d7c h1:2SbYZedeIawU8sGFnohfrdEcEMBA4V8SDouG6hly+H4= github.com/ovirt/go-ovirt v0.0.0-20210308100159-ac0bcbc88d7c/go.mod h1:fLDxPk1Sf64DBYtwIYxrnx3gPZ1q0xPdWdI1y9vxUaw= -github.com/ovirt/terraform-provider-ovirt v0.99.1-0.20210326142716-4545f80e61cd h1:dG/VniPIWmJbiCunCA2S85QULDPQhXkUhlKo1T3MOYo= -github.com/ovirt/terraform-provider-ovirt v0.99.1-0.20210326142716-4545f80e61cd/go.mod h1:xiMZ4bXb5VDorJN++WoqRbxLQ6k4sSlw59jqs5R08JQ= +github.com/ovirt/terraform-provider-ovirt v0.99.1-0.20210419101841-5d3f6567ce90 h1:7URZwDm8pcQukU2VH69h8eI1DQDLZtfCKkKtuvQ9/DA= +github.com/ovirt/terraform-provider-ovirt v0.99.1-0.20210419101841-5d3f6567ce90/go.mod h1:wnTGn9+USQJ51TMV5brymzjxUfmYmnOQZuNfYeuqky8= github.com/oxtoacart/bpool v0.0.0-20150712133111-4e1c5567d7c2/go.mod h1:L3UMQOThbttwfYRNFOWLLVXMhk5Lkio4GGOtw5UrxS0= github.com/packer-community/winrmcp v0.0.0-20180102160824-81144009af58/go.mod h1:f6Izs6JvFTdnRbziASagjZ2vmf55NSIkC/weStxCHqk= github.com/packer-community/winrmcp v0.0.0-20180921211025-c76d91c1e7db h1:9uViuKtx1jrlXLBW/pMnhOfzn3iSEdLase/But/IZRU= diff --git a/pkg/terraform/exec/plugins/ovirt.go b/pkg/terraform/exec/plugins/ovirt.go index 258be00b46..97c47dcbb0 100644 --- a/pkg/terraform/exec/plugins/ovirt.go +++ b/pkg/terraform/exec/plugins/ovirt.go @@ -8,7 +8,7 @@ import ( func init() { exec := func() { plugin.Serve(&plugin.ServeOpts{ - ProviderFunc: ovirt.Provider, + ProviderFunc: ovirt.ProviderContext(), }) } KnownPlugins["terraform-provider-ovirt"] = exec diff --git a/vendor/github.com/openshift/cluster-api-provider-ovirt/pkg/apis/ovirtprovider/v1beta1/types.go b/vendor/github.com/openshift/cluster-api-provider-ovirt/pkg/apis/ovirtprovider/v1beta1/types.go index f092332732..04daab0132 100644 --- a/vendor/github.com/openshift/cluster-api-provider-ovirt/pkg/apis/ovirtprovider/v1beta1/types.go +++ b/vendor/github.com/openshift/cluster-api-provider-ovirt/pkg/apis/ovirtprovider/v1beta1/types.go @@ -75,7 +75,12 @@ type OvirtMachineProviderSpec struct { // VMAffinityGroup contains the name of the OpenShift cluster affinity groups // It will be used to add the newly created machine to the affinity groups - AffinityGroupsNames []string `json:"affinity_groups_names,omitempty` + AffinityGroupsNames []string `json:"affinity_groups_names,omitempty"` + + // AutoPinningPolicy defines the policy to automatically set the CPU + // and NUMA including pinning to the host for the instance. + // One of "disabled, existing, adjust" + AutoPinningPolicy string `json:"auto_pinning_policy,omitempty"` } // CPU defines the VM cpu, made of (Sockets * Cores * Threads) diff --git a/vendor/github.com/ovirt/terraform-provider-ovirt/ovirt/provider.go b/vendor/github.com/ovirt/terraform-provider-ovirt/ovirt/provider.go index 7983dc5a6f..8be1518d83 100644 --- a/vendor/github.com/ovirt/terraform-provider-ovirt/ovirt/provider.go +++ b/vendor/github.com/ovirt/terraform-provider-ovirt/ovirt/provider.go @@ -9,14 +9,26 @@ package ovirt import ( "fmt" + "sync" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/terraform" ovirtsdk4 "github.com/ovirt/go-ovirt" ) +type providerContext struct { + semaphores *semaphoreProvider +} + +func ProviderContext() func() terraform.ResourceProvider { + c := &providerContext{ + semaphores: newSemaphoreProvider(), + } + return c.Provider +} + // Provider returns oVirt provider configuration -func Provider() terraform.ResourceProvider { +func (c *providerContext) Provider() terraform.ResourceProvider { return &schema.Provider{ Schema: map[string]*schema.Schema{ "username": { @@ -72,7 +84,7 @@ func Provider() terraform.ResourceProvider { ConfigureFunc: ConfigureProvider, ResourcesMap: map[string]*schema.Resource{ "ovirt_affinity_group": resourceOvirtAffinityGroup(), - "ovirt_vm": resourceOvirtVM(), + "ovirt_vm": resourceOvirtVM(c), "ovirt_template": resourceOvirtTemplate(), "ovirt_disk": resourceOvirtDisk(), "ovirt_disk_attachment": resourceOvirtDiskAttachment(), @@ -136,3 +148,36 @@ func ConfigureProvider(d *schema.ResourceData) (interface{}, error) { return connBuilder.Build() } + +func newSemaphoreProvider() *semaphoreProvider { + return &semaphoreProvider{ + lock: &sync.Mutex{}, + semaphores: map[string]chan struct{}{}, + } +} + +type semaphoreProvider struct { + lock *sync.Mutex + semaphores map[string]chan struct{} +} + +func (s *semaphoreProvider) Lock(semName string, capacity uint) { + if capacity < 1 { + panic(fmt.Sprintf("Invalid semaphoreProvider capacity %d for sem %s", capacity, semName)) + } + s.lock.Lock() + if _, ok := s.semaphores[semName]; !ok { + s.semaphores[semName] = make(chan struct{}, capacity) + } + s.lock.Unlock() + s.semaphores[semName] <- struct{}{} +} + +func (s *semaphoreProvider) Unlock(semName string) { + s.lock.Lock() + if _, ok := s.semaphores[semName]; !ok { + panic(fmt.Sprintf("semaphoreProvider unlock called before lock: %s", semName)) + } + s.lock.Unlock() + <-s.semaphores[semName] +} diff --git a/vendor/github.com/ovirt/terraform-provider-ovirt/ovirt/resource_ovirt_affinity_group.go b/vendor/github.com/ovirt/terraform-provider-ovirt/ovirt/resource_ovirt_affinity_group.go index 44bc8dc481..a1f2b2edd7 100644 --- a/vendor/github.com/ovirt/terraform-provider-ovirt/ovirt/resource_ovirt_affinity_group.go +++ b/vendor/github.com/ovirt/terraform-provider-ovirt/ovirt/resource_ovirt_affinity_group.go @@ -106,23 +106,29 @@ func resourceOvirtAffinityGroupCreate(d *schema.ResourceData, meta interface{}) } vmRuleBuilder := ovirtsdk4.NewAffinityRuleBuilder() - if _, ok := d.GetOk("vm_list"); ok { + vmRuleBuilder.Enabled(false) + if vmPositive, ok := d.GetOkExists("vm_positive"); ok { vmRuleBuilder.Enabled(true) - vmRuleBuilder.Positive(d.Get("vm_positive").(bool)) - vmRuleBuilder.Enforcing(d.Get("vm_enforcing").(bool)) - } else { - vmRuleBuilder.Enabled(false) + vmRuleBuilder.Positive(vmPositive.(bool)) } + if vmEnforcing, ok := d.GetOk("vm_enforcing"); ok { + vmRuleBuilder.Enabled(true) + vmRuleBuilder.Enforcing(vmEnforcing.(bool)) + } + agBuilder.VmsRule(vmRuleBuilder.MustBuild()) hostRuleBuilder := ovirtsdk4.NewAffinityRuleBuilder() - if _, ok := d.GetOk("host_list"); ok { + hostRuleBuilder.Enabled(false) + if hostPositive, ok := d.GetOkExists("host_positive"); ok { hostRuleBuilder.Enabled(true) - hostRuleBuilder.Positive(d.Get("host_positive").(bool)) - hostRuleBuilder.Enforcing(d.Get("host_enforcing").(bool)) - } else { - hostRuleBuilder.Enabled(false) + hostRuleBuilder.Positive(hostPositive.(bool)) } + if hostEnforcing, ok := d.GetOk("host_enforcing"); ok { + hostRuleBuilder.Enabled(true) + hostRuleBuilder.Enforcing(hostEnforcing.(bool)) + } + agBuilder.HostsRule(hostRuleBuilder.MustBuild()) log.Printf("Creating %#v", agBuilder.MustBuild()) diff --git a/vendor/github.com/ovirt/terraform-provider-ovirt/ovirt/resource_ovirt_vm.go b/vendor/github.com/ovirt/terraform-provider-ovirt/ovirt/resource_ovirt_vm.go index 5dfc5c78f3..dc0d560645 100644 --- a/vendor/github.com/ovirt/terraform-provider-ovirt/ovirt/resource_ovirt_vm.go +++ b/vendor/github.com/ovirt/terraform-provider-ovirt/ovirt/resource_ovirt_vm.go @@ -8,6 +8,7 @@ package ovirt import ( + "errors" "fmt" "log" "math" @@ -22,9 +23,9 @@ import ( // BlankTemplateID indicates the ID of default blank template in oVirt const BlankTemplateID = "00000000-0000-0000-0000-000000000000" -func resourceOvirtVM() *schema.Resource { +func resourceOvirtVM(c *providerContext) *schema.Resource { return &schema.Resource{ - Create: resourceOvirtVMCreate, + Create: c.resourceOvirtVMCreate, Read: resourceOvirtVMRead, Update: resourceOvirtVMUpdate, Delete: resourceOvirtVMDelete, @@ -361,11 +362,28 @@ func resourceOvirtVM() *schema.Resource { string(ovirtsdk4.AUTOPINNINGPOLICY_ADJUST), }, false), }, + "affinity_groups": { + Type: schema.TypeSet, + Optional: true, + Description: "The name of the Affinity Groups that the VM will join", + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "hugepages": { + Type: schema.TypeInt, + Optional: true, + Description: "The size of hugepage to use in KiB, One of 2048 or 1048576", + ValidateFunc: validation.IntInSlice([]int{ + 2048, + 1048576, + }), + }, }, } } -func resourceOvirtVMCreate(d *schema.ResourceData, meta interface{}) error { +func (c *providerContext) resourceOvirtVMCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*ovirtsdk4.Connection) // template with disks attached is conflicted with block_device @@ -407,8 +425,9 @@ func resourceOvirtVMCreate(d *schema.ResourceData, meta interface{}) error { memoryPolicyBuilder.Max(int64(maximumMemory.(int)) * int64(math.Pow(2, 20))) } + clusterId := d.Get("cluster_id").(string) cluster, err := ovirtsdk4.NewClusterBuilder(). - Id(d.Get("cluster_id").(string)).Build() + Id(clusterId).Build() if err != nil { return err } @@ -623,6 +642,17 @@ func resourceOvirtVMCreate(d *schema.ResourceData, meta interface{}) error { } } + if v, ok := d.GetOk("hugepages"); ok { + customProp, err := ovirtsdk4.NewCustomPropertyBuilder(). + Name("hugepages"). + Value(fmt.Sprint(v)). + Build() + if err != nil { + return err + } + vmBuilder.CustomPropertiesOfAny(customProp) + } + if v, ok := d.GetOk("instance_type_id"); ok { vmBuilder.InstanceTypeBuilder( ovirtsdk4.NewInstanceTypeBuilder().Id(v.(string))) @@ -714,6 +744,22 @@ func resourceOvirtVMCreate(d *schema.ResourceData, meta interface{}) error { } } + affinityGroups, affinityGroupsOk := d.GetOk("affinity_groups") + if affinityGroupsOk { + agStr, err := convInterfaceArrToStringArr(affinityGroups.(*schema.Set).List()) + if err != nil { + return err + } + ag, err := getAffinityGroups(conn, clusterId, agStr) + if err != nil { + return err + } + err = c.addVmToAffinityGroups(conn, newVM, clusterId, ag) + if err != nil { + return err + } + } + autoStart := d.Get("auto_start").(bool) if autoStart { // Try to start VM @@ -1609,3 +1655,52 @@ func getTemplateDiskAttachments(templateID string, meta interface{}) ([]*ovirtsd } return nil, nil } + +func getAffinityGroups(conn *ovirtsdk4.Connection, cID string, agNames []string) (ag []*ovirtsdk4.AffinityGroup, err error) { + var ags []*ovirtsdk4.AffinityGroup + var notFoundAGs []string + + res, err := conn.SystemService().ClustersService(). + ClusterService(cID).AffinityGroupsService(). + List().Send() + if err != nil { + return nil, err + } + agNamesMap := make(map[string]*ovirtsdk4.AffinityGroup) + for _, af := range res.MustGroups().Slice() { + agNamesMap[af.MustName()] = af + } + for _, agName := range agNames { + if _, ok := agNamesMap[agName]; !ok { + notFoundAGs = append(notFoundAGs, agName) + } else { + ags = append(ags, agNamesMap[agName]) + } + } + if len(notFoundAGs) > 0 { + return nil, fmt.Errorf("affinity groups %v were not found on cluster %s", notFoundAGs, cID) + } + return ags, nil +} + +func (c *providerContext) addVmToAffinityGroups(conn *ovirtsdk4.Connection, vm *ovirtsdk4.Vm, cID string, ags []*ovirtsdk4.AffinityGroup) error { + // TODO: Remove lock once BZ#1950767 is resolved + c.semaphores.Lock("vm-ag", 1) + defer c.semaphores.Unlock("vm-ag") + + for _, ag := range ags { + log.Printf("Adding machine %s to affinity group %s", vm.MustName(), ag.MustName()) + _, err := conn.SystemService().ClustersService(). + ClusterService(cID).AffinityGroupsService(). + GroupService(ag.MustId()).VmsService().Add().Vm(vm).Send() + // TODO: Remove error handling workaround when BZ#1931932 is resolved and backported + if err != nil && !errors.Is(err, ovirtsdk4.XMLTagNotMatchError{ActualTag: "action", ExpectedTag: "vm"}) { + return fmt.Errorf( + "failed to add VM %s to AffinityGroup %s, error: %v", + vm.MustName(), + ag.MustName(), + err) + } + } + return nil +} diff --git a/vendor/github.com/ovirt/terraform-provider-ovirt/ovirt/utils.go b/vendor/github.com/ovirt/terraform-provider-ovirt/ovirt/utils.go index 611480aa65..a1836c25bd 100644 --- a/vendor/github.com/ovirt/terraform-provider-ovirt/ovirt/utils.go +++ b/vendor/github.com/ovirt/terraform-provider-ovirt/ovirt/utils.go @@ -64,3 +64,19 @@ func parseResourceID(id string, count int) ([]string, error) { } return parts, nil } + +//Converts an array of type []interface{} to []string, notice that all the interface elements needs to be strings +func convInterfaceArrToStringArr(arr []interface{}) ([]string, error) { + var newArr []string + for _, val := range arr { + if s, ok := val.(string); ok { + newArr = append(newArr, s) + } else { + return nil, fmt.Errorf( + "error converting []interface{} to []string, "+ + "provided interface array %v contains non string elements %v", + arr, val) + } + } + return newArr, nil +} diff --git a/vendor/modules.txt b/vendor/modules.txt index c907cecb71..d6bc6f6580 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1131,7 +1131,7 @@ github.com/openshift/cluster-api-provider-kubevirt/pkg/utils ## explicit github.com/openshift/cluster-api-provider-libvirt/pkg/apis github.com/openshift/cluster-api-provider-libvirt/pkg/apis/libvirtproviderconfig/v1beta1 -# github.com/openshift/cluster-api-provider-ovirt v0.1.1-0.20210315122142-893a4db3909a +# github.com/openshift/cluster-api-provider-ovirt v0.1.1-0.20210406154451-1ea59ab6b543 ## explicit github.com/openshift/cluster-api-provider-ovirt/pkg/apis github.com/openshift/cluster-api-provider-ovirt/pkg/apis/ovirtprovider/v1beta1 @@ -1153,7 +1153,7 @@ github.com/openshift/machine-config-operator/pkg/apis/machineconfiguration.opens # github.com/ovirt/go-ovirt v0.0.0-20210308100159-ac0bcbc88d7c ## explicit github.com/ovirt/go-ovirt -# github.com/ovirt/terraform-provider-ovirt v0.99.1-0.20210326142716-4545f80e61cd +# github.com/ovirt/terraform-provider-ovirt v0.99.1-0.20210419101841-5d3f6567ce90 ## explicit github.com/ovirt/terraform-provider-ovirt/ovirt # github.com/packer-community/winrmcp v0.0.0-20180921211025-c76d91c1e7db