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  }