Compare commits

...

1 Commits

Author SHA1 Message Date
Justin Marquis
daf8c8fe69 sibling of 587c5ba1c6 2024-06-26 16:03:35 +00:00
71 changed files with 1412 additions and 2072 deletions

View File

@@ -31,7 +31,7 @@ jobs:
docs: ${{ steps.filter.outputs.docs_any_changed }}
steps:
- uses: actions/checkout@8410ad0602e1e429cee44a835ae9f77f654a6694 # v4.0.0
- uses: tj-actions/changed-files@cc3bbb0c526f8ee1d282f8c5f9f4e50745a5b457 # v44.5.4
- uses: tj-actions/changed-files@d6babd6899969df1a11d14c368283ea4436bca78 # v44.5.2
id: filter
with:
# Any file which is not under docs/, ui/ or is not a markdown file is counted as a backend file

View File

@@ -143,7 +143,7 @@ jobs:
- name: Build and push container image
id: image
uses: docker/build-push-action@31159d49c0d4756269a0940a750801a1ea5d7003 #v6.1.0
uses: docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25 #v5.4.0
with:
context: .
platforms: ${{ inputs.platforms }}

View File

@@ -64,7 +64,7 @@ jobs:
git stash pop
- name: Create pull request
uses: peter-evans/create-pull-request@c5a7806660adbe173f04e3e038b0ccdcd758773c # v6.1.0
uses: peter-evans/create-pull-request@6d6857d36972b65feb161a90e484f2984215f83e # v6.0.5
with:
commit-message: "Bump version to ${{ inputs.TARGET_VERSION }}"
title: "Bump version to ${{ inputs.TARGET_VERSION }} on ${{ inputs.TARGET_BRANCH }} branch"

View File

@@ -197,7 +197,7 @@ jobs:
echo "hashes=$(sha256sum /tmp/sbom.tar.gz | base64 -w0)" >> "$GITHUB_OUTPUT"
- name: Upload SBOM
uses: softprops/action-gh-release@a74c6b72af54cfa997e81df42d94703d6313a2d0 # v2.0.6
uses: softprops/action-gh-release@69320dbe05506a9a39fc8ae11030b214ec2d1f87 # v2.0.5
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
@@ -291,11 +291,11 @@ jobs:
# Replace the 'project-release: vX.X.X-rcX' line in SECURITY-INSIGHTS.yml
sed -i "s/project-release: v.*$/project-release: v${{ env.NEW_VERSION }}/" SECURITY-INSIGHTS.yml
# Update the 'commit-hash: XXXXXXX' line in SECURITY-INSIGHTS.yml
sed -i "s/commit-hash: .*/commit-hash: ${{ env.COMMIT_HASH }}/" SECURITY-INSIGHTS.yml
sed -i "s/commit-hash: .*/commit-hash: ${{ env.NEW_VERSION }}/" SECURITY-INSIGHTS.yml
if: ${{ env.UPDATE_VERSION == 'true' }}
- name: Create PR to update VERSION on master branch
uses: peter-evans/create-pull-request@c5a7806660adbe173f04e3e038b0ccdcd758773c # v6.1.0
uses: peter-evans/create-pull-request@6d6857d36972b65feb161a90e484f2984215f83e # v6.0.5
with:
commit-message: Bump version in master
title: "chore: Bump version in master"

View File

@@ -36,6 +36,8 @@ linters-settings:
testifylint:
enable-all: true
disable:
- error-is-as
- float-compare
- go-require
run:
timeout: 50m

View File

@@ -3,9 +3,9 @@ header:
expiration-date: '2024-10-31T00:00:00.000Z' # One year from initial release.
last-updated: '2023-10-27'
last-reviewed: '2023-10-27'
commit-hash: fe606708859574b9b6102a505e260fac5d3fb14e
commit-hash: b71277c6beb949d0199d647a582bc25822b88838
project-url: https://github.com/argoproj/argo-cd
project-release: v2.13.0
project-release: v2.9.0-rc3
changelog: https://github.com/argoproj/argo-cd/releases
license: https://github.com/argoproj/argo-cd/blob/master/LICENSE
project-lifecycle:

View File

