github.com/argoproj/argo-cd/v3@v3.2.1/test/e2e/kustomize_test.go (about) 1 package e2e 2 3 import ( 4 "strconv" 5 "testing" 6 7 "github.com/argoproj/gitops-engine/pkg/health" 8 . "github.com/argoproj/gitops-engine/pkg/sync/common" 9 "github.com/stretchr/testify/assert" 10 "github.com/stretchr/testify/require" 11 12 . "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1" 13 "github.com/argoproj/argo-cd/v3/test/e2e/fixture" 14 . "github.com/argoproj/argo-cd/v3/test/e2e/fixture/app" 15 "github.com/argoproj/argo-cd/v3/util/errors" 16 ) 17 18 func TestKustomize2AppSource(t *testing.T) { 19 patchLabelMatchesFor := func(kind string) func(app *Application) { 20 return func(_ *Application) { 21 name := "k2-patched-guestbook-ui-deploy1" 22 labelValue, err := fixture.Run( 23 "", "kubectl", "-n="+fixture.DeploymentNamespace(), 24 "get", kind, name, 25 "-ojsonpath={.metadata.labels.patched-by}") 26 require.NoError(t, err) 27 assert.Equal(t, "argo-cd", labelValue, "wrong value of 'patched-by' label of %s %s", kind, name) 28 } 29 } 30 31 Given(t). 32 Path(guestbookPath). 33 NamePrefix("k2-"). 34 NameSuffix("-deploy1"). 35 When(). 36 CreateApp(). 37 Then(). 38 Expect(SyncStatusIs(SyncStatusCodeOutOfSync)). 39 When(). 40 PatchApp(`[ 41 { 42 "op": "replace", 43 "path": "/spec/source/kustomize/namePrefix", 44 "value": "k2-patched-" 45 }, 46 { 47 "op": "add", 48 "path": "/spec/source/kustomize/commonLabels", 49 "value": { 50 "patched-by": "argo-cd" 51 } 52 } 53 ]`). 54 Then(). 55 Expect(Success("")). 56 When(). 57 Sync(). 58 Then(). 59 Expect(Success("")). 60 Expect(OperationPhaseIs(OperationSucceeded)). 61 Expect(SyncStatusIs(SyncStatusCodeSynced)). 62 Expect(HealthIs(health.HealthStatusHealthy)). 63 And(patchLabelMatchesFor("Service")). 64 And(patchLabelMatchesFor("Deployment")) 65 } 66 67 // when we have a config map generator, AND the ignore annotation, it is ignored in the app's sync status 68 func TestSyncStatusOptionIgnore(t *testing.T) { 69 var oldMap string 70 Given(t). 71 Path("kustomize-cm-gen"). 72 When(). 73 CreateApp(). 74 Sync(). 75 Then(). 76 Expect(OperationPhaseIs(OperationSucceeded)). 77 Expect(SyncStatusIs(SyncStatusCodeSynced)). 78 Expect(HealthIs(health.HealthStatusHealthy)). 79 And(func(app *Application) { 80 resourceStatus := app.Status.Resources[0] 81 assert.Contains(t, resourceStatus.Name, "my-map-") 82 assert.Equal(t, SyncStatusCodeSynced, resourceStatus.Status) 83 84 oldMap = resourceStatus.Name 85 }). 86 When(). 87 // we now force generation of a second CM 88 PatchFile("kustomization.yaml", `[{"op": "replace", "path": "/configMapGenerator/0/literals/0", "value": "foo=baz"}]`). 89 Refresh(RefreshTypeHard). 90 Then(). 91 // this is standard logging from the command - tough one - true statement 92 When(). 93 Sync(). 94 Then(). 95 Expect(OperationPhaseIs(OperationSucceeded)). 96 // this is a key check - we expect the app to be healthy because, even though we have a resources that needs 97 // pruning, because it is annotated with IgnoreExtraneous it should not contribute to the sync status 98 Expect(SyncStatusIs(SyncStatusCodeSynced)). 99 Expect(HealthIs(health.HealthStatusHealthy)). 100 And(func(app *Application) { 101 assert.Len(t, app.Status.Resources, 2) 102 for _, resourceStatus := range app.Status.Resources { 103 // new map in-sync 104 if resourceStatus.Name != oldMap { 105 assert.Contains(t, resourceStatus.Name, "my-map-") 106 // make sure we've a new map with changed name 107 assert.Equal(t, SyncStatusCodeSynced, resourceStatus.Status) 108 } else { 109 assert.Equal(t, SyncStatusCodeOutOfSync, resourceStatus.Status) 110 } 111 } 112 }) 113 } 114 115 // make sure we can create an app which has a SSH remote base 116 func TestKustomizeSSHRemoteBase(t *testing.T) { 117 Given(t). 118 // not the best test, as we should have two remote repos both with the same SSH private key 119 SSHInsecureRepoURLAdded(true). 120 RepoURLType(fixture.RepoURLTypeSSH). 121 Path(fixture.LocalOrRemotePath("ssh-kustomize-base")). 122 When(). 123 CreateApp(). 124 Sync(). 125 Then(). 126 Expect(OperationPhaseIs(OperationSucceeded)). 127 Expect(ResourceSyncStatusIs("ConfigMap", "my-map", SyncStatusCodeSynced)) 128 } 129 130 // make sure we can create an app which has a SSH remote base 131 func TestKustomizeDeclarativeInvalidApp(t *testing.T) { 132 Given(t). 133 Path("invalid-kustomize"). 134 When(). 135 Declarative("declarative-apps/app.yaml"). 136 Then(). 137 Expect(Success("")). 138 Expect(HealthIs(health.HealthStatusHealthy)). 139 Expect(SyncStatusIs(SyncStatusCodeUnknown)). 140 Expect(Condition(ApplicationConditionComparisonError, "invalid-kustomize/does-not-exist.yaml: no such file or directory")) 141 } 142 143 // Flag --load_restrictor is no longer supported in Kustomize 4 144 func TestKustomizeBuildOptionsLoadRestrictor(t *testing.T) { 145 Given(t). 146 Path(guestbookPath). 147 And(func() { 148 errors.NewHandler(t).FailOnErr(fixture.Run("", "kubectl", "patch", "cm", "argocd-cm", 149 "-n", fixture.TestNamespace(), 150 "-p", `{ "data": { "kustomize.buildOptions": "--load-restrictor LoadRestrictionsNone" } }`)) 151 }). 152 When(). 153 PatchFile("kustomization.yaml", `[{"op": "replace", "path": "/resources/1", "value": "../guestbook_local/guestbook-ui-svc.yaml"}]`). 154 CreateApp(). 155 Sync(). 156 Then(). 157 Expect(OperationPhaseIs(OperationSucceeded)). 158 Expect(HealthIs(health.HealthStatusHealthy)). 159 Expect(SyncStatusIs(SyncStatusCodeSynced)). 160 Given(). 161 And(func() { 162 errors.NewHandler(t).FailOnErr(fixture.Run("", "kubectl", "patch", "cm", "argocd-cm", 163 "-n", fixture.TestNamespace(), 164 "-p", `{ "data": { "kustomize.buildOptions": "" } }`)) 165 }) 166 } 167 168 // make sure we we can invoke the CLI to replace images 169 func TestKustomizeImages(t *testing.T) { 170 Given(t). 171 Path("kustomize"). 172 When(). 173 CreateApp(). 174 // pass two flags to check the multi flag logic works 175 AppSet("--kustomize-image", "alpine:foo", "--kustomize-image", "alpine:bar"). 176 Then(). 177 And(func(app *Application) { 178 assert.Contains(t, app.Spec.GetSource().Kustomize.Images, KustomizeImage("alpine:bar")) 179 }) 180 } 181 182 // make sure we we can invoke the CLI to replace replicas and actual deployment is set to correct value 183 func TestKustomizeReplicas2AppSource(t *testing.T) { 184 deploymentName := "guestbook-ui" 185 deploymentReplicas := 2 186 checkReplicasFor := func(kind string) func(app *Application) { 187 return func(_ *Application) { 188 name := deploymentName 189 replicas, err := fixture.Run( 190 "", "kubectl", "-n="+fixture.DeploymentNamespace(), 191 "get", kind, name, 192 "-ojsonpath={.spec.replicas}") 193 require.NoError(t, err) 194 assert.Equal(t, strconv.Itoa(deploymentReplicas), replicas, "wrong value of replicas %s %s", kind, name) 195 } 196 } 197 198 Given(t). 199 Path("guestbook"). 200 When(). 201 CreateApp(). 202 AppSet("--kustomize-replica", deploymentName+"=2"). 203 Then(). 204 And(func(app *Application) { 205 assert.Equal(t, deploymentName, app.Spec.Source.Kustomize.Replicas[0].Name) 206 }). 207 And(func(app *Application) { 208 assert.Equal(t, deploymentReplicas, int(app.Spec.Source.Kustomize.Replicas[0].Count.IntVal)) 209 }). // check Kustomize CLI 210 Expect(Success("")). 211 When(). 212 Sync(). 213 Then(). 214 Expect(Success("")). 215 Expect(OperationPhaseIs(OperationSucceeded)). 216 Expect(SyncStatusIs(SyncStatusCodeSynced)). 217 Expect(HealthIs(health.HealthStatusHealthy)). 218 And(checkReplicasFor("Deployment")) 219 } 220 221 // make sure we we can invoke the CLI to set namesuffix 222 func TestKustomizeNameSuffix(t *testing.T) { 223 Given(t). 224 Path("kustomize"). 225 When(). 226 CreateApp(). 227 AppSet("--namesuffix", "-suf"). 228 Then(). 229 And(func(app *Application) { 230 assert.Contains(t, app.Spec.GetSource().Kustomize.NameSuffix, "-suf") 231 }) 232 } 233 234 // make sure we we can invoke the CLI to set and unset namesuffix and kustomize-image 235 func TestKustomizeUnsetOverride(t *testing.T) { 236 Given(t). 237 Path("kustomize"). 238 When(). 239 CreateApp(). 240 AppSet("--namesuffix", "-suf"). 241 Then(). 242 And(func(app *Application) { 243 assert.Contains(t, app.Spec.GetSource().Kustomize.NameSuffix, "-suf") 244 }). 245 When(). 246 AppUnSet("--namesuffix"). 247 Then(). 248 And(func(app *Application) { 249 assert.Nil(t, app.Spec.GetSource().Kustomize) 250 }). 251 When(). 252 AppSet("--kustomize-image", "alpine:foo", "--kustomize-image", "alpine:bar"). 253 Then(). 254 And(func(app *Application) { 255 assert.Contains(t, app.Spec.GetSource().Kustomize.Images, KustomizeImage("alpine:bar")) 256 }). 257 When(). 258 // AppUnSet("--kustomize-image=alpine"). 259 AppUnSet("--kustomize-image", "alpine", "--kustomize-image", "alpine"). 260 Then(). 261 And(func(app *Application) { 262 assert.Nil(t, app.Spec.GetSource().Kustomize) 263 }) 264 } 265 266 // make sure we we can invoke the CLI to set and unset Deployment 267 func TestKustomizeUnsetOverrideDeployment(t *testing.T) { 268 deploymentName := "guestbook-ui" 269 deploymentReplicas := int32(2) 270 Given(t). 271 Path("guestbook"). 272 When(). // Replicas 273 CreateApp(). 274 AppSet("--kustomize-replica", deploymentName+"=2"). 275 Then(). 276 And(func(app *Application) { 277 assert.Equal(t, deploymentName, app.Spec.Source.Kustomize.Replicas[0].Name) 278 }). 279 And(func(app *Application) { 280 assert.Equal(t, deploymentReplicas, app.Spec.Source.Kustomize.Replicas[0].Count.IntVal) 281 }). 282 When(). 283 AppUnSet("--kustomize-replica", deploymentName). 284 Then(). 285 And(func(app *Application) { 286 assert.Nil(t, app.Spec.Source.Kustomize) 287 }) 288 } 289 290 // make sure kube-version gets passed down to resources 291 func TestKustomizeKubeVersion(t *testing.T) { 292 Given(t). 293 Path("kustomize-kube-version"). 294 And(func() { 295 errors.NewHandler(t).FailOnErr(fixture.Run("", "kubectl", "patch", "cm", "argocd-cm", 296 "-n", fixture.TestNamespace(), 297 "-p", `{ "data": { "kustomize.buildOptions": "--enable-helm" } }`)) 298 }). 299 When(). 300 CreateApp(). 301 Sync(). 302 Then(). 303 Expect(SyncStatusIs(SyncStatusCodeSynced)). 304 And(func(_ *Application) { 305 kubeVersion := errors.NewHandler(t).FailOnErr(fixture.Run(".", "kubectl", "-n", fixture.DeploymentNamespace(), "get", "cm", "my-map", 306 "-o", "jsonpath={.data.kubeVersion}")).(string) 307 // Capabilities.KubeVersion defaults to 1.9.0, we assume here you are running a later version 308 assert.LessOrEqual(t, fixture.GetVersions(t).ServerVersion.Format("v%s.%s.0"), kubeVersion) 309 }). 310 When(). 311 // Make sure override works. 312 AppSet("--kustomize-kube-version", "999.999.999"). 313 Sync(). 314 Then(). 315 Expect(SyncStatusIs(SyncStatusCodeSynced)). 316 And(func(_ *Application) { 317 assert.Equal(t, "v999.999.999", errors.NewHandler(t).FailOnErr(fixture.Run(".", "kubectl", "-n", fixture.DeploymentNamespace(), "get", "cm", "my-map", 318 "-o", "jsonpath={.data.kubeVersion}")).(string)) 319 }) 320 } 321 322 // make sure api versions gets passed down to resources 323 func TestKustomizeApiVersions(t *testing.T) { 324 Given(t). 325 Path("kustomize-api-versions"). 326 And(func() { 327 errors.NewHandler(t).FailOnErr(fixture.Run("", "kubectl", "patch", "cm", "argocd-cm", 328 "-n", fixture.TestNamespace(), 329 "-p", `{ "data": { "kustomize.buildOptions": "--enable-helm" } }`)) 330 }). 331 When(). 332 CreateApp(). 333 Sync(). 334 Then(). 335 Expect(SyncStatusIs(SyncStatusCodeSynced)). 336 And(func(_ *Application) { 337 apiVersions := errors.NewHandler(t).FailOnErr(fixture.Run(".", "kubectl", "-n", fixture.DeploymentNamespace(), "get", "cm", "my-map", 338 "-o", "jsonpath={.data.apiVersions}")).(string) 339 // The v1 API shouldn't be going anywhere. 340 assert.Contains(t, apiVersions, "v1") 341 }). 342 When(). 343 // Make sure override works. 344 AppSet("--kustomize-api-versions", "v1/MyTestResource"). 345 Sync(). 346 Then(). 347 Expect(SyncStatusIs(SyncStatusCodeSynced)). 348 And(func(_ *Application) { 349 apiVersions := errors.NewHandler(t).FailOnErr(fixture.Run(".", "kubectl", "-n", fixture.DeploymentNamespace(), "get", "cm", "my-map", 350 "-o", "jsonpath={.data.apiVersions}")).(string) 351 assert.Contains(t, apiVersions, "v1/MyTestResource") 352 }) 353 } 354 355 func TestKustomizeNamespaceOverride(t *testing.T) { 356 Given(t). 357 Path("kustomize-kube-version"). 358 And(func() { 359 errors.NewHandler(t).FailOnErr(fixture.Run("", "kubectl", "patch", "cm", "argocd-cm", 360 "-n", fixture.TestNamespace(), 361 "-p", `{ "data": { "kustomize.buildOptions": "--enable-helm" } }`)) 362 }). 363 When(). 364 CreateApp(). 365 Sync(). 366 Then(). 367 Expect(SyncStatusIs(SyncStatusCodeSynced)). 368 When(). 369 AppSet("--kustomize-namespace", "does-not-exist"). 370 Then(). 371 // The app should go out of sync, because the resource's target namespace changed. 372 Expect(SyncStatusIs(SyncStatusCodeOutOfSync)) 373 }