@@ -20,9 +20,15 @@ package e2e
2020
2121import (
2222 "context"
23-
24- "github.com/onsi/ginkgo"
25- "github.com/onsi/gomega"
23+ "errors"
24+ "fmt"
25+ "github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2020-06-30/compute"
26+ "github.com/Azure/azure-sdk-for-go/services/containerservice/mgmt/2020-02-01/containerservice"
27+ "github.com/Azure/go-autorest/autorest/azure/auth"
28+ . "github.com/onsi/ginkgo"
29+ . "github.com/onsi/gomega"
30+ "golang.org/x/mod/semver"
31+ corev1 "k8s.io/api/core/v1"
2632 "k8s.io/apimachinery/pkg/types"
2733 infraexpv1 "sigs.k8s.io/cluster-api-provider-azure/exp/api/v1alpha4"
2834 clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha4"
@@ -64,16 +70,16 @@ type DiscoverAndWaitForControlPlaneMachinesInput struct {
6470// DiscoverAndWaitForControlPlaneInitialized gets the azure managed control plane associated with the cluster,
6571// and waits for atleast one control plane machine to be up.
6672func DiscoverAndWaitForControlPlaneInitialized (ctx context.Context , input DiscoverAndWaitForControlPlaneMachinesInput , intervals ... interface {}) {
67- gomega . Expect (ctx ).NotTo (gomega . BeNil (), "ctx is required for DiscoverAndWaitForControlPlaneInitialized" )
68- gomega . Expect (input .Lister ).ToNot (gomega . BeNil (), "Invalid argument. input.Lister can't be nil when calling DiscoverAndWaitForControlPlaneInitialized" )
69- gomega . Expect (input .Cluster ).ToNot (gomega . BeNil (), "Invalid argument. input.Cluster can't be nil when calling DiscoverAndWaitForControlPlaneInitialized" )
73+ Expect (ctx ).NotTo (BeNil (), "ctx is required for DiscoverAndWaitForControlPlaneInitialized" )
74+ Expect (input .Lister ).ToNot (BeNil (), "Invalid argument. input.Lister can't be nil when calling DiscoverAndWaitForControlPlaneInitialized" )
75+ Expect (input .Cluster ).ToNot (BeNil (), "Invalid argument. input.Cluster can't be nil when calling DiscoverAndWaitForControlPlaneInitialized" )
7076
7177 controlPlane := GetAzureManagedControlPlaneByCluster (ctx , GetAzureManagedControlPlaneByClusterInput {
7278 Lister : input .Lister ,
7379 ClusterName : input .Cluster .Name ,
7480 Namespace : input .Cluster .Namespace ,
7581 })
76- gomega . Expect (controlPlane ).ToNot (gomega . BeNil ())
82+ Expect (controlPlane ).ToNot (BeNil ())
7783
7884 Logf ("Waiting for the first control plane machine managed by %s/%s to be provisioned" , controlPlane .Namespace , controlPlane .Name )
7985 WaitForAtLeastOneControlPlaneAndMachineToExist (ctx , WaitForControlPlaneAndMachinesReadyInput {
@@ -87,16 +93,16 @@ func DiscoverAndWaitForControlPlaneInitialized(ctx context.Context, input Discov
8793// DiscoverAndWaitForControlPlaneReady gets the azure managed control plane associated with the cluster,
8894// and waits for all the control plane machines to be up.
8995func DiscoverAndWaitForControlPlaneReady (ctx context.Context , input DiscoverAndWaitForControlPlaneMachinesInput , intervals ... interface {}) {
90- gomega . Expect (ctx ).NotTo (gomega . BeNil (), "ctx is required for DiscoverAndWaitForControlPlaneReady" )
91- gomega . Expect (input .Lister ).ToNot (gomega . BeNil (), "Invalid argument. input.Lister can't be nil when calling DiscoverAndWaitForControlPlaneReady" )
92- gomega . Expect (input .Cluster ).ToNot (gomega . BeNil (), "Invalid argument. input.Cluster can't be nil when calling DiscoverAndWaitForControlPlaneReady" )
96+ Expect (ctx ).NotTo (BeNil (), "ctx is required for DiscoverAndWaitForControlPlaneReady" )
97+ Expect (input .Lister ).ToNot (BeNil (), "Invalid argument. input.Lister can't be nil when calling DiscoverAndWaitForControlPlaneReady" )
98+ Expect (input .Cluster ).ToNot (BeNil (), "Invalid argument. input.Cluster can't be nil when calling DiscoverAndWaitForControlPlaneReady" )
9399
94100 controlPlane := GetAzureManagedControlPlaneByCluster (ctx , GetAzureManagedControlPlaneByClusterInput {
95101 Lister : input .Lister ,
96102 ClusterName : input .Cluster .Name ,
97103 Namespace : input .Cluster .Namespace ,
98104 })
99- gomega . Expect (controlPlane ).ToNot (gomega . BeNil ())
105+ Expect (controlPlane ).ToNot (BeNil ())
100106
101107 Logf ("Waiting for the first control plane machine managed by %s/%s to be provisioned" , controlPlane .Namespace , controlPlane .Name )
102108 WaitForAllControlPlaneAndMachinesToExist (ctx , WaitForControlPlaneAndMachinesReadyInput {
@@ -119,8 +125,8 @@ type GetAzureManagedControlPlaneByClusterInput struct {
119125// it is necessary to ensure this is already happened before calling it.
120126func GetAzureManagedControlPlaneByCluster (ctx context.Context , input GetAzureManagedControlPlaneByClusterInput ) * infraexpv1.AzureManagedControlPlane {
121127 controlPlaneList := & infraexpv1.AzureManagedControlPlaneList {}
122- gomega . Expect (input .Lister .List (ctx , controlPlaneList , byClusterOptions (input .ClusterName , input .Namespace )... )).To (gomega . Succeed (), "Failed to list AzureManagedControlPlane object for Cluster %s/%s" , input .Namespace , input .ClusterName )
123- gomega . Expect (len (controlPlaneList .Items )).ToNot (gomega . BeNumerically (">" , 1 ), "Cluster %s/%s should not have more than 1 AzureManagedControlPlane object" , input .Namespace , input .ClusterName )
128+ Expect (input .Lister .List (ctx , controlPlaneList , byClusterOptions (input .ClusterName , input .Namespace )... )).To (Succeed (), "Failed to list AzureManagedControlPlane object for Cluster %s/%s" , input .Namespace , input .ClusterName )
129+ Expect (len (controlPlaneList .Items )).ToNot (BeNumerically (">" , 1 ), "Cluster %s/%s should not have more than 1 AzureManagedControlPlane object" , input .Namespace , input .ClusterName )
124130 if len (controlPlaneList .Items ) == 1 {
125131 return & controlPlaneList .Items [0 ]
126132 }
@@ -137,13 +143,13 @@ type WaitForControlPlaneAndMachinesReadyInput struct {
137143
138144// WaitForAtLeastOneControlPlaneAndMachineToExist waits for atleast one control plane machine to be provisioned.
139145func WaitForAtLeastOneControlPlaneAndMachineToExist (ctx context.Context , input WaitForControlPlaneAndMachinesReadyInput , intervals ... interface {}) {
140- ginkgo . By ("Waiting for atleast one control plane node to exist" )
146+ By ("Waiting for atleast one control plane node to exist" )
141147 WaitForControlPlaneMachinesToExist (ctx , input , atLeastOne , intervals ... )
142148}
143149
144150// WaitForAllControlPlaneAndMachinesToExist waits for all control plane machines to be provisioned.
145151func WaitForAllControlPlaneAndMachinesToExist (ctx context.Context , input WaitForControlPlaneAndMachinesReadyInput , intervals ... interface {}) {
146- ginkgo . By ("Waiting for all control plane nodes to exist" )
152+ By ("Waiting for all control plane nodes to exist" )
147153 WaitForControlPlaneMachinesToExist (ctx , input , all , intervals ... )
148154}
149155
@@ -168,7 +174,7 @@ func (r controlPlaneReplicas) value(mp *clusterv1exp.MachinePool) int {
168174
169175// WaitForControlPlaneMachinesToExist waits for a certain number of control plane machines to be provisioned represented.
170176func WaitForControlPlaneMachinesToExist (ctx context.Context , input WaitForControlPlaneAndMachinesReadyInput , minReplicas controlPlaneReplicas , intervals ... interface {}) {
171- gomega . Eventually (func () (bool , error ) {
177+ Eventually (func () (bool , error ) {
172178 controlPlaneMachinePool := & clusterv1exp.MachinePool {}
173179 if err := input .Getter .Get (ctx , types.NamespacedName {Namespace : input .Namespace , Name : input .ControlPlane .Spec .DefaultPoolRef .Name },
174180 controlPlaneMachinePool ); err != nil {
@@ -177,7 +183,50 @@ func WaitForControlPlaneMachinesToExist(ctx context.Context, input WaitForContro
177183 }
178184 return len (controlPlaneMachinePool .Status .NodeRefs ) >= minReplicas .value (controlPlaneMachinePool ), nil
179185
180- }, intervals ... ).Should (gomega .Equal (true ))
186+ }, intervals ... ).Should (Equal (true ))
187+ }
188+
189+ // GetAKSKubernetesVersion gets the kubernetes version for AKS clusters.
190+ func GetAKSKubernetesVersion (ctx context.Context , e2eConfig * clusterctl.E2EConfig ) (string , error ) {
191+ e2eAKSVersion := e2eConfig .GetVariable (AKSKubernetesVersion )
192+
193+ location := e2eConfig .GetVariable (AzureLocation )
194+
195+ settings , err := auth .GetSettingsFromEnvironment ()
196+ Expect (err ).NotTo (HaveOccurred ())
197+ subscriptionID := settings .GetSubscriptionID ()
198+ authorizer , err := settings .GetAuthorizer ()
199+ Expect (err ).NotTo (HaveOccurred ())
200+ containerServiceClient := containerservice .NewContainerServicesClient (subscriptionID )
201+ containerServiceClient .Authorizer = authorizer
202+
203+ result , err := containerServiceClient .ListOrchestrators (ctx , location , ManagedClustersResourceType )
204+ if err != nil {
205+ return "" , err
206+ }
207+
208+ // For 1.19 release this will be 1.19.0
209+ baseVersion := fmt .Sprintf ("%s.0" , semver .MajorMinor (e2eAKSVersion ))
210+ maxVersion := fmt .Sprintf ("%s.0" , semver .MajorMinor (e2eAKSVersion ))
211+ for _ , o := range * result .Orchestrators {
212+ orchVersion := fmt .Sprintf ("v%s" , * o .OrchestratorVersion )
213+ // test k8s version matches with one of the supported aks versions.
214+ if orchVersion == e2eAKSVersion {
215+ return e2eAKSVersion , nil
216+ }
217+
218+ // find the highest aks version for a given major.minor
219+ if semver .MajorMinor (orchVersion ) == semver .MajorMinor (maxVersion ) && semver .Compare (orchVersion , maxVersion ) > 0 {
220+ maxVersion = orchVersion
221+ }
222+ }
223+
224+ // This means there is no version supported by AKS for this major.minor
225+ if semver .Compare (maxVersion , baseVersion ) == 0 {
226+ return "" , errors .New (fmt .Sprintf ("No AKS versions found for %s" , semver .MajorMinor (baseVersion )))
227+ }
228+
229+ return maxVersion , nil
181230}
182231
183232// byClusterOptions returns a set of ListOptions that allows to identify all the objects belonging to a Cluster.
@@ -189,3 +238,39 @@ func byClusterOptions(name, namespace string) []client.ListOption {
189238 },
190239 }
191240}
241+
242+ // AKSResourcesValidationSpecInput is the input for AKSResourcesValidationSpec
243+ type AKSResourcesValidationSpecInput struct {
244+ BootstrapClusterProxy framework.ClusterProxy
245+ Namespace * corev1.Namespace
246+ ClusterName string
247+ }
248+
249+ // AKSResourcesValidationSpec implements a test that verifies the resources created by an AKS cluster.
250+ func AKSResourcesValidationSpec (ctx context.Context , inputGetter func () AKSResourcesValidationSpecInput ) {
251+ var (
252+ specName = "aks-resources-validation"
253+ input AKSResourcesValidationSpecInput
254+ )
255+
256+ input = inputGetter ()
257+ Expect (input .ClusterName ).NotTo (BeEmpty (), "Invalid argument. input.ClusterName can't be empty when calling %s spec" , specName )
258+
259+ By ("creating Azure clients with the workload cluster's subscription, and querying for vmss" )
260+ var controlPlane = & infraexpv1.AzureManagedControlPlane {}
261+ Expect (input .BootstrapClusterProxy .GetClient ().Get (ctx ,
262+ types.NamespacedName {input .Namespace .Name , input .ClusterName }, controlPlane )).To (Succeed ())
263+
264+ settings , err := auth .GetSettingsFromEnvironment ()
265+ Expect (err ).NotTo (HaveOccurred ())
266+ subscriptionID := settings .GetSubscriptionID ()
267+ authorizer , err := settings .GetAuthorizer ()
268+ Expect (err ).NotTo (HaveOccurred ())
269+ vmssClient := compute .NewVirtualMachineScaleSetsClient (subscriptionID )
270+ vmssClient .Authorizer = authorizer
271+
272+ rgName := controlPlane .Spec .NodeResourceGroupName
273+ scalesets , err := vmssClient .List (ctx , rgName )
274+ Expect (err ).NotTo (HaveOccurred ())
275+ Expect (len (scalesets .Values ())).To (BeNumerically (">" , 0 ))
276+ }
0 commit comments