@@ -155,7 +155,6 @@ Currently, the following organizations are **officially** using Argo CD:
1. [Karrot](https://www.daangn.com/)
1. [KarrotPay](https://www.daangnpay.com/)
1. [Kasa](https://kasa.co.kr/)
1. [Kave Home](https://kavehome.com)
1. [Keeeb](https://www.keeeb.com/)
1. [KelkooGroup](https://www.kelkoogroup.com)
1. [Keptn](https://keptn.sh)

View File

@@ -1 +1 @@
2.13.0
2.12.0-rc2

View File

@@ -43,9 +43,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/handler"
"sigs.k8s.io/controller-runtime/pkg/predicate"
"github.com/argoproj/argo-cd/v2/applicationset/controllers/template"
"github.com/argoproj/argo-cd/v2/applicationset/generators"
"github.com/argoproj/argo-cd/v2/applicationset/status"
"github.com/argoproj/argo-cd/v2/applicationset/utils"
"github.com/argoproj/argo-cd/v2/common"
"github.com/argoproj/argo-cd/v2/util/db"
@@ -131,20 +129,18 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque
// Log a warning if there are unrecognized generators
_ = utils.CheckInvalidGenerators(&applicationSetInfo)
// desiredApplications is the main list of all expected Applications from all generators in this appset.
desiredApplications, applicationSetReason, generatorsErr := template.GenerateApplications(logCtx, applicationSetInfo, r.Generators, r.Renderer, r.Client)
if generatorsErr != nil {
desiredApplications, applicationSetReason, err := r.generateApplications(logCtx, applicationSetInfo)
if err != nil {
_ = r.setApplicationSetStatusCondition(ctx,
&applicationSetInfo,
argov1alpha1.ApplicationSetCondition{
Type: argov1alpha1.ApplicationSetConditionErrorOccurred,
Message: generatorsErr.Error(),
Message: err.Error(),
Reason: string(applicationSetReason),
Status: argov1alpha1.ApplicationSetConditionStatusTrue,
}, parametersGenerated,
)
if len(desiredApplications) < 1 {
return ctrl.Result{}, generatorsErr
}
return ctrl.Result{}, err
}
parametersGenerated = true
@@ -322,7 +318,7 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque
requeueAfter := r.getMinRequeueAfter(&applicationSetInfo)
if len(validateErrors) == 0 && generatorsErr == nil {
if len(validateErrors) == 0 {
if err := r.setApplicationSetStatusCondition(ctx,
&applicationSetInfo,
argov1alpha1.ApplicationSetCondition{
@@ -497,6 +493,88 @@ func (r *ApplicationSetReconciler) getMinRequeueAfter(applicationSetInfo *argov1
return res
}
func getTempApplication(applicationSetTemplate argov1alpha1.ApplicationSetTemplate) *argov1alpha1.Application {
var tmplApplication argov1alpha1.Application
tmplApplication.Annotations = applicationSetTemplate.Annotations
tmplApplication.Labels = applicationSetTemplate.Labels
tmplApplication.Namespace = applicationSetTemplate.Namespace
tmplApplication.Name = applicationSetTemplate.Name
tmplApplication.Spec = applicationSetTemplate.Spec
tmplApplication.Finalizers = applicationSetTemplate.Finalizers
return &tmplApplication
}
func (r *ApplicationSetReconciler) generateApplications(logCtx *log.Entry, applicationSetInfo argov1alpha1.ApplicationSet) ([]argov1alpha1.Application, argov1alpha1.ApplicationSetReasonType, error) {
var res []argov1alpha1.Application
var firstError error
var applicationSetReason argov1alpha1.ApplicationSetReasonType
for _, requestedGenerator := range applicationSetInfo.Spec.Generators {
t, err := generators.Transform(requestedGenerator, r.Generators, applicationSetInfo.Spec.Template, &applicationSetInfo, map[string]interface{}{}, r.Client)
if err != nil {
logCtx.WithError(err).WithField("generator", requestedGenerator).
Error("error generating application from params")
if firstError == nil {
firstError = err
applicationSetReason = argov1alpha1.ApplicationSetReasonApplicationParamsGenerationError
}
continue
}
for _, a := range t {
tmplApplication := getTempApplication(a.Template)
for _, p := range a.Params {
app, err := r.Renderer.RenderTemplateParams(tmplApplication, applicationSetInfo.Spec.SyncPolicy, p, applicationSetInfo.Spec.GoTemplate, applicationSetInfo.Spec.GoTemplateOptions)
if err != nil {
logCtx.WithError(err).WithField("params", a.Params).WithField("generator", requestedGenerator).
Error("error generating application from params")
if firstError == nil {
firstError = err
applicationSetReason = argov1alpha1.ApplicationSetReasonRenderTemplateParamsError
}
continue
}
if applicationSetInfo.Spec.TemplatePatch != nil {
patchedApplication, err := r.applyTemplatePatch(app, applicationSetInfo, p)
if err != nil {
log.WithError(err).WithField("params", a.Params).WithField("generator", requestedGenerator).
Error("error generating application from params")
if firstError == nil {
firstError = err
applicationSetReason = argov1alpha1.ApplicationSetReasonRenderTemplateParamsError
}
continue
}
app = patchedApplication
}
res = append(res, *app)
}
}
logCtx.WithField("generator", requestedGenerator).Infof("generated %d applications", len(res))
logCtx.WithField("generator", requestedGenerator).Debugf("apps from generator: %+v", res)
}
return res, applicationSetReason, firstError
}
func (r *ApplicationSetReconciler) applyTemplatePatch(app *argov1alpha1.Application, applicationSetInfo argov1alpha1.ApplicationSet, params map[string]interface{}) (*argov1alpha1.Application, error) {
replacedTemplate, err := r.Renderer.Replace(*applicationSetInfo.Spec.TemplatePatch, params, applicationSetInfo.Spec.GoTemplate, applicationSetInfo.Spec.GoTemplateOptions)
if err != nil {
return nil, fmt.Errorf("error replacing values in templatePatch: %w", err)
}
return applyTemplatePatch(app, replacedTemplate)
}
func ignoreNotAllowedNamespaces(namespaces []string) predicate.Predicate {
return predicate.Funcs{
CreateFunc: func(e event.CreateEvent) bool {
@@ -570,6 +648,10 @@ func (r *ApplicationSetReconciler) createOrUpdateInCluster(ctx context.Context,
var firstError error
// Creates or updates the application in appList
for _, generatedApp := range desiredApplications {
// The app's namespace must be the same as the AppSet's namespace to preserve the appsets-in-any-namespace
// security boundary.
generatedApp.Namespace = applicationSet.Namespace
appLog := logCtx.WithFields(log.Fields{"app": generatedApp.QualifiedName()})
// Normalize to avoid fighting with the application controller.
@@ -1267,8 +1349,8 @@ func findApplicationStatusIndex(appStatuses []argov1alpha1.ApplicationSetApplica
}
func (r *ApplicationSetReconciler) updateResourcesStatus(ctx context.Context, logCtx *log.Entry, appset *argov1alpha1.ApplicationSet, apps []argov1alpha1.Application) error {
statusMap := status.GetResourceStatusMap(appset)
statusMap = status.BuildResourceStatus(statusMap, apps)
statusMap := getResourceStatusMap(appset)
statusMap = buildResourceStatus(statusMap, apps)
statuses := []argov1alpha1.ResourceStatus{}
for _, status := range statusMap {
@@ -1293,6 +1375,58 @@ func (r *ApplicationSetReconciler) updateResourcesStatus(ctx context.Context, lo
return nil
}
func buildResourceStatus(statusMap map[string]argov1alpha1.ResourceStatus, apps []argov1alpha1.Application) map[string]argov1alpha1.ResourceStatus {
appMap := map[string]argov1alpha1.Application{}
for _, app := range apps {
appCopy := app
appMap[app.Name] = app
gvk := app.GroupVersionKind()
// Create status if it does not exist
status, ok := statusMap[app.Name]
if !ok {
status = argov1alpha1.ResourceStatus{
Group: gvk.Group,
Version: gvk.Version,
Kind: gvk.Kind,
Name: app.Name,
Namespace: app.Namespace,
Status: app.Status.Sync.Status,
Health: &appCopy.Status.Health,
}
}
status.Group = gvk.Group
status.Version = gvk.Version
status.Kind = gvk.Kind
status.Name = app.Name
status.Namespace = app.Namespace
status.Status = app.Status.Sync.Status
status.Health = &appCopy.Status.Health
statusMap[app.Name] = status
}
cleanupDeletedApplicationStatuses(statusMap, appMap)
return statusMap
}
func getResourceStatusMap(appset *argov1alpha1.ApplicationSet) map[string]argov1alpha1.ResourceStatus {
statusMap := map[string]argov1alpha1.ResourceStatus{}
for _, status := range appset.Status.Resources {
statusMap[status.Name] = status
}
return statusMap
}
func cleanupDeletedApplicationStatuses(statusMap map[string]argov1alpha1.ResourceStatus, apps map[string]argov1alpha1.Application) {
for name := range statusMap {
if _, ok := apps[name]; !ok {
delete(statusMap, name)
}
}
}
// setApplicationSetApplicationStatus updates the ApplicationSet's status field
// with any new/changed Application statuses.
func (r *ApplicationSetReconciler) setAppSetApplicationStatus(ctx context.Context, logCtx *log.Entry, applicationSet *argov1alpha1.ApplicationSet, applicationStatuses []argov1alpha1.ApplicationSetApplicationStatus) error {

View File

@@ -25,6 +25,7 @@ import (
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/cache"
crtcache "sigs.k8s.io/controller-runtime/pkg/cache"
"sigs.k8s.io/controller-runtime/pkg/client"
crtclient "sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/fake"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
@@ -34,11 +35,11 @@ import (
"github.com/argoproj/gitops-engine/pkg/sync/common"
"github.com/argoproj/argo-cd/v2/applicationset/generators"
"github.com/argoproj/argo-cd/v2/applicationset/generators/mocks"
"github.com/argoproj/argo-cd/v2/applicationset/utils"
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
appclientset "github.com/argoproj/argo-cd/v2/pkg/client/clientset/versioned/fake"
"github.com/argoproj/argo-cd/v2/util/collections"
dbmocks "github.com/argoproj/argo-cd/v2/util/db/mocks"
"github.com/argoproj/argo-cd/v2/pkg/apis/application"
@@ -72,6 +73,287 @@ func (f *fakeCache) GetInformer(ctx context.Context, obj crtclient.Object, opt .
return &fakeInformer{}, nil
}
type generatorMock struct {
mock.Mock
}
func (g *generatorMock) GetTemplate(appSetGenerator *v1alpha1.ApplicationSetGenerator) *v1alpha1.ApplicationSetTemplate {
args := g.Called(appSetGenerator)
return args.Get(0).(*v1alpha1.ApplicationSetTemplate)
}
func (g *generatorMock) GenerateParams(appSetGenerator *v1alpha1.ApplicationSetGenerator, _ *v1alpha1.ApplicationSet, client client.Client) ([]map[string]interface{}, error) {
args := g.Called(appSetGenerator)
return args.Get(0).([]map[string]interface{}), args.Error(1)
}
func (g *generatorMock) Replace(tmpl string, replaceMap map[string]interface{}, useGoTemplate bool, goTemplateOptions []string) (string, error) {
args := g.Called(tmpl, replaceMap, useGoTemplate, goTemplateOptions)
return args.Get(0).(string), args.Error(1)
}
type rendererMock struct {
mock.Mock
}
func (g *generatorMock) GetRequeueAfter(appSetGenerator *v1alpha1.ApplicationSetGenerator) time.Duration {
args := g.Called(appSetGenerator)
return args.Get(0).(time.Duration)
}
func (r *rendererMock) RenderTemplateParams(tmpl *v1alpha1.Application, syncPolicy *v1alpha1.ApplicationSetSyncPolicy, params map[string]interface{}, useGoTemplate bool, goTemplateOptions []string) (*v1alpha1.Application, error) {
args := r.Called(tmpl, params, useGoTemplate, goTemplateOptions)
if args.Error(1) != nil {
return nil, args.Error(1)
}
return args.Get(0).(*v1alpha1.Application), args.Error(1)
}
func (r *rendererMock) Replace(tmpl string, replaceMap map[string]interface{}, useGoTemplate bool, goTemplateOptions []string) (string, error) {
args := r.Called(tmpl, replaceMap, useGoTemplate, goTemplateOptions)
return args.Get(0).(string), args.Error(1)
}
func TestExtractApplications(t *testing.T) {
scheme := runtime.NewScheme()
err := v1alpha1.AddToScheme(scheme)
require.NoError(t, err)
for _, c := range []struct {
name string
params []map[string]interface{}
template v1alpha1.ApplicationSetTemplate
generateParamsError error
rendererError error
expectErr bool
expectedReason v1alpha1.ApplicationSetReasonType
}{
{
name: "Generate two applications",
params: []map[string]interface{}{{"name": "app1"}, {"name": "app2"}},
template: v1alpha1.ApplicationSetTemplate{
ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{
Name: "name",
Namespace: "namespace",
Labels: map[string]string{"label_name": "label_value"},
},
Spec: v1alpha1.ApplicationSpec{},
},
expectedReason: "",
},
{
name: "Handles error from the generator",
generateParamsError: fmt.Errorf("error"),
expectErr: true,
expectedReason: v1alpha1.ApplicationSetReasonApplicationParamsGenerationError,
},
{
name: "Handles error from the render",
params: []map[string]interface{}{{"name": "app1"}, {"name": "app2"}},
template: v1alpha1.ApplicationSetTemplate{
ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{
Name: "name",
Namespace: "namespace",
Labels: map[string]string{"label_name": "label_value"},
},
Spec: v1alpha1.ApplicationSpec{},
},
rendererError: fmt.Errorf("error"),
expectErr: true,
expectedReason: v1alpha1.ApplicationSetReasonRenderTemplateParamsError,
},
} {
cc := c
app := v1alpha1.Application{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
},
}
t.Run(cc.name, func(t *testing.T) {
appSet := &v1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "name",
Namespace: "namespace",
},
}
client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(appSet).Build()
generatorMock := generatorMock{}
generator := v1alpha1.ApplicationSetGenerator{
List: &v1alpha1.ListGenerator{},
}
generatorMock.On("GenerateParams", &generator).
Return(cc.params, cc.generateParamsError)
generatorMock.On("GetTemplate", &generator).
Return(&v1alpha1.ApplicationSetTemplate{})
rendererMock := rendererMock{}
var expectedApps []v1alpha1.Application
if cc.generateParamsError == nil {
for _, p := range cc.params {
if cc.rendererError != nil {
rendererMock.On("RenderTemplateParams", getTempApplication(cc.template), p, false, []string(nil)).
Return(nil, cc.rendererError)
} else {
rendererMock.On("RenderTemplateParams", getTempApplication(cc.template), p, false, []string(nil)).
Return(&app, nil)
expectedApps = append(expectedApps, app)
}
}
}
r := ApplicationSetReconciler{
Client: client,
Scheme: scheme,
Recorder: record.NewFakeRecorder(1),
Generators: map[string]generators.Generator{
"List": &generatorMock,
},
Renderer: &rendererMock,
KubeClientset: kubefake.NewSimpleClientset(),
Cache: &fakeCache{},
}
got, reason, err := r.generateApplications(log.NewEntry(log.StandardLogger()), v1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "name",
Namespace: "namespace",
},
Spec: v1alpha1.ApplicationSetSpec{
Generators: []v1alpha1.ApplicationSetGenerator{generator},
Template: cc.template,
},
})
if cc.expectErr {
require.Error(t, err)
} else {
require.NoError(t, err)
}
assert.Equal(t, expectedApps, got)
assert.Equal(t, cc.expectedReason, reason)
generatorMock.AssertNumberOfCalls(t, "GenerateParams", 1)
if cc.generateParamsError == nil {
rendererMock.AssertNumberOfCalls(t, "RenderTemplateParams", len(cc.params))
}
})
}
}
func TestMergeTemplateApplications(t *testing.T) {
scheme := runtime.NewScheme()
_ = v1alpha1.AddToScheme(scheme)
_ = v1alpha1.AddToScheme(scheme)
client := fake.NewClientBuilder().WithScheme(scheme).Build()
for _, c := range []struct {
name string
params []map[string]interface{}
template v1alpha1.ApplicationSetTemplate
overrideTemplate v1alpha1.ApplicationSetTemplate
expectedMerged v1alpha1.ApplicationSetTemplate
expectedApps []v1alpha1.Application
}{
{
name: "Generate app",
params: []map[string]interface{}{{"name": "app1"}},
template: v1alpha1.ApplicationSetTemplate{
ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{
Name: "name",
Namespace: "namespace",
Labels: map[string]string{"label_name": "label_value"},
},
Spec: v1alpha1.ApplicationSpec{},
},
overrideTemplate: v1alpha1.ApplicationSetTemplate{
ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{
Name: "test",
Labels: map[string]string{"foo": "bar"},
},
Spec: v1alpha1.ApplicationSpec{},
},
expectedMerged: v1alpha1.ApplicationSetTemplate{
ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{
Name: "test",
Namespace: "namespace",
Labels: map[string]string{"label_name": "label_value", "foo": "bar"},
},
Spec: v1alpha1.ApplicationSpec{},
},
expectedApps: []v1alpha1.Application{
{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: "test",
Labels: map[string]string{"foo": "bar"},
},
Spec: v1alpha1.ApplicationSpec{},
},
},
},
} {
cc := c
t.Run(cc.name, func(t *testing.T) {
generatorMock := generatorMock{}
generator := v1alpha1.ApplicationSetGenerator{
List: &v1alpha1.ListGenerator{},
}
generatorMock.On("GenerateParams", &generator).
Return(cc.params, nil)
generatorMock.On("GetTemplate", &generator).
Return(&cc.overrideTemplate)
rendererMock := rendererMock{}
rendererMock.On("RenderTemplateParams", getTempApplication(cc.expectedMerged), cc.params[0], false, []string(nil)).
Return(&cc.expectedApps[0], nil)
r := ApplicationSetReconciler{
Client: client,
Scheme: scheme,
Recorder: record.NewFakeRecorder(1),
Generators: map[string]generators.Generator{
"List": &generatorMock,
},
Renderer: &rendererMock,
KubeClientset: kubefake.NewSimpleClientset(),
}
got, _, _ := r.generateApplications(log.NewEntry(log.StandardLogger()), v1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "name",
Namespace: "namespace",
},
Spec: v1alpha1.ApplicationSetSpec{
Generators: []v1alpha1.ApplicationSetGenerator{generator},
Template: cc.template,
},
},
)
assert.Equal(t, cc.expectedApps, got)
})
}
}
func TestCreateOrUpdateInCluster(t *testing.T) {
scheme := runtime.NewScheme()
err := v1alpha1.AddToScheme(scheme)
@@ -104,10 +386,8 @@ func TestCreateOrUpdateInCluster(t *testing.T) {
desiredApps: []v1alpha1.Application{
{
ObjectMeta: metav1.ObjectMeta{
Name: "app1",
Namespace: "namespace",
Name: "app1",
},
Spec: v1alpha1.ApplicationSpec{Project: "default"},
},
},
expected: []v1alpha1.Application{
@@ -159,8 +439,7 @@ func TestCreateOrUpdateInCluster(t *testing.T) {
desiredApps: []v1alpha1.Application{
{
ObjectMeta: metav1.ObjectMeta{
Name: "app1",
Namespace: "namespace",
Name: "app1",
},
Spec: v1alpha1.ApplicationSpec{
Project: "project",
@@ -218,8 +497,7 @@ func TestCreateOrUpdateInCluster(t *testing.T) {
desiredApps: []v1alpha1.Application{
{
ObjectMeta: metav1.ObjectMeta{
Name: "app2",
Namespace: "namespace",
Name: "app2",
},
Spec: v1alpha1.ApplicationSpec{
Project: "project",
@@ -278,7 +556,6 @@ func TestCreateOrUpdateInCluster(t *testing.T) {
{
ObjectMeta: metav1.ObjectMeta{
Name: "app1",
Namespace: "namespace",
Labels: map[string]string{"label-key": "label-value"},
Annotations: map[string]string{"annot-key": "annot-value"},
},
@@ -342,8 +619,7 @@ func TestCreateOrUpdateInCluster(t *testing.T) {
desiredApps: []v1alpha1.Application{
{
ObjectMeta: metav1.ObjectMeta{
Name: "app1",
Namespace: "namespace",
Name: "app1",
},
Spec: v1alpha1.ApplicationSpec{
Project: "project",
@@ -409,8 +685,7 @@ func TestCreateOrUpdateInCluster(t *testing.T) {
desiredApps: []v1alpha1.Application{
{
ObjectMeta: metav1.ObjectMeta{
Name: "app1",
Namespace: "namespace",
Name: "app1",
},
Spec: v1alpha1.ApplicationSpec{
Project: "project",
@@ -483,7 +758,6 @@ func TestCreateOrUpdateInCluster(t *testing.T) {
{
ObjectMeta: metav1.ObjectMeta{
Name: "app1",
Namespace: "namespace",
Labels: map[string]string{"label-key": "label-value"},
Annotations: map[string]string{"annot-key": "annot-value"},
},
@@ -561,8 +835,7 @@ func TestCreateOrUpdateInCluster(t *testing.T) {
desiredApps: []v1alpha1.Application{
{
ObjectMeta: metav1.ObjectMeta{
Name: "app1",
Namespace: "namespace",
Name: "app1",
},
Spec: v1alpha1.ApplicationSpec{
Project: "project",
@@ -631,8 +904,7 @@ func TestCreateOrUpdateInCluster(t *testing.T) {
desiredApps: []v1alpha1.Application{
{
ObjectMeta: metav1.ObjectMeta{
Name: "app1",
Namespace: "namespace",
Name: "app1",
},
Spec: v1alpha1.ApplicationSpec{
Project: "project",
@@ -682,8 +954,7 @@ func TestCreateOrUpdateInCluster(t *testing.T) {
desiredApps: []v1alpha1.Application{
{
ObjectMeta: metav1.ObjectMeta{
Name: "app1",
Namespace: "namespace",
Name: "app1",
},
Spec: v1alpha1.ApplicationSpec{
Project: "project",
@@ -761,8 +1032,7 @@ func TestCreateOrUpdateInCluster(t *testing.T) {
desiredApps: []v1alpha1.Application{
{
ObjectMeta: metav1.ObjectMeta{
Name: "app1",
Namespace: "namespace",
Name: "app1",
},
Spec: v1alpha1.ApplicationSpec{
Project: "project",
@@ -865,8 +1135,7 @@ func TestCreateOrUpdateInCluster(t *testing.T) {
desiredApps: []v1alpha1.Application{
{
ObjectMeta: metav1.ObjectMeta{
Name: "app1",
Namespace: "namespace",
Name: "app1",
},
Spec: v1alpha1.ApplicationSpec{
Project: "project",
@@ -967,8 +1236,7 @@ func TestCreateOrUpdateInCluster(t *testing.T) {
desiredApps: []v1alpha1.Application{
{
ObjectMeta: metav1.ObjectMeta{
Name: "app1",
Namespace: "namespace",
Name: "app1",
},
Spec: v1alpha1.ApplicationSpec{
Project: "project",
@@ -1049,8 +1317,7 @@ func TestCreateOrUpdateInCluster(t *testing.T) {
desiredApps: []v1alpha1.Application{
{
ObjectMeta: metav1.ObjectMeta{
Name: "app1",
Namespace: "namespace",
Name: "app1",
},
Spec: v1alpha1.ApplicationSpec{
Project: "project",
@@ -1494,8 +1761,7 @@ func TestCreateApplications(t *testing.T) {
apps: []v1alpha1.Application{
{
ObjectMeta: metav1.ObjectMeta{
Name: "app1",
Namespace: "namespace",
Name: "app1",
},
},
},
@@ -1550,8 +1816,7 @@ func TestCreateApplications(t *testing.T) {
apps: []v1alpha1.Application{
{
ObjectMeta: metav1.ObjectMeta{
Name: "app1",
Namespace: "namespace",
Name: "app1",
},
Spec: v1alpha1.ApplicationSpec{
Project: "project",
@@ -1609,8 +1874,7 @@ func TestCreateApplications(t *testing.T) {
apps: []v1alpha1.Application{
{
ObjectMeta: metav1.ObjectMeta{
Name: "app2",
Namespace: "namespace",
Name: "app2",
},
Spec: v1alpha1.ApplicationSpec{
Project: "project",
@@ -1842,15 +2106,15 @@ func TestGetMinRequeueAfter(t *testing.T) {
Clusters: &v1alpha1.ClusterGenerator{},
}
generatorMock0 := mocks.Generator{}
generatorMock0 := generatorMock{}
generatorMock0.On("GetRequeueAfter", &generator).
Return(generators.NoRequeueAfter)
generatorMock1 := mocks.Generator{}
generatorMock1 := generatorMock{}
generatorMock1.On("GetRequeueAfter", &generator).
Return(time.Duration(1) * time.Second)
generatorMock10 := mocks.Generator{}
generatorMock10 := generatorMock{}
generatorMock10.On("GetRequeueAfter", &generator).
Return(time.Duration(10) * time.Second)
@@ -2207,90 +2471,6 @@ func TestReconcilerValidationProjectErrorBehaviour(t *testing.T) {
require.Error(t, err)
}
func TestReconcilerCreateAppsRecoveringRenderError(t *testing.T) {
scheme := runtime.NewScheme()
err := v1alpha1.AddToScheme(scheme)
require.NoError(t, err)
err = v1alpha1.AddToScheme(scheme)
require.NoError(t, err)
project := v1alpha1.AppProject{
ObjectMeta: metav1.ObjectMeta{Name: "default", Namespace: "argocd"},
}
appSet := v1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "name",
Namespace: "argocd",
},
Spec: v1alpha1.ApplicationSetSpec{
GoTemplate: true,
Generators: []v1alpha1.ApplicationSetGenerator{
{
List: &v1alpha1.ListGenerator{
Elements: []apiextensionsv1.JSON{{
Raw: []byte(`{"name": "very-good-app"}`),
}, {
Raw: []byte(`{"name": "bad-app"}`),
}},
},
},
},
Template: v1alpha1.ApplicationSetTemplate{
ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{
Name: "{{ index (splitList \"-\" .name ) 2 }}",
Namespace: "argocd",
},
Spec: v1alpha1.ApplicationSpec{
Source: &v1alpha1.ApplicationSource{RepoURL: "https://github.com/argoproj/argocd-example-apps", Path: "guestbook"},
Project: "default",
Destination: v1alpha1.ApplicationDestination{Server: "https://kubernetes.default.svc"},
},
},
},
}
kubeclientset := kubefake.NewSimpleClientset()
argoDBMock := dbmocks.ArgoDB{}
argoObjs := []runtime.Object{&project}
client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&appSet).WithStatusSubresource(&appSet).WithIndex(&v1alpha1.Application{}, ".metadata.controller", appControllerIndexer).Build()
r := ApplicationSetReconciler{
Client: client,
Scheme: scheme,
Renderer: &utils.Render{},
Recorder: record.NewFakeRecorder(1),
Cache: &fakeCache{},
Generators: map[string]generators.Generator{
"List": generators.NewListGenerator(),
},
ArgoDB: &argoDBMock,
ArgoAppClientset: appclientset.NewSimpleClientset(argoObjs...),
KubeClientset: kubeclientset,
Policy: v1alpha1.ApplicationsSyncPolicySync,
ArgoCDNamespace: "argocd",
}
req := ctrl.Request{
NamespacedName: types.NamespacedName{
Namespace: "argocd",
Name: "name",
},
}
// Verify that on generatorsError, no error is returned, but the object is requeued
res, err := r.Reconcile(context.Background(), req)
require.NoError(t, err)
assert.Equal(t, ReconcileRequeueOnValidationError, res.RequeueAfter)
var app v1alpha1.Application
// make sure good app got created
err = r.Client.Get(context.TODO(), crtclient.ObjectKey{Namespace: "argocd", Name: "app"}, &app)
require.NoError(t, err)
assert.Equal(t, "app", app.Name)
}
func TestSetApplicationSetStatusCondition(t *testing.T) {
scheme := runtime.NewScheme()
err := v1alpha1.AddToScheme(scheme)
@@ -2669,6 +2849,120 @@ func TestDeletePerformedWithSyncPolicyCreateOnlyAndAllowPolicyOverrideFalse(t *t
assert.Empty(t, apps.Items)
}
// Test app generation from a go template application set using a pull request generator
func TestGenerateAppsUsingPullRequestGenerator(t *testing.T) {
scheme := runtime.NewScheme()
client := fake.NewClientBuilder().WithScheme(scheme).Build()
for _, cases := range []struct {
name string
params []map[string]interface{}
template v1alpha1.ApplicationSetTemplate
expectedApp []v1alpha1.Application
}{
{
name: "Generate an application from a go template application set manifest using a pull request generator",
params: []map[string]interface{}{
{
"number": "1",
"branch": "branch1",
"branch_slug": "branchSlug1",
"head_sha": "089d92cbf9ff857a39e6feccd32798ca700fb958",
"head_short_sha": "089d92cb",
"branch_slugify_default": "feat/a_really+long_pull_request_name_to_test_argo_slugification_and_branch_name_shortening_feature",
"branch_slugify_smarttruncate_disabled": "feat/areallylongpullrequestnametotestargoslugificationandbranchnameshorteningfeature",
"branch_slugify_smarttruncate_enabled": "feat/testwithsmarttruncateenabledramdomlonglistofcharacters",
"labels": []string{"label1"},
},
},
template: v1alpha1.ApplicationSetTemplate{
ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{
Name: "AppSet-{{.branch}}-{{.number}}",
Labels: map[string]string{
"app1": "{{index .labels 0}}",
"branch-test1": "AppSet-{{.branch_slugify_default | slugify }}",
"branch-test2": "AppSet-{{.branch_slugify_smarttruncate_disabled | slugify 49 false }}",
"branch-test3": "AppSet-{{.branch_slugify_smarttruncate_enabled | slugify 50 true }}",
},
},
Spec: v1alpha1.ApplicationSpec{
Source: &v1alpha1.ApplicationSource{
RepoURL: "https://testurl/testRepo",
TargetRevision: "{{.head_short_sha}}",
},
Destination: v1alpha1.ApplicationDestination{
Server: "https://kubernetes.default.svc",
Namespace: "AppSet-{{.branch_slug}}-{{.head_sha}}",
},
},
},
expectedApp: []v1alpha1.Application{
{
ObjectMeta: metav1.ObjectMeta{
Name: "AppSet-branch1-1",
Labels: map[string]string{
"app1": "label1",
"branch-test1": "AppSet-feat-a-really-long-pull-request-name-to-test-argo",
"branch-test2": "AppSet-feat-areallylongpullrequestnametotestargoslugific",
"branch-test3": "AppSet-feat",
},
},
Spec: v1alpha1.ApplicationSpec{
Source: &v1alpha1.ApplicationSource{
RepoURL: "https://testurl/testRepo",
TargetRevision: "089d92cb",
},
Destination: v1alpha1.ApplicationDestination{
Server: "https://kubernetes.default.svc",
Namespace: "AppSet-branchSlug1-089d92cbf9ff857a39e6feccd32798ca700fb958",
},
},
},
},
},
} {
t.Run(cases.name, func(t *testing.T) {
generatorMock := generatorMock{}
generator := v1alpha1.ApplicationSetGenerator{
PullRequest: &v1alpha1.PullRequestGenerator{},
}
generatorMock.On("GenerateParams", &generator).
Return(cases.params, nil)
generatorMock.On("GetTemplate", &generator).
Return(&cases.template, nil)
appSetReconciler := ApplicationSetReconciler{
Client: client,
Scheme: scheme,
Recorder: record.NewFakeRecorder(1),
Cache: &fakeCache{},
Generators: map[string]generators.Generator{
"PullRequest": &generatorMock,
},
Renderer: &utils.Render{},
KubeClientset: kubefake.NewSimpleClientset(),
}
gotApp, _, _ := appSetReconciler.generateApplications(log.NewEntry(log.StandardLogger()), v1alpha1.ApplicationSet{
Spec: v1alpha1.ApplicationSetSpec{
GoTemplate: true,
Generators: []v1alpha1.ApplicationSetGenerator{{
PullRequest: &v1alpha1.PullRequestGenerator{},
}},
Template: cases.template,
},
},
)
assert.EqualValues(t, cases.expectedApp[0].ObjectMeta.Name, gotApp[0].ObjectMeta.Name)
assert.EqualValues(t, cases.expectedApp[0].Spec.Source.TargetRevision, gotApp[0].Spec.Source.TargetRevision)
assert.EqualValues(t, cases.expectedApp[0].Spec.Destination.Namespace, gotApp[0].Spec.Destination.Namespace)
assert.True(t, collections.StringMapsEqual(cases.expectedApp[0].ObjectMeta.Labels, gotApp[0].ObjectMeta.Labels))
})
}
}
func TestPolicies(t *testing.T) {
scheme := runtime.NewScheme()
err := v1alpha1.AddToScheme(scheme)

View File

@@ -56,14 +56,14 @@ func TestRequeueAfter(t *testing.T) {
},
}
fakeDynClient := dynfake.NewSimpleDynamicClientWithCustomListKinds(runtime.NewScheme(), gvrToListKind, duckType)
scmConfig := generators.NewSCMConfig("", []string{""}, true, nil)
terminalGenerators := map[string]generators.Generator{
"List": generators.NewListGenerator(),
"Clusters": generators.NewClusterGenerator(k8sClient, ctx, appClientset, "argocd"),
"Git": generators.NewGitGenerator(mockServer),
"SCMProvider": generators.NewSCMProviderGenerator(fake.NewClientBuilder().WithObjects(&corev1.Secret{}).Build(), scmConfig),
"SCMProvider": generators.NewSCMProviderGenerator(fake.NewClientBuilder().WithObjects(&corev1.Secret{}).Build(), generators.SCMAuthProviders{}, "", []string{""}, true),
"ClusterDecisionResource": generators.NewDuckTypeGenerator(ctx, fakeDynClient, appClientset, "argocd"),
"PullRequest": generators.NewPullRequestGenerator(k8sClient, scmConfig),
"PullRequest": generators.NewPullRequestGenerator(k8sClient, generators.SCMAuthProviders{}, "", []string{""}, true),
}
nestedGenerators := map[string]generators.Generator{

View File

@@ -1,99 +0,0 @@
package template
import (
"fmt"
"sigs.k8s.io/controller-runtime/pkg/client"
log "github.com/sirupsen/logrus"
"github.com/argoproj/argo-cd/v2/applicationset/generators"
"github.com/argoproj/argo-cd/v2/applicationset/utils"
argov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
)
func GenerateApplications(logCtx *log.Entry, applicationSetInfo argov1alpha1.ApplicationSet, g map[string]generators.Generator, renderer utils.Renderer, client client.Client) ([]argov1alpha1.Application, argov1alpha1.ApplicationSetReasonType, error) {
var res []argov1alpha1.Application
var firstError error
var applicationSetReason argov1alpha1.ApplicationSetReasonType
for _, requestedGenerator := range applicationSetInfo.Spec.Generators {
t, err := generators.Transform(requestedGenerator, g, applicationSetInfo.Spec.Template, &applicationSetInfo, map[string]interface{}{}, client)
if err != nil {
logCtx.WithError(err).WithField("generator", requestedGenerator).
Error("error generating application from params")
if firstError == nil {
firstError = err
applicationSetReason = argov1alpha1.ApplicationSetReasonApplicationParamsGenerationError
}
continue
}
for _, a := range t {
tmplApplication := GetTempApplication(a.Template)
for _, p := range a.Params {
app, err := renderer.RenderTemplateParams(tmplApplication, applicationSetInfo.Spec.SyncPolicy, p, applicationSetInfo.Spec.GoTemplate, applicationSetInfo.Spec.GoTemplateOptions)
if err != nil {
logCtx.WithError(err).WithField("params", a.Params).WithField("generator", requestedGenerator).
Error("error generating application from params")
if firstError == nil {
firstError = err
applicationSetReason = argov1alpha1.ApplicationSetReasonRenderTemplateParamsError
}
continue
}
if applicationSetInfo.Spec.TemplatePatch != nil {
patchedApplication, err := renderTemplatePatch(renderer, app, applicationSetInfo, p)
if err != nil {
log.WithError(err).WithField("params", a.Params).WithField("generator", requestedGenerator).
Error("error generating application from params")
if firstError == nil {
firstError = err
applicationSetReason = argov1alpha1.ApplicationSetReasonRenderTemplateParamsError
}
continue
}
app = patchedApplication
}
// The app's namespace must be the same as the AppSet's namespace to preserve the appsets-in-any-namespace
// security boundary.
app.Namespace = applicationSetInfo.Namespace
res = append(res, *app)
}
}
logCtx.WithField("generator", requestedGenerator).Infof("generated %d applications", len(res))
logCtx.WithField("generator", requestedGenerator).Debugf("apps from generator: %+v", res)
}
return res, applicationSetReason, firstError
}
func renderTemplatePatch(r utils.Renderer, app *argov1alpha1.Application, applicationSetInfo argov1alpha1.ApplicationSet, params map[string]interface{}) (*argov1alpha1.Application, error) {
replacedTemplate, err := r.Replace(*applicationSetInfo.Spec.TemplatePatch, params, applicationSetInfo.Spec.GoTemplate, applicationSetInfo.Spec.GoTemplateOptions)
if err != nil {
return nil, fmt.Errorf("error replacing values in templatePatch: %w", err)
}
return applyTemplatePatch(app, replacedTemplate)
}
func GetTempApplication(applicationSetTemplate argov1alpha1.ApplicationSetTemplate) *argov1alpha1.Application {
var tmplApplication argov1alpha1.Application
tmplApplication.Annotations = applicationSetTemplate.Annotations
tmplApplication.Labels = applicationSetTemplate.Labels
tmplApplication.Namespace = applicationSetTemplate.Namespace
tmplApplication.Name = applicationSetTemplate.Name
tmplApplication.Spec = applicationSetTemplate.Spec
tmplApplication.Finalizers = applicationSetTemplate.Finalizers
return &tmplApplication
}

View File

@@ -1,349 +0,0 @@
package template
import (
"fmt"
"testing"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
log "github.com/sirupsen/logrus"
"github.com/stretchr/testify/assert"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"github.com/argoproj/argo-cd/v2/applicationset/generators"
genmock "github.com/argoproj/argo-cd/v2/applicationset/generators/mocks"
"github.com/argoproj/argo-cd/v2/applicationset/utils"
rendmock "github.com/argoproj/argo-cd/v2/applicationset/utils/mocks"
"github.com/argoproj/argo-cd/v2/pkg/apis/application"
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
"github.com/argoproj/argo-cd/v2/util/collections"
)
func TestGenerateApplications(t *testing.T) {
scheme := runtime.NewScheme()
err := v1alpha1.AddToScheme(scheme)
require.NoError(t, err)
err = v1alpha1.AddToScheme(scheme)
require.NoError(t, err)
for _, c := range []struct {
name string
params []map[string]interface{}
template v1alpha1.ApplicationSetTemplate
generateParamsError error
rendererError error
expectErr bool
expectedReason v1alpha1.ApplicationSetReasonType
}{
{
name: "Generate two applications",
params: []map[string]interface{}{{"name": "app1"}, {"name": "app2"}},
template: v1alpha1.ApplicationSetTemplate{
ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{
Name: "name",
Namespace: "namespace",
Labels: map[string]string{"label_name": "label_value"},
},
Spec: v1alpha1.ApplicationSpec{},
},
expectedReason: "",
},
{
name: "Handles error from the generator",
generateParamsError: fmt.Errorf("error"),
expectErr: true,
expectedReason: v1alpha1.ApplicationSetReasonApplicationParamsGenerationError,
},
{
name: "Handles error from the render",
params: []map[string]interface{}{{"name": "app1"}, {"name": "app2"}},
template: v1alpha1.ApplicationSetTemplate{
ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{
Name: "name",
Namespace: "namespace",
Labels: map[string]string{"label_name": "label_value"},
},
Spec: v1alpha1.ApplicationSpec{},
},
rendererError: fmt.Errorf("error"),
expectErr: true,
expectedReason: v1alpha1.ApplicationSetReasonRenderTemplateParamsError,
},
} {
cc := c
app := v1alpha1.Application{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: "namespace",
},
TypeMeta: metav1.TypeMeta{
Kind: application.ApplicationKind,
APIVersion: "argoproj.io/v1alpha1",
},
}
t.Run(cc.name, func(t *testing.T) {
generatorMock := genmock.Generator{}
generator := v1alpha1.ApplicationSetGenerator{
List: &v1alpha1.ListGenerator{},
}
generatorMock.On("GenerateParams", &generator, mock.AnythingOfType("*v1alpha1.ApplicationSet"), mock.Anything).
Return(cc.params, cc.generateParamsError)
generatorMock.On("GetTemplate", &generator).
Return(&v1alpha1.ApplicationSetTemplate{})
rendererMock := rendmock.Renderer{}
var expectedApps []v1alpha1.Application
if cc.generateParamsError == nil {
for _, p := range cc.params {
if cc.rendererError != nil {
rendererMock.On("RenderTemplateParams", GetTempApplication(cc.template), mock.AnythingOfType("*v1alpha1.ApplicationSetSyncPolicy"), p, false, []string(nil)).
Return(nil, cc.rendererError)
} else {
rendererMock.On("RenderTemplateParams", GetTempApplication(cc.template), mock.AnythingOfType("*v1alpha1.ApplicationSetSyncPolicy"), p, false, []string(nil)).
Return(&app, nil)
expectedApps = append(expectedApps, app)
}
}
}
generators := map[string]generators.Generator{
"List": &generatorMock,
}
renderer := &rendererMock
got, reason, err := GenerateApplications(log.NewEntry(log.StandardLogger()), v1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "name",
Namespace: "namespace",
},
Spec: v1alpha1.ApplicationSetSpec{
Generators: []v1alpha1.ApplicationSetGenerator{generator},
Template: cc.template,
},
},
generators,
renderer,
nil,
)
if cc.expectErr {
require.Error(t, err)
} else {
require.NoError(t, err)
}
assert.Equal(t, expectedApps, got)
assert.Equal(t, cc.expectedReason, reason)
generatorMock.AssertNumberOfCalls(t, "GenerateParams", 1)
if cc.generateParamsError == nil {
rendererMock.AssertNumberOfCalls(t, "RenderTemplateParams", len(cc.params))
}
})
}
}
func TestMergeTemplateApplications(t *testing.T) {
for _, c := range []struct {
name string
params []map[string]interface{}
template v1alpha1.ApplicationSetTemplate
overrideTemplate v1alpha1.ApplicationSetTemplate
expectedMerged v1alpha1.ApplicationSetTemplate
expectedApps []v1alpha1.Application
}{
{
name: "Generate app",
params: []map[string]interface{}{{"name": "app1"}},
template: v1alpha1.ApplicationSetTemplate{
ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{
Name: "name",
Namespace: "namespace",
Labels: map[string]string{"label_name": "label_value"},
},
Spec: v1alpha1.ApplicationSpec{},
},
overrideTemplate: v1alpha1.ApplicationSetTemplate{
ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{
Name: "test",
Labels: map[string]string{"foo": "bar"},
},
Spec: v1alpha1.ApplicationSpec{},
},
expectedMerged: v1alpha1.ApplicationSetTemplate{
ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{
Name: "test",
Namespace: "namespace",
Labels: map[string]string{"label_name": "label_value", "foo": "bar"},
},
Spec: v1alpha1.ApplicationSpec{},
},
expectedApps: []v1alpha1.Application{
{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: "test",
Labels: map[string]string{"foo": "bar"},
},
Spec: v1alpha1.ApplicationSpec{},
},
},
},
} {
cc := c
t.Run(cc.name, func(t *testing.T) {
generatorMock := genmock.Generator{}
generator := v1alpha1.ApplicationSetGenerator{
List: &v1alpha1.ListGenerator{},
}
generatorMock.On("GenerateParams", &generator, mock.AnythingOfType("*v1alpha1.ApplicationSet"), mock.Anything).
Return(cc.params, nil)
generatorMock.On("GetTemplate", &generator).
Return(&cc.overrideTemplate)
rendererMock := rendmock.Renderer{}
rendererMock.On("RenderTemplateParams", GetTempApplication(cc.expectedMerged), mock.AnythingOfType("*v1alpha1.ApplicationSetSyncPolicy"), cc.params[0], false, []string(nil)).
Return(&cc.expectedApps[0], nil)
generators := map[string]generators.Generator{
"List": &generatorMock,
}
renderer := &rendererMock
got, _, _ := GenerateApplications(log.NewEntry(log.StandardLogger()), v1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "name",
Namespace: "namespace",
},
Spec: v1alpha1.ApplicationSetSpec{
Generators: []v1alpha1.ApplicationSetGenerator{generator},
Template: cc.template,
},
},
generators,
renderer,
nil,
)
assert.Equal(t, cc.expectedApps, got)
})
}
}
// Test app generation from a go template application set using a pull request generator
func TestGenerateAppsUsingPullRequestGenerator(t *testing.T) {
for _, cases := range []struct {
name string
params []map[string]interface{}
template v1alpha1.ApplicationSetTemplate
expectedApp []v1alpha1.Application
}{
{
name: "Generate an application from a go template application set manifest using a pull request generator",
params: []map[string]interface{}{
{
"number": "1",
"branch": "branch1",
"branch_slug": "branchSlug1",
"head_sha": "089d92cbf9ff857a39e6feccd32798ca700fb958",
"head_short_sha": "089d92cb",
"branch_slugify_default": "feat/a_really+long_pull_request_name_to_test_argo_slugification_and_branch_name_shortening_feature",
"branch_slugify_smarttruncate_disabled": "feat/areallylongpullrequestnametotestargoslugificationandbranchnameshorteningfeature",
"branch_slugify_smarttruncate_enabled": "feat/testwithsmarttruncateenabledramdomlonglistofcharacters",
"labels": []string{"label1"},
},
},
template: v1alpha1.ApplicationSetTemplate{
ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{
Name: "AppSet-{{.branch}}-{{.number}}",
Labels: map[string]string{
"app1": "{{index .labels 0}}",
"branch-test1": "AppSet-{{.branch_slugify_default | slugify }}",
"branch-test2": "AppSet-{{.branch_slugify_smarttruncate_disabled | slugify 49 false }}",
"branch-test3": "AppSet-{{.branch_slugify_smarttruncate_enabled | slugify 50 true }}",
},
},
Spec: v1alpha1.ApplicationSpec{
Source: &v1alpha1.ApplicationSource{
RepoURL: "https://testurl/testRepo",
TargetRevision: "{{.head_short_sha}}",
},
Destination: v1alpha1.ApplicationDestination{
Server: "https://kubernetes.default.svc",
Namespace: "AppSet-{{.branch_slug}}-{{.head_sha}}",
},
},
},
expectedApp: []v1alpha1.Application{
{
ObjectMeta: metav1.ObjectMeta{
Name: "AppSet-branch1-1",
Labels: map[string]string{
"app1": "label1",
"branch-test1": "AppSet-feat-a-really-long-pull-request-name-to-test-argo",
"branch-test2": "AppSet-feat-areallylongpullrequestnametotestargoslugific",
"branch-test3": "AppSet-feat",
},
},
Spec: v1alpha1.ApplicationSpec{
Source: &v1alpha1.ApplicationSource{
RepoURL: "https://testurl/testRepo",
TargetRevision: "089d92cb",
},
Destination: v1alpha1.ApplicationDestination{
Server: "https://kubernetes.default.svc",
Namespace: "AppSet-branchSlug1-089d92cbf9ff857a39e6feccd32798ca700fb958",
},
},
},
},
},
} {
t.Run(cases.name, func(t *testing.T) {
generatorMock := genmock.Generator{}
generator := v1alpha1.ApplicationSetGenerator{
PullRequest: &v1alpha1.PullRequestGenerator{},
}
generatorMock.On("GenerateParams", &generator, mock.AnythingOfType("*v1alpha1.ApplicationSet"), mock.Anything).
Return(cases.params, nil)
generatorMock.On("GetTemplate", &generator).
Return(&cases.template, nil)
generators := map[string]generators.Generator{
"PullRequest": &generatorMock,
}
renderer := &utils.Render{}
gotApp, _, _ := GenerateApplications(log.NewEntry(log.StandardLogger()), v1alpha1.ApplicationSet{
Spec: v1alpha1.ApplicationSetSpec{
GoTemplate: true,
Generators: []v1alpha1.ApplicationSetGenerator{{
PullRequest: &v1alpha1.PullRequestGenerator{},
}},
Template: cases.template,
},
},
generators,
renderer,
nil,
)
assert.EqualValues(t, cases.expectedApp[0].ObjectMeta.Name, gotApp[0].ObjectMeta.Name)
assert.EqualValues(t, cases.expectedApp[0].Spec.Source.TargetRevision, gotApp[0].Spec.Source.TargetRevision)
assert.EqualValues(t, cases.expectedApp[0].Spec.Destination.Namespace, gotApp[0].Spec.Destination.Namespace)
assert.True(t, collections.StringMapsEqual(cases.expectedApp[0].ObjectMeta.Labels, gotApp[0].ObjectMeta.Labels))
})
}
}

View File

@@ -1,4 +1,4 @@
package template
package controllers
import (
"encoding/json"

View File

@@ -1,4 +1,4 @@
package template
package controllers
import (
"testing"

View File

@@ -9,8 +9,6 @@ import (
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
)
//go:generate go run github.com/vektra/mockery/v2@v2.40.2 --name=Generator
// Generator defines the interface implemented by all ApplicationSet generators.
type Generator interface {
// GenerateParams interprets the ApplicationSet and generates all relevant parameters for the application template.

View File

@@ -1073,7 +1073,7 @@ func TestGitGenerator_GenerateParams_list_x_git_matrix_generator(t *testing.T) {
// of that bug.
listGeneratorMock := &generatorMock{}
listGeneratorMock.On("GenerateParams", mock.AnythingOfType("*v1alpha1.ApplicationSetGenerator"), mock.AnythingOfType("*v1alpha1.ApplicationSet"), mock.Anything).Return([]map[string]interface{}{
listGeneratorMock.On("GenerateParams", mock.AnythingOfType("*v1alpha1.ApplicationSetGenerator"), mock.AnythingOfType("*v1alpha1.ApplicationSet")).Return([]map[string]interface{}{
{"some": "value"},
}, nil)
listGeneratorMock.On("GetTemplate", mock.AnythingOfType("*v1alpha1.ApplicationSetGenerator")).Return(&argoprojiov1alpha1.ApplicationSetTemplate{})

View File

@@ -1,100 +0,0 @@
// Code generated by mockery v2.40.2. DO NOT EDIT.
package mocks
import (
client "sigs.k8s.io/controller-runtime/pkg/client"
mock "github.com/stretchr/testify/mock"
time "time"
v1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
)
// Generator is an autogenerated mock type for the Generator type
type Generator struct {
mock.Mock
}
// GenerateParams provides a mock function with given fields: appSetGenerator, applicationSetInfo, _a2
func (_m *Generator) GenerateParams(appSetGenerator *v1alpha1.ApplicationSetGenerator, applicationSetInfo *v1alpha1.ApplicationSet, _a2 client.Client) ([]map[string]interface{}, error) {
ret := _m.Called(appSetGenerator, applicationSetInfo, _a2)
if len(ret) == 0 {
panic("no return value specified for GenerateParams")
}
var r0 []map[string]interface{}
var r1 error
if rf, ok := ret.Get(0).(func(*v1alpha1.ApplicationSetGenerator, *v1alpha1.ApplicationSet, client.Client) ([]map[string]interface{}, error)); ok {
return rf(appSetGenerator, applicationSetInfo, _a2)
}
if rf, ok := ret.Get(0).(func(*v1alpha1.ApplicationSetGenerator, *v1alpha1.ApplicationSet, client.Client) []map[string]interface{}); ok {
r0 = rf(appSetGenerator, applicationSetInfo, _a2)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]map[string]interface{})
}
}
if rf, ok := ret.Get(1).(func(*v1alpha1.ApplicationSetGenerator, *v1alpha1.ApplicationSet, client.Client) error); ok {
r1 = rf(appSetGenerator, applicationSetInfo, _a2)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// GetRequeueAfter provides a mock function with given fields: appSetGenerator
func (_m *Generator) GetRequeueAfter(appSetGenerator *v1alpha1.ApplicationSetGenerator) time.Duration {
ret := _m.Called(appSetGenerator)
if len(ret) == 0 {
panic("no return value specified for GetRequeueAfter")
}
var r0 time.Duration
if rf, ok := ret.Get(0).(func(*v1alpha1.ApplicationSetGenerator) time.Duration); ok {
r0 = rf(appSetGenerator)
} else {
r0 = ret.Get(0).(time.Duration)
}
return r0
}
// GetTemplate provides a mock function with given fields: appSetGenerator
func (_m *Generator) GetTemplate(appSetGenerator *v1alpha1.ApplicationSetGenerator) *v1alpha1.ApplicationSetTemplate {
ret := _m.Called(appSetGenerator)
if len(ret) == 0 {
panic("no return value specified for GetTemplate")
}
var r0 *v1alpha1.ApplicationSetTemplate
if rf, ok := ret.Get(0).(func(*v1alpha1.ApplicationSetGenerator) *v1alpha1.ApplicationSetTemplate); ok {
r0 = rf(appSetGenerator)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*v1alpha1.ApplicationSetTemplate)
}
}
return r0
}
// NewGenerator creates a new instance of Generator. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
// The first argument is typically a *testing.T value.
func NewGenerator(t interface {
mock.TestingT
Cleanup(func())
}) *Generator {
mock := &Generator{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}

View File

@@ -24,13 +24,19 @@ const (
type PullRequestGenerator struct {
client client.Client
selectServiceProviderFunc func(context.Context, *argoprojiov1alpha1.PullRequestGenerator, *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error)
SCMConfig
auth SCMAuthProviders
scmRootCAPath string
allowedSCMProviders []string
enableSCMProviders bool
}
func NewPullRequestGenerator(client client.Client, scmConfig SCMConfig) Generator {
func NewPullRequestGenerator(client client.Client, auth SCMAuthProviders, scmRootCAPath string, allowedScmProviders []string, enableSCMProviders bool) Generator {
g := &PullRequestGenerator{
client: client,
SCMConfig: scmConfig,
client: client,
auth: auth,
scmRootCAPath: scmRootCAPath,
allowedSCMProviders: allowedScmProviders,
enableSCMProviders: enableSCMProviders,
}
g.selectServiceProviderFunc = g.selectServiceProvider
return g
@@ -187,7 +193,7 @@ func (g *PullRequestGenerator) selectServiceProvider(ctx context.Context, genera
func (g *PullRequestGenerator) github(ctx context.Context, cfg *argoprojiov1alpha1.PullRequestGeneratorGithub, applicationSetInfo *argoprojiov1alpha1.ApplicationSet) (pullrequest.PullRequestService, error) {
// use an app if it was configured
if cfg.AppSecretName != "" {
auth, err := g.GitHubApps.GetAuthSecret(ctx, cfg.AppSecretName)
auth, err := g.auth.GitHubApps.GetAuthSecret(ctx, cfg.AppSecretName)
if err != nil {
return nil, fmt.Errorf("error getting GitHub App secret: %w", err)
}

View File

@@ -283,6 +283,7 @@ func TestAllowedSCMProviderPullRequest(t *testing.T) {
cases := []struct {
name string
providerConfig *argoprojiov1alpha1.PullRequestGenerator
expectedError error
}{
{
name: "Error Github",
@@ -291,6 +292,7 @@ func TestAllowedSCMProviderPullRequest(t *testing.T) {
API: "https://myservice.mynamespace.svc.cluster.local",
},
},
expectedError: &ErrDisallowedSCMProvider{},
},
{
name: "Error Gitlab",
@@ -299,6 +301,7 @@ func TestAllowedSCMProviderPullRequest(t *testing.T) {
API: "https://myservice.mynamespace.svc.cluster.local",
},
},
expectedError: &ErrDisallowedSCMProvider{},
},
{
name: "Error Gitea",
@@ -307,6 +310,7 @@ func TestAllowedSCMProviderPullRequest(t *testing.T) {
API: "https://myservice.mynamespace.svc.cluster.local",
},
},
expectedError: &ErrDisallowedSCMProvider{},
},
{
name: "Error Bitbucket",
@@ -315,6 +319,7 @@ func TestAllowedSCMProviderPullRequest(t *testing.T) {
API: "https://myservice.mynamespace.svc.cluster.local",
},
},
expectedError: &ErrDisallowedSCMProvider{},
},
}
@@ -324,13 +329,13 @@ func TestAllowedSCMProviderPullRequest(t *testing.T) {
t.Run(testCaseCopy.name, func(t *testing.T) {
t.Parallel()
pullRequestGenerator := NewPullRequestGenerator(nil, NewSCMConfig("", []string{
pullRequestGenerator := NewPullRequestGenerator(nil, SCMAuthProviders{}, "", []string{
"github.myorg.com",
"gitlab.myorg.com",
"gitea.myorg.com",
"bitbucket.myorg.com",
"azuredevops.myorg.com",
}, true, nil))
}, true)
applicationSetInfo := argoprojiov1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
@@ -346,14 +351,13 @@ func TestAllowedSCMProviderPullRequest(t *testing.T) {
_, err := pullRequestGenerator.GenerateParams(&applicationSetInfo.Spec.Generators[0], &applicationSetInfo, nil)
require.Error(t, err, "Must return an error")
var expectedError ErrDisallowedSCMProvider
assert.ErrorAs(t, err, &expectedError)
assert.ErrorAs(t, err, testCaseCopy.expectedError)
})
}
}
func TestSCMProviderDisabled_PRGenerator(t *testing.T) {
generator := NewPullRequestGenerator(nil, NewSCMConfig("", []string{}, false, nil))
generator := NewPullRequestGenerator(nil, SCMAuthProviders{}, "", []string{}, false)
applicationSetInfo := argoprojiov1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{

View File

@@ -29,36 +29,29 @@ type SCMProviderGenerator struct {
client client.Client
// Testing hooks.
overrideProvider scm_provider.SCMProviderService
SCMConfig
}
type SCMConfig struct {
SCMAuthProviders
scmRootCAPath string
allowedSCMProviders []string
enableSCMProviders bool
GitHubApps github_app_auth.Credentials
}
func NewSCMConfig(scmRootCAPath string, allowedSCMProviders []string, enableSCMProviders bool, gitHubApps github_app_auth.Credentials) SCMConfig {
return SCMConfig{
type SCMAuthProviders struct {
GitHubApps github_app_auth.Credentials
}
func NewSCMProviderGenerator(client client.Client, providers SCMAuthProviders, scmRootCAPath string, allowedSCMProviders []string, enableSCMProviders bool) Generator {
return &SCMProviderGenerator{
client: client,
SCMAuthProviders: providers,
scmRootCAPath: scmRootCAPath,
allowedSCMProviders: allowedSCMProviders,
enableSCMProviders: enableSCMProviders,
GitHubApps: gitHubApps,
}
}
func NewSCMProviderGenerator(client client.Client, scmConfig SCMConfig) Generator {
return &SCMProviderGenerator{
client: client,
SCMConfig: scmConfig,
}
}
// Testing generator
func NewTestSCMProviderGenerator(overrideProvider scm_provider.SCMProviderService) Generator {
return &SCMProviderGenerator{overrideProvider: overrideProvider, SCMConfig: SCMConfig{
enableSCMProviders: true,
}}
return &SCMProviderGenerator{overrideProvider: overrideProvider, enableSCMProviders: true}
}
func (g *SCMProviderGenerator) GetRequeueAfter(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator) time.Duration {

View File

@@ -174,7 +174,7 @@ func TestSCMProviderGenerateParams(t *testing.T) {
mockProvider := &scm_provider.MockProvider{
Repos: testCaseCopy.repos,
}
scmGenerator := &SCMProviderGenerator{overrideProvider: mockProvider, SCMConfig: SCMConfig{enableSCMProviders: true}}
scmGenerator := &SCMProviderGenerator{overrideProvider: mockProvider, enableSCMProviders: true}
applicationSetInfo := argoprojiov1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "set",
@@ -204,6 +204,7 @@ func TestAllowedSCMProvider(t *testing.T) {
cases := []struct {
name string
providerConfig *argoprojiov1alpha1.SCMProviderGenerator
expectedError error
}{
{
name: "Error Github",
@@ -212,6 +213,7 @@ func TestAllowedSCMProvider(t *testing.T) {
API: "https://myservice.mynamespace.svc.cluster.local",
},
},
expectedError: &ErrDisallowedSCMProvider{},
},
{
name: "Error Gitlab",
@@ -220,6 +222,7 @@ func TestAllowedSCMProvider(t *testing.T) {
API: "https://myservice.mynamespace.svc.cluster.local",
},
},
expectedError: &ErrDisallowedSCMProvider{},
},
{
name: "Error Gitea",
@@ -228,6 +231,7 @@ func TestAllowedSCMProvider(t *testing.T) {
API: "https://myservice.mynamespace.svc.cluster.local",
},
},
expectedError: &ErrDisallowedSCMProvider{},
},
{
name: "Error Bitbucket",
@@ -236,6 +240,7 @@ func TestAllowedSCMProvider(t *testing.T) {
API: "https://myservice.mynamespace.svc.cluster.local",
},
},
expectedError: &ErrDisallowedSCMProvider{},
},
{
name: "Error AzureDevops",
@@ -244,6 +249,7 @@ func TestAllowedSCMProvider(t *testing.T) {
API: "https://myservice.mynamespace.svc.cluster.local",
},
},
expectedError: &ErrDisallowedSCMProvider{},
},
}
@@ -254,16 +260,14 @@ func TestAllowedSCMProvider(t *testing.T) {
t.Parallel()
scmGenerator := &SCMProviderGenerator{
SCMConfig: SCMConfig{
allowedSCMProviders: []string{
"github.myorg.com",
"gitlab.myorg.com",
"gitea.myorg.com",
"bitbucket.myorg.com",
"azuredevops.myorg.com",
},
enableSCMProviders: true,
allowedSCMProviders: []string{
"github.myorg.com",
"gitlab.myorg.com",
"gitea.myorg.com",
"bitbucket.myorg.com",
"azuredevops.myorg.com",
},
enableSCMProviders: true,
}
applicationSetInfo := argoprojiov1alpha1.ApplicationSet{
@@ -280,14 +284,13 @@ func TestAllowedSCMProvider(t *testing.T) {
_, err := scmGenerator.GenerateParams(&applicationSetInfo.Spec.Generators[0], &applicationSetInfo, nil)
require.Error(t, err, "Must return an error")
var expectedError ErrDisallowedSCMProvider
assert.ErrorAs(t, err, &expectedError)
assert.ErrorAs(t, err, testCaseCopy.expectedError)
})
}
}
func TestSCMProviderDisabled_SCMGenerator(t *testing.T) {
generator := &SCMProviderGenerator{SCMConfig: SCMConfig{enableSCMProviders: false}}
generator := &SCMProviderGenerator{enableSCMProviders: false}
applicationSetInfo := argoprojiov1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{

View File

@@ -1,49 +0,0 @@
package generators
import (
"context"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/kubernetes"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/argoproj/argo-cd/v2/applicationset/services"
)
func GetGenerators(ctx context.Context, c client.Client, k8sClient kubernetes.Interface, namespace string, argoCDService services.Repos, dynamicClient dynamic.Interface, scmConfig SCMConfig) map[string]Generator {
terminalGenerators := map[string]Generator{
"List": NewListGenerator(),
"Clusters": NewClusterGenerator(c, ctx, k8sClient, namespace),
"Git": NewGitGenerator(argoCDService),
"SCMProvider": NewSCMProviderGenerator(c, scmConfig),
"ClusterDecisionResource": NewDuckTypeGenerator(ctx, dynamicClient, k8sClient, namespace),
"PullRequest": NewPullRequestGenerator(c, scmConfig),
"Plugin": NewPluginGenerator(c, ctx, k8sClient, namespace),
}
nestedGenerators := map[string]Generator{
"List": terminalGenerators["List"],
"Clusters": terminalGenerators["Clusters"],
"Git": terminalGenerators["Git"],
"SCMProvider": terminalGenerators["SCMProvider"],
"ClusterDecisionResource": terminalGenerators["ClusterDecisionResource"],
"PullRequest": terminalGenerators["PullRequest"],
"Plugin": terminalGenerators["Plugin"],
"Matrix": NewMatrixGenerator(terminalGenerators),
"Merge": NewMergeGenerator(terminalGenerators),
}
topLevelGenerators := map[string]Generator{
"List": terminalGenerators["List"],
"Clusters": terminalGenerators["Clusters"],
"Git": terminalGenerators["Git"],
"SCMProvider": terminalGenerators["SCMProvider"],
"ClusterDecisionResource": terminalGenerators["ClusterDecisionResource"],
"PullRequest": terminalGenerators["PullRequest"],
"Plugin": terminalGenerators["Plugin"],
"Matrix": NewMatrixGenerator(nestedGenerators),
"Merge": NewMergeGenerator(nestedGenerators),
}
return topLevelGenerators
}

View File

@@ -191,6 +191,6 @@ func TestNewArgoCDService(t *testing.T) {
service, err := NewArgoCDService(func(ctx context.Context, url, project string) (*v1alpha1.Repository, error) {
return &v1alpha1.Repository{}, nil
}, false, &repo_mocks.Clientset{}, false)
require.NoError(t, err)
require.NoError(t, err, err)
assert.NotNil(t, service)
}

View File

@@ -1,57 +0,0 @@
package status
import (
argov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
)
func BuildResourceStatus(statusMap map[string]argov1alpha1.ResourceStatus, apps []argov1alpha1.Application) map[string]argov1alpha1.ResourceStatus {
appMap := map[string]argov1alpha1.Application{}
for _, app := range apps {
appCopy := app
appMap[app.Name] = app
gvk := app.GroupVersionKind()
// Create status if it does not exist
status, ok := statusMap[app.Name]
if !ok {
status = argov1alpha1.ResourceStatus{
Group: gvk.Group,
Version: gvk.Version,
Kind: gvk.Kind,
Name: app.Name,
Namespace: app.Namespace,
Status: app.Status.Sync.Status,
Health: &appCopy.Status.Health,
}
}
status.Group = gvk.Group
status.Version = gvk.Version
status.Kind = gvk.Kind
status.Name = app.Name
status.Namespace = app.Namespace
status.Status = app.Status.Sync.Status
status.Health = &appCopy.Status.Health
statusMap[app.Name] = status
}
cleanupDeletedApplicationStatuses(statusMap, appMap)
return statusMap
}
func GetResourceStatusMap(appset *argov1alpha1.ApplicationSet) map[string]argov1alpha1.ResourceStatus {
statusMap := map[string]argov1alpha1.ResourceStatus{}
for _, status := range appset.Status.Resources {
statusMap[status.Name] = status
}
return statusMap
}
func cleanupDeletedApplicationStatuses(statusMap map[string]argov1alpha1.ResourceStatus, apps map[string]argov1alpha1.Application) {
for name := range statusMap {
if _, ok := apps[name]; !ok {
delete(statusMap, name)
}
}
}

View File

@@ -1,86 +0,0 @@
// Code generated by mockery v2.40.2. DO NOT EDIT.
package mocks
import (
mock "github.com/stretchr/testify/mock"
v1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
)
// Renderer is an autogenerated mock type for the Renderer type
type Renderer struct {
mock.Mock
}
// RenderTemplateParams provides a mock function with given fields: tmpl, syncPolicy, params, useGoTemplate, goTemplateOptions
func (_m *Renderer) RenderTemplateParams(tmpl *v1alpha1.Application, syncPolicy *v1alpha1.ApplicationSetSyncPolicy, params map[string]interface{}, useGoTemplate bool, goTemplateOptions []string) (*v1alpha1.Application, error) {
ret := _m.Called(tmpl, syncPolicy, params, useGoTemplate, goTemplateOptions)
if len(ret) == 0 {
panic("no return value specified for RenderTemplateParams")
}
var r0 *v1alpha1.Application
var r1 error
if rf, ok := ret.Get(0).(func(*v1alpha1.Application, *v1alpha1.ApplicationSetSyncPolicy, map[string]interface{}, bool, []string) (*v1alpha1.Application, error)); ok {
return rf(tmpl, syncPolicy, params, useGoTemplate, goTemplateOptions)
}
if rf, ok := ret.Get(0).(func(*v1alpha1.Application, *v1alpha1.ApplicationSetSyncPolicy, map[string]interface{}, bool, []string) *v1alpha1.Application); ok {
r0 = rf(tmpl, syncPolicy, params, useGoTemplate, goTemplateOptions)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*v1alpha1.Application)
}
}
if rf, ok := ret.Get(1).(func(*v1alpha1.Application, *v1alpha1.ApplicationSetSyncPolicy, map[string]interface{}, bool, []string) error); ok {
r1 = rf(tmpl, syncPolicy, params, useGoTemplate, goTemplateOptions)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// Replace provides a mock function with given fields: tmpl, replaceMap, useGoTemplate, goTemplateOptions
func (_m *Renderer) Replace(tmpl string, replaceMap map[string]interface{}, useGoTemplate bool, goTemplateOptions []string) (string, error) {
ret := _m.Called(tmpl, replaceMap, useGoTemplate, goTemplateOptions)
if len(ret) == 0 {
panic("no return value specified for Replace")
}
var r0 string
var r1 error
if rf, ok := ret.Get(0).(func(string, map[string]interface{}, bool, []string) (string, error)); ok {
return rf(tmpl, replaceMap, useGoTemplate, goTemplateOptions)
}
if rf, ok := ret.Get(0).(func(string, map[string]interface{}, bool, []string) string); ok {
r0 = rf(tmpl, replaceMap, useGoTemplate, goTemplateOptions)
} else {
r0 = ret.Get(0).(string)
}
if rf, ok := ret.Get(1).(func(string, map[string]interface{}, bool, []string) error); ok {
r1 = rf(tmpl, replaceMap, useGoTemplate, goTemplateOptions)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// NewRenderer creates a new instance of Renderer. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
// The first argument is typically a *testing.T value.
func NewRenderer(t interface {
mock.TestingT
Cleanup(func())
}) *Renderer {
mock := &Renderer{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}

View File

@@ -25,8 +25,6 @@ import (
argoappsv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
)
//go:generate go run github.com/vektra/mockery/v2@v2.40.2 --name=Renderer
var sprigFuncMap = sprig.GenericFuncMap() // a singleton for better performance
func init() {

View File

@@ -1967,11 +1967,6 @@
"type": "boolean",
"name": "upsert",
"in": "query"
},
{
"type": "boolean",
"name": "dryRun",
"in": "query"
}
],
"responses": {
@@ -6965,7 +6960,7 @@
},
"serverVersion": {
"type": "string",
"title": "Deprecated: use Info.ServerVersion field instead.\nThe server version"
"title": "DEPRECATED: use Info.ServerVersion field instead.\nThe server version"
},
"shard": {
"description": "Shard contains optional shard number. Calculated on the fly by the application controller if not specified.",

View File

@@ -152,7 +152,9 @@ func NewCommand() *cobra.Command {
appSetConfig := appclientset.NewForConfigOrDie(mgr.GetConfig())
argoCDDB := db.NewDB(namespace, argoSettingsMgr, k8sClient)
scmConfig := generators.NewSCMConfig(scmRootCAPath, allowedScmProviders, enableScmProviders, github_app.NewAuthCredentials(argoCDDB.(db.RepoCredsDB)))
scmAuth := generators.SCMAuthProviders{
GitHubApps: github_app.NewAuthCredentials(argoCDDB.(db.RepoCredsDB)),
}
tlsConfig := apiclient.TLSConfiguration{
DisableTLS: repoServerPlaintext,
@@ -172,7 +174,39 @@ func NewCommand() *cobra.Command {
argoCDService, err := services.NewArgoCDService(argoCDDB.GetRepository, gitSubmoduleEnabled, repoClientset, enableNewGitFileGlobbing)
errors.CheckError(err)
topLevelGenerators := generators.GetGenerators(ctx, mgr.GetClient(), k8sClient, namespace, argoCDService, dynamicClient, scmConfig)
terminalGenerators := map[string]generators.Generator{
"List": generators.NewListGenerator(),
"Clusters": generators.NewClusterGenerator(mgr.GetClient(), ctx, k8sClient, namespace),
"Git": generators.NewGitGenerator(argoCDService),
"SCMProvider": generators.NewSCMProviderGenerator(mgr.GetClient(), scmAuth, scmRootCAPath, allowedScmProviders, enableScmProviders),
"ClusterDecisionResource": generators.NewDuckTypeGenerator(ctx, dynamicClient, k8sClient, namespace),
"PullRequest": generators.NewPullRequestGenerator(mgr.GetClient(), scmAuth, scmRootCAPath, allowedScmProviders, enableScmProviders),
"Plugin": generators.NewPluginGenerator(mgr.GetClient(), ctx, k8sClient, namespace),
}
nestedGenerators := map[string]generators.Generator{
"List": terminalGenerators["List"],
"Clusters": terminalGenerators["Clusters"],
"Git": terminalGenerators["Git"],
"SCMProvider": terminalGenerators["SCMProvider"],
"ClusterDecisionResource": terminalGenerators["ClusterDecisionResource"],
"PullRequest": terminalGenerators["PullRequest"],
"Plugin": terminalGenerators["Plugin"],
"Matrix": generators.NewMatrixGenerator(terminalGenerators),
"Merge": generators.NewMergeGenerator(terminalGenerators),
}
topLevelGenerators := map[string]generators.Generator{
"List": terminalGenerators["List"],
"Clusters": terminalGenerators["Clusters"],
"Git": terminalGenerators["Git"],
"SCMProvider": terminalGenerators["SCMProvider"],
"ClusterDecisionResource": terminalGenerators["ClusterDecisionResource"],
"PullRequest": terminalGenerators["PullRequest"],
"Plugin": terminalGenerators["Plugin"],
"Matrix": generators.NewMatrixGenerator(nestedGenerators),
"Merge": generators.NewMergeGenerator(nestedGenerators),
}
// start a webhook server that listens to incoming webhook payloads
webhookHandler, err := webhook.NewWebhookHandler(namespace, argoSettingsMgr, mgr.GetClient(), topLevelGenerators)

View File

@@ -12,10 +12,8 @@ import (
"github.com/argoproj/pkg/stats"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
"sigs.k8s.io/controller-runtime/pkg/client"
cmdutil "github.com/argoproj/argo-cd/v2/cmd/util"
"github.com/argoproj/argo-cd/v2/common"
@@ -44,7 +42,6 @@ const (
var (
failureRetryCount = env.ParseNumFromEnv(failureRetryCountEnv, 0, 0, 10)
failureRetryPeriodMilliSeconds = env.ParseNumFromEnv(failureRetryPeriodMilliSecondsEnv, 100, 0, 1000)
gitSubmoduleEnabled = env.ParseBoolFromEnv(common.EnvGitSubmoduleEnabled, true)
)
// NewCommand returns a new instance of an argocd command
@@ -82,12 +79,6 @@ func NewCommand() *cobra.Command {
staticAssetsDir string
applicationNamespaces []string
enableProxyExtension bool
// ApplicationSet
enableNewGitFileGlobbing bool
scmRootCAPath string
allowedScmProviders []string
enableScmProviders bool
)
command := &cobra.Command{
Use: cliName,
@@ -139,12 +130,6 @@ func NewCommand() *cobra.Command {
StrictValidation: repoServerStrictTLS,
}
dynamicClient := dynamic.NewForConfigOrDie(config)
controllerClient, err := client.New(config, client.Options{})
errors.CheckError(err)
controllerClient = client.NewDryRunClient(controllerClient)
// Load CA information to use for validating connections to the
// repository server, if strict TLS validation was requested.
if !repoServerPlaintext && repoServerStrictTLS {
@@ -194,47 +179,37 @@ func NewCommand() *cobra.Command {
}
argoCDOpts := server.ArgoCDServerOpts{
Insecure: insecure,
ListenPort: listenPort,
ListenHost: listenHost,
MetricsPort: metricsPort,
MetricsHost: metricsHost,
Namespace: namespace,
BaseHRef: baseHRef,
RootPath: rootPath,
DynamicClientset: dynamicClient,
KubeControllerClientset: controllerClient,
KubeClientset: kubeclientset,
AppClientset: appClientSet,
RepoClientset: repoclientset,
DexServerAddr: dexServerAddress,
DexTLSConfig: dexTlsConfig,
DisableAuth: disableAuth,
ContentTypes: contentTypesList,
EnableGZip: enableGZip,
TLSConfigCustomizer: tlsConfigCustomizer,
Cache: cache,
RepoServerCache: repoServerCache,
XFrameOptions: frameOptions,
ContentSecurityPolicy: contentSecurityPolicy,
RedisClient: redisClient,
StaticAssetsDir: staticAssetsDir,
ApplicationNamespaces: applicationNamespaces,
EnableProxyExtension: enableProxyExtension,
}
appsetOpts := server.ApplicationSetOpts{
GitSubmoduleEnabled: gitSubmoduleEnabled,
EnableNewGitFileGlobbing: enableNewGitFileGlobbing,
ScmRootCAPath: scmRootCAPath,
AllowedScmProviders: allowedScmProviders,
EnableScmProviders: enableScmProviders,
Insecure: insecure,
ListenPort: listenPort,
ListenHost: listenHost,
MetricsPort: metricsPort,
MetricsHost: metricsHost,
Namespace: namespace,
BaseHRef: baseHRef,
RootPath: rootPath,
KubeClientset: kubeclientset,
AppClientset: appClientSet,
RepoClientset: repoclientset,
DexServerAddr: dexServerAddress,
DexTLSConfig: dexTlsConfig,
DisableAuth: disableAuth,
ContentTypes: contentTypesList,
EnableGZip: enableGZip,
TLSConfigCustomizer: tlsConfigCustomizer,
Cache: cache,
RepoServerCache: repoServerCache,
XFrameOptions: frameOptions,
ContentSecurityPolicy: contentSecurityPolicy,
RedisClient: redisClient,
StaticAssetsDir: staticAssetsDir,
ApplicationNamespaces: applicationNamespaces,
EnableProxyExtension: enableProxyExtension,
}
stats.RegisterStackDumper()
stats.StartStatsTicker(10 * time.Minute)
stats.RegisterHeapDumper("memprofile")
argocd := server.NewServer(ctx, argoCDOpts, appsetOpts)
argocd := server.NewServer(ctx, argoCDOpts)
argocd.Init(ctx)
lns, err := argocd.Listen()
errors.CheckError(err)
@@ -257,7 +232,7 @@ func NewCommand() *cobra.Command {
Example: templates.Examples(`
# Start the Argo CD API server with default settings
$ argocd-server
# Start the Argo CD API server on a custom port and enable tracing
$ argocd-server --port 8888 --otlp-address localhost:4317
`),
@@ -294,13 +269,6 @@ func NewCommand() *cobra.Command {
command.Flags().BoolVar(&dexServerStrictTLS, "dex-server-strict-tls", env.ParseBoolFromEnv("ARGOCD_SERVER_DEX_SERVER_STRICT_TLS", false), "Perform strict validation of TLS certificates when connecting to dex server")
command.Flags().StringSliceVar(&applicationNamespaces, "application-namespaces", env.StringsFromEnv("ARGOCD_APPLICATION_NAMESPACES", []string{}, ","), "List of additional namespaces where application resources can be managed in")
command.Flags().BoolVar(&enableProxyExtension, "enable-proxy-extension", env.ParseBoolFromEnv("ARGOCD_SERVER_ENABLE_PROXY_EXTENSION", false), "Enable Proxy Extension feature")
// Flags related to the applicationSet component.
command.Flags().StringVar(&scmRootCAPath, "appset-scm-root-ca-path", env.StringFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_SCM_ROOT_CA_PATH", ""), "Provide Root CA Path for self-signed TLS Certificates")
command.Flags().BoolVar(&enableScmProviders, "appset-enable-scm-providers", env.ParseBoolFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_SCM_PROVIDERS", true), "Enable retrieving information from SCM providers, used by the SCM and PR generators (Default: true)")
command.Flags().StringSliceVar(&allowedScmProviders, "appset-allowed-scm-providers", env.StringsFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_ALLOWED_SCM_PROVIDERS", []string{}, ","), "The list of allowed custom SCM provider API URLs. This restriction does not apply to SCM or PR generators which do not accept a custom API URL. (Default: Empty = all)")
command.Flags().BoolVar(&enableNewGitFileGlobbing, "appset-enable-new-git-file-globbing", env.ParseBoolFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_NEW_GIT_FILE_GLOBBING", false), "Enable new globbing in Git files generator.")
tlsConfigCustomizerSrc = tls.AddTLSFlagsToCmd(command)
cacheSrc = servercache.AddCacheFlagsToCmd(command, cacheutil.Options{
OnClientCreated: func(client *redis.Client) {

View File

@@ -114,17 +114,13 @@ func NewApplicationSetGetCommand(clientOpts *argocdclient.ClientOptions) *cobra.
// NewApplicationSetCreateCommand returns a new instance of an `argocd appset create` command
func NewApplicationSetCreateCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
var output string
var upsert, dryRun bool
var upsert bool
command := &cobra.Command{
Use: "create",
Short: "Create one or more ApplicationSets",
Example: templates.Examples(`
# Create ApplicationSets
argocd appset create <filename or URL> (<filename or URL>...)
# Dry-run AppSet creation to see what applications would be managed
argocd appset create --dry-run <filename or URL> -o json | jq -r '.status.resources[].name'
`),
Run: func(c *cobra.Command, args []string) {
ctx := c.Context()
@@ -161,16 +157,10 @@ func NewApplicationSetCreateCommand(clientOpts *argocdclient.ClientOptions) *cob
appSetCreateRequest := applicationset.ApplicationSetCreateRequest{
Applicationset: appset,
Upsert: upsert,
DryRun: dryRun,
}
created, err := appIf.Create(ctx, &appSetCreateRequest)
errors.CheckError(err)
dryRunMsg := ""
if dryRun {
dryRunMsg = " (dry-run)"
}
var action string
if existing == nil {
action = "created"
@@ -180,31 +170,11 @@ func NewApplicationSetCreateCommand(clientOpts *argocdclient.ClientOptions) *cob
action = "updated"
}
c.PrintErrf("ApplicationSet '%s' %s%s\n", created.ObjectMeta.Name, action, dryRunMsg)
switch output {
case "yaml", "json":
err := PrintResource(created, output)
errors.CheckError(err)
case "wide", "":
printAppSetSummaryTable(created)
if len(created.Status.Conditions) > 0 {
fmt.Println()
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
printAppSetConditions(w, created)
_ = w.Flush()
fmt.Println()
}
default:
errors.CheckError(fmt.Errorf("unknown output format: %s", output))
}
fmt.Printf("ApplicationSet '%s' %s\n", created.ObjectMeta.Name, action)
}
},
}
command.Flags().BoolVar(&upsert, "upsert", false, "Allows to override ApplicationSet with the same name even if supplied ApplicationSet spec is different from existing spec")
command.Flags().BoolVar(&dryRun, "dry-run", false, "Allows to evaluate the ApplicationSet template on the server to get a preview of the applications that would be created")
command.Flags().StringVarP(&output, "output", "o", "wide", "Output format. One of: json|yaml|wide")
return command
}
@@ -219,7 +189,7 @@ func NewApplicationSetListCommand(clientOpts *argocdclient.ClientOptions) *cobra
command := &cobra.Command{
Use: "list",
Short: "List ApplicationSets",
Example: templates.Examples(`
Example: templates.Examples(`
# List all ApplicationSets
argocd appset list
`),
@@ -260,7 +230,7 @@ func NewApplicationSetDeleteCommand(clientOpts *argocdclient.ClientOptions) *cob
command := &cobra.Command{
Use: "delete",
Short: "Delete one or more ApplicationSets",
Example: templates.Examples(`
Example: templates.Examples(`
# Delete an applicationset
argocd appset delete APPSETNAME (APPSETNAME...)
`),

View File

@@ -9,7 +9,6 @@ import (
"time"
"github.com/spf13/cobra"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/argoproj/argo-cd/v2/cmd/argocd/commands/initialize"
"github.com/argoproj/argo-cd/v2/common"
@@ -21,7 +20,6 @@ import (
"github.com/spf13/pflag"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/kubernetes"
cache2 "k8s.io/client-go/tools/cache"
"k8s.io/client-go/tools/clientcmd"
@@ -233,17 +231,6 @@ func MaybeStartLocalServer(ctx context.Context, clientOpts *apiclient.ClientOpti
return fmt.Errorf("error creating kubernetes clientset: %w", err)
}
dynamicClientset, err := dynamic.NewForConfig(restConfig)
if err != nil {
return fmt.Errorf("error creating kubernetes dynamic clientset: %w", err)
}
controllerClientset, err := client.New(restConfig, client.Options{})
if err != nil {
return fmt.Errorf("error creating kubernetes controller clientset: %w", err)
}
controllerClientset = client.NewDryRunClient(controllerClientset)
namespace, _, err := clientConfig.Namespace()
if err != nil {
return fmt.Errorf("error getting namespace: %w", err)
@@ -255,21 +242,19 @@ func MaybeStartLocalServer(ctx context.Context, clientOpts *apiclient.ClientOpti
}
appstateCache := appstatecache.NewCache(cache.NewCache(&forwardCacheClient{namespace: namespace, context: ctxStr, compression: compression, redisHaProxyName: clientOpts.RedisHaProxyName, redisName: clientOpts.RedisName}), time.Hour)
srv := server.NewServer(ctx, server.ArgoCDServerOpts{
EnableGZip: false,
Namespace: namespace,
ListenPort: *port,
AppClientset: appClientset,
DisableAuth: true,
RedisClient: redis.NewClient(&redis.Options{Addr: mr.Addr()}),
Cache: servercache.NewCache(appstateCache, 0, 0, 0),
KubeClientset: kubeClientset,
DynamicClientset: dynamicClientset,
KubeControllerClientset: controllerClientset,
Insecure: true,
ListenHost: *address,
RepoClientset: &forwardRepoClientset{namespace: namespace, context: ctxStr, repoServerName: clientOpts.RepoServerName, kubeClientset: kubeClientset},
EnableProxyExtension: false,
}, server.ApplicationSetOpts{})
EnableGZip: false,
Namespace: namespace,
ListenPort: *port,
AppClientset: appClientset,
DisableAuth: true,
RedisClient: redis.NewClient(&redis.Options{Addr: mr.Addr()}),
Cache: servercache.NewCache(appstateCache, 0, 0, 0),
KubeClientset: kubeClientset,
Insecure: true,
ListenHost: *address,
RepoClientset: &forwardRepoClientset{namespace: namespace, context: ctxStr, repoServerName: clientOpts.RepoServerName, kubeClientset: kubeClientset},
EnableProxyExtension: false,
})
srv.Init(ctx)
lns, err := srv.Listen()

View File

@@ -374,8 +374,8 @@ data:
var fakePostDeleteHook = `
{
"apiVersion": "v1",
"kind": "Pod",
"apiVersion": "batch/v1",
"kind": "Job",
"metadata": {
"name": "post-delete-hook",
"namespace": "default",
@@ -388,22 +388,93 @@ var fakePostDeleteHook = `
}
},
"spec": {
"containers": [
{
"name": "post-delete-hook",
"image": "busybox",
"restartPolicy": "Never",
"command": [
"/bin/sh",
"-c",
"sleep 5 && echo hello from the post-delete-hook pod"
]
"template": {
"metadata": {
"name": "post-delete-hook"
},
"spec": {
"containers": [
{
"name": "post-delete-hook",
"image": "busybox",
"command": [
"/bin/sh",
"-c",
"sleep 5 && echo hello from the post-delete-hook job"
]
}
],
"restartPolicy": "Never"
}
]
}
}
}
`
var fakeServiceAccount = `
{
"apiVersion": "v1",
"kind": "ServiceAccount",
"metadata": {
"name": "hook-serviceaccount",
"namespace": "default",
"annotations": {
"argocd.argoproj.io/hook": "PostDelete",
"argocd.argoproj.io/hook-delete-policy": "BeforeHookCreation,HookSucceeded"
}
}
}
`
var fakeRole = `
{
"apiVersion": "rbac.authorization.k8s.io/v1",
"kind": "Role",
"metadata": {
"name": "hook-role",
"namespace": "default",
"annotations": {
"argocd.argoproj.io/hook": "PostDelete",
"argocd.argoproj.io/hook-delete-policy": "BeforeHookCreation,HookSucceeded"
}
},
"rules": [
{
"apiGroups": [""],
"resources": ["secrets"],
"verbs": ["get", "delete", "list"]
}
]
}
`
var fakeRoleBinding = `
{
"apiVersion": "rbac.authorization.k8s.io/v1",
"kind": "RoleBinding",
"metadata": {
"name": "hook-rolebinding",
"namespace": "default",
"annotations": {
"argocd.argoproj.io/hook": "PostDelete",
"argocd.argoproj.io/hook-delete-policy": "BeforeHookCreation,HookSucceeded"
}
},
"roleRef": {
"apiGroup": "rbac.authorization.k8s.io",
"kind": "Role",
"name": "hook-role"
},
"subjects": [
{
"kind": "ServiceAccount",
"name": "hook-serviceaccount",
"namespace": "default"
}
]
}
`
func newFakeApp() *v1alpha1.Application {
return createFakeApp(fakeApp)
}
@@ -439,12 +510,39 @@ func newFakeCM() map[string]interface{} {
}
func newFakePostDeleteHook() map[string]interface{} {
var cm map[string]interface{}
err := yaml.Unmarshal([]byte(fakePostDeleteHook), &cm)
var hook map[string]interface{}
err := yaml.Unmarshal([]byte(fakePostDeleteHook), &hook)
if err != nil {
panic(err)
}
return cm
return hook
}
func newFakeRoleBinding() map[string]interface{} {
var roleBinding map[string]interface{}
err := yaml.Unmarshal([]byte(fakeRoleBinding), &roleBinding)
if err != nil {
panic(err)
}
return roleBinding
}
func newFakeRole() map[string]interface{} {
var role map[string]interface{}
err := yaml.Unmarshal([]byte(fakeRole), &role)
if err != nil {
panic(err)
}
return role
}
func newFakeServiceAccount() map[string]interface{} {
var serviceAccount map[string]interface{}
err := yaml.Unmarshal([]byte(fakeServiceAccount), &serviceAccount)
if err != nil {
panic(err)
}
return serviceAccount
}
func TestAutoSync(t *testing.T) {
@@ -721,7 +819,7 @@ func TestFinalizeAppDeletion(t *testing.T) {
// Ensure any stray resources irregularly labeled with instance label of app are not deleted upon deleting,
// when app project restriction is in place
t.Run("ProjectRestrictionEnforced", func(*testing.T) {
t.Run("ProjectRestrictionEnforced", func(t *testing.T) {
restrictedProj := v1alpha1.AppProject{
ObjectMeta: metav1.ObjectMeta{
Name: "restricted",
@@ -882,7 +980,13 @@ func TestFinalizeAppDeletion(t *testing.T) {
app.SetPostDeleteFinalizer()
app.Spec.Destination.Namespace = test.FakeArgoCDNamespace
liveHook := &unstructured.Unstructured{Object: newFakePostDeleteHook()}
require.NoError(t, unstructured.SetNestedField(liveHook.Object, "Succeeded", "status", "phase"))
conditions := []interface{}{
map[string]interface{}{
"type": "Complete",
"status": "True",
},
}
require.NoError(t, unstructured.SetNestedField(liveHook.Object, conditions, "status", "conditions"))
ctrl := newFakeController(&fakeData{
manifestResponses: []*apiclient.ManifestResponse{{
Manifests: []string{fakePostDeleteHook},
@@ -916,15 +1020,27 @@ func TestFinalizeAppDeletion(t *testing.T) {
app := newFakeApp()
app.SetPostDeleteFinalizer("cleanup")
app.Spec.Destination.Namespace = test.FakeArgoCDNamespace
liveRoleBinding := &unstructured.Unstructured{Object: newFakeRoleBinding()}
liveRole := &unstructured.Unstructured{Object: newFakeRole()}
liveServiceAccount := &unstructured.Unstructured{Object: newFakeServiceAccount()}
liveHook := &unstructured.Unstructured{Object: newFakePostDeleteHook()}
require.NoError(t, unstructured.SetNestedField(liveHook.Object, "Succeeded", "status", "phase"))
conditions := []interface{}{
map[string]interface{}{
"type": "Complete",
"status": "True",
},
}
require.NoError(t, unstructured.SetNestedField(liveHook.Object, conditions, "status", "conditions"))
ctrl := newFakeController(&fakeData{
manifestResponses: []*apiclient.ManifestResponse{{
Manifests: []string{fakePostDeleteHook},
Manifests: []string{fakeRoleBinding, fakeRole, fakeServiceAccount, fakePostDeleteHook},
}},
apps: []runtime.Object{app, &defaultProj},
managedLiveObjs: map[kube.ResourceKey]*unstructured.Unstructured{
kube.GetResourceKey(liveHook): liveHook,
kube.GetResourceKey(liveRoleBinding): liveRoleBinding,
kube.GetResourceKey(liveRole): liveRole,
kube.GetResourceKey(liveServiceAccount): liveServiceAccount,
kube.GetResourceKey(liveHook): liveHook,
},
}, nil)
@@ -943,9 +1059,14 @@ func TestFinalizeAppDeletion(t *testing.T) {
return []*v1alpha1.Cluster{}, nil
})
require.NoError(t, err)
// post-delete hook is deleted
require.Len(t, ctrl.kubectl.(*MockKubectl).DeletedResources, 1)
require.Equal(t, "post-delete-hook", ctrl.kubectl.(*MockKubectl).DeletedResources[0].Name)
// post-delete hooks are deleted
require.Len(t, ctrl.kubectl.(*MockKubectl).DeletedResources, 4)
deletedResources := []string{}
for _, res := range ctrl.kubectl.(*MockKubectl).DeletedResources {
deletedResources = append(deletedResources, res.Name)
}
expectedNames := []string{"hook-rolebinding", "hook-role", "hook-serviceaccount", "post-delete-hook"}
require.ElementsMatch(t, expectedNames, deletedResources, "Deleted resources should match expected names")
// finalizer is not removed
assert.False(t, patched)
})
@@ -1645,7 +1766,7 @@ func TestProcessRequestedAppOperation_FailedHasRetries(t *testing.T) {
message, _, _ := unstructured.NestedString(receivedPatch, "status", "operationState", "message")
assert.Contains(t, message, "Retrying attempt #1")
retryCount, _, _ := unstructured.NestedFloat64(receivedPatch, "status", "operationState", "retryCount")
assert.InEpsilon(t, float64(1), retryCount, 0.0001)
assert.Equal(t, float64(1), retryCount)
}
func TestProcessRequestedAppOperation_RunningPreviouslyFailed(t *testing.T) {

View File

@@ -98,6 +98,18 @@ func (ctrl *ApplicationController) executePostDeleteHooks(app *v1alpha1.Applicat
if err != nil {
return false, err
}
if hookHealth == nil {
logCtx.WithFields(log.Fields{
"group": obj.GroupVersionKind().Group,
"version": obj.GroupVersionKind().Version,
"kind": obj.GetKind(),
"name": obj.GetName(),
"namespace": obj.GetNamespace(),
}).Info("No health check defined for resource, considering it healthy")
hookHealth = &health.HealthStatus{
Status: health.HealthStatusHealthy,
}
}
if hookHealth.Status == health.HealthStatusProgressing {
progressingHooksCnt++
}
@@ -128,6 +140,11 @@ func (ctrl *ApplicationController) cleanupPostDeleteHooks(liveObjs map[kube.Reso
if err != nil {
return false, err
}
if hookHealth == nil {
hookHealth = &health.HealthStatus{
Status: health.HealthStatusHealthy,
}
}
if health.IsWorse(aggregatedHealth, hookHealth.Status) {
aggregatedHealth = hookHealth.Status
}

View File

@@ -343,15 +343,3 @@ metadata:
data:
applicationsetcontroller.log.level: debug
```
## Previewing changes
To preview changes that the ApplicationSet controller would make to Applications, you can create the AppSet in dry-run
mode. This works whether the AppSet already exists or not.
```shell
argocd appset create --dry-run ./appset.yaml -o json | jq -r '.status.resources[].name'
```
The dry-run will populate the returned ApplicationSet's status with the Applications which would be managed with the
given config. You can compare to the existing Applications to see what would change.

View File

@@ -617,7 +617,7 @@ Edit the `--insecure` flag in the `argocd-server` command of the argocd-server d
### Creating a service
Now you need an externally accessible service. This is practically the same as the internal service Argo CD has, but with Google Cloud annotations. Note that this service is annotated to use a [Network Endpoint Group](https://cloud.google.com/load-balancing/docs/negs) (NEG) to allow your load balancer to send traffic directly to your pods without using kube-proxy, so remove the `neg` annotation if that's not what you want.
Now you need an externally accessible service. This is practically the same as the internal service Argo CD has, but with Google Cloud annotations. Note that this service is annotated to use a [Network Endpoint Group](https://cloud.google.com/load-balancing/docs/negs) (NEG) to allow your load balancer to send traffic directly to your pods without using kube-proxy, so remove the `neg` annotation it that's not what you want.
The service:

View File

@@ -29,10 +29,6 @@ argocd-server [flags]
--api-content-types string Semicolon separated list of allowed content types for non GET api requests. Any content type is allowed if empty. (default "application/json")
--app-state-cache-expiration duration Cache expiration for app state (default 1h0m0s)
--application-namespaces strings List of additional namespaces where application resources can be managed in
--appset-allowed-scm-providers strings The list of allowed custom SCM provider API URLs. This restriction does not apply to SCM or PR generators which do not accept a custom API URL. (Default: Empty = all)
--appset-enable-new-git-file-globbing Enable new globbing in Git files generator.
--appset-enable-scm-providers Enable retrieving information from SCM providers, used by the SCM and PR generators (Default: true) (default true)
--appset-scm-root-ca-path string Provide Root CA Path for self-signed TLS Certificates
--as string Username to impersonate for the operation
--as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups.
--as-uid string UID to impersonate for the operation

View File

@@ -1,2 +1,5 @@
This page is populated for released Argo CD versions. Use the version selector to view this table for a specific
version.
| Argo CD version | Kubernetes versions |
|-----------------|---------------------|
| 2.12 | |
| 2.11 | v1.29, v1.28, v1.27, v1.26, v1.25 |
| 2.10 | v1.28, v1.27, v1.26, v1.25 |

View File

@@ -13,18 +13,13 @@ argocd appset create [flags]
```
# Create ApplicationSets
argocd appset create <filename or URL> (<filename or URL>...)
# Dry-run AppSet creation to see what applications would be managed
argocd appset create --dry-run <filename or URL> -o json | jq -r '.status.resources[].name'
```
### Options
```
--dry-run Allows to evaluate the ApplicationSet template on the server to get a preview of the applications that would be created
-h, --help help for create
-o, --output string Output format. One of: json|yaml|wide (default "wide")
--upsert Allows to override ApplicationSet with the same name even if supplied ApplicationSet spec is different from existing spec
-h, --help help for create
--upsert Allows to override ApplicationSet with the same name even if supplied ApplicationSet spec is different from existing spec
```
### Options inherited from parent commands

View File

@@ -74,8 +74,7 @@ If you have a slash `/` in your pointer path, you need to replace it with the `~
spec:
ignoreDifferences:
- kind: Node
jsonPointers:
- /metadata/labels/node-role.kubernetes.io~1worker
jsonPointers: /metadata/labels/node-role.kubernetes.io~1worker
```
## System-Level Configuration

4
go.mod
View File

@@ -52,14 +52,14 @@ require (
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0
github.com/grpc-ecosystem/grpc-gateway v1.16.0
github.com/hashicorp/go-retryablehttp v0.7.4
github.com/hashicorp/go-retryablehttp v0.7.7
github.com/imdario/mergo v0.3.16
github.com/improbable-eng/grpc-web v0.15.0
github.com/itchyny/gojq v0.12.13
github.com/jeremywohl/flatten v1.0.1
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
github.com/ktrysmt/go-bitbucket v0.9.67
github.com/mattn/go-isatty v0.0.19
github.com/mattn/go-isatty v0.0.20
github.com/mattn/go-zglob v0.0.4
github.com/microsoft/azure-devops-go-api/azuredevops v1.0.0-b5
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1

16
go.sum
View File

@@ -892,6 +892,8 @@ github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870/go.mod h1:5tD+ne
github.com/fatih/camelcase v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8=
github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk=
github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
@@ -1242,14 +1244,14 @@ github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtng
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI=
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-retryablehttp v0.5.1/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
github.com/hashicorp/go-retryablehttp v0.7.4 h1:ZQgVdpTdAL7WpMIwLzCfbalOcSUdkDZnpUv3/+BxzFA=
github.com/hashicorp/go-retryablehttp v0.7.4/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8=
github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU=
github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk=
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
@@ -1383,13 +1385,15 @@ github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsI
github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=

View File

@@ -5,7 +5,7 @@ kind: Kustomization
images:
- name: quay.io/argoproj/argocd
newName: quay.io/argoproj/argocd
newTag: latest
newTag: v2.12.0-rc2
resources:
- ./application-controller
- ./dex

View File

@@ -17,356 +17,332 @@ spec:
spec:
serviceAccountName: argocd-server
containers:
- name: argocd-server
image: quay.io/argoproj/argocd:latest
imagePullPolicy: Always
args:
- /usr/local/bin/argocd-server
env:
- name: REDIS_PASSWORD
valueFrom:
secretKeyRef:
key: auth
name: argocd-redis
- name: ARGOCD_SERVER_INSECURE
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.insecure
optional: true
- name: ARGOCD_SERVER_BASEHREF
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.basehref
optional: true
- name: ARGOCD_SERVER_ROOTPATH
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.rootpath
optional: true
- name: ARGOCD_SERVER_LOGFORMAT
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.log.format
optional: true
- name: ARGOCD_SERVER_LOG_LEVEL
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.log.level
optional: true
- name: ARGOCD_SERVER_REPO_SERVER
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: repo.server
optional: true
- name: ARGOCD_SERVER_DEX_SERVER
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.dex.server
optional: true
- name: ARGOCD_SERVER_DISABLE_AUTH
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.disable.auth
optional: true
- name: ARGOCD_SERVER_ENABLE_GZIP
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.enable.gzip
optional: true
- name: ARGOCD_SERVER_REPO_SERVER_TIMEOUT_SECONDS
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.repo.server.timeout.seconds
optional: true
- name: ARGOCD_SERVER_X_FRAME_OPTIONS
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.x.frame.options
optional: true
- name: ARGOCD_SERVER_CONTENT_SECURITY_POLICY
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.content.security.policy
optional: true
- name: ARGOCD_SERVER_REPO_SERVER_PLAINTEXT
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.repo.server.plaintext
optional: true
- name: ARGOCD_SERVER_REPO_SERVER_STRICT_TLS
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.repo.server.strict.tls
optional: true
- name: ARGOCD_SERVER_DEX_SERVER_PLAINTEXT
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.dex.server.plaintext
optional: true
- name: ARGOCD_SERVER_DEX_SERVER_STRICT_TLS
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.dex.server.strict.tls
optional: true
- name: ARGOCD_TLS_MIN_VERSION
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.tls.minversion
optional: true
- name: ARGOCD_TLS_MAX_VERSION
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.tls.maxversion
optional: true
- name: ARGOCD_TLS_CIPHERS
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.tls.ciphers
optional: true
- name: ARGOCD_SERVER_CONNECTION_STATUS_CACHE_EXPIRATION
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.connection.status.cache.expiration
optional: true
- name: ARGOCD_SERVER_OIDC_CACHE_EXPIRATION
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.oidc.cache.expiration
optional: true
- name: ARGOCD_SERVER_LOGIN_ATTEMPTS_EXPIRATION
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.login.attempts.expiration
optional: true
- name: ARGOCD_SERVER_STATIC_ASSETS
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.staticassets
optional: true
- name: ARGOCD_APP_STATE_CACHE_EXPIRATION
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.app.state.cache.expiration
optional: true
- name: REDIS_SERVER
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: redis.server
optional: true
- name: REDIS_COMPRESSION
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: redis.compression
optional: true
- name: REDISDB
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: redis.db
optional: true
- name: ARGOCD_DEFAULT_CACHE_EXPIRATION
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.default.cache.expiration
optional: true
- name: ARGOCD_MAX_COOKIE_NUMBER
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.http.cookie.maxnumber
optional: true
- name: ARGOCD_SERVER_LISTEN_ADDRESS
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.listen.address
optional: true
- name: ARGOCD_SERVER_METRICS_LISTEN_ADDRESS
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.metrics.listen.address
optional: true
- name: ARGOCD_SERVER_OTLP_ADDRESS
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: otlp.address
optional: true
- name: ARGOCD_SERVER_OTLP_INSECURE
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: otlp.insecure
optional: true
- name: ARGOCD_SERVER_OTLP_HEADERS
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: otlp.headers
optional: true
- name: ARGOCD_APPLICATION_NAMESPACES
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: application.namespaces
optional: true
- name: ARGOCD_SERVER_ENABLE_PROXY_EXTENSION
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.enable.proxy.extension
optional: true
- name: ARGOCD_K8SCLIENT_RETRY_MAX
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.k8sclient.retry.max
optional: true
- name: ARGOCD_K8SCLIENT_RETRY_BASE_BACKOFF
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.k8sclient.retry.base.backoff
optional: true
- name: ARGOCD_API_CONTENT_TYPES
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.api.content.types
optional: true
- name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_NEW_GIT_FILE_GLOBBING
valueFrom:
configMapKeyRef:
key: applicationsetcontroller.enable.new.git.file.globbing
name: argocd-cmd-params-cm
optional: true
- name: ARGOCD_APPLICATIONSET_CONTROLLER_SCM_ROOT_CA_PATH
valueFrom:
configMapKeyRef:
key: applicationsetcontroller.scm.root.ca.path
name: argocd-cmd-params-cm
optional: true
- name: ARGOCD_APPLICATIONSET_CONTROLLER_ALLOWED_SCM_PROVIDERS
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: applicationsetcontroller.allowed.scm.providers
optional: true
- name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_SCM_PROVIDERS
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: applicationsetcontroller.enable.scm.providers
optional: true
volumeMounts:
- name: ssh-known-hosts
mountPath: /app/config/ssh
- name: tls-certs
mountPath: /app/config/tls
- name: argocd-repo-server-tls
mountPath: /app/config/server/tls
- name: argocd-dex-server-tls
mountPath: /app/config/dex/tls
- mountPath: /home/argocd
name: plugins-home
- mountPath: /tmp
name: tmp
ports:
- containerPort: 8080
- containerPort: 8083
livenessProbe:
httpGet:
path: /healthz?full=true
port: 8080
initialDelaySeconds: 3
periodSeconds: 30
timeoutSeconds: 5
readinessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 3
periodSeconds: 30
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
runAsNonRoot: true
capabilities:
drop:
- ALL
seccompProfile:
type: RuntimeDefault
volumes:
- emptyDir: {}
name: plugins-home
- emptyDir: {}
name: tmp
- name: argocd-server
image: quay.io/argoproj/argocd:latest
imagePullPolicy: Always
args:
- /usr/local/bin/argocd-server
env:
- name: REDIS_PASSWORD
valueFrom:
secretKeyRef:
key: auth
name: argocd-redis
- name: ARGOCD_SERVER_INSECURE
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.insecure
optional: true
- name: ARGOCD_SERVER_BASEHREF
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.basehref
optional: true
- name: ARGOCD_SERVER_ROOTPATH
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.rootpath
optional: true
- name: ARGOCD_SERVER_LOGFORMAT
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.log.format
optional: true
- name: ARGOCD_SERVER_LOG_LEVEL
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.log.level
optional: true
- name: ARGOCD_SERVER_REPO_SERVER
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: repo.server
optional: true
- name: ARGOCD_SERVER_DEX_SERVER
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.dex.server
optional: true
- name: ARGOCD_SERVER_DISABLE_AUTH
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.disable.auth
optional: true
- name: ARGOCD_SERVER_ENABLE_GZIP
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.enable.gzip
optional: true
- name: ARGOCD_SERVER_REPO_SERVER_TIMEOUT_SECONDS
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.repo.server.timeout.seconds
optional: true
- name: ARGOCD_SERVER_X_FRAME_OPTIONS
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.x.frame.options
optional: true
- name: ARGOCD_SERVER_CONTENT_SECURITY_POLICY
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.content.security.policy
optional: true
- name: ARGOCD_SERVER_REPO_SERVER_PLAINTEXT
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.repo.server.plaintext
optional: true
- name: ARGOCD_SERVER_REPO_SERVER_STRICT_TLS
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.repo.server.strict.tls
optional: true
- name: ARGOCD_SERVER_DEX_SERVER_PLAINTEXT
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.dex.server.plaintext
optional: true
- name: ARGOCD_SERVER_DEX_SERVER_STRICT_TLS
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.dex.server.strict.tls
optional: true
- name: ARGOCD_TLS_MIN_VERSION
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.tls.minversion
optional: true
- name: ARGOCD_TLS_MAX_VERSION
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.tls.maxversion
optional: true
- name: ARGOCD_TLS_CIPHERS
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.tls.ciphers
optional: true
- name: ARGOCD_SERVER_CONNECTION_STATUS_CACHE_EXPIRATION
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.connection.status.cache.expiration
optional: true
- name: ARGOCD_SERVER_OIDC_CACHE_EXPIRATION
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.oidc.cache.expiration
optional: true
- name: ARGOCD_SERVER_LOGIN_ATTEMPTS_EXPIRATION
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.login.attempts.expiration
optional: true
- name: ARGOCD_SERVER_STATIC_ASSETS
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.staticassets
optional: true
- name: ARGOCD_APP_STATE_CACHE_EXPIRATION
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.app.state.cache.expiration
optional: true
- name: REDIS_SERVER
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: redis.server
optional: true
- name: REDIS_COMPRESSION
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: redis.compression
optional: true
- name: REDISDB
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: redis.db
optional: true
- name: ARGOCD_DEFAULT_CACHE_EXPIRATION
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.default.cache.expiration
optional: true
- name: ARGOCD_MAX_COOKIE_NUMBER
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.http.cookie.maxnumber
optional: true
- name: ARGOCD_SERVER_LISTEN_ADDRESS
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.listen.address
optional: true
- name: ARGOCD_SERVER_METRICS_LISTEN_ADDRESS
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.metrics.listen.address
optional: true
- name: ARGOCD_SERVER_OTLP_ADDRESS
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: otlp.address
optional: true
- name: ARGOCD_SERVER_OTLP_INSECURE
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: otlp.insecure
optional: true
- name: ARGOCD_SERVER_OTLP_HEADERS
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: otlp.headers
optional: true
- name: ARGOCD_APPLICATION_NAMESPACES
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: application.namespaces
optional: true
- name: ARGOCD_SERVER_ENABLE_PROXY_EXTENSION
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.enable.proxy.extension
optional: true
- name: ARGOCD_K8SCLIENT_RETRY_MAX
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.k8sclient.retry.max
optional: true
- name: ARGOCD_K8SCLIENT_RETRY_BASE_BACKOFF
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.k8sclient.retry.base.backoff
optional: true
- name: ARGOCD_API_CONTENT_TYPES
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.api.content.types
optional: true
volumeMounts:
- name: ssh-known-hosts
configMap:
name: argocd-ssh-known-hosts-cm
mountPath: /app/config/ssh
- name: tls-certs
configMap:
name: argocd-tls-certs-cm
mountPath: /app/config/tls
- name: argocd-repo-server-tls
secret:
secretName: argocd-repo-server-tls
optional: true
items:
- key: tls.crt
path: tls.crt
- key: tls.key
path: tls.key
- key: ca.crt
path: ca.crt
mountPath: /app/config/server/tls
- name: argocd-dex-server-tls
secret:
secretName: argocd-dex-server-tls
optional: true
items:
- key: tls.crt
path: tls.crt
- key: ca.crt
path: ca.crt
mountPath: /app/config/dex/tls
- mountPath: /home/argocd
name: plugins-home
- mountPath: /tmp
name: tmp
ports:
- containerPort: 8080
- containerPort: 8083
livenessProbe:
httpGet:
path: /healthz?full=true
port: 8080
initialDelaySeconds: 3
periodSeconds: 30
timeoutSeconds: 5
readinessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 3
periodSeconds: 30
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
runAsNonRoot: true
capabilities:
drop:
- ALL
seccompProfile:
type: RuntimeDefault
volumes:
- emptyDir: {}
name: plugins-home
- emptyDir: {}
name: tmp
- name: ssh-known-hosts
configMap:
name: argocd-ssh-known-hosts-cm
- name: tls-certs
configMap:
name: argocd-tls-certs-cm
- name: argocd-repo-server-tls
secret:
secretName: argocd-repo-server-tls
optional: true
items:
- key: tls.crt
path: tls.crt
- key: tls.key
path: tls.key
- key: ca.crt
path: ca.crt
- name: argocd-dex-server-tls
secret:
secretName: argocd-dex-server-tls
optional: true
items:
- key: tls.crt
path: tls.crt
- key: ca.crt
path: ca.crt
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
app.kubernetes.io/name: argocd-server
topologyKey: kubernetes.io/hostname
- weight: 5
podAffinityTerm:
labelSelector:
matchLabels:
app.kubernetes.io/part-of: argocd
topologyKey: kubernetes.io/hostname
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
app.kubernetes.io/name: argocd-server
topologyKey: kubernetes.io/hostname
- weight: 5
podAffinityTerm:
labelSelector:
matchLabels:
app.kubernetes.io/part-of: argocd
topologyKey: kubernetes.io/hostname

View File

@@ -21268,7 +21268,7 @@ spec:
key: applicationsetcontroller.enable.scm.providers
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.12.0-rc2
imagePullPolicy: Always
name: argocd-applicationset-controller
ports:
@@ -21386,7 +21386,7 @@ spec:
- argocd
- admin
- redis-initial-password
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.12.0-rc2
imagePullPolicy: IfNotPresent
name: secret-init
securityContext:
@@ -21639,7 +21639,7 @@ spec:
value: /helm-working-dir
- name: HELM_DATA_HOME
value: /helm-working-dir
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.12.0-rc2
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
@@ -21691,7 +21691,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /var/run/argocd/argocd-cmp-server
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.12.0-rc2
name: copyutil
securityContext:
allowPrivilegeEscalation: false
@@ -21963,7 +21963,7 @@ spec:
key: controller.ignore.normalizer.jq.timeout
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.12.0-rc2
imagePullPolicy: Always
name: argocd-application-controller
ports:

View File

@@ -12,4 +12,4 @@ resources:
images:
- name: quay.io/argoproj/argocd
newName: quay.io/argoproj/argocd
newTag: latest
newTag: v2.12.0-rc2

View File

@@ -12,7 +12,7 @@ patches:
images:
- name: quay.io/argoproj/argocd
newName: quay.io/argoproj/argocd
newTag: latest
newTag: v2.12.0-rc2
resources:
- ../../base/application-controller
- ../../base/applicationset-controller

View File

@@ -22609,7 +22609,7 @@ spec:
key: applicationsetcontroller.enable.scm.providers
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.12.0-rc2
imagePullPolicy: Always
name: argocd-applicationset-controller
ports:
@@ -22732,7 +22732,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /shared/argocd-dex
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.12.0-rc2
imagePullPolicy: Always
name: copyutil
securityContext:
@@ -22814,7 +22814,7 @@ spec:
key: notificationscontroller.selfservice.enabled
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.12.0-rc2
imagePullPolicy: Always
livenessProbe:
tcpSocket:
@@ -22933,7 +22933,7 @@ spec:
- argocd
- admin
- redis-initial-password
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.12.0-rc2
imagePullPolicy: IfNotPresent
name: secret-init
securityContext:
@@ -23214,7 +23214,7 @@ spec:
value: /helm-working-dir
- name: HELM_DATA_HOME
value: /helm-working-dir
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.12.0-rc2
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
@@ -23266,7 +23266,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /var/run/argocd/argocd-cmp-server
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.12.0-rc2
name: copyutil
securityContext:
allowPrivilegeEscalation: false
@@ -23590,31 +23590,7 @@ spec:
key: server.api.content.types
name: argocd-cmd-params-cm
optional: true
- name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_NEW_GIT_FILE_GLOBBING
valueFrom:
configMapKeyRef:
key: applicationsetcontroller.enable.new.git.file.globbing
name: argocd-cmd-params-cm
optional: true
- name: ARGOCD_APPLICATIONSET_CONTROLLER_SCM_ROOT_CA_PATH
valueFrom:
configMapKeyRef:
key: applicationsetcontroller.scm.root.ca.path
name: argocd-cmd-params-cm
optional: true
- name: ARGOCD_APPLICATIONSET_CONTROLLER_ALLOWED_SCM_PROVIDERS
valueFrom:
configMapKeyRef:
key: applicationsetcontroller.allowed.scm.providers
name: argocd-cmd-params-cm
optional: true
- name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_SCM_PROVIDERS
valueFrom:
configMapKeyRef:
key: applicationsetcontroller.enable.scm.providers
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.12.0-rc2
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -23913,7 +23889,7 @@ spec:
key: controller.ignore.normalizer.jq.timeout
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.12.0-rc2
imagePullPolicy: Always
name: argocd-application-controller
ports:

View File

@@ -1686,7 +1686,7 @@ spec:
key: applicationsetcontroller.enable.scm.providers
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.12.0-rc2
imagePullPolicy: Always
name: argocd-applicationset-controller
ports:
@@ -1809,7 +1809,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /shared/argocd-dex
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.12.0-rc2
imagePullPolicy: Always
name: copyutil
securityContext:
@@ -1891,7 +1891,7 @@ spec:
key: notificationscontroller.selfservice.enabled
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.12.0-rc2
imagePullPolicy: Always
livenessProbe:
tcpSocket:
@@ -2010,7 +2010,7 @@ spec:
- argocd
- admin
- redis-initial-password
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.12.0-rc2
imagePullPolicy: IfNotPresent
name: secret-init
securityContext:
@@ -2291,7 +2291,7 @@ spec:
value: /helm-working-dir
- name: HELM_DATA_HOME
value: /helm-working-dir
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.12.0-rc2
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
@@ -2343,7 +2343,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /var/run/argocd/argocd-cmp-server
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.12.0-rc2
name: copyutil
securityContext:
allowPrivilegeEscalation: false
@@ -2667,31 +2667,7 @@ spec:
key: server.api.content.types
name: argocd-cmd-params-cm
optional: true
- name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_NEW_GIT_FILE_GLOBBING
valueFrom:
configMapKeyRef:
key: applicationsetcontroller.enable.new.git.file.globbing
name: argocd-cmd-params-cm
optional: true
- name: ARGOCD_APPLICATIONSET_CONTROLLER_SCM_ROOT_CA_PATH
valueFrom:
configMapKeyRef:
key: applicationsetcontroller.scm.root.ca.path
name: argocd-cmd-params-cm
optional: true
- name: ARGOCD_APPLICATIONSET_CONTROLLER_ALLOWED_SCM_PROVIDERS
valueFrom:
configMapKeyRef:
key: applicationsetcontroller.allowed.scm.providers
name: argocd-cmd-params-cm
optional: true
- name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_SCM_PROVIDERS
valueFrom:
configMapKeyRef:
key: applicationsetcontroller.enable.scm.providers
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.12.0-rc2
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -2990,7 +2966,7 @@ spec:
key: controller.ignore.normalizer.jq.timeout
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.12.0-rc2
imagePullPolicy: Always
name: argocd-application-controller
ports:

View File

@@ -21726,7 +21726,7 @@ spec:
key: applicationsetcontroller.enable.scm.providers
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.12.0-rc2
imagePullPolicy: Always
name: argocd-applicationset-controller
ports:
@@ -21849,7 +21849,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /shared/argocd-dex
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.12.0-rc2
imagePullPolicy: Always
name: copyutil
securityContext:
@@ -21931,7 +21931,7 @@ spec:
key: notificationscontroller.selfservice.enabled
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.12.0-rc2
imagePullPolicy: Always
livenessProbe:
tcpSocket:
@@ -22031,7 +22031,7 @@ spec:
- argocd
- admin
- redis-initial-password
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.12.0-rc2
imagePullPolicy: IfNotPresent
name: secret-init
securityContext:
@@ -22284,7 +22284,7 @@ spec:
value: /helm-working-dir
- name: HELM_DATA_HOME
value: /helm-working-dir
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.12.0-rc2
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
@@ -22336,7 +22336,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /var/run/argocd/argocd-cmp-server
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.12.0-rc2
name: copyutil
securityContext:
allowPrivilegeEscalation: false
@@ -22658,31 +22658,7 @@ spec:
key: server.api.content.types
name: argocd-cmd-params-cm
optional: true
- name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_NEW_GIT_FILE_GLOBBING
valueFrom:
configMapKeyRef:
key: applicationsetcontroller.enable.new.git.file.globbing
name: argocd-cmd-params-cm
optional: true
- name: ARGOCD_APPLICATIONSET_CONTROLLER_SCM_ROOT_CA_PATH
valueFrom:
configMapKeyRef:
key: applicationsetcontroller.scm.root.ca.path
name: argocd-cmd-params-cm
optional: true
- name: ARGOCD_APPLICATIONSET_CONTROLLER_ALLOWED_SCM_PROVIDERS
valueFrom:
configMapKeyRef:
key: applicationsetcontroller.allowed.scm.providers
name: argocd-cmd-params-cm
optional: true
- name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_SCM_PROVIDERS
valueFrom:
configMapKeyRef:
key: applicationsetcontroller.enable.scm.providers
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.12.0-rc2
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -22981,7 +22957,7 @@ spec:
key: controller.ignore.normalizer.jq.timeout
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.12.0-rc2
imagePullPolicy: Always
name: argocd-application-controller
ports:

View File

@@ -803,7 +803,7 @@ spec:
key: applicationsetcontroller.enable.scm.providers
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.12.0-rc2
imagePullPolicy: Always
name: argocd-applicationset-controller
ports:
@@ -926,7 +926,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /shared/argocd-dex
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.12.0-rc2
imagePullPolicy: Always
name: copyutil
securityContext:
@@ -1008,7 +1008,7 @@ spec:
key: notificationscontroller.selfservice.enabled
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.12.0-rc2
imagePullPolicy: Always
livenessProbe:
tcpSocket:
@@ -1108,7 +1108,7 @@ spec:
- argocd
- admin
- redis-initial-password
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.12.0-rc2
imagePullPolicy: IfNotPresent
name: secret-init
securityContext:
@@ -1361,7 +1361,7 @@ spec:
value: /helm-working-dir
- name: HELM_DATA_HOME
value: /helm-working-dir
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.12.0-rc2
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
@@ -1413,7 +1413,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /var/run/argocd/argocd-cmp-server
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.12.0-rc2
name: copyutil
securityContext:
allowPrivilegeEscalation: false
@@ -1735,31 +1735,7 @@ spec:
key: server.api.content.types
name: argocd-cmd-params-cm
optional: true
- name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_NEW_GIT_FILE_GLOBBING
valueFrom:
configMapKeyRef:
key: applicationsetcontroller.enable.new.git.file.globbing
name: argocd-cmd-params-cm
optional: true
- name: ARGOCD_APPLICATIONSET_CONTROLLER_SCM_ROOT_CA_PATH
valueFrom:
configMapKeyRef:
key: applicationsetcontroller.scm.root.ca.path
name: argocd-cmd-params-cm
optional: true
- name: ARGOCD_APPLICATIONSET_CONTROLLER_ALLOWED_SCM_PROVIDERS
valueFrom:
configMapKeyRef:
key: applicationsetcontroller.allowed.scm.providers
name: argocd-cmd-params-cm
optional: true
- name: ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_SCM_PROVIDERS
valueFrom:
configMapKeyRef:
key: applicationsetcontroller.enable.scm.providers
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.12.0-rc2
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -2058,7 +2034,7 @@ spec:
key: controller.ignore.normalizer.jq.timeout
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v2.12.0-rc2
imagePullPolicy: Always
name: argocd-application-controller
ports:

View File

@@ -214,7 +214,6 @@ func (m *ApplicationSetResponse) GetApplicationset() *v1alpha1.ApplicationSet {
type ApplicationSetCreateRequest struct {
Applicationset *v1alpha1.ApplicationSet `protobuf:"bytes,1,opt,name=applicationset,proto3" json:"applicationset,omitempty"`
Upsert bool `protobuf:"varint,2,opt,name=upsert,proto3" json:"upsert,omitempty"`
DryRun bool `protobuf:"varint,3,opt,name=dryRun,proto3" json:"dryRun,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@@ -267,13 +266,6 @@ func (m *ApplicationSetCreateRequest) GetUpsert() bool {
return false
}
func (m *ApplicationSetCreateRequest) GetDryRun() bool {
if m != nil {
return m.DryRun
}
return false
}
type ApplicationSetDeleteRequest struct {
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
// The application set namespace. Default empty is argocd control plane namespace
@@ -400,44 +392,43 @@ func init() {
}
var fileDescriptor_eacb9df0ce5738fa = []byte{
// 586 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x95, 0xcd, 0x8a, 0x13, 0x41,
0x10, 0xc7, 0xe9, 0xcd, 0x12, 0xb3, 0xad, 0x28, 0x34, 0xb8, 0x1b, 0x47, 0x89, 0x61, 0x0e, 0x6b,
0x5c, 0xdd, 0x1e, 0x12, 0x3d, 0xe9, 0xc9, 0x0f, 0x58, 0x84, 0x20, 0x3a, 0x2b, 0x0a, 0x7a, 0x90,
0xde, 0x49, 0x31, 0x3b, 0xee, 0x64, 0xa6, 0xed, 0xee, 0x19, 0x58, 0x16, 0x2f, 0x82, 0x4f, 0xe0,
0x1b, 0xe8, 0xc5, 0x07, 0xf0, 0xee, 0xc1, 0x8b, 0x47, 0xc1, 0x17, 0x90, 0xe8, 0x83, 0x48, 0xf7,
0x4c, 0x92, 0x9d, 0x26, 0x9b, 0x08, 0xc6, 0xdb, 0x54, 0x77, 0x4f, 0xd5, 0xaf, 0xaa, 0xfe, 0xd5,
0x8d, 0xb7, 0x24, 0x88, 0x1c, 0x84, 0xc7, 0x38, 0x8f, 0xa3, 0x80, 0xa9, 0x28, 0x4d, 0x24, 0x28,
0xcb, 0xa4, 0x5c, 0xa4, 0x2a, 0x25, 0x67, 0xab, 0xab, 0xce, 0xa5, 0x30, 0x4d, 0xc3, 0x18, 0x3c,
0xc6, 0x23, 0x8f, 0x25, 0x49, 0xaa, 0x8a, 0x9d, 0xe2, 0xb4, 0xd3, 0x0f, 0x23, 0xb5, 0x9f, 0xed,
0xd1, 0x20, 0x1d, 0x7a, 0x4c, 0x84, 0x29, 0x17, 0xe9, 0x2b, 0xf3, 0xb1, 0x1d, 0x0c, 0xbc, 0xbc,
0xe7, 0xf1, 0x83, 0x50, 0xff, 0x29, 0x8f, 0xc7, 0xf2, 0xf2, 0x2e, 0x8b, 0xf9, 0x3e, 0xeb, 0x7a,
0x21, 0x24, 0x20, 0x98, 0x82, 0x41, 0xe1, 0xcd, 0x7d, 0x8a, 0xd7, 0xef, 0x4c, 0xcf, 0xed, 0x82,
0xda, 0x01, 0xf5, 0x38, 0x03, 0x71, 0x48, 0x08, 0x5e, 0x4d, 0xd8, 0x10, 0x9a, 0xa8, 0x8d, 0x3a,
0x6b, 0xbe, 0xf9, 0x26, 0x1d, 0x7c, 0x8e, 0x71, 0x2e, 0x41, 0x3d, 0x64, 0x43, 0x90, 0x9c, 0x05,
0xd0, 0x5c, 0x31, 0xdb, 0xf6, 0xb2, 0x7b, 0x84, 0x37, 0xaa, 0x7e, 0xfb, 0x91, 0x2c, 0x1d, 0x3b,
0xb8, 0xa1, 0x99, 0x21, 0x50, 0xb2, 0x89, 0xda, 0xb5, 0xce, 0x9a, 0x3f, 0xb1, 0xf5, 0x9e, 0x84,
0x18, 0x02, 0x95, 0x8a, 0xd2, 0xf3, 0xc4, 0x9e, 0x15, 0xbc, 0x36, 0x3b, 0xf8, 0x27, 0x64, 0x67,
0xe5, 0x83, 0xe4, 0xba, 0xb8, 0xa4, 0x89, 0x4f, 0x95, 0xc1, 0xca, 0xc4, 0xc6, 0x26, 0x51, 0xd8,
0xea, 0x83, 0x01, 0x38, 0xdd, 0xeb, 0xd3, 0x69, 0xc1, 0xe9, 0xb8, 0xe0, 0xe6, 0xe3, 0x65, 0x30,
0xa0, 0x79, 0x8f, 0xf2, 0x83, 0x90, 0xea, 0x82, 0xd3, 0x63, 0xbf, 0xd3, 0x71, 0xc1, 0xa9, 0xc5,
0x61, 0xc5, 0x70, 0xbf, 0x22, 0x7c, 0xb1, 0x7a, 0xe4, 0x9e, 0x00, 0xa6, 0xc0, 0x87, 0xd7, 0x19,
0xc8, 0x59, 0x54, 0xe8, 0xff, 0x53, 0x91, 0x75, 0x5c, 0xcf, 0xb8, 0x04, 0x51, 0xd4, 0xa0, 0xe1,
0x97, 0x96, 0x5e, 0x1f, 0x88, 0x43, 0x3f, 0x4b, 0x4c, 0xe5, 0x1b, 0x7e, 0x69, 0xb9, 0x2f, 0xec,
0x24, 0xee, 0x43, 0x0c, 0xd3, 0x24, 0xfe, 0x4d, 0x4a, 0xcf, 0x6c, 0x29, 0x3d, 0x11, 0x00, 0x4b,
0xd0, 0x68, 0xef, 0x57, 0x1d, 0x9f, 0xaf, 0x7a, 0xde, 0x05, 0x91, 0x47, 0x01, 0x90, 0x8f, 0x08,
0xd7, 0x76, 0x40, 0x91, 0x4d, 0x6a, 0x0d, 0xec, 0xec, 0x59, 0x71, 0x96, 0xda, 0x0d, 0x77, 0xf3,
0xed, 0x8f, 0xdf, 0xef, 0x57, 0xda, 0xa4, 0x65, 0x6e, 0x80, 0xbc, 0x6b, 0xdd, 0x1a, 0xd2, 0x3b,
0xd2, 0x89, 0xbe, 0x21, 0x1f, 0x10, 0x5e, 0xd5, 0x63, 0x45, 0xae, 0xcc, 0xc7, 0x9c, 0x8c, 0x9e,
0xf3, 0x68, 0x99, 0x9c, 0xda, 0xad, 0x7b, 0xd9, 0xb0, 0x5e, 0x20, 0x1b, 0x27, 0xb0, 0x92, 0xcf,
0x08, 0xd7, 0x0b, 0x49, 0x93, 0x6b, 0xf3, 0x31, 0x2b, 0xc2, 0x5f, 0x72, 0x49, 0x3d, 0x83, 0x79,
0xd5, 0x3d, 0x09, 0xf3, 0x96, 0x3d, 0x01, 0xef, 0x10, 0xae, 0x17, 0x22, 0x5e, 0x84, 0x5d, 0x91,
0xba, 0xb3, 0x40, 0x31, 0xe3, 0x7b, 0x68, 0xdc, 0xe3, 0xad, 0x45, 0x3d, 0xfe, 0x82, 0xf0, 0x19,
0x1f, 0x64, 0x9a, 0x89, 0x00, 0xb4, 0xee, 0x17, 0xf5, 0x7a, 0x32, 0x1b, 0xcb, 0xed, 0xb5, 0x76,
0xeb, 0xde, 0x34, 0xcc, 0x94, 0x5c, 0x9f, 0xcf, 0xec, 0x89, 0x92, 0x77, 0x5b, 0x09, 0x80, 0xbb,
0x0f, 0xbe, 0x8d, 0x5a, 0xe8, 0xfb, 0xa8, 0x85, 0x7e, 0x8e, 0x5a, 0xe8, 0xf9, 0xed, 0xbf, 0x7b,
0xbd, 0x82, 0x38, 0x82, 0xc4, 0x7e, 0x2e, 0xf7, 0xea, 0xe6, 0xcd, 0xba, 0xf1, 0x27, 0x00, 0x00,
0xff, 0xff, 0xd5, 0xe2, 0xa9, 0xbf, 0x5d, 0x07, 0x00, 0x00,
// 573 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x95, 0x4f, 0x8b, 0x13, 0x3f,
0x18, 0xc7, 0xc9, 0x76, 0xe9, 0x6f, 0x37, 0x3f, 0x51, 0x08, 0xb8, 0x5b, 0x47, 0xa9, 0x65, 0x0e,
0x6b, 0x5d, 0xdd, 0x84, 0x56, 0x4f, 0x7a, 0xf2, 0x0f, 0x2c, 0x42, 0x11, 0x9d, 0x15, 0x05, 0x3d,
0x48, 0x76, 0xfa, 0x30, 0x3b, 0xee, 0x74, 0x12, 0x93, 0x74, 0x40, 0x16, 0x2f, 0x82, 0xaf, 0xc0,
0x77, 0xa0, 0x17, 0xc1, 0xab, 0x77, 0xaf, 0x1e, 0x05, 0xdf, 0x80, 0x54, 0x5f, 0x88, 0x4c, 0x66,
0xda, 0xee, 0x84, 0x6e, 0x2b, 0x58, 0x6f, 0x79, 0xf2, 0xe7, 0x79, 0x3e, 0x79, 0x9e, 0xef, 0x93,
0xe0, 0x6d, 0x0d, 0x2a, 0x03, 0xc5, 0xb8, 0x94, 0x49, 0x1c, 0x72, 0x13, 0x8b, 0x54, 0x83, 0x71,
0x4c, 0x2a, 0x95, 0x30, 0x82, 0x9c, 0xae, 0xce, 0x7a, 0x17, 0x22, 0x21, 0xa2, 0x04, 0x18, 0x97,
0x31, 0xe3, 0x69, 0x2a, 0x4c, 0xb1, 0x52, 0xec, 0xf6, 0x7a, 0x51, 0x6c, 0x0e, 0x86, 0xfb, 0x34,
0x14, 0x03, 0xc6, 0x55, 0x24, 0xa4, 0x12, 0x2f, 0xec, 0x60, 0x27, 0xec, 0xb3, 0xac, 0xcb, 0xe4,
0x61, 0x94, 0x9f, 0xd4, 0xc7, 0x63, 0xb1, 0xac, 0xc3, 0x13, 0x79, 0xc0, 0x3b, 0x2c, 0x82, 0x14,
0x14, 0x37, 0xd0, 0x2f, 0xbc, 0xf9, 0x8f, 0xf1, 0xc6, 0xad, 0xe9, 0xbe, 0x3d, 0x30, 0xbb, 0x60,
0x1e, 0x0e, 0x41, 0xbd, 0x22, 0x04, 0xaf, 0xa6, 0x7c, 0x00, 0x0d, 0xd4, 0x42, 0xed, 0xf5, 0xc0,
0x8e, 0x49, 0x1b, 0x9f, 0xe1, 0x52, 0x6a, 0x30, 0xf7, 0xf9, 0x00, 0xb4, 0xe4, 0x21, 0x34, 0x56,
0xec, 0xb2, 0x3b, 0xed, 0x1f, 0xe1, 0xcd, 0xaa, 0xdf, 0x5e, 0xac, 0x4b, 0xc7, 0x1e, 0x5e, 0xcb,
0x99, 0x21, 0x34, 0xba, 0x81, 0x5a, 0xb5, 0xf6, 0x7a, 0x30, 0xb1, 0xf3, 0x35, 0x0d, 0x09, 0x84,
0x46, 0xa8, 0xd2, 0xf3, 0xc4, 0x9e, 0x15, 0xbc, 0x36, 0x3b, 0xf8, 0x47, 0xe4, 0xde, 0x2a, 0x00,
0x2d, 0xf3, 0xe4, 0x92, 0x06, 0xfe, 0xaf, 0x0c, 0x56, 0x5e, 0x6c, 0x6c, 0x12, 0x83, 0x9d, 0x3a,
0x58, 0x80, 0xff, 0xbb, 0x3d, 0x3a, 0x4d, 0x38, 0x1d, 0x27, 0xdc, 0x0e, 0x9e, 0x87, 0x7d, 0x9a,
0x75, 0xa9, 0x3c, 0x8c, 0x68, 0x9e, 0x70, 0x7a, 0xec, 0x38, 0x1d, 0x27, 0x9c, 0x3a, 0x1c, 0x4e,
0x0c, 0xff, 0x13, 0xc2, 0xe7, 0xab, 0x5b, 0xee, 0x28, 0xe0, 0x06, 0x02, 0x78, 0x39, 0x04, 0x3d,
0x8b, 0x0a, 0xfd, 0x7b, 0x2a, 0xb2, 0x81, 0xeb, 0x43, 0xa9, 0x41, 0x15, 0x39, 0x58, 0x0b, 0x4a,
0xcb, 0x7f, 0xe6, 0xc2, 0xde, 0x85, 0x04, 0xa6, 0xb0, 0x7f, 0x27, 0x99, 0x27, 0xae, 0x64, 0x1e,
0x29, 0x80, 0x25, 0x68, 0xb1, 0xfb, 0xb3, 0x8e, 0xcf, 0x56, 0x3d, 0xef, 0x81, 0xca, 0xe2, 0x10,
0xc8, 0x07, 0x84, 0x6b, 0xbb, 0x60, 0xc8, 0x16, 0x75, 0x1a, 0x73, 0x76, 0x4f, 0x78, 0x4b, 0xcd,
0xba, 0xbf, 0xf5, 0xe6, 0xfb, 0xaf, 0x77, 0x2b, 0x2d, 0xd2, 0xb4, 0x9d, 0x9e, 0x75, 0x9c, 0xd7,
0x41, 0xb3, 0xa3, 0xfc, 0xa2, 0xaf, 0xc9, 0x7b, 0x84, 0x57, 0xf3, 0xf6, 0x21, 0x97, 0xe6, 0x63,
0x4e, 0x5a, 0xcc, 0x7b, 0xb0, 0x4c, 0xce, 0xdc, 0xad, 0x7f, 0xd1, 0xb2, 0x9e, 0x23, 0x9b, 0x27,
0xb0, 0x92, 0xcf, 0x08, 0xd7, 0x0b, 0xe9, 0x92, 0x2b, 0xf3, 0x31, 0x2b, 0x02, 0x5f, 0x72, 0x4a,
0x99, 0xc5, 0xbc, 0xec, 0x9f, 0x84, 0x79, 0xc3, 0x55, 0xfa, 0x5b, 0x84, 0xeb, 0x85, 0x88, 0x17,
0x61, 0x57, 0xa4, 0xee, 0x2d, 0x50, 0xcc, 0xf8, 0xbd, 0x19, 0xd7, 0x78, 0x7b, 0x51, 0x8d, 0xbf,
0x20, 0x7c, 0x2a, 0x00, 0x2d, 0x86, 0x2a, 0x84, 0x5c, 0xf7, 0x8b, 0x6a, 0x3d, 0xe9, 0x8d, 0xe5,
0xd6, 0x3a, 0x77, 0xeb, 0x5f, 0xb7, 0xcc, 0x94, 0x5c, 0x9d, 0xcf, 0xcc, 0x54, 0xc9, 0xbb, 0x63,
0x14, 0xc0, 0xed, 0x7b, 0x5f, 0x47, 0x4d, 0xf4, 0x6d, 0xd4, 0x44, 0x3f, 0x46, 0x4d, 0xf4, 0xf4,
0xe6, 0x9f, 0xfd, 0x52, 0x61, 0x12, 0x43, 0xea, 0x7e, 0x8b, 0xfb, 0x75, 0xfb, 0x37, 0x5d, 0xfb,
0x1d, 0x00, 0x00, 0xff, 0xff, 0xfa, 0x8f, 0x0f, 0xad, 0x45, 0x07, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.
@@ -835,16 +826,6 @@ func (m *ApplicationSetCreateRequest) MarshalToSizedBuffer(dAtA []byte) (int, er
i -= len(m.XXX_unrecognized)
copy(dAtA[i:], m.XXX_unrecognized)
}
if m.DryRun {
i--
if m.DryRun {
dAtA[i] = 1
} else {
dAtA[i] = 0
}
i--
dAtA[i] = 0x18
}
if m.Upsert {
i--
if m.Upsert {
@@ -1042,9 +1023,6 @@ func (m *ApplicationSetCreateRequest) Size() (n int) {
if m.Upsert {
n += 2
}
if m.DryRun {
n += 2
}
if m.XXX_unrecognized != nil {
n += len(m.XXX_unrecognized)
}
@@ -1563,26 +1541,6 @@ func (m *ApplicationSetCreateRequest) Unmarshal(dAtA []byte) error {
}
}
m.Upsert = bool(v != 0)
case 3:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field DryRun", wireType)
}
var v int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowApplicationset
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
v |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
m.DryRun = bool(v != 0)
default:
iNdEx = preIndex
skippy, err := skipApplicationset(dAtA[iNdEx:])

View File

@@ -613,7 +613,7 @@ func TestRevisionChartDetails(t *testing.T) {
fixtures := newFixtures()
t.Cleanup(fixtures.mockCache.StopRedisCallback)
details, err := fixtures.cache.GetRevisionChartDetails("test-repo", "test-revision", "v1.0.0")
require.ErrorIs(t, err, ErrCacheMiss)
require.ErrorAs(t, err, &ErrCacheMiss)
assert.Equal(t, &appv1.ChartDetails{}, details)
fixtures.mockCache.AssertCacheCalledTimes(t, &mocks.CacheCallCounts{ExternalGets: 1})
})
@@ -679,7 +679,7 @@ func TestGetGitDirectories(t *testing.T) {
fixtures := newFixtures()
t.Cleanup(fixtures.mockCache.StopRedisCallback)
directories, err := fixtures.cache.GetGitDirectories("test-repo", "test-revision")
require.ErrorIs(t, err, ErrCacheMiss)
require.ErrorAs(t, err, &ErrCacheMiss)
assert.Empty(t, directories)
fixtures.mockCache.AssertCacheCalledTimes(t, &mocks.CacheCallCounts{ExternalGets: 1})
})
@@ -733,7 +733,7 @@ func TestGetGitFiles(t *testing.T) {
fixtures := newFixtures()
t.Cleanup(fixtures.mockCache.StopRedisCallback)
directories, err := fixtures.cache.GetGitFiles("test-repo", "test-revision", "*.json")
require.ErrorIs(t, err, ErrCacheMiss)
require.ErrorAs(t, err, &ErrCacheMiss)
assert.Empty(t, directories)
fixtures.mockCache.AssertCacheCalledTimes(t, &mocks.CacheCallCounts{ExternalGets: 1})
})

View File

@@ -2769,7 +2769,10 @@ func (s *Service) UpdateRevisionForPaths(_ context.Context, request *apiclient.U
return nil, status.Errorf(codes.Internal, "unable to get changed files for repo %s with revision %s: %v", repo.Repo, revision, err)
}
changed := apppathutil.AppFilesHaveChanged(refreshPaths, files)
changed := false
if len(files) != 0 {
changed = apppathutil.AppFilesHaveChanged(refreshPaths, files)
}
if !changed {
logCtx.Debugf("no changes found for application %s in repo %s from revision %s to revision %s", request.AppName, repo.Repo, syncedRevision, revision)

View File

@@ -17,26 +17,18 @@ import (
apierr "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/cache"
"sigs.k8s.io/controller-runtime/pkg/client"
appsettemplate "github.com/argoproj/argo-cd/v2/applicationset/controllers/template"
"github.com/argoproj/argo-cd/v2/applicationset/generators"
"github.com/argoproj/argo-cd/v2/applicationset/services"
appsetstatus "github.com/argoproj/argo-cd/v2/applicationset/status"
appsetutils "github.com/argoproj/argo-cd/v2/applicationset/utils"
"github.com/argoproj/argo-cd/v2/pkg/apiclient/applicationset"
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
appclientset "github.com/argoproj/argo-cd/v2/pkg/client/clientset/versioned"
applisters "github.com/argoproj/argo-cd/v2/pkg/client/listers/application/v1alpha1"
repoapiclient "github.com/argoproj/argo-cd/v2/reposerver/apiclient"
"github.com/argoproj/argo-cd/v2/server/rbacpolicy"
"github.com/argoproj/argo-cd/v2/util/argo"
"github.com/argoproj/argo-cd/v2/util/collections"
"github.com/argoproj/argo-cd/v2/util/db"
"github.com/argoproj/argo-cd/v2/util/github_app"
"github.com/argoproj/argo-cd/v2/util/rbac"
"github.com/argoproj/argo-cd/v2/util/security"
"github.com/argoproj/argo-cd/v2/util/session"
@@ -44,36 +36,24 @@ import (
)
type Server struct {
ns string
db db.ArgoDB
enf *rbac.Enforcer
k8sClient kubernetes.Interface
dynamicClient dynamic.Interface
client client.Client
repoClientSet repoapiclient.Clientset
appclientset appclientset.Interface
appsetInformer cache.SharedIndexInformer
appsetLister applisters.ApplicationSetLister
projLister applisters.AppProjectNamespaceLister
auditLogger *argo.AuditLogger
settings *settings.SettingsManager
projectLock sync.KeyLock
enabledNamespaces []string
GitSubmoduleEnabled bool
EnableNewGitFileGlobbing bool
ScmRootCAPath string
AllowedScmProviders []string
EnableScmProviders bool
ns string
db db.ArgoDB
enf *rbac.Enforcer
appclientset appclientset.Interface
appsetInformer cache.SharedIndexInformer
appsetLister applisters.ApplicationSetLister
projLister applisters.AppProjectNamespaceLister
auditLogger *argo.AuditLogger
settings *settings.SettingsManager
projectLock sync.KeyLock
enabledNamespaces []string
}
// NewServer returns a new instance of the ApplicationSet service
func NewServer(
db db.ArgoDB,
kubeclientset kubernetes.Interface,
dynamicClientset dynamic.Interface,
kubeControllerClientset client.Client,
enf *rbac.Enforcer,
repoClientSet repoapiclient.Clientset,
appclientset appclientset.Interface,
appsetInformer cache.SharedIndexInformer,
appsetLister applisters.ApplicationSetLister,
@@ -82,33 +62,19 @@ func NewServer(
namespace string,
projectLock sync.KeyLock,
enabledNamespaces []string,
gitSubmoduleEnabled bool,
enableNewGitFileGlobbing bool,
scmRootCAPath string,
allowedScmProviders []string,
enableScmProviders bool,
) applicationset.ApplicationSetServiceServer {
s := &Server{
ns: namespace,
db: db,
enf: enf,
dynamicClient: dynamicClientset,
client: kubeControllerClientset,
k8sClient: kubeclientset,
repoClientSet: repoClientSet,
appclientset: appclientset,
appsetInformer: appsetInformer,
appsetLister: appsetLister,
projLister: projLister,
settings: settings,
projectLock: projectLock,
auditLogger: argo.NewAuditLogger(namespace, kubeclientset, "argocd-server"),
enabledNamespaces: enabledNamespaces,
GitSubmoduleEnabled: gitSubmoduleEnabled,
EnableNewGitFileGlobbing: enableNewGitFileGlobbing,
ScmRootCAPath: scmRootCAPath,
AllowedScmProviders: allowedScmProviders,
EnableScmProviders: enableScmProviders,
ns: namespace,
db: db,
enf: enf,
appclientset: appclientset,
appsetInformer: appsetInformer,
appsetLister: appsetLister,
projLister: projLister,
settings: settings,
projectLock: projectLock,
auditLogger: argo.NewAuditLogger(namespace, kubeclientset, "argocd-server"),
enabledNamespaces: enabledNamespaces,
}
return s
}
@@ -200,23 +166,6 @@ func (s *Server) Create(ctx context.Context, q *applicationset.ApplicationSetCre
return nil, fmt.Errorf("error checking create permissions for ApplicationSets %s : %w", appset.Name, err)
}
if q.GetDryRun() {
apps, err := s.generateApplicationSetApps(ctx, *appset, namespace)
if err != nil {
return nil, fmt.Errorf("unable to generate Applications of ApplicationSet: %w", err)
}
statusMap := appsetstatus.GetResourceStatusMap(appset)
statusMap = appsetstatus.BuildResourceStatus(statusMap, apps)
statuses := []v1alpha1.ResourceStatus{}
for _, status := range statusMap {
statuses = append(statuses, status)
}
appset.Status.Resources = statuses
return appset, nil
}
s.projectLock.RLock(projectName)
defer s.projectLock.RUnlock(projectName)
@@ -260,30 +209,6 @@ func (s *Server) Create(ctx context.Context, q *applicationset.ApplicationSetCre
return updated, nil
}
func (s *Server) generateApplicationSetApps(ctx context.Context, appset v1alpha1.ApplicationSet, namespace string) ([]v1alpha1.Application, error) {
logCtx := log.WithField("applicationset", appset.Name)
argoCDDB := s.db
scmConfig := generators.NewSCMConfig(s.ScmRootCAPath, s.AllowedScmProviders, s.EnableScmProviders, github_app.NewAuthCredentials(argoCDDB.(db.RepoCredsDB)))
getRepository := func(ctx context.Context, url, project string) (*v1alpha1.Repository, error) {
return s.db.GetRepository(ctx, url, project)
}
argoCDService, err := services.NewArgoCDService(getRepository, s.GitSubmoduleEnabled, s.repoClientSet, s.EnableNewGitFileGlobbing)
if err != nil {
return nil, fmt.Errorf("error creating ArgoCDService: %w", err)
}
appSetGenerators := generators.GetGenerators(ctx, s.client, s.k8sClient, namespace, argoCDService, s.dynamicClient, scmConfig)
apps, _, err := appsettemplate.GenerateApplications(logCtx, appset, appSetGenerators, &appsetutils.Render{}, s.client)
if err != nil {
return nil, fmt.Errorf("error generating applications: %w", err)
}
return apps, nil
}
func (s *Server) updateAppSet(appset *v1alpha1.ApplicationSet, newAppset *v1alpha1.ApplicationSet, ctx context.Context, merge bool) (*v1alpha1.ApplicationSet, error) {
if appset != nil && appset.Spec.Template.Spec.Project != newAppset.Spec.Template.Spec.Project {
// When changing projects, caller must have applicationset create and update privileges in new project

View File

@@ -37,7 +37,6 @@ message ApplicationSetResponse {
message ApplicationSetCreateRequest {
github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.ApplicationSet applicationset = 1;
bool upsert = 2;
bool dryRun = 3;
}
@@ -55,6 +54,7 @@ message ApplicationSetTreeQuery {
// ApplicationSetService
service ApplicationSetService {
// Get returns an applicationset by name
rpc Get (ApplicationSetGetQuery) returns (github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.ApplicationSet) {
option (google.api.http).get = "/api/v1/applicationsets/{name}";

View File

@@ -2,7 +2,6 @@ package applicationset
import (
"context"
"sort"
"testing"
"github.com/argoproj/gitops-engine/pkg/health"
@@ -10,7 +9,6 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
v1 "k8s.io/api/core/v1"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/kubernetes/fake"
@@ -145,10 +143,7 @@ func newTestAppSetServerWithEnforcerConfigure(f func(*rbac.Enforcer), namespace
server := NewServer(
db,
kubeclientset,
nil,
nil,
enforcer,
nil,
fakeAppsClientset,
appInformer,
factory.Argoproj().V1alpha1().ApplicationSets().Lister(),
@@ -157,11 +152,6 @@ func newTestAppSetServerWithEnforcerConfigure(f func(*rbac.Enforcer), namespace
testNamespace,
sync.NewKeyLock(),
[]string{testNamespace, "external-namespace"},
true,
true,
"",
[]string{},
true,
)
return server.(*Server)
}
@@ -368,60 +358,6 @@ func TestCreateAppSetWrongNamespace(t *testing.T) {
assert.Equal(t, "namespace 'NOT-ALLOWED' is not permitted", err.Error())
}
func TestCreateAppSetDryRun(t *testing.T) {
testAppSet := newTestAppSet()
appServer := newTestAppSetServer()
testAppSet.Spec.Template.Name = "{{name}}"
testAppSet.Spec.Generators = []appsv1.ApplicationSetGenerator{
{
List: &appsv1.ListGenerator{
Elements: []apiextensionsv1.JSON{{Raw: []byte(`{"name": "a"}`)}, {Raw: []byte(`{"name": "b"}`)}},
},
},
}
createReq := applicationset.ApplicationSetCreateRequest{
Applicationset: testAppSet,
DryRun: true,
}
result, err := appServer.Create(context.Background(), &createReq)
require.NoError(t, err)
assert.Len(t, result.Status.Resources, 2)
// Sort resulting application by name
sort.Slice(result.Status.Resources, func(i, j int) bool {
return result.Status.Resources[i].Name < result.Status.Resources[j].Name
})
assert.Equal(t, "a", result.Status.Resources[0].Name)
assert.Equal(t, testAppSet.Namespace, result.Status.Resources[0].Namespace)
assert.Equal(t, "b", result.Status.Resources[1].Name)
assert.Equal(t, testAppSet.Namespace, result.Status.Resources[1].Namespace)
}
func TestCreateAppSetDryRunWithDuplicate(t *testing.T) {
testAppSet := newTestAppSet()
appServer := newTestAppSetServer()
testAppSet.Spec.Template.Name = "{{name}}"
testAppSet.Spec.Generators = []appsv1.ApplicationSetGenerator{
{
List: &appsv1.ListGenerator{
Elements: []apiextensionsv1.JSON{{Raw: []byte(`{"name": "a"}`)}, {Raw: []byte(`{"name": "a"}`)}},
},
},
}
createReq := applicationset.ApplicationSetCreateRequest{
Applicationset: testAppSet,
DryRun: true,
}
result, err := appServer.Create(context.Background(), &createReq)
require.NoError(t, err)
assert.Len(t, result.Status.Resources, 1)
assert.Equal(t, "a", result.Status.Resources[0].Name)
assert.Equal(t, testAppSet.Namespace, result.Status.Resources[0].Namespace)
}
func TestGetAppSet(t *testing.T) {
appSet1 := newTestAppSet(func(appset *appsv1.ApplicationSet) {
appset.Name = "AppSet1"

View File

@@ -54,10 +54,8 @@ import (
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/cache"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/argoproj/argo-cd/v2/common"
"github.com/argoproj/argo-cd/v2/pkg/apiclient"
@@ -169,7 +167,6 @@ func init() {
// ArgoCDServer is the API server for Argo CD
type ArgoCDServer struct {
ArgoCDServerOpts
ApplicationSetOpts
ssoClientApp *oidc.ClientApp
settings *settings_util.ArgoCDSettings
@@ -201,41 +198,31 @@ type ArgoCDServer struct {
}
type ArgoCDServerOpts struct {
DisableAuth bool
ContentTypes []string
EnableGZip bool
Insecure bool
StaticAssetsDir string
ListenPort int
ListenHost string
MetricsPort int
MetricsHost string
Namespace string
DexServerAddr string
DexTLSConfig *dexutil.DexTLSConfig
BaseHRef string
RootPath string
DynamicClientset dynamic.Interface
KubeControllerClientset client.Client
KubeClientset kubernetes.Interface
AppClientset appclientset.Interface
RepoClientset repoapiclient.Clientset
Cache *servercache.Cache
RepoServerCache *repocache.Cache
RedisClient *redis.Client
TLSConfigCustomizer tlsutil.ConfigCustomizer
XFrameOptions string
ContentSecurityPolicy string
ApplicationNamespaces []string
EnableProxyExtension bool
}
type ApplicationSetOpts struct {
GitSubmoduleEnabled bool
EnableNewGitFileGlobbing bool
ScmRootCAPath string
AllowedScmProviders []string
EnableScmProviders bool
DisableAuth bool
ContentTypes []string
EnableGZip bool
Insecure bool
StaticAssetsDir string
ListenPort int
ListenHost string
MetricsPort int
MetricsHost string
Namespace string
DexServerAddr string
DexTLSConfig *dexutil.DexTLSConfig
BaseHRef string
RootPath string
KubeClientset kubernetes.Interface
AppClientset appclientset.Interface
RepoClientset repoapiclient.Clientset
Cache *servercache.Cache
RepoServerCache *repocache.Cache
RedisClient *redis.Client
TLSConfigCustomizer tlsutil.ConfigCustomizer
XFrameOptions string
ContentSecurityPolicy string
ApplicationNamespaces []string
EnableProxyExtension bool
}
// HTTPMetricsRegistry exposes operations to update http metrics in the Argo CD
@@ -272,7 +259,7 @@ func initializeDefaultProject(opts ArgoCDServerOpts) error {
}
// NewServer returns a new instance of the Argo CD API server
func NewServer(ctx context.Context, opts ArgoCDServerOpts, appsetOpts ApplicationSetOpts) *ArgoCDServer {
func NewServer(ctx context.Context, opts ArgoCDServerOpts) *ArgoCDServer {
settingsMgr := settings_util.NewSettingsManager(ctx, opts.KubeClientset, opts.Namespace)
settings, err := settingsMgr.InitializeSettings(opts.Insecure)
errorsutil.CheckError(err)
@@ -328,27 +315,26 @@ func NewServer(ctx context.Context, opts ArgoCDServerOpts, appsetOpts Applicatio
em := extension.NewManager(logger, sg, ag, pg, enf)
a := &ArgoCDServer{
ArgoCDServerOpts: opts,
ApplicationSetOpts: appsetOpts,
log: logger,
settings: settings,
sessionMgr: sessionMgr,
settingsMgr: settingsMgr,
enf: enf,
projInformer: projInformer,
projLister: projLister,
appInformer: appInformer,
appLister: appLister,
appsetInformer: appsetInformer,
appsetLister: appsetLister,
policyEnforcer: policyEnf,
userStateStorage: userStateStorage,
staticAssets: http.FS(staticFS),
db: dbInstance,
apiFactory: apiFactory,
secretInformer: secretInformer,
configMapInformer: configMapInformer,
extensionManager: em,
ArgoCDServerOpts: opts,
log: logger,
settings: settings,
sessionMgr: sessionMgr,
settingsMgr: settingsMgr,
enf: enf,
projInformer: projInformer,
projLister: projLister,
appInformer: appInformer,
appLister: appLister,
appsetInformer: appsetInformer,
appsetLister: appsetLister,
policyEnforcer: policyEnf,
userStateStorage: userStateStorage,
staticAssets: http.FS(staticFS),
db: dbInstance,
apiFactory: apiFactory,
secretInformer: secretInformer,
configMapInformer: configMapInformer,
extensionManager: em,
}
err = a.logInClusterWarnings()
@@ -882,10 +868,7 @@ func newArgoCDServiceSet(a *ArgoCDServer) *ArgoCDServiceSet {
applicationSetService := applicationset.NewServer(
a.db,
a.KubeClientset,
a.DynamicClientset,
a.KubeControllerClientset,
a.enf,
a.RepoClientset,
a.AppClientset,
a.appsetInformer,
a.appsetLister,
@@ -893,13 +876,7 @@ func newArgoCDServiceSet(a *ArgoCDServer) *ArgoCDServiceSet {
a.settingsMgr,
a.Namespace,
projectLock,
a.ApplicationNamespaces,
a.GitSubmoduleEnabled,
a.EnableNewGitFileGlobbing,
a.ScmRootCAPath,
a.AllowedScmProviders,
a.EnableScmProviders,
)
a.ApplicationNamespaces)
projectService := project.NewServer(a.Namespace, a.KubeClientset, a.AppClientset, a.enf, projectLock, a.sessionMgr, a.policyEnforcer, a.projInformer, a.settingsMgr, a.db)
appsInAnyNamespaceEnabled := len(a.ArgoCDServerOpts.ApplicationNamespaces) > 0

View File

@@ -19,13 +19,9 @@ import (
"github.com/stretchr/testify/require"
"google.golang.org/grpc/metadata"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/kubernetes/fake"
"sigs.k8s.io/yaml"
dynfake "k8s.io/client-go/dynamic/fake"
clientfake "sigs.k8s.io/controller-runtime/pkg/client/fake"
"github.com/argoproj/argo-cd/v2/common"
"github.com/argoproj/argo-cd/v2/pkg/apiclient"
"github.com/argoproj/argo-cd/v2/pkg/apiclient/session"
@@ -56,12 +52,10 @@ func fakeServer(t *testing.T) (*FakeArgoCDServer, func()) {
kubeclientset := fake.NewSimpleClientset(cm, secret)
appClientSet := apps.NewSimpleClientset()
redis, closer := test.NewInMemoryRedis()
port, err := test.GetFreePort()
mockRepoClient := &mocks.Clientset{RepoServerServiceClient: &mocks.RepoServerServiceClient{}}
tmpAssetsDir := t.TempDir()
dynamicClient := dynfake.NewSimpleDynamicClient(runtime.NewScheme())
fakeClient := clientfake.NewClientBuilder().Build()
port, err := test.GetFreePort()
if err != nil {
panic(err)
}
@@ -84,13 +78,11 @@ func fakeServer(t *testing.T) (*FakeArgoCDServer, func()) {
1*time.Minute,
1*time.Minute,
),
RedisClient: redis,
RepoClientset: mockRepoClient,
StaticAssetsDir: tmpAssetsDir,
DynamicClientset: dynamicClient,
KubeControllerClientset: fakeClient,
RedisClient: redis,
RepoClientset: mockRepoClient,
StaticAssetsDir: tmpAssetsDir,
}
srv := NewServer(context.Background(), argoCDOpts, ApplicationSetOpts{})
srv := NewServer(context.Background(), argoCDOpts)
fakeSrv := &FakeArgoCDServer{srv, tmpAssetsDir}
return fakeSrv, closer
}
@@ -126,7 +118,7 @@ func TestEnforceProjectToken(t *testing.T) {
mockRepoClient := &mocks.Clientset{RepoServerServiceClient: &mocks.RepoServerServiceClient{}}
t.Run("TestEnforceProjectTokenSuccessful", func(t *testing.T) {
s := NewServer(context.Background(), ArgoCDServerOpts{Namespace: test.FakeArgoCDNamespace, KubeClientset: kubeclientset, AppClientset: apps.NewSimpleClientset(&existingProj), RepoClientset: mockRepoClient}, ApplicationSetOpts{})
s := NewServer(context.Background(), ArgoCDServerOpts{Namespace: test.FakeArgoCDNamespace, KubeClientset: kubeclientset, AppClientset: apps.NewSimpleClientset(&existingProj), RepoClientset: mockRepoClient})
cancel := test.StartInformer(s.projInformer)
defer cancel()
claims := jwt.MapClaims{"sub": defaultSub, "iat": defaultIssuedAt}
@@ -135,21 +127,21 @@ func TestEnforceProjectToken(t *testing.T) {
})
t.Run("TestEnforceProjectTokenWithDiffCreateAtFailure", func(t *testing.T) {
s := NewServer(context.Background(), ArgoCDServerOpts{Namespace: test.FakeArgoCDNamespace, KubeClientset: kubeclientset, AppClientset: apps.NewSimpleClientset(&existingProj), RepoClientset: mockRepoClient}, ApplicationSetOpts{})
s := NewServer(context.Background(), ArgoCDServerOpts{Namespace: test.FakeArgoCDNamespace, KubeClientset: kubeclientset, AppClientset: apps.NewSimpleClientset(&existingProj), RepoClientset: mockRepoClient})
diffCreateAt := defaultIssuedAt + 1
claims := jwt.MapClaims{"sub": defaultSub, "iat": diffCreateAt}
assert.False(t, s.enf.Enforce(claims, "applications", "get", defaultTestObject))
})
t.Run("TestEnforceProjectTokenIncorrectSubFormatFailure", func(t *testing.T) {
s := NewServer(context.Background(), ArgoCDServerOpts{Namespace: test.FakeArgoCDNamespace, KubeClientset: kubeclientset, AppClientset: apps.NewSimpleClientset(&existingProj), RepoClientset: mockRepoClient}, ApplicationSetOpts{})
s := NewServer(context.Background(), ArgoCDServerOpts{Namespace: test.FakeArgoCDNamespace, KubeClientset: kubeclientset, AppClientset: apps.NewSimpleClientset(&existingProj), RepoClientset: mockRepoClient})
invalidSub := "proj:test"
claims := jwt.MapClaims{"sub": invalidSub, "iat": defaultIssuedAt}
assert.False(t, s.enf.Enforce(claims, "applications", "get", defaultTestObject))
})
t.Run("TestEnforceProjectTokenNoTokenFailure", func(t *testing.T) {
s := NewServer(context.Background(), ArgoCDServerOpts{Namespace: test.FakeArgoCDNamespace, KubeClientset: kubeclientset, AppClientset: apps.NewSimpleClientset(&existingProj), RepoClientset: mockRepoClient}, ApplicationSetOpts{})
s := NewServer(context.Background(), ArgoCDServerOpts{Namespace: test.FakeArgoCDNamespace, KubeClientset: kubeclientset, AppClientset: apps.NewSimpleClientset(&existingProj), RepoClientset: mockRepoClient})
nonExistentToken := "fake-token"
invalidSub := fmt.Sprintf(subFormat, projectName, nonExistentToken)
claims := jwt.MapClaims{"sub": invalidSub, "iat": defaultIssuedAt}
@@ -159,7 +151,7 @@ func TestEnforceProjectToken(t *testing.T) {
t.Run("TestEnforceProjectTokenNotJWTTokenFailure", func(t *testing.T) {
proj := existingProj.DeepCopy()
proj.Spec.Roles[0].JWTTokens = nil
s := NewServer(context.Background(), ArgoCDServerOpts{Namespace: test.FakeArgoCDNamespace, KubeClientset: kubeclientset, AppClientset: apps.NewSimpleClientset(proj), RepoClientset: mockRepoClient}, ApplicationSetOpts{})
s := NewServer(context.Background(), ArgoCDServerOpts{Namespace: test.FakeArgoCDNamespace, KubeClientset: kubeclientset, AppClientset: apps.NewSimpleClientset(proj), RepoClientset: mockRepoClient})
claims := jwt.MapClaims{"sub": defaultSub, "iat": defaultIssuedAt}
assert.False(t, s.enf.Enforce(claims, "applications", "get", defaultTestObject))
})
@@ -172,7 +164,7 @@ func TestEnforceProjectToken(t *testing.T) {
proj := existingProj.DeepCopy()
proj.Spec.Roles[0] = role
s := NewServer(context.Background(), ArgoCDServerOpts{Namespace: test.FakeArgoCDNamespace, KubeClientset: kubeclientset, AppClientset: apps.NewSimpleClientset(proj), RepoClientset: mockRepoClient}, ApplicationSetOpts{})
s := NewServer(context.Background(), ArgoCDServerOpts{Namespace: test.FakeArgoCDNamespace, KubeClientset: kubeclientset, AppClientset: apps.NewSimpleClientset(proj), RepoClientset: mockRepoClient})
cancel := test.StartInformer(s.projInformer)
defer cancel()
claims := jwt.MapClaims{"sub": defaultSub, "iat": defaultIssuedAt}
@@ -183,7 +175,7 @@ func TestEnforceProjectToken(t *testing.T) {
})
t.Run("TestEnforceProjectTokenWithIdSuccessful", func(t *testing.T) {
s := NewServer(context.Background(), ArgoCDServerOpts{Namespace: test.FakeArgoCDNamespace, KubeClientset: kubeclientset, AppClientset: apps.NewSimpleClientset(&existingProj), RepoClientset: mockRepoClient}, ApplicationSetOpts{})
s := NewServer(context.Background(), ArgoCDServerOpts{Namespace: test.FakeArgoCDNamespace, KubeClientset: kubeclientset, AppClientset: apps.NewSimpleClientset(&existingProj), RepoClientset: mockRepoClient})
cancel := test.StartInformer(s.projInformer)
defer cancel()
claims := jwt.MapClaims{"sub": defaultSub, "jti": defaultId}
@@ -192,7 +184,7 @@ func TestEnforceProjectToken(t *testing.T) {
})
t.Run("TestEnforceProjectTokenWithInvalidIdFailure", func(t *testing.T) {
s := NewServer(context.Background(), ArgoCDServerOpts{Namespace: test.FakeArgoCDNamespace, KubeClientset: kubeclientset, AppClientset: apps.NewSimpleClientset(&existingProj), RepoClientset: mockRepoClient}, ApplicationSetOpts{})
s := NewServer(context.Background(), ArgoCDServerOpts{Namespace: test.FakeArgoCDNamespace, KubeClientset: kubeclientset, AppClientset: apps.NewSimpleClientset(&existingProj), RepoClientset: mockRepoClient})
invalidId := "invalidId"
claims := jwt.MapClaims{"sub": defaultSub, "jti": defaultId}
res := s.enf.Enforce(claims, "applications", "get", invalidId)
@@ -276,7 +268,7 @@ func TestInitializingExistingDefaultProject(t *testing.T) {
RepoClientset: mockRepoClient,
}
argocd := NewServer(context.Background(), argoCDOpts, ApplicationSetOpts{})
argocd := NewServer(context.Background(), argoCDOpts)
assert.NotNil(t, argocd)
proj, err := appClientSet.ArgoprojV1alpha1().AppProjects(test.FakeArgoCDNamespace).Get(context.Background(), v1alpha1.DefaultAppProjectName, metav1.GetOptions{})
@@ -299,7 +291,7 @@ func TestInitializingNotExistingDefaultProject(t *testing.T) {
RepoClientset: mockRepoClient,
}
argocd := NewServer(context.Background(), argoCDOpts, ApplicationSetOpts{})
argocd := NewServer(context.Background(), argoCDOpts)
assert.NotNil(t, argocd)
proj, err := appClientSet.ArgoprojV1alpha1().AppProjects(test.FakeArgoCDNamespace).Get(context.Background(), v1alpha1.DefaultAppProjectName, metav1.GetOptions{})
@@ -341,7 +333,7 @@ func TestEnforceProjectGroups(t *testing.T) {
}
mockRepoClient := &mocks.Clientset{RepoServerServiceClient: &mocks.RepoServerServiceClient{}}
kubeclientset := fake.NewSimpleClientset(test.NewFakeConfigMap(), test.NewFakeSecret())
s := NewServer(context.Background(), ArgoCDServerOpts{Namespace: test.FakeArgoCDNamespace, KubeClientset: kubeclientset, AppClientset: apps.NewSimpleClientset(&existingProj), RepoClientset: mockRepoClient}, ApplicationSetOpts{})
s := NewServer(context.Background(), ArgoCDServerOpts{Namespace: test.FakeArgoCDNamespace, KubeClientset: kubeclientset, AppClientset: apps.NewSimpleClientset(&existingProj), RepoClientset: mockRepoClient})
cancel := test.StartInformer(s.projInformer)
defer cancel()
claims := jwt.MapClaims{
@@ -403,7 +395,7 @@ func TestRevokedToken(t *testing.T) {
},
}
s := NewServer(context.Background(), ArgoCDServerOpts{Namespace: test.FakeArgoCDNamespace, KubeClientset: kubeclientset, AppClientset: apps.NewSimpleClientset(&existingProj), RepoClientset: mockRepoClient}, ApplicationSetOpts{})
s := NewServer(context.Background(), ArgoCDServerOpts{Namespace: test.FakeArgoCDNamespace, KubeClientset: kubeclientset, AppClientset: apps.NewSimpleClientset(&existingProj), RepoClientset: mockRepoClient})
cancel := test.StartInformer(s.projInformer)
defer cancel()
claims := jwt.MapClaims{"sub": defaultSub, "iat": defaultIssuedAt}
@@ -458,7 +450,7 @@ func TestAuthenticate(t *testing.T) {
AppClientset: appClientSet,
RepoClientset: mockRepoClient,
}
argocd := NewServer(context.Background(), argoCDOpts, ApplicationSetOpts{})
argocd := NewServer(context.Background(), argoCDOpts)
ctx := context.Background()
if testData.user != "" {
token, err := argocd.sessionMgr.Create(testData.user, 0, "abc")
@@ -595,7 +587,7 @@ connectors:
if withFakeSSO && useDexForSSO {
argoCDOpts.DexServerAddr = ts.URL
}
argocd = NewServer(context.Background(), argoCDOpts, ApplicationSetOpts{})
argocd = NewServer(context.Background(), argoCDOpts)
var err error
argocd.ssoClientApp, err = oidc.NewClientApp(argocd.settings, argocd.DexServerAddr, argocd.DexTLSConfig, argocd.BaseHRef, cache.NewInMemoryCache(24*time.Hour))
require.NoError(t, err)
@@ -1079,7 +1071,7 @@ func TestTranslateGrpcCookieHeader(t *testing.T) {
AppClientset: apps.NewSimpleClientset(),
RepoClientset: &mocks.Clientset{RepoServerServiceClient: &mocks.RepoServerServiceClient{}},
}
argocd := NewServer(context.Background(), argoCDOpts, ApplicationSetOpts{})
argocd := NewServer(context.Background(), argoCDOpts)
t.Run("TokenIsNotEmpty", func(t *testing.T) {
recorder := httptest.NewRecorder()

View File

@@ -522,101 +522,6 @@ func TestSimpleListGeneratorGoTemplate(t *testing.T) {
Delete().Then().Expect(ApplicationsDoNotExist([]argov1alpha1.Application{*expectedAppNewMetadata}))
}
func TestCreateApplicationDespiteParamsError(t *testing.T) {
expectedErrorMessage := `failed to execute go template {{.cluster}}-guestbook: template: :1:2: executing "" at <.cluster>: map has no entry for key "cluster"`
expectedConditionsParamsError := []v1alpha1.ApplicationSetCondition{
{
Type: v1alpha1.ApplicationSetConditionErrorOccurred,
Status: v1alpha1.ApplicationSetConditionStatusTrue,
Message: expectedErrorMessage,
Reason: v1alpha1.ApplicationSetReasonRenderTemplateParamsError,
},
{
Type: v1alpha1.ApplicationSetConditionParametersGenerated,
Status: v1alpha1.ApplicationSetConditionStatusFalse,
Message: expectedErrorMessage,
Reason: v1alpha1.ApplicationSetReasonErrorOccurred,
},
{
Type: v1alpha1.ApplicationSetConditionResourcesUpToDate,
Status: v1alpha1.ApplicationSetConditionStatusFalse,
Message: expectedErrorMessage,
Reason: v1alpha1.ApplicationSetReasonRenderTemplateParamsError,
},
}
expectedApp := argov1alpha1.Application{
TypeMeta: metav1.TypeMeta{
Kind: application.ApplicationKind,
APIVersion: "argoproj.io/v1alpha1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "my-cluster-guestbook",
Namespace: fixture.TestNamespace(),
Finalizers: []string{"resources-finalizer.argocd.argoproj.io"},
},
Spec: argov1alpha1.ApplicationSpec{
Project: "default",
Source: &argov1alpha1.ApplicationSource{
RepoURL: "https://github.com/argoproj/argocd-example-apps.git",
TargetRevision: "HEAD",
Path: "guestbook",
},
Destination: argov1alpha1.ApplicationDestination{
Server: "https://kubernetes.default.svc",
Namespace: "guestbook",
},
},
}
Given(t).
// Create a ListGenerator-based ApplicationSet
When().Create(v1alpha1.ApplicationSet{
ObjectMeta: metav1.ObjectMeta{
Name: "simple-list-generator",
},
Spec: v1alpha1.ApplicationSetSpec{
GoTemplate: true,
GoTemplateOptions: []string{"missingkey=error"},
Template: v1alpha1.ApplicationSetTemplate{
ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{Name: "{{.cluster}}-guestbook"},
Spec: argov1alpha1.ApplicationSpec{
Project: "default",
Source: &argov1alpha1.ApplicationSource{
RepoURL: "https://github.com/argoproj/argocd-example-apps.git",
TargetRevision: "HEAD",
Path: "guestbook",
},
Destination: argov1alpha1.ApplicationDestination{
Server: "{{.url}}",
Namespace: "guestbook",
},
},
},
Generators: []v1alpha1.ApplicationSetGenerator{
{
List: &v1alpha1.ListGenerator{
Elements: []apiextensionsv1.JSON{
{
Raw: []byte(`{"cluster": "my-cluster","url": "https://kubernetes.default.svc"}`),
},
{
Raw: []byte(`{"invalidCluster": "invalid-cluster","url": "https://kubernetes.default.svc"}`),
},
},
},
},
},
},
}).Then().Expect(ApplicationsExist([]argov1alpha1.Application{expectedApp})).
// verify the ApplicationSet status conditions were set correctly
Expect(ApplicationSetHasConditions("simple-list-generator", expectedConditionsParamsError)).
// Delete the ApplicationSet, and verify it deletes the Applications
When().
Delete().Then().Expect(ApplicationsDoNotExist([]argov1alpha1.Application{expectedApp}))
}
func TestRenderHelmValuesObject(t *testing.T) {
expectedApp := argov1alpha1.Application{
TypeMeta: metav1.TypeMeta{

View File

@@ -1,4 +1,4 @@
FROM docker.io/library/node:22.3.0@sha256:b98ec1c96103fbe1a9e449b3854bbc0a0ed1c5936882ae0939d4c3a771265b4b as node
FROM docker.io/library/node:22.3.0@sha256:5e4044ff6001d06e7748e35bfa4f80c73cf5f5a7360a1b782995e038a01b0585 as node
RUN apt-get update && apt-get install --no-install-recommends -y \
software-properties-common

View File

@@ -14,12 +14,12 @@
"dependencies": {
"@types/selenium-webdriver": "^4.1.23",
"assert": "^2.1.0",
"chromedriver": "^126.0.2",
"chromedriver": "^126.0.1",
"selenium-webdriver": "^4.21.0"
},
"devDependencies": {
"@types/mocha": "^10.0.6",
"@types/node": "^20.14.7",
"@types/node": "^20.14.4",
"dotenv": "^16.4.5",
"mocha": "^10.4.0",
"prettier": "^2.8.8",

View File

@@ -38,10 +38,10 @@
resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-10.0.6.tgz#818551d39113081048bdddbef96701b4e8bb9d1b"
integrity sha512-dJvrYWxP/UcXm36Qn36fxhUKu8A/xMRXVT2cliFF1Z7UA9liG5Psj3ezNSZw+5puH2czDXRLcXQxf8JbJt0ejg==
"@types/node@*", "@types/node@^20.14.7":
version "20.14.7"
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.14.7.tgz#342cada27f97509eb8eb2dbc003edf21ce8ab5a8"
integrity sha512-uTr2m2IbJJucF3KUxgnGOZvYbN0QgkGyWxG6973HCpMYFy2KfcgYuIwkJQMQkt1VbBMlvWRbpshFTLxnxCZjKQ==
"@types/node@*", "@types/node@^20.14.4":
version "20.14.4"
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.14.4.tgz#3426db474378502882036d595ec9e79a9b17d1e6"
integrity sha512-1ChboN+57suCT2t/f8lwtPY/k3qTpuD/qnqQuYoBg6OQOcPyaw7PiZVdGpaZYAvhDDtqrt0oAaM8+oSu1xsUGw==
dependencies:
undici-types "~5.26.4"
@@ -262,10 +262,10 @@ chokidar@3.5.3:
optionalDependencies:
fsevents "~2.3.2"
chromedriver@^126.0.2:
version "126.0.2"
resolved "https://registry.yarnpkg.com/chromedriver/-/chromedriver-126.0.2.tgz#0c0840cd1ba00b73fa16d4292fa739860ee20ec8"
integrity sha512-61R0w7C+uJVCykabdqWsvitne2rg3MTI8xOKJosk+YbKdyLeGHYiCCeU82ZsUY+v9qnN1p48THcthgKubxPRWQ==
chromedriver@^126.0.1:
version "126.0.1"
resolved "https://registry.yarnpkg.com/chromedriver/-/chromedriver-126.0.1.tgz#2591500833ba5baa626c2725f2877cce02237883"
integrity sha512-uV4xIvpPimKmV1/Hn9oX0C57tjsBbVtOeKFX9JzzPYpsu8xiSUAdqa3A8mgZE5DMJKDDoDyDIrA656QncVWRzg==
dependencies:
"@testim/chrome-version" "^1.1.4"
axios "^1.6.7"

View File

@@ -112,12 +112,12 @@ func GetAppRefreshPaths(app *v1alpha1.Application) []string {
}
// AppFilesHaveChanged returns true if any of the changed files are under the given refresh paths
// If refreshPaths is empty, it will always return true
// If refreshPaths or changedFiles are empty, it will always return true
func AppFilesHaveChanged(refreshPaths []string, changedFiles []string) bool {
// empty slice means there was no changes to any files
// so we should not refresh
// an empty slice of changed files means that the payload didn't include a list
// of changed files and we have to assume that a refresh is required
if len(changedFiles) == 0 {
return false
return true
}
if len(refreshPaths) == 0 {

View File

@@ -134,7 +134,7 @@ func Test_AppFilesHaveChanged(t *testing.T) {
changeExpected bool
}{
{"default no path", &v1alpha1.Application{}, []string{"README.md"}, true},
{"no files changed", getApp(".", "source/path"), []string{}, false},
{"no files changed", getApp(".", "source/path"), []string{}, true},
{"relative path - matching", getApp(".", "source/path"), []string{"source/path/my-deployment.yaml"}, true},
{"relative path, multi source - matching #1", getMultiSourceApp(".", "source/path", "other/path"), []string{"source/path/my-deployment.yaml"}, true},
{"relative path, multi source - matching #2", getMultiSourceApp(".", "other/path", "source/path"), []string{"source/path/my-deployment.yaml"}, true},

View File

@@ -147,12 +147,12 @@ func TestStateDiff(t *testing.T) {
replicas, found, err := unstructured.NestedFloat64(normalized.Object, "spec", "replicas")
require.NoError(t, err)
assert.True(t, found)
assert.InEpsilon(t, float64(tc.expectedNormalizedReplicas), replicas, 0.0001)
assert.Equal(t, float64(tc.expectedNormalizedReplicas), replicas)
predicted := testutil.YamlToUnstructured(string(result.PredictedLive))
predictedReplicas, found, err := unstructured.NestedFloat64(predicted.Object, "spec", "replicas")
require.NoError(t, err)
assert.True(t, found)
assert.InEpsilon(t, float64(tc.expectedPredictedReplicas), predictedReplicas, 0.0001)
assert.Equal(t, float64(tc.expectedPredictedReplicas), predictedReplicas)
})
}
}

View File

@@ -38,16 +38,14 @@ func TestNormalize(t *testing.T) {
liveReplicas, ok, err := unstructured.NestedFloat64(liveResult.Object, "spec", "replicas")
assert.False(t, ok)
require.NoError(t, err)
assert.Zero(t, desiredReplicas)
assert.Zero(t, liveReplicas)
assert.Equal(t, liveReplicas, desiredReplicas)
liveRevisionHistory, ok, err := unstructured.NestedFloat64(liveResult.Object, "spec", "revisionHistoryLimit")
assert.False(t, ok)
require.NoError(t, err)
desiredRevisionHistory, ok, err := unstructured.NestedFloat64(desiredResult.Object, "spec", "revisionHistoryLimit")
assert.False(t, ok)
require.NoError(t, err)
assert.Zero(t, desiredRevisionHistory)
assert.Zero(t, liveRevisionHistory)
assert.Equal(t, liveRevisionHistory, desiredRevisionHistory)
})
t.Run("will keep conflicting fields if not from trusted manager", func(t *testing.T) {
// given
@@ -148,7 +146,7 @@ func TestNormalize(t *testing.T) {
func validateNestedFloat64(t *testing.T, expected float64, obj *unstructured.Unstructured, fields ...string) {
t.Helper()
current := getNestedFloat64(t, obj, fields...)
assert.InEpsilon(t, expected, current, 0.0001)
assert.Equal(t, expected, current)
}
func getNestedFloat64(t *testing.T, obj *unstructured.Unstructured, fields ...string) float64 {

View File

@@ -156,13 +156,13 @@ func TestParseAppInstanceValueColon(t *testing.T) {
func TestParseAppInstanceValueWrongFormat1(t *testing.T) {
resourceTracking := NewResourceTracking()
_, err := resourceTracking.ParseAppInstanceValue("app")
require.ErrorIs(t, err, WrongResourceTrackingFormat)
require.Error(t, err, WrongResourceTrackingFormat)
}
func TestParseAppInstanceValueWrongFormat2(t *testing.T) {
resourceTracking := NewResourceTracking()
_, err := resourceTracking.ParseAppInstanceValue("app;group/kind/ns")
require.ErrorIs(t, err, WrongResourceTrackingFormat)
require.Error(t, err, WrongResourceTrackingFormat)
}
func TestParseAppInstanceValueCorrectFormat(t *testing.T) {

View File

@@ -145,7 +145,7 @@ func TestRedisMetrics(t *testing.T) {
require.NoError(t, err)
err = c.Write(metric)
require.NoError(t, err)
assert.InEpsilon(t, float64(2), metric.Counter.GetValue(), 0.0001)
assert.Equal(t, float64(2), metric.Counter.GetValue())
// faulty client failed request
err = faultyClient.Get("foo", &res)
@@ -154,7 +154,7 @@ func TestRedisMetrics(t *testing.T) {
require.NoError(t, err)
err = c.Write(metric)
require.NoError(t, err)
assert.InEpsilon(t, float64(1), metric.Counter.GetValue(), 0.0001)
assert.Equal(t, float64(1), metric.Counter.GetValue())
// both clients histogram count
o, err := ms.redisRequestHistogram.GetMetricWithLabelValues("mock")

View File

@@ -64,7 +64,7 @@ func TestParseFloatFromEnv(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
t.Setenv(envKey, tt.env)
f := ParseFloatFromEnv(envKey, def, min, max)
assert.InEpsilon(t, tt.expected, f, 0.0001)
assert.Equal(t, tt.expected, f)
})
}
}

View File

@@ -481,7 +481,7 @@ func TestGenerateAppState_XSS(t *testing.T) {
}
returnURL, err := app.verifyAppState(req, httptest.NewRecorder(), state)
require.NoError(t, err)
require.NoError(t, err, InvalidRedirectURLError)
assert.Equal(t, expectedReturnURL, returnURL)
})
}