sigs.k8s.io/cluster-api-provider-azure@v1.14.3/azure/services/publicips/publicips_test.go (about) 1 /* 2 Copyright 2020 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package publicips 18 19 import ( 20 "context" 21 "io" 22 "net/http" 23 "strings" 24 "testing" 25 26 "github.com/Azure/azure-sdk-for-go/sdk/azcore" 27 "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources" 28 . "github.com/onsi/gomega" 29 "go.uber.org/mock/gomock" 30 "k8s.io/client-go/kubernetes/scheme" 31 "k8s.io/utils/ptr" 32 infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1" 33 "sigs.k8s.io/cluster-api-provider-azure/azure" 34 "sigs.k8s.io/cluster-api-provider-azure/azure/services/async/mock_async" 35 "sigs.k8s.io/cluster-api-provider-azure/azure/services/publicips/mock_publicips" 36 gomockinternal "sigs.k8s.io/cluster-api-provider-azure/internal/test/matchers/gomock" 37 "sigs.k8s.io/cluster-api-provider-azure/util/reconciler" 38 clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" 39 ) 40 41 func init() { 42 _ = clusterv1.AddToScheme(scheme.Scheme) 43 } 44 45 var ( 46 fakePublicIPSpec1 = PublicIPSpec{ 47 Name: "my-publicip", 48 ResourceGroup: "my-rg", 49 DNSName: "fakedns.mydomain.io", 50 IsIPv6: false, 51 ClusterName: "my-cluster", 52 Location: "centralIndia", 53 FailureDomains: []*string{ptr.To("failure-domain-id-1"), ptr.To("failure-domain-id-2"), ptr.To("failure-domain-id-3")}, 54 AdditionalTags: infrav1.Tags{ 55 "Name": "my-publicip-ipv6", 56 "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": "owned", 57 }, 58 } 59 fakePublicIPSpec2 = PublicIPSpec{ 60 Name: "my-publicip-2", 61 ResourceGroup: "my-rg", 62 DNSName: "fakedns2-52959.uksouth.cloudapp.azure.com", 63 IsIPv6: false, 64 ClusterName: "my-cluster", 65 Location: "centralIndia", 66 FailureDomains: []*string{ptr.To("failure-domain-id-1"), ptr.To("failure-domain-id-2"), ptr.To("failure-domain-id-3")}, 67 AdditionalTags: infrav1.Tags{ 68 "Name": "my-publicip-ipv6", 69 "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": "owned", 70 }, 71 } 72 fakePublicIPSpec3 = PublicIPSpec{ 73 Name: "my-publicip-3", 74 ResourceGroup: "my-rg", 75 DNSName: "", 76 IsIPv6: false, 77 ClusterName: "my-cluster", 78 Location: "centralIndia", 79 FailureDomains: []*string{ptr.To("failure-domain-id-1"), ptr.To("failure-domain-id-2"), ptr.To("failure-domain-id-3")}, 80 AdditionalTags: infrav1.Tags{ 81 "Name": "my-publicip-ipv6", 82 "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": "owned", 83 }, 84 } 85 fakePublicIPSpecIpv6 = PublicIPSpec{ 86 Name: "my-publicip-ipv6", 87 ResourceGroup: "my-rg", 88 DNSName: "fakename.mydomain.io", 89 IsIPv6: true, 90 ClusterName: "my-cluster", 91 Location: "centralIndia", 92 FailureDomains: []*string{ptr.To("failure-domain-id-1"), ptr.To("failure-domain-id-2"), ptr.To("failure-domain-id-3")}, 93 AdditionalTags: infrav1.Tags{ 94 "Name": "my-publicip-ipv6", 95 "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": "owned", 96 "foo": "bar", 97 }, 98 } 99 100 managedTags = armresources.TagsResource{ 101 Properties: &armresources.Tags{ 102 Tags: map[string]*string{ 103 "foo": ptr.To("bar"), 104 "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": ptr.To("owned"), 105 }, 106 }, 107 } 108 109 unmanagedTags = armresources.TagsResource{ 110 Properties: &armresources.Tags{ 111 Tags: map[string]*string{ 112 "foo": ptr.To("bar"), 113 "something": ptr.To("else"), 114 }, 115 }, 116 } 117 118 internalError = &azcore.ResponseError{ 119 RawResponse: &http.Response{ 120 Body: io.NopCloser(strings.NewReader("#: Internal Server Error: StatusCode=500")), 121 StatusCode: http.StatusInternalServerError, 122 }, 123 } 124 ) 125 126 func TestReconcilePublicIP(t *testing.T) { 127 testcases := []struct { 128 name string 129 expectedError string 130 expect func(s *mock_publicips.MockPublicIPScopeMockRecorder, m *mock_async.MockTagsGetterMockRecorder, r *mock_async.MockReconcilerMockRecorder) 131 }{ 132 { 133 name: "noop if no public IPs", 134 expectedError: "", 135 expect: func(s *mock_publicips.MockPublicIPScopeMockRecorder, m *mock_async.MockTagsGetterMockRecorder, r *mock_async.MockReconcilerMockRecorder) { 136 s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) 137 s.PublicIPSpecs().Return([]azure.ResourceSpecGetter{}) 138 }, 139 }, 140 { 141 name: "successfully create public IPs", 142 expectedError: "", 143 expect: func(s *mock_publicips.MockPublicIPScopeMockRecorder, m *mock_async.MockTagsGetterMockRecorder, r *mock_async.MockReconcilerMockRecorder) { 144 s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) 145 s.PublicIPSpecs().Return([]azure.ResourceSpecGetter{&fakePublicIPSpec1, &fakePublicIPSpec2, &fakePublicIPSpec3, &fakePublicIPSpecIpv6}) 146 r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePublicIPSpec1, serviceName).Return(nil, nil) 147 r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePublicIPSpec2, serviceName).Return(nil, nil) 148 r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePublicIPSpec3, serviceName).Return(nil, nil) 149 r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePublicIPSpecIpv6, serviceName).Return(nil, nil) 150 s.UpdatePutStatus(infrav1.PublicIPsReadyCondition, serviceName, nil) 151 }, 152 }, 153 { 154 name: "fail to create a public IP", 155 expectedError: internalError.Error(), 156 expect: func(s *mock_publicips.MockPublicIPScopeMockRecorder, m *mock_async.MockTagsGetterMockRecorder, r *mock_async.MockReconcilerMockRecorder) { 157 s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) 158 s.PublicIPSpecs().Return([]azure.ResourceSpecGetter{&fakePublicIPSpec1, &fakePublicIPSpec2, &fakePublicIPSpec3, &fakePublicIPSpecIpv6}) 159 r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePublicIPSpec1, serviceName).Return(nil, nil) 160 r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePublicIPSpec2, serviceName).Return(nil, nil) 161 r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePublicIPSpec3, serviceName).Return(nil, internalError) 162 r.CreateOrUpdateResource(gomockinternal.AContext(), &fakePublicIPSpecIpv6, serviceName).Return(nil, nil) 163 s.UpdatePutStatus(infrav1.PublicIPsReadyCondition, serviceName, internalError) 164 }, 165 }, 166 } 167 168 for _, tc := range testcases { 169 tc := tc 170 t.Run(tc.name, func(t *testing.T) { 171 g := NewWithT(t) 172 173 t.Parallel() 174 mockCtrl := gomock.NewController(t) 175 defer mockCtrl.Finish() 176 177 scopeMock := mock_publicips.NewMockPublicIPScope(mockCtrl) 178 tagsGetterMock := mock_async.NewMockTagsGetter(mockCtrl) 179 reconcilerMock := mock_async.NewMockReconciler(mockCtrl) 180 181 tc.expect(scopeMock.EXPECT(), tagsGetterMock.EXPECT(), reconcilerMock.EXPECT()) 182 183 s := &Service{ 184 Scope: scopeMock, 185 TagsGetter: tagsGetterMock, 186 Reconciler: reconcilerMock, 187 } 188 189 err := s.Reconcile(context.TODO()) 190 if tc.expectedError != "" { 191 g.Expect(err).To(HaveOccurred()) 192 g.Expect(err).To(MatchError(tc.expectedError)) 193 } else { 194 g.Expect(err).NotTo(HaveOccurred()) 195 } 196 }) 197 } 198 } 199 200 func TestDeletePublicIP(t *testing.T) { 201 testcases := []struct { 202 name string 203 expectedError string 204 expect func(s *mock_publicips.MockPublicIPScopeMockRecorder, m *mock_async.MockTagsGetterMockRecorder, r *mock_async.MockReconcilerMockRecorder) 205 }{ 206 { 207 name: "noop if no public IPs", 208 expectedError: "", 209 expect: func(s *mock_publicips.MockPublicIPScopeMockRecorder, m *mock_async.MockTagsGetterMockRecorder, r *mock_async.MockReconcilerMockRecorder) { 210 s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) 211 s.PublicIPSpecs().Return([]azure.ResourceSpecGetter{}) 212 }, 213 }, 214 { 215 name: "successfully delete managed public IPs and ignore unmanaged public IPs", 216 expectedError: "", 217 expect: func(s *mock_publicips.MockPublicIPScopeMockRecorder, m *mock_async.MockTagsGetterMockRecorder, r *mock_async.MockReconcilerMockRecorder) { 218 s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) 219 s.PublicIPSpecs().Return([]azure.ResourceSpecGetter{&fakePublicIPSpec1, &fakePublicIPSpec2, &fakePublicIPSpec3, &fakePublicIPSpecIpv6}) 220 221 s.SubscriptionID().Return("123") 222 m.GetAtScope(gomockinternal.AContext(), azure.PublicIPID("123", fakePublicIPSpec1.ResourceGroupName(), fakePublicIPSpec1.ResourceName())).Return(managedTags, nil) 223 s.ClusterName().Return("my-cluster") 224 r.DeleteResource(gomockinternal.AContext(), &fakePublicIPSpec1, serviceName).Return(nil) 225 226 s.SubscriptionID().Return("123") 227 m.GetAtScope(gomockinternal.AContext(), azure.PublicIPID("123", fakePublicIPSpec2.ResourceGroupName(), fakePublicIPSpec2.ResourceName())).Return(managedTags, nil) 228 s.ClusterName().Return("my-cluster") 229 r.DeleteResource(gomockinternal.AContext(), &fakePublicIPSpec2, serviceName).Return(nil) 230 231 s.SubscriptionID().Return("123") 232 m.GetAtScope(gomockinternal.AContext(), azure.PublicIPID("123", fakePublicIPSpec3.ResourceGroupName(), fakePublicIPSpec3.ResourceName())).Return(unmanagedTags, nil) 233 s.ClusterName().Return("my-cluster") 234 235 s.SubscriptionID().Return("123") 236 m.GetAtScope(gomockinternal.AContext(), azure.PublicIPID("123", fakePublicIPSpecIpv6.ResourceGroupName(), fakePublicIPSpecIpv6.ResourceName())).Return(managedTags, nil) 237 s.ClusterName().Return("my-cluster") 238 r.DeleteResource(gomockinternal.AContext(), &fakePublicIPSpecIpv6, serviceName).Return(nil) 239 240 s.UpdateDeleteStatus(infrav1.PublicIPsReadyCondition, serviceName, nil) 241 }, 242 }, 243 { 244 name: "noop if no managed public IPs", 245 expectedError: "", 246 expect: func(s *mock_publicips.MockPublicIPScopeMockRecorder, m *mock_async.MockTagsGetterMockRecorder, r *mock_async.MockReconcilerMockRecorder) { 247 s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) 248 s.PublicIPSpecs().Return([]azure.ResourceSpecGetter{&fakePublicIPSpec1, &fakePublicIPSpec2, &fakePublicIPSpec3, &fakePublicIPSpecIpv6}) 249 250 s.SubscriptionID().Return("123") 251 m.GetAtScope(gomockinternal.AContext(), azure.PublicIPID("123", fakePublicIPSpec1.ResourceGroupName(), fakePublicIPSpec1.ResourceName())).Return(unmanagedTags, nil) 252 s.ClusterName().Return("my-cluster") 253 254 s.SubscriptionID().Return("123") 255 m.GetAtScope(gomockinternal.AContext(), azure.PublicIPID("123", fakePublicIPSpec2.ResourceGroupName(), fakePublicIPSpec2.ResourceName())).Return(unmanagedTags, nil) 256 s.ClusterName().Return("my-cluster") 257 258 s.SubscriptionID().Return("123") 259 m.GetAtScope(gomockinternal.AContext(), azure.PublicIPID("123", fakePublicIPSpec3.ResourceGroupName(), fakePublicIPSpec3.ResourceName())).Return(unmanagedTags, nil) 260 s.ClusterName().Return("my-cluster") 261 262 s.SubscriptionID().Return("123") 263 m.GetAtScope(gomockinternal.AContext(), azure.PublicIPID("123", fakePublicIPSpecIpv6.ResourceGroupName(), fakePublicIPSpecIpv6.ResourceName())).Return(unmanagedTags, nil) 264 s.ClusterName().Return("my-cluster") 265 }, 266 }, 267 { 268 name: "fail to delete managed public IP", 269 expectedError: internalError.Error(), 270 expect: func(s *mock_publicips.MockPublicIPScopeMockRecorder, m *mock_async.MockTagsGetterMockRecorder, r *mock_async.MockReconcilerMockRecorder) { 271 s.DefaultedAzureServiceReconcileTimeout().Return(reconciler.DefaultAzureServiceReconcileTimeout) 272 s.PublicIPSpecs().Return([]azure.ResourceSpecGetter{&fakePublicIPSpec1, &fakePublicIPSpec2, &fakePublicIPSpec3, &fakePublicIPSpecIpv6}) 273 274 s.SubscriptionID().Return("123") 275 m.GetAtScope(gomockinternal.AContext(), azure.PublicIPID("123", fakePublicIPSpec1.ResourceGroupName(), fakePublicIPSpec1.ResourceName())).Return(managedTags, nil) 276 s.ClusterName().Return("my-cluster") 277 r.DeleteResource(gomockinternal.AContext(), &fakePublicIPSpec1, serviceName).Return(nil) 278 279 s.SubscriptionID().Return("123") 280 m.GetAtScope(gomockinternal.AContext(), azure.PublicIPID("123", fakePublicIPSpec2.ResourceGroupName(), fakePublicIPSpec2.ResourceName())).Return(managedTags, nil) 281 s.ClusterName().Return("my-cluster") 282 r.DeleteResource(gomockinternal.AContext(), &fakePublicIPSpec2, serviceName).Return(nil) 283 284 s.SubscriptionID().Return("123") 285 m.GetAtScope(gomockinternal.AContext(), azure.PublicIPID("123", fakePublicIPSpec3.ResourceGroupName(), fakePublicIPSpec3.ResourceName())).Return(managedTags, nil) 286 s.ClusterName().Return("my-cluster") 287 r.DeleteResource(gomockinternal.AContext(), &fakePublicIPSpec3, serviceName).Return(internalError) 288 289 s.SubscriptionID().Return("123") 290 m.GetAtScope(gomockinternal.AContext(), azure.PublicIPID("123", fakePublicIPSpecIpv6.ResourceGroupName(), fakePublicIPSpecIpv6.ResourceName())).Return(managedTags, nil) 291 s.ClusterName().Return("my-cluster") 292 r.DeleteResource(gomockinternal.AContext(), &fakePublicIPSpecIpv6, serviceName).Return(nil) 293 294 s.UpdateDeleteStatus(infrav1.PublicIPsReadyCondition, serviceName, internalError) 295 }, 296 }, 297 } 298 299 for _, tc := range testcases { 300 tc := tc 301 t.Run(tc.name, func(t *testing.T) { 302 g := NewWithT(t) 303 304 t.Parallel() 305 mockCtrl := gomock.NewController(t) 306 defer mockCtrl.Finish() 307 308 scopeMock := mock_publicips.NewMockPublicIPScope(mockCtrl) 309 tagsGetterMock := mock_async.NewMockTagsGetter(mockCtrl) 310 reconcilerMock := mock_async.NewMockReconciler(mockCtrl) 311 312 tc.expect(scopeMock.EXPECT(), tagsGetterMock.EXPECT(), reconcilerMock.EXPECT()) 313 314 s := &Service{ 315 Scope: scopeMock, 316 TagsGetter: tagsGetterMock, 317 Reconciler: reconcilerMock, 318 } 319 320 err := s.Delete(context.TODO()) 321 if tc.expectedError != "" { 322 g.Expect(err).To(HaveOccurred()) 323 g.Expect(err).To(MatchError(tc.expectedError)) 324 } else { 325 g.Expect(err).NotTo(HaveOccurred()) 326 } 327 }) 328 } 329 }