@@ -17,7 +17,9 @@ limitations under the License.
1717package machineset
1818
1919import (
20+ "context"
2021 "fmt"
22+ "strings"
2123 "testing"
2224 "time"
2325
@@ -26,11 +28,13 @@ import (
2628 apierrors "k8s.io/apimachinery/pkg/api/errors"
2729 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2830 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
31+ "k8s.io/apimachinery/pkg/runtime/schema"
2932 "k8s.io/apimachinery/pkg/util/intstr"
3033 "k8s.io/client-go/tools/record"
3134 "k8s.io/utils/ptr"
3235 "sigs.k8s.io/controller-runtime/pkg/client"
3336 "sigs.k8s.io/controller-runtime/pkg/client/fake"
37+ "sigs.k8s.io/controller-runtime/pkg/client/interceptor"
3438 "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
3539 "sigs.k8s.io/controller-runtime/pkg/reconcile"
3640
@@ -2346,6 +2350,157 @@ func TestMachineSetReconciler_syncReplicas(t *testing.T) {
23462350 })
23472351}
23482352
2353+ func TestMachineSetReconciler_syncReplicas_WithErrors (t * testing.T ) {
2354+ t .Run ("should hold off on sync replicas when create Infrastructure of machine failed " , func (t * testing.T ) {
2355+ g := NewWithT (t )
2356+ fakeClient := fake .NewClientBuilder ().WithObjects ().WithInterceptorFuncs (interceptor.Funcs {
2357+ Create : func (ctx context.Context , client client.WithWatch , obj client.Object , opts ... client.CreateOption ) error {
2358+ // simulate scenarios where infra object creation fails
2359+ if obj .GetObjectKind ().GroupVersionKind ().Kind == "GenericInfrastructureMachine" {
2360+ return fmt .Errorf ("inject error for create machineInfrastructure" )
2361+ }
2362+ return client .Create (ctx , obj , opts ... )
2363+ },
2364+ }).Build ()
2365+
2366+ r := & Reconciler {
2367+ Client : fakeClient ,
2368+ }
2369+ testCluster := & clusterv1.Cluster {}
2370+ testCluster .Namespace = "default"
2371+ testCluster .Name = "test-cluster"
2372+ version := "v1.14.2"
2373+ duration10m := & metav1.Duration {Duration : 10 * time .Minute }
2374+ machineSet := & clusterv1.MachineSet {
2375+ ObjectMeta : metav1.ObjectMeta {
2376+ Name : "machineset1" ,
2377+ Namespace : metav1 .NamespaceDefault ,
2378+ Finalizers : []string {"block-deletion" },
2379+ },
2380+ Spec : clusterv1.MachineSetSpec {
2381+ Replicas : ptr.To [int32 ](1 ),
2382+ ClusterName : "test-cluster" ,
2383+ Template : clusterv1.MachineTemplateSpec {
2384+ Spec : clusterv1.MachineSpec {
2385+ ClusterName : testCluster .Name ,
2386+ Version : & version ,
2387+ Bootstrap : clusterv1.Bootstrap {
2388+ ConfigRef : & corev1.ObjectReference {
2389+ APIVersion : "bootstrap.cluster.x-k8s.io/v1beta1" ,
2390+ Kind : "GenericBootstrapConfigTemplate" ,
2391+ Name : "ms-template" ,
2392+ Namespace : metav1 .NamespaceDefault ,
2393+ },
2394+ },
2395+ InfrastructureRef : corev1.ObjectReference {
2396+ APIVersion : "infrastructure.cluster.x-k8s.io/v1beta1" ,
2397+ Kind : "GenericInfrastructureMachineTemplate" ,
2398+ Name : "ms-template" ,
2399+ Namespace : metav1 .NamespaceDefault ,
2400+ },
2401+ NodeDrainTimeout : duration10m ,
2402+ NodeDeletionTimeout : duration10m ,
2403+ NodeVolumeDetachTimeout : duration10m ,
2404+ },
2405+ },
2406+ },
2407+ }
2408+
2409+ // Create bootstrap template resource.
2410+ bootstrapResource := map [string ]interface {}{
2411+ "kind" : "GenericBootstrapConfig" ,
2412+ "apiVersion" : "bootstrap.cluster.x-k8s.io/v1beta1" ,
2413+ "metadata" : map [string ]interface {}{
2414+ "annotations" : map [string ]interface {}{
2415+ "precedence" : "GenericBootstrapConfig" ,
2416+ },
2417+ },
2418+ }
2419+ bootstrapTmpl := & unstructured.Unstructured {
2420+ Object : map [string ]interface {}{
2421+ "spec" : map [string ]interface {}{
2422+ "template" : bootstrapResource ,
2423+ },
2424+ },
2425+ }
2426+ bootstrapTmpl .SetKind ("GenericBootstrapConfigTemplate" )
2427+ bootstrapTmpl .SetAPIVersion ("bootstrap.cluster.x-k8s.io/v1beta1" )
2428+ bootstrapTmpl .SetName ("ms-template" )
2429+ bootstrapTmpl .SetNamespace (metav1 .NamespaceDefault )
2430+ g .Expect (r .Client .Create (context .TODO (), bootstrapTmpl )).To (Succeed ())
2431+
2432+ // Create infrastructure template resource.
2433+ infraResource := map [string ]interface {}{
2434+ "kind" : "GenericInfrastructureMachine" ,
2435+ "apiVersion" : "infrastructure.cluster.x-k8s.io/v1beta1" ,
2436+ "metadata" : map [string ]interface {}{
2437+ "annotations" : map [string ]interface {}{
2438+ "precedence" : "GenericInfrastructureMachineTemplate" ,
2439+ },
2440+ },
2441+ "spec" : map [string ]interface {}{
2442+ "size" : "3xlarge" ,
2443+ },
2444+ }
2445+ infraTmpl := & unstructured.Unstructured {
2446+ Object : map [string ]interface {}{
2447+ "spec" : map [string ]interface {}{
2448+ "template" : infraResource ,
2449+ },
2450+ },
2451+ }
2452+ infraTmpl .SetKind ("GenericInfrastructureMachineTemplate" )
2453+ infraTmpl .SetAPIVersion ("infrastructure.cluster.x-k8s.io/v1beta1" )
2454+ infraTmpl .SetName ("ms-template" )
2455+ infraTmpl .SetNamespace (metav1 .NamespaceDefault )
2456+ g .Expect (r .Client .Create (context .TODO (), infraTmpl )).To (Succeed ())
2457+
2458+ s := & scope {
2459+ cluster : testCluster ,
2460+ machineSet : machineSet ,
2461+ machines : []* clusterv1.Machine {},
2462+ getAndAdoptMachinesForMachineSetSucceeded : true ,
2463+ }
2464+ _ , err := r .syncReplicas (ctx , s )
2465+ g .Expect (err ).To (HaveOccurred ())
2466+
2467+ // Verify the proper condition is set on the MachineSet.
2468+ condition := clusterv1 .MachinesCreatedCondition
2469+ g .Expect (conditions .Has (machineSet , condition )).To (BeTrue (), "MachineSet should have the %s condition set" , condition )
2470+
2471+ machinesCreatedCondition := conditions .Get (machineSet , condition )
2472+ g .Expect (machinesCreatedCondition .Status ).
2473+ To (Equal (corev1 .ConditionFalse ), "%s condition status should be %s" , condition , corev1 .ConditionFalse )
2474+ g .Expect (machinesCreatedCondition .Reason ).
2475+ To (Equal (clusterv1 .InfrastructureTemplateCloningFailedReason ), "%s condition reason should be %s" , condition , clusterv1 .InfrastructureTemplateCloningFailedReason )
2476+
2477+ // Verify no new Machines are created.
2478+ machineList := & clusterv1.MachineList {}
2479+ g .Expect (r .Client .List (ctx , machineList )).To (Succeed ())
2480+ g .Expect (machineList .Items ).To (BeEmpty (), "There should not be any machines" )
2481+
2482+ // Verify no boostrap object created
2483+ bootstrapList := & unstructured.UnstructuredList {}
2484+ bootstrapList .SetGroupVersionKind (schema.GroupVersionKind {
2485+ Group : bootstrapTmpl .GetObjectKind ().GroupVersionKind ().Group ,
2486+ Version : bootstrapTmpl .GetObjectKind ().GroupVersionKind ().Version ,
2487+ Kind : strings .TrimSuffix (bootstrapTmpl .GetObjectKind ().GroupVersionKind ().Kind , clusterv1 .TemplateSuffix ),
2488+ })
2489+ g .Expect (r .Client .List (ctx , bootstrapList )).To (Succeed ())
2490+ g .Expect (bootstrapList .Items ).To (BeEmpty (), "There should not be any bootstrap object" )
2491+
2492+ // Verify no infra object created
2493+ infraList := & unstructured.UnstructuredList {}
2494+ infraList .SetGroupVersionKind (schema.GroupVersionKind {
2495+ Group : infraTmpl .GetObjectKind ().GroupVersionKind ().Group ,
2496+ Version : infraTmpl .GetObjectKind ().GroupVersionKind ().Version ,
2497+ Kind : strings .TrimSuffix (infraTmpl .GetObjectKind ().GroupVersionKind ().Kind , clusterv1 .TemplateSuffix ),
2498+ })
2499+ g .Expect (r .Client .List (ctx , infraList )).To (Succeed ())
2500+ g .Expect (infraList .Items ).To (BeEmpty (), "There should not be any infra object" )
2501+ })
2502+ }
2503+
23492504func TestComputeDesiredMachine (t * testing.T ) {
23502505 duration5s := & metav1.Duration {Duration : 5 * time .Second }
23512506 duration10s := & metav1.Duration {Duration : 10 * time .Second }
0 commit comments