Compare commits

...

20 Commits

Author SHA1 Message Date
github-actions[bot]
007a5aea6e Bump version to 3.1.0-rc3 on release-3.1 branch (#23764)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: crenshaw-dev <350466+crenshaw-dev@users.noreply.github.com>
2025-07-11 13:59:43 -04:00
gcp-cherry-pick-bot[bot]
36cc2d1b86 fix(health): CRD health check message (#23690) (cherry-pick #23691) (#23738)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2025-07-10 10:18:17 -04:00
github-actions[bot]
9db5e25e03 Bump version to 3.1.0-rc2 on release-3.1 branch (#23743)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: crenshaw-dev <350466+crenshaw-dev@users.noreply.github.com>
2025-07-10 10:17:47 -04:00
gcp-cherry-pick-bot[bot]
8eaccb7ea0 feat(helm): upgrading helm to 3.18.4 (cherry-pick #23724) (#23731)
Signed-off-by: Mubarak Jama <mubarak.jama@gmail.com>
Co-authored-by: Mubarak Jama <83465122+mubarak-j@users.noreply.github.com>
2025-07-09 21:29:09 -10:00
gcp-cherry-pick-bot[bot]
fed347da29 docs(images): add a note about missing images for 3.0 releases (#23612) (cherry-pick #23712) (#23713)
Signed-off-by: rumstead <37445536+rumstead@users.noreply.github.com>
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Co-authored-by: rumstead <37445536+rumstead@users.noreply.github.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2025-07-09 13:56:43 -04:00
gcp-cherry-pick-bot[bot]
1cbd28cb30 fix(server): make parameterized resource actions backwards-compatible (cherry-pick #23695) (#23709)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2025-07-09 11:21:17 -04:00
gcp-cherry-pick-bot[bot]
6fe5ec794a fix: improves the ui message when an operation is terminated due to controller sync timeout (cherry-pick #23657) (#23672)
Signed-off-by: Patroklos Papapetrou <ppapapetrou76@gmail.com>
Co-authored-by: Papapetrou Patroklos <1743100+ppapapetrou76@users.noreply.github.com>
2025-07-09 06:37:58 +03:00
Alexandre Gaudreault
6142c5bf56 fix(sync): auto-sync loop when FailOnSharedResource (#23357) (#23640)
Signed-off-by: Alexandre Gaudreault <alexandre_gaudreault@intuit.com>
2025-07-02 15:00:37 -04:00
Michael Crenshaw
563d45b8db feat(kustomize): upgrade to 5.7.0 (#23619) (#23625)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2025-07-02 10:54:37 -04:00
gcp-cherry-pick-bot[bot]
37f2793e95 fix(hydrator): omit Argocd- trailers from hydrator.metadata (cherry-pick #23463) (#23621)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2025-07-01 13:21:19 -04:00
gcp-cherry-pick-bot[bot]
7224a15502 feat(helm): upgrade to 3.18.3 (cherry-pick #23618) (#23620)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2025-07-01 11:52:47 -04:00
gcp-cherry-pick-bot[bot]
dd675feb33 fix: UI error with ApplicationSet in any namespace (cherry-pick #23601) (#23604)
Signed-off-by: jaqxues <32979131+jaqxues@users.noreply.github.com>
Co-authored-by: jaqxues <32979131+jaqxues@users.noreply.github.com>
2025-06-30 00:41:55 -10:00
gcp-cherry-pick-bot[bot]
c215dbf202 fix: OCI client, avoid calling tags/list if revision is not a constraint #23580 (cherry-pick #23581) (#23582)
Signed-off-by: Diego Erdody <diego.erdody@dexterity.ai>
Co-authored-by: Diego Erdody <erdody@gmail.com>
Co-authored-by: Diego Erdody <diego.erdody@dexterity.ai>
2025-06-26 23:55:19 +02:00
gcp-cherry-pick-bot[bot]
75f7016d89 fix(controller): get commit server url from env (cherry-pick #23536) (#23541)
Signed-off-by: Alexej Disterhoft <alexej.disterhoft@redcare-pharmacy.com>
Co-authored-by: Alexej Disterhoft <alexej@disterhoft.de>
2025-06-24 13:31:39 -04:00
gcp-cherry-pick-bot[bot]
4a7e581080 fix: kustomize components + monorepos (cherry-pick #23486) (#23540)
Signed-off-by: Blake Pettersson <blake.pettersson@gmail.com>
Co-authored-by: Blake Pettersson <blake.pettersson@gmail.com>
2025-06-24 18:07:20 +02:00
gcp-cherry-pick-bot[bot]
320f46f06b fix(darwin): remove the need for cgo when building a darwin binary on linux (cherry-pick #23507) (#23526)
Signed-off-by: rumstead <37445536+rumstead@users.noreply.github.com>
Co-authored-by: rumstead <37445536+rumstead@users.noreply.github.com>
2025-06-23 12:07:29 -04:00
gcp-cherry-pick-bot[bot]
d69639a073 fix(controller): impersonation with destination name (#23309) (cherry-pick #23504) (#23519)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2025-06-23 09:52:54 -04:00
github-actions[bot]
b75f532a91 Bump version to 3.1.0-rc1 on release-3.1 branch (#23498)
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: agaudreault <47184027+agaudreault@users.noreply.github.com>
2025-06-19 13:08:02 -04:00
gcp-cherry-pick-bot[bot]
200dc1d499 ci: fix supported-version script (cherry-pick #23496) (#23497)
Signed-off-by: Alexandre Gaudreault <alexandre_gaudreault@intuit.com>
Co-authored-by: Alexandre Gaudreault <alexandre_gaudreault@intuit.com>
2025-06-19 13:03:51 -04:00
Christian Hernandez
3f1d9bf5a2 chore: Updated Blog Link for v3.1 (#23494)
Signed-off-by: Christian Hernandez <christian@chernand.io>
2025-06-19 17:27:33 +02:00
83 changed files with 2041 additions and 559 deletions

View File

@@ -21,7 +21,7 @@ builds:
- -X github.com/argoproj/argo-cd/v3/common.gitCommit={{ .FullCommit }}
- -X github.com/argoproj/argo-cd/v3/common.gitTreeState={{ .Env.GIT_TREE_STATE }}
- -X github.com/argoproj/argo-cd/v3/common.kubectlVersion={{ .Env.KUBECTL_VERSION }}
- '{{ if or (eq .Runtime.Goos "linux") (eq .Runtime.Goos "windows") }}-extldflags="-static"{{ end }}'
- -extldflags="-static"
goos:
- linux
- windows
@@ -42,15 +42,6 @@ builds:
goarch: ppc64le
- goos: windows
goarch: arm64
overrides:
- goos: darwin
goarch: amd64
env:
- CGO_ENABLED=1
- goos: darwin
goarch: arm64
env:
- CGO_ENABLED=1
archives:
- id: argocd-archive
@@ -89,7 +80,7 @@ release:
All Argo CD container images are signed by cosign. A Provenance is generated for container images and CLI binaries which meet the SLSA Level 3 specifications. See the [documentation](https://argo-cd.readthedocs.io/en/stable/operator-manual/signed-release-assets) on how to verify.
## Release Notes Blog Post
For a detailed breakdown of the key changes and improvements in this release, check out the [official blog post](https://blog.argoproj.io/argo-cd-v3-0-release-candidate-a0b933f4e58f)
For a detailed breakdown of the key changes and improvements in this release, check out the [official blog post](https://blog.argoproj.io/announcing-argo-cd-v3-1-f4389bc783c8)
## Upgrading

View File

@@ -1 +1 @@
3.1.0
3.1.0-rc3

81
assets/swagger.json generated
View File

@@ -1473,10 +1473,11 @@
}
},
"post": {
"description": "Deprecated: use RunResourceActionV2 instead. This version does not support resource action parameters but is\nmaintained for backward compatibility. It will be removed in a future release.",
"tags": [
"ApplicationService"
],
"summary": "RunResourceAction run resource action",
"summary": "RunResourceAction runs a resource action",
"operationId": "ApplicationService_RunResourceAction",
"parameters": [
{
@@ -1490,7 +1491,81 @@
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/applicationResourceActionRunRequest"
"type": "string"
}
},
{
"type": "string",
"name": "namespace",
"in": "query"
},
{
"type": "string",
"name": "resourceName",
"in": "query"
},
{
"type": "string",
"name": "version",
"in": "query"
},
{
"type": "string",
"name": "group",
"in": "query"
},
{
"type": "string",
"name": "kind",
"in": "query"
},
{
"type": "string",
"name": "appNamespace",
"in": "query"
},
{
"type": "string",
"name": "project",
"in": "query"
}
],
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/applicationApplicationResponse"
}
},
"default": {
"description": "An unexpected error response.",
"schema": {
"$ref": "#/definitions/runtimeError"
}
}
}
}
},
"/api/v1/applications/{name}/resource/actions/v2": {
"post": {
"tags": [
"ApplicationService"
],
"summary": "RunResourceActionV2 runs a resource action with parameters",
"operationId": "ApplicationService_RunResourceActionV2",
"parameters": [
{
"type": "string",
"name": "name",
"in": "path",
"required": true
},
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/applicationResourceActionRunRequestV2"
}
}
],
@@ -5127,7 +5202,7 @@
}
}
},
"applicationResourceActionRunRequest": {
"applicationResourceActionRunRequestV2": {
"type": "object",
"properties": {
"action": {

View File

@@ -1,3 +1,5 @@
//go:build !darwin || (cgo && darwin)
package commands
import (

View File

@@ -0,0 +1,25 @@
//go:build darwin && !cgo
// Package commands
// This file is used when the GOOS is darwin and CGO is not enabled.
// It provides a no-op implementation of newAzureCommand to allow goreleaser to build
// a darwin binary on a linux machine.
package commands
import (
"log"
"github.com/spf13/cobra"
"github.com/argoproj/argo-cd/v3/util/workloadidentity"
)
func newAzureCommand() *cobra.Command {
command := &cobra.Command{
Use: "azure",
Run: func(c *cobra.Command, _ []string) {
log.Fatalf(workloadidentity.CGOError)
},
}
return command
}

View File

@@ -8,23 +8,23 @@ import (
"strconv"
"text/tabwriter"
"github.com/argoproj/argo-cd/v3/util/templates"
"github.com/argoproj/argo-cd/v3/cmd/util"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"google.golang.org/grpc/codes"
"k8s.io/utils/ptr"
"sigs.k8s.io/yaml"
"github.com/argoproj/argo-cd/v3/cmd/argocd/commands/headless"
"github.com/argoproj/argo-cd/v3/cmd/util"
argocdclient "github.com/argoproj/argo-cd/v3/pkg/apiclient"
applicationpkg "github.com/argoproj/argo-cd/v3/pkg/apiclient/application"
"github.com/argoproj/argo-cd/v3/pkg/apis/application"
"github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
"github.com/argoproj/argo-cd/v3/util/argo"
"github.com/argoproj/argo-cd/v3/util/errors"
"github.com/argoproj/argo-cd/v3/util/grpc"
utilio "github.com/argoproj/argo-cd/v3/util/io"
"github.com/argoproj/argo-cd/v3/util/templates"
)
type DisplayedAction struct {
@@ -192,7 +192,26 @@ func NewApplicationResourceActionsRunCommand(clientOpts *argocdclient.ClientOpti
obj := filteredObjects[i]
gvk := obj.GroupVersionKind()
objResourceName := obj.GetName()
_, err := appIf.RunResourceAction(ctx, &applicationpkg.ResourceActionRunRequest{
_, err := appIf.RunResourceActionV2(ctx, &applicationpkg.ResourceActionRunRequestV2{
Name: &appName,
AppNamespace: &appNs,
Namespace: ptr.To(obj.GetNamespace()),
ResourceName: ptr.To(objResourceName),
Group: ptr.To(gvk.Group),
Kind: ptr.To(gvk.Kind),
Version: ptr.To(gvk.GroupVersion().Version),
Action: ptr.To(actionName),
// TODO: add support for parameters
})
if err == nil {
continue
}
if grpc.UnwrapGRPCStatus(err).Code() != codes.Unimplemented {
errors.CheckError(err)
}
fmt.Println("RunResourceActionV2 is not supported by the server, falling back to RunResourceAction.")
//nolint:staticcheck // RunResourceAction is deprecated, but we still need to support it for backward compatibility.
_, err = appIf.RunResourceAction(ctx, &applicationpkg.ResourceActionRunRequest{
Name: &appName,
AppNamespace: &appNs,
Namespace: ptr.To(obj.GetNamespace()),

View File

@@ -2228,10 +2228,15 @@ func (c *fakeAppServiceClient) ListResourceActions(_ context.Context, _ *applica
return nil, nil
}
// nolint:staticcheck // ResourceActionRunRequest is deprecated, but we still need to implement it to satisfy the server interface.
func (c *fakeAppServiceClient) RunResourceAction(_ context.Context, _ *applicationpkg.ResourceActionRunRequest, _ ...grpc.CallOption) (*applicationpkg.ApplicationResponse, error) {
return nil, nil
}
func (c *fakeAppServiceClient) RunResourceActionV2(_ context.Context, _ *applicationpkg.ResourceActionRunRequestV2, _ ...grpc.CallOption) (*applicationpkg.ApplicationResponse, error) {
return nil, nil
}
func (c *fakeAppServiceClient) DeleteResource(_ context.Context, _ *applicationpkg.ApplicationResourceDeleteRequest, _ ...grpc.CallOption) (*applicationpkg.ApplicationResponse, error) {
return nil, nil
}

View File

@@ -220,6 +220,7 @@ type hydratorMetadataFile struct {
// Subject is the subject line of the DRY commit message, i.e. `git show --format=%s`.
Subject string `json:"subject,omitempty"`
// Body is the body of the DRY commit message, excluding the subject line, i.e. `git show --format=%b`.
// Known Argocd- trailers with valid values are removed, but all other trailers are kept.
Body string `json:"body,omitempty"`
References []v1alpha1.RevisionReference `json:"references,omitempty"`
}

View File

@@ -18,6 +18,7 @@ import (
"github.com/argoproj/argo-cd/v3/commitserver/apiclient"
appv1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
"github.com/argoproj/argo-cd/v3/util/git"
"github.com/argoproj/argo-cd/v3/util/io"
)
@@ -48,8 +49,10 @@ func WriteForPaths(root *os.Root, repoUrl, drySha string, dryCommitMetadata *app
subject, body, _ := strings.Cut(message, "\n\n")
_, bodyMinusTrailers := git.GetReferences(log.WithFields(log.Fields{"repo": repoUrl, "revision": drySha}), body)
// Write the top-level readme.
err := writeMetadata(root, "", hydratorMetadataFile{DrySHA: drySha, RepoURL: repoUrl, Author: author, Subject: subject, Body: body, Date: date, References: references})
err := writeMetadata(root, "", hydratorMetadataFile{DrySHA: drySha, RepoURL: repoUrl, Author: author, Subject: subject, Body: bodyMinusTrailers, Date: date, References: references})
if err != nil {
return fmt.Errorf("failed to write top-level hydrator metadata: %w", err)
}

View File

@@ -9,7 +9,6 @@ import (
"os"
"path"
"path/filepath"
"strings"
"testing"
"time"
@@ -73,9 +72,13 @@ func TestWriteForPaths(t *testing.T) {
now := metav1.NewTime(time.Now())
metadata := &appsv1.RevisionMetadata{
Author: "test-author",
Date: &now,
Message: "test-message",
Author: "test-author",
Date: &now,
Message: `test-message
Signed-off-by: Test User <test@example.com>
Argocd-reference-commit-sha: abc123
`,
References: []appsv1.RevisionReference{
{
Commit: &appsv1.CommitMetadata{
@@ -97,16 +100,15 @@ func TestWriteForPaths(t *testing.T) {
topMetadataBytes, err := os.ReadFile(topMetadataPath)
require.NoError(t, err)
expectedSubject, expectedBody, _ := strings.Cut(metadata.Message, "\n\n")
var topMetadata hydratorMetadataFile
err = json.Unmarshal(topMetadataBytes, &topMetadata)
require.NoError(t, err)
assert.Equal(t, repoURL, topMetadata.RepoURL)
assert.Equal(t, drySha, topMetadata.DrySHA)
assert.Equal(t, metadata.Author, topMetadata.Author)
assert.Equal(t, expectedSubject, topMetadata.Subject)
assert.Equal(t, expectedBody, topMetadata.Body)
assert.Equal(t, "test-message", topMetadata.Subject)
// The body should exclude the Argocd- trailers.
assert.Equal(t, "Signed-off-by: Test User <test@example.com>\n", topMetadata.Body)
assert.Equal(t, metadata.Date.Format(time.RFC3339), topMetadata.Date)
assert.Equal(t, metadata.References, topMetadata.References)

View File

@@ -1483,7 +1483,7 @@ func (ctrl *ApplicationController) processRequestedAppOperation(app *appv1.Appli
} else {
state.Phase = synccommon.OperationRunning
state.RetryCount++
state.Message = fmt.Sprintf("%s. Retrying attempt #%d at %s.", state.Message, state.RetryCount, retryAt.Format(time.Kitchen))
state.Message = fmt.Sprintf("%s due to application controller sync timeout. Retrying attempt #%d at %s.", state.Message, state.RetryCount, retryAt.Format(time.Kitchen))
}
} else if state.RetryCount > 0 {
state.Message = fmt.Sprintf("%s (retried %d times).", state.Message, state.RetryCount)

View File

@@ -2090,7 +2090,7 @@ func TestProcessRequestedAppOperation_FailedHasRetries(t *testing.T) {
phase, _, _ := unstructured.NestedString(receivedPatch, "status", "operationState", "phase")
assert.Equal(t, string(synccommon.OperationRunning), phase)
message, _, _ := unstructured.NestedString(receivedPatch, "status", "operationState", "message")
assert.Contains(t, message, "Retrying attempt #1")
assert.Contains(t, message, "due to application controller sync timeout. Retrying attempt #1")
retryCount, _, _ := unstructured.NestedFloat64(receivedPatch, "status", "operationState", "retryCount")
assert.InEpsilon(t, float64(1), retryCount, 0.0001)
}

View File

@@ -108,15 +108,6 @@ func (m *appStateManager) SyncAppState(app *v1alpha1.Application, state *v1alpha
}
syncOp = *state.Operation.Sync
// validates if it should fail the sync if it finds shared resources
hasSharedResource, sharedResourceMessage := hasSharedResourceCondition(app)
if syncOp.SyncOptions.HasOption("FailOnSharedResource=true") &&
hasSharedResource {
state.Phase = common.OperationFailed
state.Message = "Shared resource found: " + sharedResourceMessage
return
}
isMultiSourceRevision := app.Spec.HasMultipleSources()
rollback := len(syncOp.Sources) > 0 || syncOp.Source != nil
if rollback {
@@ -207,6 +198,15 @@ func (m *appStateManager) SyncAppState(app *v1alpha1.Application, state *v1alpha
syncRes.Revision = compareResult.syncStatus.Revision
syncRes.Revisions = compareResult.syncStatus.Revisions
// validates if it should fail the sync if it finds shared resources
hasSharedResource, sharedResourceMessage := hasSharedResourceCondition(app)
if syncOp.SyncOptions.HasOption("FailOnSharedResource=true") &&
hasSharedResource {
state.Phase = common.OperationFailed
state.Message = "Shared resource found: %s" + sharedResourceMessage
return
}
// If there are any comparison or spec errors error conditions do not perform the operation
if errConditions := app.Status.GetConditions(map[v1alpha1.ApplicationConditionType]bool{
v1alpha1.ApplicationConditionComparisonError: true,
@@ -324,7 +324,7 @@ func (m *appStateManager) SyncAppState(app *v1alpha1.Application, state *v1alpha
return
}
if impersonationEnabled {
serviceAccountToImpersonate, err := deriveServiceAccountToImpersonate(proj, app)
serviceAccountToImpersonate, err := deriveServiceAccountToImpersonate(proj, app, destCluster)
if err != nil {
state.Phase = common.OperationError
state.Message = fmt.Sprintf("failed to find a matching service account to impersonate: %v", err)
@@ -607,7 +607,7 @@ func syncWindowPreventsSync(app *v1alpha1.Application, proj *v1alpha1.AppProject
// deriveServiceAccountToImpersonate determines the service account to be used for impersonation for the sync operation.
// The returned service account will be fully qualified including namespace and the service account name in the format system:serviceaccount:<namespace>:<service_account>
func deriveServiceAccountToImpersonate(project *v1alpha1.AppProject, application *v1alpha1.Application) (string, error) {
func deriveServiceAccountToImpersonate(project *v1alpha1.AppProject, application *v1alpha1.Application, destCluster *v1alpha1.Cluster) (string, error) {
// spec.Destination.Namespace is optional. If not specified, use the Application's
// namespace
serviceAccountNamespace := application.Spec.Destination.Namespace
@@ -617,7 +617,7 @@ func deriveServiceAccountToImpersonate(project *v1alpha1.AppProject, application
// Loop through the destinationServiceAccounts and see if there is any destination that is a candidate.
// if so, return the service account specified for that destination.
for _, item := range project.Spec.DestinationServiceAccounts {
dstServerMatched, err := glob.MatchWithError(item.Server, application.Spec.Destination.Server)
dstServerMatched, err := glob.MatchWithError(item.Server, destCluster.Server)
if err != nil {
return "", fmt.Errorf("invalid glob pattern for destination server: %w", err)
}

View File

@@ -5,7 +5,7 @@ import (
"testing"
"github.com/argoproj/gitops-engine/pkg/sync"
"github.com/argoproj/gitops-engine/pkg/sync/common"
synccommon "github.com/argoproj/gitops-engine/pkg/sync/common"
"github.com/argoproj/gitops-engine/pkg/utils/kube"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -14,6 +14,7 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"github.com/argoproj/argo-cd/v3/common"
"github.com/argoproj/argo-cd/v3/controller/testdata"
"github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
"github.com/argoproj/argo-cd/v3/reposerver/apiclient"
@@ -196,11 +197,15 @@ func TestAppStateManager_SyncAppState(t *testing.T) {
controller *ApplicationController
}
setup := func() *fixture {
setup := func(liveObjects map[kube.ResourceKey]*unstructured.Unstructured) *fixture {
app := newFakeApp()
app.Status.OperationState = nil
app.Status.History = nil
if liveObjects == nil {
liveObjects = make(map[kube.ResourceKey]*unstructured.Unstructured)
}
project := &v1alpha1.AppProject{
ObjectMeta: metav1.ObjectMeta{
Namespace: test.FakeArgoCDNamespace,
@@ -208,6 +213,12 @@ func TestAppStateManager_SyncAppState(t *testing.T) {
},
Spec: v1alpha1.AppProjectSpec{
SignatureKeys: []v1alpha1.SignatureKey{{KeyID: "test"}},
Destinations: []v1alpha1.ApplicationDestination{
{
Namespace: "*",
Server: "*",
},
},
},
}
data := fakeData{
@@ -218,7 +229,7 @@ func TestAppStateManager_SyncAppState(t *testing.T) {
Server: test.FakeClusterURL,
Revision: "abc123",
},
managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured),
managedLiveObjs: liveObjects,
}
ctrl := newFakeController(&data, nil)
@@ -231,13 +242,23 @@ func TestAppStateManager_SyncAppState(t *testing.T) {
t.Run("will fail the sync if finds shared resources", func(t *testing.T) {
// given
t.Parallel()
f := setup()
syncErrorMsg := "deployment already applied by another application"
condition := v1alpha1.ApplicationCondition{
Type: v1alpha1.ApplicationConditionSharedResourceWarning,
Message: syncErrorMsg,
}
f.application.Status.Conditions = append(f.application.Status.Conditions, condition)
sharedObject := kube.MustToUnstructured(&corev1.ConfigMap{
TypeMeta: metav1.TypeMeta{
APIVersion: "v1",
Kind: "ConfigMap",
},
ObjectMeta: metav1.ObjectMeta{
Name: "configmap1",
Namespace: "default",
Annotations: map[string]string{
common.AnnotationKeyAppInstance: "guestbook:/ConfigMap:default/configmap1",
},
},
})
liveObjects := make(map[kube.ResourceKey]*unstructured.Unstructured)
liveObjects[kube.GetResourceKey(sharedObject)] = sharedObject
f := setup(liveObjects)
// Sync with source unspecified
opState := &v1alpha1.OperationState{Operation: v1alpha1.Operation{
@@ -251,8 +272,8 @@ func TestAppStateManager_SyncAppState(t *testing.T) {
f.controller.appStateManager.SyncAppState(f.application, opState)
// then
assert.Equal(t, common.OperationFailed, opState.Phase)
assert.Contains(t, opState.Message, syncErrorMsg)
assert.Equal(t, synccommon.OperationFailed, opState.Phase)
assert.Contains(t, opState.Message, "ConfigMap/configmap1 is part of applications fake-argocd-ns/my-app and guestbook")
})
}
@@ -315,13 +336,13 @@ func TestSyncWindowDeniesSync(t *testing.T) {
Source: &v1alpha1.ApplicationSource{},
},
},
Phase: common.OperationRunning,
Phase: synccommon.OperationRunning,
}
// when
f.controller.appStateManager.SyncAppState(f.application, opState)
// then
assert.Equal(t, common.OperationRunning, opState.Phase)
assert.Equal(t, synccommon.OperationRunning, opState.Phase)
assert.Contains(t, opState.Message, opMessage)
})
}
@@ -651,6 +672,7 @@ func TestDeriveServiceAccountMatchingNamespaces(t *testing.T) {
type fixture struct {
project *v1alpha1.AppProject
application *v1alpha1.Application
cluster *v1alpha1.Cluster
}
setup := func(destinationServiceAccounts []v1alpha1.ApplicationDestinationServiceAccount, destinationNamespace, destinationServerURL, applicationNamespace string) *fixture {
@@ -676,9 +698,14 @@ func TestDeriveServiceAccountMatchingNamespaces(t *testing.T) {
},
},
}
cluster := &v1alpha1.Cluster{
Server: "https://kubernetes.svc.local",
Name: "test-cluster",
}
return &fixture{
project: project,
application: app,
cluster: cluster,
}
}
@@ -694,7 +721,7 @@ func TestDeriveServiceAccountMatchingNamespaces(t *testing.T) {
f := setup(destinationServiceAccounts, destinationNamespace, destinationServerURL, applicationNamespace)
// when
sa, err := deriveServiceAccountToImpersonate(f.project, f.application)
sa, err := deriveServiceAccountToImpersonate(f.project, f.application, f.cluster)
assert.Equal(t, expectedSA, sa)
// then, there should be an error saying no valid match was found
@@ -718,7 +745,7 @@ func TestDeriveServiceAccountMatchingNamespaces(t *testing.T) {
f := setup(destinationServiceAccounts, destinationNamespace, destinationServerURL, applicationNamespace)
// when
sa, err := deriveServiceAccountToImpersonate(f.project, f.application)
sa, err := deriveServiceAccountToImpersonate(f.project, f.application, f.cluster)
// then, there should be no error and should use the right service account for impersonation
require.NoError(t, err)
@@ -757,7 +784,7 @@ func TestDeriveServiceAccountMatchingNamespaces(t *testing.T) {
f := setup(destinationServiceAccounts, destinationNamespace, destinationServerURL, applicationNamespace)
// when
sa, err := deriveServiceAccountToImpersonate(f.project, f.application)
sa, err := deriveServiceAccountToImpersonate(f.project, f.application, f.cluster)
// then, there should be no error and should use the right service account for impersonation
require.NoError(t, err)
@@ -796,7 +823,7 @@ func TestDeriveServiceAccountMatchingNamespaces(t *testing.T) {
f := setup(destinationServiceAccounts, destinationNamespace, destinationServerURL, applicationNamespace)
// when
sa, err := deriveServiceAccountToImpersonate(f.project, f.application)
sa, err := deriveServiceAccountToImpersonate(f.project, f.application, f.cluster)
// then, there should be no error and it should use the first matching service account for impersonation
require.NoError(t, err)
@@ -830,7 +857,7 @@ func TestDeriveServiceAccountMatchingNamespaces(t *testing.T) {
f := setup(destinationServiceAccounts, destinationNamespace, destinationServerURL, applicationNamespace)
// when
sa, err := deriveServiceAccountToImpersonate(f.project, f.application)
sa, err := deriveServiceAccountToImpersonate(f.project, f.application, f.cluster)
// then, there should not be any error and should use the first matching glob pattern service account for impersonation
require.NoError(t, err)
@@ -865,7 +892,7 @@ func TestDeriveServiceAccountMatchingNamespaces(t *testing.T) {
f := setup(destinationServiceAccounts, destinationNamespace, destinationServerURL, applicationNamespace)
// when
sa, err := deriveServiceAccountToImpersonate(f.project, f.application)
sa, err := deriveServiceAccountToImpersonate(f.project, f.application, f.cluster)
// then, there should be an error saying no match was found
require.EqualError(t, err, expectedErrMsg)
@@ -893,7 +920,7 @@ func TestDeriveServiceAccountMatchingNamespaces(t *testing.T) {
f := setup(destinationServiceAccounts, destinationNamespace, destinationServerURL, applicationNamespace)
// when
sa, err := deriveServiceAccountToImpersonate(f.project, f.application)
sa, err := deriveServiceAccountToImpersonate(f.project, f.application, f.cluster)
// then, there should not be any error and the service account configured for with empty namespace should be used.
require.NoError(t, err)
@@ -927,7 +954,7 @@ func TestDeriveServiceAccountMatchingNamespaces(t *testing.T) {
f := setup(destinationServiceAccounts, destinationNamespace, destinationServerURL, applicationNamespace)
// when
sa, err := deriveServiceAccountToImpersonate(f.project, f.application)
sa, err := deriveServiceAccountToImpersonate(f.project, f.application, f.cluster)
// then, there should not be any error and the catch all service account should be returned
require.NoError(t, err)
@@ -951,7 +978,7 @@ func TestDeriveServiceAccountMatchingNamespaces(t *testing.T) {
f := setup(destinationServiceAccounts, destinationNamespace, destinationServerURL, applicationNamespace)
// when
sa, err := deriveServiceAccountToImpersonate(f.project, f.application)
sa, err := deriveServiceAccountToImpersonate(f.project, f.application, f.cluster)
// then, there must be an error as the glob pattern is invalid.
require.ErrorContains(t, err, "invalid glob pattern for destination namespace")
@@ -985,7 +1012,35 @@ func TestDeriveServiceAccountMatchingNamespaces(t *testing.T) {
f := setup(destinationServiceAccounts, destinationNamespace, destinationServerURL, applicationNamespace)
// when
sa, err := deriveServiceAccountToImpersonate(f.project, f.application)
sa, err := deriveServiceAccountToImpersonate(f.project, f.application, f.cluster)
assert.Equal(t, expectedSA, sa)
// then, there should not be any error and the service account with its namespace should be returned.
require.NoError(t, err)
})
t.Run("app destination name instead of server URL", func(t *testing.T) {
t.Parallel()
destinationServiceAccounts := []v1alpha1.ApplicationDestinationServiceAccount{
{
Server: "https://kubernetes.svc.local",
Namespace: "*",
DefaultServiceAccount: "test-sa",
},
}
destinationNamespace := "testns"
destinationServerURL := "https://kubernetes.svc.local"
applicationNamespace := "argocd-ns"
expectedSA := "system:serviceaccount:testns:test-sa"
f := setup(destinationServiceAccounts, destinationNamespace, destinationServerURL, applicationNamespace)
// Use destination name instead of server URL
f.application.Spec.Destination.Server = ""
f.application.Spec.Destination.Name = f.cluster.Name
// when
sa, err := deriveServiceAccountToImpersonate(f.project, f.application, f.cluster)
assert.Equal(t, expectedSA, sa)
// then, there should not be any error and the service account with its namespace should be returned.
@@ -999,6 +1054,7 @@ func TestDeriveServiceAccountMatchingServers(t *testing.T) {
type fixture struct {
project *v1alpha1.AppProject
application *v1alpha1.Application
cluster *v1alpha1.Cluster
}
setup := func(destinationServiceAccounts []v1alpha1.ApplicationDestinationServiceAccount, destinationNamespace, destinationServerURL, applicationNamespace string) *fixture {
@@ -1024,9 +1080,14 @@ func TestDeriveServiceAccountMatchingServers(t *testing.T) {
},
},
}
cluster := &v1alpha1.Cluster{
Server: "https://kubernetes.svc.local",
Name: "test-cluster",
}
return &fixture{
project: project,
application: app,
cluster: cluster,
}
}
@@ -1062,7 +1123,7 @@ func TestDeriveServiceAccountMatchingServers(t *testing.T) {
f := setup(destinationServiceAccounts, destinationNamespace, destinationServerURL, applicationNamespace)
// when
sa, err := deriveServiceAccountToImpersonate(f.project, f.application)
sa, err := deriveServiceAccountToImpersonate(f.project, f.application, f.cluster)
// then, there should not be any error and the right service account must be returned.
require.NoError(t, err)
@@ -1101,7 +1162,7 @@ func TestDeriveServiceAccountMatchingServers(t *testing.T) {
f := setup(destinationServiceAccounts, destinationNamespace, destinationServerURL, applicationNamespace)
// when
sa, err := deriveServiceAccountToImpersonate(f.project, f.application)
sa, err := deriveServiceAccountToImpersonate(f.project, f.application, f.cluster)
// then, there should not be any error and first matching service account should be used
require.NoError(t, err)
@@ -1135,7 +1196,7 @@ func TestDeriveServiceAccountMatchingServers(t *testing.T) {
f := setup(destinationServiceAccounts, destinationNamespace, destinationServerURL, applicationNamespace)
// when
sa, err := deriveServiceAccountToImpersonate(f.project, f.application)
sa, err := deriveServiceAccountToImpersonate(f.project, f.application, f.cluster)
assert.Equal(t, expectedSA, sa)
// then, there should not be any error and the service account of the glob pattern, being the first match should be returned.
@@ -1170,7 +1231,7 @@ func TestDeriveServiceAccountMatchingServers(t *testing.T) {
f := setup(destinationServiceAccounts, destinationNamespace, destinationServerURL, applicationNamespace)
// when
sa, err := deriveServiceAccountToImpersonate(f.project, f.application)
sa, err := deriveServiceAccountToImpersonate(f.project, f.application, &v1alpha1.Cluster{Server: destinationServerURL})
// then, there an error with appropriate message must be returned
require.EqualError(t, err, expectedErr)
@@ -1204,7 +1265,7 @@ func TestDeriveServiceAccountMatchingServers(t *testing.T) {
f := setup(destinationServiceAccounts, destinationNamespace, destinationServerURL, applicationNamespace)
// when
sa, err := deriveServiceAccountToImpersonate(f.project, f.application)
sa, err := deriveServiceAccountToImpersonate(f.project, f.application, f.cluster)
// then, there should not be any error and the service account of the glob pattern match must be returned.
require.NoError(t, err)
@@ -1228,7 +1289,7 @@ func TestDeriveServiceAccountMatchingServers(t *testing.T) {
f := setup(destinationServiceAccounts, destinationNamespace, destinationServerURL, applicationNamespace)
// when
sa, err := deriveServiceAccountToImpersonate(f.project, f.application)
sa, err := deriveServiceAccountToImpersonate(f.project, f.application, f.cluster)
// then, there must be an error as the glob pattern is invalid.
require.ErrorContains(t, err, "invalid glob pattern for destination server")
@@ -1262,12 +1323,40 @@ func TestDeriveServiceAccountMatchingServers(t *testing.T) {
f := setup(destinationServiceAccounts, destinationNamespace, destinationServerURL, applicationNamespace)
// when
sa, err := deriveServiceAccountToImpersonate(f.project, f.application)
sa, err := deriveServiceAccountToImpersonate(f.project, f.application, &v1alpha1.Cluster{Server: destinationServerURL})
// then, there should not be any error and the service account with the given namespace prefix must be returned.
require.NoError(t, err)
assert.Equal(t, expectedSA, sa)
})
t.Run("app destination name instead of server URL", func(t *testing.T) {
t.Parallel()
destinationServiceAccounts := []v1alpha1.ApplicationDestinationServiceAccount{
{
Server: "https://kubernetes.svc.local",
Namespace: "*",
DefaultServiceAccount: "test-sa",
},
}
destinationNamespace := "testns"
destinationServerURL := "https://kubernetes.svc.local"
applicationNamespace := "argocd-ns"
expectedSA := "system:serviceaccount:testns:test-sa"
f := setup(destinationServiceAccounts, destinationNamespace, destinationServerURL, applicationNamespace)
// Use destination name instead of server URL
f.application.Spec.Destination.Server = ""
f.application.Spec.Destination.Name = f.cluster.Name
// when
sa, err := deriveServiceAccountToImpersonate(f.project, f.application, f.cluster)
assert.Equal(t, expectedSA, sa)
// then, there should not be any error and the service account with its namespace should be returned.
require.NoError(t, err)
})
}
func TestSyncWithImpersonate(t *testing.T) {
@@ -1337,13 +1426,13 @@ func TestSyncWithImpersonate(t *testing.T) {
Source: &v1alpha1.ApplicationSource{},
},
},
Phase: common.OperationRunning,
Phase: synccommon.OperationRunning,
}
// when
f.controller.appStateManager.SyncAppState(f.application, opState)
// then, app sync should fail with expected error message in operation state
assert.Equal(t, common.OperationError, opState.Phase)
assert.Equal(t, synccommon.OperationError, opState.Phase)
assert.Contains(t, opState.Message, opMessage)
})
@@ -1358,13 +1447,13 @@ func TestSyncWithImpersonate(t *testing.T) {
Source: &v1alpha1.ApplicationSource{},
},
},
Phase: common.OperationRunning,
Phase: synccommon.OperationRunning,
}
// when
f.controller.appStateManager.SyncAppState(f.application, opState)
// then app sync should fail with expected error message in operation state
assert.Equal(t, common.OperationError, opState.Phase)
assert.Equal(t, synccommon.OperationError, opState.Phase)
assert.Contains(t, opState.Message, opMessage)
})
@@ -1379,13 +1468,13 @@ func TestSyncWithImpersonate(t *testing.T) {
Source: &v1alpha1.ApplicationSource{},
},
},
Phase: common.OperationRunning,
Phase: synccommon.OperationRunning,
}
// when
f.controller.appStateManager.SyncAppState(f.application, opState)
// then app sync should not fail
assert.Equal(t, common.OperationSucceeded, opState.Phase)
assert.Equal(t, synccommon.OperationSucceeded, opState.Phase)
assert.Contains(t, opState.Message, opMessage)
})
@@ -1400,13 +1489,38 @@ func TestSyncWithImpersonate(t *testing.T) {
Source: &v1alpha1.ApplicationSource{},
},
},
Phase: common.OperationRunning,
Phase: synccommon.OperationRunning,
}
// when
f.controller.appStateManager.SyncAppState(f.application, opState)
// then application sync should pass using the control plane service account
assert.Equal(t, common.OperationSucceeded, opState.Phase)
assert.Equal(t, synccommon.OperationSucceeded, opState.Phase)
assert.Contains(t, opState.Message, opMessage)
})
t.Run("app destination name instead of server URL", func(t *testing.T) {
// given app sync impersonation feature is enabled with an application referring a project matching service account
f := setup(true, test.FakeDestNamespace, "test-sa")
opMessage := "successfully synced (no more tasks)"
opState := &v1alpha1.OperationState{
Operation: v1alpha1.Operation{
Sync: &v1alpha1.SyncOperation{
Source: &v1alpha1.ApplicationSource{},
},
},
Phase: synccommon.OperationRunning,
}
f.application.Spec.Destination.Server = ""
f.application.Spec.Destination.Name = "minikube"
// when
f.controller.appStateManager.SyncAppState(f.application, opState)
// then app sync should not fail
assert.Equal(t, synccommon.OperationSucceeded, opState.Phase)
assert.Contains(t, opState.Message, opMessage)
})
}
@@ -1474,7 +1588,7 @@ func TestClientSideApplyMigration(t *testing.T) {
f.controller.appStateManager.SyncAppState(f.application, opState)
// then
assert.Equal(t, common.OperationSucceeded, opState.Phase)
assert.Equal(t, synccommon.OperationSucceeded, opState.Phase)
assert.Contains(t, opState.Message, "successfully synced")
})
@@ -1492,7 +1606,7 @@ func TestClientSideApplyMigration(t *testing.T) {
f.controller.appStateManager.SyncAppState(f.application, opState)
// then
assert.Equal(t, common.OperationSucceeded, opState.Phase)
assert.Equal(t, synccommon.OperationSucceeded, opState.Phase)
assert.Contains(t, opState.Message, "successfully synced")
})
@@ -1510,7 +1624,7 @@ func TestClientSideApplyMigration(t *testing.T) {
f.controller.appStateManager.SyncAppState(f.application, opState)
// then
assert.Equal(t, common.OperationSucceeded, opState.Phase)
assert.Equal(t, synccommon.OperationSucceeded, opState.Phase)
assert.Contains(t, opState.Message, "successfully synced")
})
}

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 |
|-----------------|---------------------|
| 3.1 | v1.33, v1.32, v1.31, v1.30 |
| 3.0 | v1.32, v1.31, v1.30, v1.29 |
| 2.14 | v1.31, v1.30, v1.29, v1.28 |

View File

@@ -7,6 +7,13 @@ applicable) restore Argo CD 2.x default behavior.
Once 3.0 is released, no more 2.x minor versions will be released. We will continue to cut patch releases for the two
most recent minor versions (so 2.14 until 3.2 is released and 2.13 until 3.1 is released).
## Images missing release notes on GitHub
!!! important
Images 3.0.7 - 3.0.9 are missing release notes on GitHub. There was an issue with GoReleaser and building the darwin
CLI that prevented the release notes from being published. More information can be found
on [PR #23507](https://github.com/argoproj/argo-cd/pull/23507)
## Breaking Changes
### Fine-Grained RBAC for application `update` and `delete` sub-resources

View File

@@ -20,6 +20,28 @@ The `--staticassets` directory in the API server (`/app/shared` by default) is n
symlinks. This is to help protect against symlink attacks. If you have any symlinks in your `--staticassets` directory
to a location outside the directory, they will return a 500 error starting with 3.1.
## v1 Actions API Deprecated
The `/api/v1/applications/{name}/resource/actions` endpoint is deprecated in favor of `/api/v1/applications/{name}/resource/actions/v2`.
This endpoint allows API users to run a custom resource action on a specific resource in an application.
The old endpoint accepted various parameters as query parameters. The POST body was the action name.
The new endpoint accepts all parameters as part of the POST body as a JSON object. The new endpoint also supports a new
`resourceActionParameters` field to parameterize action runs.
The old endpoint will be removed in a future release, so users should migrate to the new endpoint as soon as possible.
API clients will just need to change the endpoint URL and switch query string parameters to a JSON body.
If the old endpoint is used, the API will log a warning message:
> RunResourceAction was called. RunResourceAction is deprecated and will be removed in a future release. Use RunResourceActionV2 instead.
The CLI will fall back to the old endpoint if the new one is not available. If it falls back, it will log a warning message:
> RunResourceActionV2 is not supported by the server, falling back to RunResourceAction.
## OpenID Connect authorization code flow with PKCE is now handled by the server instead of the UI
Previously, when PKCE was enabled, the authorization code flow (the process which happens when you log in to Argo CD using OpenID Connect) was handled by the UI, whereas this flow was handled by the server if PKCE was not enabled. The server now always handles this flow, PKCE being enabled or not.
@@ -37,3 +59,13 @@ If it returns `"enablePKCEAuthentication": true`, then PKCE is used.
### Remediation
On your identity provider, ensure that the OIDC client used for Argo CD has the `/auth/callback` endpoint of your Argo CD URL (e.g. https://argocd.example.com/auth/callback) in the redirect URIs.
## Helm Upgraded to 3.18.4
Argo CD v3.1 upgrades the bundled Helm version to 3.18.4. There are no breaking changes in Helm 3.18 according to the
[release notes](https://github.com/helm/helm/releases/tag/v3.18.0).
## Kustomize Upgraded to 5.7.0
Argo CD v3.1 upgrades the bundled Kustomize version to 5.7.0. There are no breaking changes in Kustomize 5.7 according
to the [release notes](https://github.com/kubernetes-sigs/kustomize/releases/tag/kustomize%2Fv5.7.0).

View File

@@ -230,6 +230,12 @@ The commit metadata will appear in the hydrated commit's root hydrator.metadata
```json
{
"author": "CI <ci@example.com>",
"subject": "chore: bump image to b82add2",
"date": "2025-06-09T13:50:08-04:00",
"body": "Signed-off-by: CI <ci@example.com>\n",
"drySha": "6cb951525937865dced818bbdd78c89b2d2b3045",
"repoURL": "https://git.example.com/owner/manifests-repo",
"references": [
{
"commit": {
@@ -248,6 +254,10 @@ The commit metadata will appear in the hydrated commit's root hydrator.metadata
}
```
The top-level "body" field contains the commit message of the DRY commit minus the subject line and any
`Argocd-reference-commit-*` trailers that were used in `references`. Unrecognized or invalid trailers are preserved in
the body.
Although `references` is an array, the source hydrator currently only supports a single related commit. If a trailer is
specified more than once, the last one will be used.

View File

@@ -1,12 +1,19 @@
#!/usr/bin/env sh
# Usage: ./add-helm-checksums.sh 3.9.4 # use the desired version
# Usage: ./add-helm-checksums.sh <helm-version> # use the desired version e.g. 3.18.4
set -e
for arch in amd64 arm64 ppc64le s390x; do
wget "https://get.helm.sh/helm-v$1-linux-$arch.tar.gz.sha256sum" -O "helm-v$1-linux-$arch.tar.gz.sha256"
checksumfile="helm-v$1-linux-$arch.tar.gz.sha256"
wget "https://get.helm.sh/helm-v$1-linux-$arch.tar.gz.sha256sum" -O "$checksumfile"
outname="$(git rev-parse --show-toplevel)/hack/installers/checksums/helm-v$1-linux-$arch.tar.gz.sha256"
mv $checksumfile $outname
done
for arch in amd64 arm64; do
wget "https://get.helm.sh/helm-v$1-darwin-$arch.tar.gz.sha256sum" -O "helm-v$1-darwin-$arch.tar.gz.sha256"
checksumfile="helm-v$1-darwin-$arch.tar.gz.sha256"
wget "https://get.helm.sh/helm-v$1-darwin-$arch.tar.gz.sha256sum" -O "$checksumfile"
outname="$(git rev-parse --show-toplevel)/hack/installers/checksums/helm-v$1-darwin-$arch.tar.gz.sha256"
mv $checksumfile $outname
done

View File

@@ -0,0 +1 @@
d186851d40b1999c5d75696bc0b754e4d29e860c8d0cf4c132ac1b1940c5cffc helm-v3.18.3-darwin-amd64.tar.gz

View File

@@ -0,0 +1 @@
3fe3e9739ab3c75d88bfe13e464a79a2a7a804fc692c3258fa6a9d185d53e377 helm-v3.18.3-darwin-arm64.tar.gz

View File

@@ -0,0 +1 @@
6ec85f306dd8fe9eb05c61ba4593182b2afcfefb52f21add3fe043ebbdc48e39 helm-v3.18.3-linux-amd64.tar.gz

View File

@@ -0,0 +1 @@
3382ebdc6d6e027371551a63fc6e0a3073a1aec1061e346692932da61cfd8d24 helm-v3.18.3-linux-arm64.tar.gz

View File

@@ -0,0 +1 @@
ca5ab0bb205488276095881f04b72bfed5c0ddb92f715940dde6a7ccae72818c helm-v3.18.3-linux-ppc64le.tar.gz

View File

@@ -0,0 +1 @@
be261f040b59c04ad4f1ce6fc2f976e500167475cadb468bf78cb9772300fb5d helm-v3.18.3-linux-s390x.tar.gz

View File

@@ -0,0 +1 @@
860a7238285b44b5dc7b3c4dad6194316885d7015d77c34e23177e0e9554af8f helm-v3.18.4-darwin-amd64.tar.gz

View File

@@ -0,0 +1 @@
041849741550b20710d7ad0956e805ebd960b483fe978864f8e7fdd03ca84ec8 helm-v3.18.4-darwin-arm64.tar.gz

View File

@@ -0,0 +1 @@
f8180838c23d7c7d797b208861fecb591d9ce1690d8704ed1e4cb8e2add966c1 helm-v3.18.4-linux-amd64.tar.gz

View File

@@ -0,0 +1 @@
c0a45e67eef0c7416a8a8c9e9d5d2d30d70e4f4d3f7bea5de28241fffa8f3b89 helm-v3.18.4-linux-arm64.tar.gz

View File

@@ -0,0 +1 @@
dbd74c59e7710f26e058596723abbf73662b553e01f40dfb08508ffffaeb7b81 helm-v3.18.4-linux-ppc64le.tar.gz

View File

@@ -0,0 +1 @@
c8bafb34bcebd53494f0223239977e1ff7b487e714598a5843a0cb1788e20075 helm-v3.18.4-linux-s390x.tar.gz

View File

@@ -0,0 +1 @@
277a7401f969ce3945e8f0ff8b0cce6f4353854db1ff89ba070001e3246e7f22 kustomize_5.7.0_darwin_amd64.tar.gz

View File

@@ -0,0 +1 @@
c0dac68dc7870e1f673ae4d8fb554df971e0b9b9f0affc4be4c0852f62d0796e kustomize_5.7.0_darwin_arm64.tar.gz

View File

@@ -0,0 +1 @@
0d98f06d6d2c2c0ff8923cc136a517af74aaa187f1b9f3e17ff370d0625ede84 kustomize_5.7.0_linux_amd64.tar.gz

View File

@@ -0,0 +1 @@
744bb1bc1854b6634dea9eaf6db2f401a734ed25d6837baa6f91157d79c27d5e kustomize_5.7.0_linux_arm64.tar.gz

View File

@@ -0,0 +1 @@
752e750d5f349156ea228ae01cf57be22e6cc29f0f05748a1bca7fa870393561 kustomize_5.7.0_linux_ppc64le.tar.gz

View File

@@ -0,0 +1 @@
64898beb154a111c1a98f8cff066fdfa866c4c73505e9a9b5fa6ec39f0292558 kustomize_5.7.0_linux_s390x.tar.gz

View File

@@ -11,7 +11,7 @@
# Use ./hack/installers/checksums/add-helm-checksums.sh and
# add-kustomize-checksums.sh to help download checksums.
###############################################################################
helm3_version=3.17.1
kustomize5_version=5.6.0
helm3_version=3.18.4
kustomize5_version=5.7.0
protoc_version=29.3
oras_version=1.2.0

View File

@@ -3,25 +3,22 @@
out="| Argo CD version | Kubernetes versions |\n"
out+="|-----------------|---------------------|\n"
argocd_minor_version=$(git rev-parse --abbrev-ref HEAD | sed 's/release-//')
argocd_major_version_num=$(echo "$argocd_minor_version" | sed -E 's/\.[0-9]+//')
argocd_minor_version_num=$(echo "$argocd_minor_version" | sed -E 's/[0-9]+\.//')
argocd_current_version=$(git rev-parse --abbrev-ref HEAD | sed 's/release-//')
argocd_major_version_num=$(echo "$argocd_current_version" | sed -E 's/\.[0-9]+//')
argocd_minor_version_num=$(echo "$argocd_current_version" | sed -E 's/[0-9]+\.//')
minor_version_decrement=0
for _ in {1..3}; do
minor_version_num=$((argocd_minor_version_num - minor_version_decrement))
minor_version="${argocd_major_version_num}.${minor_version_num}"
git checkout "release-$minor_version" > /dev/null || exit 1
argocd_version="${argocd_major_version_num}.${argocd_minor_version_num}"
git checkout "release-$argocd_version" > /dev/null || exit 1
line=$(yq '.jobs["test-e2e"].strategy.matrix |
# k3s-version was an array prior to 2.12. This checks for the old format first and then falls back to the new format.
(.["k3s-version"] // (.k3s | map(.version))) |
.[]' .github/workflows/ci-build.yaml | \
jq --arg minor_version "$minor_version" --raw-input --slurp --raw-output \
'split("\n")[:-1] | map(sub("\\.[0-9]+$"; "")) | join(", ") | "| \($minor_version) | \(.) |"')
jq --arg argocd_version "$argocd_version" --raw-input --slurp --raw-output \
'split("\n")[:-1] | map(sub("\\.[0-9]+$"; "")) | join(", ") | "| \($argocd_version) | \(.) |"')
out+="$line\n"
minor_version_decrement=$((minor_version_decrement + 1))
# If we're at minor version 0, there's no further version back in this series. Instead, move to the latest version in
# the previous major release series.
@@ -29,13 +26,11 @@ for _ in {1..3}; do
argocd_major_version_num=$((argocd_major_version_num - 1))
# Get the latest minor version in the previous series.
argocd_minor_version_num=$(git tag -l "v$argocd_major_version_num.*" | sort -V | tail -n 1 | sed -E 's/\.[0-9]+$//' | sed -E 's/^v[0-9]+\.//')
# Don't decrement the minor version, since we're switching to the previous major release series. We want the latest
# minor version in that series.
minor_version_decrement=0
else
argocd_minor_version_num=$((argocd_minor_version_num - 1))
fi
done
git checkout "release-$argocd_minor_version"
git checkout "release-$argocd_current_version"
printf "$out" > docs/operator-manual/tested-kubernetes-versions.md

View File

@@ -253,6 +253,12 @@ spec:
name: argocd-cmd-params-cm
key: controller.cluster.cache.events.processing.interval
optional: true
- name: ARGOCD_APPLICATION_CONTROLLER_COMMIT_SERVER
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: commit.server
optional: true
image: quay.io/argoproj/argocd:latest
imagePullPolicy: Always
name: argocd-application-controller

View File

@@ -268,6 +268,12 @@ spec:
name: argocd-cmd-params-cm
key: controller.cluster.cache.events.processing.interval
optional: true
- name: ARGOCD_APPLICATION_CONTROLLER_COMMIT_SERVER
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: commit.server
optional: true
- name: KUBECACHEDIR
value: /tmp/kubecache
image: quay.io/argoproj/argocd:latest

View File

@@ -12,4 +12,4 @@ resources:
images:
- name: quay.io/argoproj/argocd
newName: quay.io/argoproj/argocd
newTag: latest
newTag: v3.1.0-rc3

View File

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

View File

@@ -24699,7 +24699,7 @@ spec:
key: applicationsetcontroller.requeue.after
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: Always
name: argocd-applicationset-controller
ports:
@@ -24825,7 +24825,7 @@ spec:
key: log.format.timestamp
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
@@ -24953,7 +24953,7 @@ spec:
- argocd
- admin
- redis-initial-password
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: IfNotPresent
name: secret-init
securityContext:
@@ -25226,7 +25226,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:v3.1.0-rc3
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
@@ -25278,7 +25278,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /var/run/argocd/argocd-cmp-server
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
name: copyutil
securityContext:
allowPrivilegeEscalation: false
@@ -25612,9 +25612,15 @@ spec:
key: controller.cluster.cache.events.processing.interval
name: argocd-cmd-params-cm
optional: true
- name: ARGOCD_APPLICATION_CONTROLLER_COMMIT_SERVER
valueFrom:
configMapKeyRef:
key: commit.server
name: argocd-cmd-params-cm
optional: true
- name: KUBECACHEDIR
value: /tmp/kubecache
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: Always
name: argocd-application-controller
ports:

View File

@@ -24667,7 +24667,7 @@ spec:
key: applicationsetcontroller.requeue.after
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: Always
name: argocd-applicationset-controller
ports:
@@ -24787,7 +24787,7 @@ spec:
- argocd
- admin
- redis-initial-password
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: IfNotPresent
name: secret-init
securityContext:
@@ -25060,7 +25060,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:v3.1.0-rc3
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
@@ -25112,7 +25112,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /var/run/argocd/argocd-cmp-server
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
name: copyutil
securityContext:
allowPrivilegeEscalation: false
@@ -25446,9 +25446,15 @@ spec:
key: controller.cluster.cache.events.processing.interval
name: argocd-cmd-params-cm
optional: true
- name: ARGOCD_APPLICATION_CONTROLLER_COMMIT_SERVER
valueFrom:
configMapKeyRef:
key: commit.server
name: argocd-cmd-params-cm
optional: true
- name: KUBECACHEDIR
value: /tmp/kubecache
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
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: v3.1.0-rc3

View File

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

View File

@@ -26065,7 +26065,7 @@ spec:
key: applicationsetcontroller.requeue.after
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: Always
name: argocd-applicationset-controller
ports:
@@ -26191,7 +26191,7 @@ spec:
key: log.format.timestamp
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
@@ -26342,7 +26342,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /shared/argocd-dex
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: Always
name: copyutil
securityContext:
@@ -26438,7 +26438,7 @@ spec:
key: notificationscontroller.repo.server.plaintext
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: Always
livenessProbe:
tcpSocket:
@@ -26562,7 +26562,7 @@ spec:
- argocd
- admin
- redis-initial-password
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: IfNotPresent
name: secret-init
securityContext:
@@ -26861,7 +26861,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:v3.1.0-rc3
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
@@ -26913,7 +26913,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /var/run/argocd/argocd-cmp-server
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
name: copyutil
securityContext:
allowPrivilegeEscalation: false
@@ -27287,7 +27287,7 @@ spec:
key: server.sync.replace.allowed
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -27657,9 +27657,15 @@ spec:
key: controller.cluster.cache.events.processing.interval
name: argocd-cmd-params-cm
optional: true
- name: ARGOCD_APPLICATION_CONTROLLER_COMMIT_SERVER
valueFrom:
configMapKeyRef:
key: commit.server
name: argocd-cmd-params-cm
optional: true
- name: KUBECACHEDIR
value: /tmp/kubecache
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: Always
name: argocd-application-controller
ports:

View File

@@ -26035,7 +26035,7 @@ spec:
key: applicationsetcontroller.requeue.after
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: Always
name: argocd-applicationset-controller
ports:
@@ -26178,7 +26178,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /shared/argocd-dex
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: Always
name: copyutil
securityContext:
@@ -26274,7 +26274,7 @@ spec:
key: notificationscontroller.repo.server.plaintext
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: Always
livenessProbe:
tcpSocket:
@@ -26398,7 +26398,7 @@ spec:
- argocd
- admin
- redis-initial-password
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: IfNotPresent
name: secret-init
securityContext:
@@ -26697,7 +26697,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:v3.1.0-rc3
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
@@ -26749,7 +26749,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /var/run/argocd/argocd-cmp-server
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
name: copyutil
securityContext:
allowPrivilegeEscalation: false
@@ -27123,7 +27123,7 @@ spec:
key: server.sync.replace.allowed
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -27493,9 +27493,15 @@ spec:
key: controller.cluster.cache.events.processing.interval
name: argocd-cmd-params-cm
optional: true
- name: ARGOCD_APPLICATION_CONTROLLER_COMMIT_SERVER
valueFrom:
configMapKeyRef:
key: commit.server
name: argocd-cmd-params-cm
optional: true
- name: KUBECACHEDIR
value: /tmp/kubecache
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: Always
name: argocd-application-controller
ports:

View File

@@ -1868,7 +1868,7 @@ spec:
key: applicationsetcontroller.requeue.after
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: Always
name: argocd-applicationset-controller
ports:
@@ -1994,7 +1994,7 @@ spec:
key: log.format.timestamp
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
@@ -2145,7 +2145,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /shared/argocd-dex
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: Always
name: copyutil
securityContext:
@@ -2241,7 +2241,7 @@ spec:
key: notificationscontroller.repo.server.plaintext
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: Always
livenessProbe:
tcpSocket:
@@ -2365,7 +2365,7 @@ spec:
- argocd
- admin
- redis-initial-password
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: IfNotPresent
name: secret-init
securityContext:
@@ -2664,7 +2664,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:v3.1.0-rc3
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
@@ -2716,7 +2716,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /var/run/argocd/argocd-cmp-server
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
name: copyutil
securityContext:
allowPrivilegeEscalation: false
@@ -3090,7 +3090,7 @@ spec:
key: server.sync.replace.allowed
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -3460,9 +3460,15 @@ spec:
key: controller.cluster.cache.events.processing.interval
name: argocd-cmd-params-cm
optional: true
- name: ARGOCD_APPLICATION_CONTROLLER_COMMIT_SERVER
valueFrom:
configMapKeyRef:
key: commit.server
name: argocd-cmd-params-cm
optional: true
- name: KUBECACHEDIR
value: /tmp/kubecache
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: Always
name: argocd-application-controller
ports:

View File

@@ -1838,7 +1838,7 @@ spec:
key: applicationsetcontroller.requeue.after
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: Always
name: argocd-applicationset-controller
ports:
@@ -1981,7 +1981,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /shared/argocd-dex
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: Always
name: copyutil
securityContext:
@@ -2077,7 +2077,7 @@ spec:
key: notificationscontroller.repo.server.plaintext
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: Always
livenessProbe:
tcpSocket:
@@ -2201,7 +2201,7 @@ spec:
- argocd
- admin
- redis-initial-password
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: IfNotPresent
name: secret-init
securityContext:
@@ -2500,7 +2500,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:v3.1.0-rc3
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
@@ -2552,7 +2552,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /var/run/argocd/argocd-cmp-server
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
name: copyutil
securityContext:
allowPrivilegeEscalation: false
@@ -2926,7 +2926,7 @@ spec:
key: server.sync.replace.allowed
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -3296,9 +3296,15 @@ spec:
key: controller.cluster.cache.events.processing.interval
name: argocd-cmd-params-cm
optional: true
- name: ARGOCD_APPLICATION_CONTROLLER_COMMIT_SERVER
valueFrom:
configMapKeyRef:
key: commit.server
name: argocd-cmd-params-cm
optional: true
- name: KUBECACHEDIR
value: /tmp/kubecache
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: Always
name: argocd-application-controller
ports:

View File

@@ -25159,7 +25159,7 @@ spec:
key: applicationsetcontroller.requeue.after
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: Always
name: argocd-applicationset-controller
ports:
@@ -25285,7 +25285,7 @@ spec:
key: log.format.timestamp
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
@@ -25436,7 +25436,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /shared/argocd-dex
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: Always
name: copyutil
securityContext:
@@ -25532,7 +25532,7 @@ spec:
key: notificationscontroller.repo.server.plaintext
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: Always
livenessProbe:
tcpSocket:
@@ -25634,7 +25634,7 @@ spec:
- argocd
- admin
- redis-initial-password
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: IfNotPresent
name: secret-init
securityContext:
@@ -25907,7 +25907,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:v3.1.0-rc3
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
@@ -25959,7 +25959,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /var/run/argocd/argocd-cmp-server
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
name: copyutil
securityContext:
allowPrivilegeEscalation: false
@@ -26331,7 +26331,7 @@ spec:
key: server.sync.replace.allowed
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -26701,9 +26701,15 @@ spec:
key: controller.cluster.cache.events.processing.interval
name: argocd-cmd-params-cm
optional: true
- name: ARGOCD_APPLICATION_CONTROLLER_COMMIT_SERVER
valueFrom:
configMapKeyRef:
key: commit.server
name: argocd-cmd-params-cm
optional: true
- name: KUBECACHEDIR
value: /tmp/kubecache
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: Always
name: argocd-application-controller
ports:

22
manifests/install.yaml generated
View File

@@ -25127,7 +25127,7 @@ spec:
key: applicationsetcontroller.requeue.after
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: Always
name: argocd-applicationset-controller
ports:
@@ -25270,7 +25270,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /shared/argocd-dex
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: Always
name: copyutil
securityContext:
@@ -25366,7 +25366,7 @@ spec:
key: notificationscontroller.repo.server.plaintext
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: Always
livenessProbe:
tcpSocket:
@@ -25468,7 +25468,7 @@ spec:
- argocd
- admin
- redis-initial-password
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: IfNotPresent
name: secret-init
securityContext:
@@ -25741,7 +25741,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:v3.1.0-rc3
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
@@ -25793,7 +25793,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /var/run/argocd/argocd-cmp-server
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
name: copyutil
securityContext:
allowPrivilegeEscalation: false
@@ -26165,7 +26165,7 @@ spec:
key: server.sync.replace.allowed
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -26535,9 +26535,15 @@ spec:
key: controller.cluster.cache.events.processing.interval
name: argocd-cmd-params-cm
optional: true
- name: ARGOCD_APPLICATION_CONTROLLER_COMMIT_SERVER
valueFrom:
configMapKeyRef:
key: commit.server
name: argocd-cmd-params-cm
optional: true
- name: KUBECACHEDIR
value: /tmp/kubecache
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: Always
name: argocd-application-controller
ports:

View File

@@ -962,7 +962,7 @@ spec:
key: applicationsetcontroller.requeue.after
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: Always
name: argocd-applicationset-controller
ports:
@@ -1088,7 +1088,7 @@ spec:
key: log.format.timestamp
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
@@ -1239,7 +1239,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /shared/argocd-dex
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: Always
name: copyutil
securityContext:
@@ -1335,7 +1335,7 @@ spec:
key: notificationscontroller.repo.server.plaintext
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: Always
livenessProbe:
tcpSocket:
@@ -1437,7 +1437,7 @@ spec:
- argocd
- admin
- redis-initial-password
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: IfNotPresent
name: secret-init
securityContext:
@@ -1710,7 +1710,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:v3.1.0-rc3
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
@@ -1762,7 +1762,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /var/run/argocd/argocd-cmp-server
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
name: copyutil
securityContext:
allowPrivilegeEscalation: false
@@ -2134,7 +2134,7 @@ spec:
key: server.sync.replace.allowed
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -2504,9 +2504,15 @@ spec:
key: controller.cluster.cache.events.processing.interval
name: argocd-cmd-params-cm
optional: true
- name: ARGOCD_APPLICATION_CONTROLLER_COMMIT_SERVER
valueFrom:
configMapKeyRef:
key: commit.server
name: argocd-cmd-params-cm
optional: true
- name: KUBECACHEDIR
value: /tmp/kubecache
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: Always
name: argocd-application-controller
ports:

View File

@@ -930,7 +930,7 @@ spec:
key: applicationsetcontroller.requeue.after
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: Always
name: argocd-applicationset-controller
ports:
@@ -1073,7 +1073,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /shared/argocd-dex
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: Always
name: copyutil
securityContext:
@@ -1169,7 +1169,7 @@ spec:
key: notificationscontroller.repo.server.plaintext
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: Always
livenessProbe:
tcpSocket:
@@ -1271,7 +1271,7 @@ spec:
- argocd
- admin
- redis-initial-password
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: IfNotPresent
name: secret-init
securityContext:
@@ -1544,7 +1544,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:v3.1.0-rc3
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
@@ -1596,7 +1596,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /var/run/argocd/argocd-cmp-server
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
name: copyutil
securityContext:
allowPrivilegeEscalation: false
@@ -1968,7 +1968,7 @@ spec:
key: server.sync.replace.allowed
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -2338,9 +2338,15 @@ spec:
key: controller.cluster.cache.events.processing.interval
name: argocd-cmd-params-cm
optional: true
- name: ARGOCD_APPLICATION_CONTROLLER_COMMIT_SERVER
valueFrom:
configMapKeyRef:
key: commit.server
name: argocd-cmd-params-cm
optional: true
- name: KUBECACHEDIR
value: /tmp/kubecache
image: quay.io/argoproj/argocd:latest
image: quay.io/argoproj/argocd:v3.1.0-rc3
imagePullPolicy: Always
name: argocd-application-controller
ports:

File diff suppressed because it is too large Load Diff

View File

@@ -1715,6 +1715,10 @@ func local_request_ApplicationService_ListResourceActions_0(ctx context.Context,
}
var (
filter_ApplicationService_RunResourceAction_0 = &utilities.DoubleArray{Encoding: map[string]int{"action": 0, "name": 1}, Base: []int{1, 1, 2, 0, 0}, Check: []int{0, 1, 1, 2, 3}}
)
func request_ApplicationService_RunResourceAction_0(ctx context.Context, marshaler runtime.Marshaler, client ApplicationServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ResourceActionRunRequest
var metadata runtime.ServerMetadata
@@ -1723,7 +1727,7 @@ func request_ApplicationService_RunResourceAction_0(ctx context.Context, marshal
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.Action); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
@@ -1745,6 +1749,13 @@ func request_ApplicationService_RunResourceAction_0(ctx context.Context, marshal
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err)
}
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ApplicationService_RunResourceAction_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.RunResourceAction(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
@@ -1754,6 +1765,48 @@ func local_request_ApplicationService_RunResourceAction_0(ctx context.Context, m
var protoReq ResourceActionRunRequest
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.Action); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["name"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "name")
}
protoReq.Name, err = runtime.StringP(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err)
}
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ApplicationService_RunResourceAction_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.RunResourceAction(ctx, &protoReq)
return msg, metadata, err
}
func request_ApplicationService_RunResourceActionV2_0(ctx context.Context, marshaler runtime.Marshaler, client ApplicationServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ResourceActionRunRequestV2
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
@@ -1780,7 +1833,42 @@ func local_request_ApplicationService_RunResourceAction_0(ctx context.Context, m
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err)
}
msg, err := server.RunResourceAction(ctx, &protoReq)
msg, err := client.RunResourceActionV2(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_ApplicationService_RunResourceActionV2_0(ctx context.Context, marshaler runtime.Marshaler, server ApplicationServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ResourceActionRunRequestV2
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["name"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "name")
}
protoReq.Name, err = runtime.StringP(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err)
}
msg, err := server.RunResourceActionV2(ctx, &protoReq)
return msg, metadata, err
}
@@ -2637,6 +2725,29 @@ func RegisterApplicationServiceHandlerServer(ctx context.Context, mux *runtime.S
})
mux.Handle("POST", pattern_ApplicationService_RunResourceActionV2_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_ApplicationService_RunResourceActionV2_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ApplicationService_RunResourceActionV2_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("DELETE", pattern_ApplicationService_DeleteResource_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
@@ -3261,6 +3372,26 @@ func RegisterApplicationServiceHandlerClient(ctx context.Context, mux *runtime.S
})
mux.Handle("POST", pattern_ApplicationService_RunResourceActionV2_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ApplicationService_RunResourceActionV2_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ApplicationService_RunResourceActionV2_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("DELETE", pattern_ApplicationService_DeleteResource_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
@@ -3415,6 +3546,8 @@ var (
pattern_ApplicationService_RunResourceAction_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4, 2, 5}, []string{"api", "v1", "applications", "name", "resource", "actions"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ApplicationService_RunResourceActionV2_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4, 2, 5, 2, 6}, []string{"api", "v1", "applications", "name", "resource", "actions", "v2"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ApplicationService_DeleteResource_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"api", "v1", "applications", "name", "resource"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_ApplicationService_PodLogs_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6}, []string{"api", "v1", "applications", "name", "pods", "podName", "logs"}, "", runtime.AssumeColonVerbOpt(true)))
@@ -3477,6 +3610,8 @@ var (
forward_ApplicationService_RunResourceAction_0 = runtime.ForwardResponseMessage
forward_ApplicationService_RunResourceActionV2_0 = runtime.ForwardResponseMessage
forward_ApplicationService_DeleteResource_0 = runtime.ForwardResponseMessage
forward_ApplicationService_PodLogs_0 = runtime.ForwardResponseStream

View File

@@ -20,23 +20,29 @@ if #obj.status.conditions == 0 then
end
local isEstablished
local isTerminating
local namesNotAccepted
local hasViolations
local conditionMsg = ""
for _, condition in pairs(obj.status.conditions) do
-- Check if CRD is terminating
if condition.type == "Terminating" and condition.status == "True" then
isTerminating = true
conditionMsg = condition.message
hs.status = "Progressing"
hs.message = "CRD is terminating: " .. condition.message
return hs
end
-- Check if K8s has accepted names for this CRD
if condition.type == "NamesAccepted" and condition.status == "False" then
namesNotAccepted = true
conditionMsg = condition.message
hs.status = "Degraded"
hs.message = "CRD names have not been accepted: " .. condition.message
return hs
end
-- Checking if CRD has violations
if condition.type == "NonStructuralSchema" and condition.status == "True" then
hs.status = "Degraded"
hs.message = "Schema violations found: " .. condition.message
return hs
end
-- Checking if CRD is established
@@ -44,25 +50,6 @@ for _, condition in pairs(obj.status.conditions) do
isEstablished = true
conditionMsg = condition.message
end
-- Checking if CRD has violations
if condition.type == "NonStructuralSchema" and condition.status == "True" then
hasViolations = true
conditionMsg = condition.message
end
end
if isTerminating then
hs.status = "Progressing"
hs.message = "CRD is terminating: " .. conditionMsg
return hs
end
if namesNotAccepted then
hs.status = "Degraded"
hs.message = "CRD names have not been accepted: " .. conditionMsg
return hs
end
if not isEstablished then
@@ -71,12 +58,6 @@ if not isEstablished then
return hs
end
if hasViolations then
hs.status = "Degraded"
hs.message = "Schema violations found: " .. conditionMsg
return hs
end
hs.status = "Healthy"
hs.message = "CRD is healthy"
return hs

View File

@@ -47,15 +47,15 @@ status:
reason: NoConflicts
status: 'True'
type: NamesAccepted
- lastTransitionTime: '2024-05-19T23:35:28Z'
message: the initial names have been accepted
reason: InitialNamesAccepted
status: 'True'
type: Established
- lastTransitionTime: '2024-10-26T19:44:57Z'
message: 'spec.preserveUnknownFields: Invalid value: true: must be false'
reason: Violations
status: 'True'
type: NonStructuralSchema
- lastTransitionTime: '2024-05-19T23:35:28Z'
message: the initial names have been accepted
reason: InitialNamesAccepted
status: 'True'
type: Established
storedVersions:
- v1alpha1

View File

@@ -2497,7 +2497,32 @@ func (s *Server) getAvailableActions(resourceOverrides map[string]v1alpha1.Resou
return availableActions, nil
}
// RunResourceAction runs a resource action on a live resource
//
// Deprecated: use RunResourceActionV2 instead. This version does not support resource action parameters but is
// maintained for backward compatibility. It will be removed in a future release.
func (s *Server) RunResourceAction(ctx context.Context, q *application.ResourceActionRunRequest) (*application.ApplicationResponse, error) {
log.WithFields(log.Fields{
"action": q.Action,
"application": q.Name,
"app-namespace": q.AppNamespace,
"project": q.Project,
"user": session.Username(ctx),
}).Warn("RunResourceAction was called. RunResourceAction is deprecated and will be removed in a future release. Use RunResourceActionV2 instead.")
qV2 := &application.ResourceActionRunRequestV2{
Name: q.Name,
AppNamespace: q.AppNamespace,
Namespace: q.Namespace,
ResourceName: q.ResourceName,
Kind: q.Kind,
Version: q.Version,
Group: q.Group,
Project: q.Project,
}
return s.RunResourceActionV2(ctx, qV2)
}
func (s *Server) RunResourceActionV2(ctx context.Context, q *application.ResourceActionRunRequestV2) (*application.ApplicationResponse, error) {
resourceRequest := &application.ApplicationResourceRequest{
Name: q.Name,
AppNamespace: q.AppNamespace,

View File

@@ -208,7 +208,22 @@ message ResourceActionParameters {
required string value = 2;
}
// ResourceActionRunRequest is a request to run a resource action.
// This message is deprecated and replaced by ResourceActionRunRequestV2.
message ResourceActionRunRequest {
option deprecated = true;
required string name = 1;
optional string namespace = 2;
required string resourceName = 3;
required string version = 4;
optional string group = 5;
required string kind = 6;
required string action = 7;
optional string appNamespace = 8;
optional string project = 9;
}
message ResourceActionRunRequestV2 {
required string name = 1;
optional string namespace = 2;
required string resourceName = 3;
@@ -470,10 +485,22 @@ service ApplicationService {
option (google.api.http).get = "/api/v1/applications/{name}/resource/actions";
}
// RunResourceAction run resource action
// RunResourceAction runs a resource action
//
// Deprecated: use RunResourceActionV2 instead. This version does not support resource action parameters but is
// maintained for backward compatibility. It will be removed in a future release.
rpc RunResourceAction(ResourceActionRunRequest) returns (ApplicationResponse) {
option deprecated = true;
option (google.api.http) = {
post: "/api/v1/applications/{name}/resource/actions"
body: "action"
};
}
// RunResourceActionV2 runs a resource action with parameters
rpc RunResourceActionV2(ResourceActionRunRequestV2) returns (ApplicationResponse) {
option (google.api.http) = {
post: "/api/v1/applications/{name}/resource/actions/v2"
body: "*"
};
}

View File

@@ -989,15 +989,15 @@ func TestNoAppEnumeration(t *testing.T) {
})
t.Run("RunResourceAction", func(t *testing.T) {
_, err := appServer.RunResourceAction(adminCtx, &application.ResourceActionRunRequest{Name: ptr.To("test"), ResourceName: ptr.To("test"), Group: ptr.To("apps"), Kind: ptr.To("Deployment"), Namespace: ptr.To("test"), Action: ptr.To("restart")})
_, err := appServer.RunResourceActionV2(adminCtx, &application.ResourceActionRunRequestV2{Name: ptr.To("test"), ResourceName: ptr.To("test"), Group: ptr.To("apps"), Kind: ptr.To("Deployment"), Namespace: ptr.To("test"), Action: ptr.To("restart")})
require.NoError(t, err)
_, err = appServer.RunResourceAction(noRoleCtx, &application.ResourceActionRunRequest{Name: ptr.To("test")})
_, err = appServer.RunResourceActionV2(noRoleCtx, &application.ResourceActionRunRequestV2{Name: ptr.To("test")})
require.EqualError(t, err, common.PermissionDeniedAPIError.Error(), "error message must be _only_ the permission error, to avoid leaking information about app existence")
_, err = appServer.RunResourceAction(noRoleCtx, &application.ResourceActionRunRequest{Group: ptr.To("argoproj.io"), Kind: ptr.To("Application"), Name: ptr.To("test")})
_, err = appServer.RunResourceActionV2(noRoleCtx, &application.ResourceActionRunRequestV2{Group: ptr.To("argoproj.io"), Kind: ptr.To("Application"), Name: ptr.To("test")})
require.EqualError(t, err, common.PermissionDeniedAPIError.Error(), "error message must be _only_ the permission error, to avoid leaking information about app existence")
_, err = appServer.RunResourceAction(adminCtx, &application.ResourceActionRunRequest{Name: ptr.To("doest-not-exist")})
_, err = appServer.RunResourceActionV2(adminCtx, &application.ResourceActionRunRequestV2{Name: ptr.To("doest-not-exist")})
require.EqualError(t, err, common.PermissionDeniedAPIError.Error(), "error message must be _only_ the permission error, to avoid leaking information about app existence")
_, err = appServer.RunResourceAction(adminCtx, &application.ResourceActionRunRequest{Name: ptr.To("doest-not-exist"), Project: ptr.To("test")})
_, err = appServer.RunResourceActionV2(adminCtx, &application.ResourceActionRunRequestV2{Name: ptr.To("doest-not-exist"), Project: ptr.To("test")})
assert.EqualError(t, err, "rpc error: code = NotFound desc = applications.argoproj.io \"doest-not-exist\" not found", "when the request specifies a project, we can return the standard k8s error message")
})
@@ -2536,7 +2536,7 @@ func TestRunNewStyleResourceAction(t *testing.T) {
err := appStateCache.SetAppResourcesTree(testApp.Name, &v1alpha1.ApplicationTree{Nodes: nodes})
require.NoError(t, err)
appResponse, runErr := appServer.RunResourceAction(t.Context(), &application.ResourceActionRunRequest{
appResponse, runErr := appServer.RunResourceActionV2(t.Context(), &application.ResourceActionRunRequestV2{
Name: &testApp.Name,
Namespace: &namespace,
Action: &action,
@@ -2562,7 +2562,7 @@ func TestRunNewStyleResourceAction(t *testing.T) {
err := appStateCache.SetAppResourcesTree(testApp.Name, &v1alpha1.ApplicationTree{Nodes: nodes})
require.NoError(t, err)
appResponse, runErr := appServer.RunResourceAction(t.Context(), &application.ResourceActionRunRequest{
appResponse, runErr := appServer.RunResourceActionV2(t.Context(), &application.ResourceActionRunRequestV2{
Name: &testApp.Name,
Namespace: &namespace,
Action: &action,
@@ -2633,7 +2633,7 @@ func TestRunOldStyleResourceAction(t *testing.T) {
err := appStateCache.SetAppResourcesTree(testApp.Name, &v1alpha1.ApplicationTree{Nodes: nodes})
require.NoError(t, err)
appResponse, runErr := appServer.RunResourceAction(t.Context(), &application.ResourceActionRunRequest{
appResponse, runErr := appServer.RunResourceActionV2(t.Context(), &application.ResourceActionRunRequestV2{
Name: &testApp.Name,
Namespace: &namespace,
Action: &action,

View File

@@ -875,7 +875,7 @@ func TestNamespacedResourceAction(t *testing.T) {
require.NoError(t, err)
assert.Equal(t, []*ResourceAction{{Name: "sample", Disabled: false}}, actions.Actions)
_, err = client.RunResourceAction(t.Context(), &applicationpkg.ResourceActionRunRequest{
_, err = client.RunResourceActionV2(t.Context(), &applicationpkg.ResourceActionRunRequestV2{
Name: &app.Name,
Group: ptr.To("apps"),
Kind: ptr.To("Deployment"),
@@ -1076,7 +1076,7 @@ func assertNSResourceActions(t *testing.T, appName string, successful bool) {
})
assertError(err, expectedError)
_, err = cdClient.RunResourceAction(t.Context(), &applicationpkg.ResourceActionRunRequest{
_, err = cdClient.RunResourceActionV2(t.Context(), &applicationpkg.ResourceActionRunRequestV2{
Name: &appName,
AppNamespace: ptr.To(fixture.AppNamespace()),
ResourceName: ptr.To("guestbook-ui"),

View File

@@ -1086,7 +1086,7 @@ func TestOldStyleResourceAction(t *testing.T) {
require.NoError(t, err)
assert.Equal(t, []*ResourceAction{{Name: "sample", Disabled: false}}, actions.Actions)
_, err = client.RunResourceAction(t.Context(), &applicationpkg.ResourceActionRunRequest{
_, err = client.RunResourceActionV2(t.Context(), &applicationpkg.ResourceActionRunRequestV2{
Name: &app.Name,
Group: ptr.To("apps"),
Kind: ptr.To("Deployment"),
@@ -1192,7 +1192,7 @@ func TestNewStyleResourceActionPermitted(t *testing.T) {
require.NoError(t, err)
assert.Equal(t, []*ResourceAction{{Name: "sample", Disabled: false}}, actions.Actions)
_, err = client.RunResourceAction(t.Context(), &applicationpkg.ResourceActionRunRequest{
_, err = client.RunResourceActionV2(t.Context(), &applicationpkg.ResourceActionRunRequestV2{
Name: &app.Name,
Group: ptr.To("batch"),
Kind: ptr.To("CronJob"),
@@ -1304,7 +1304,7 @@ func TestNewStyleResourceActionMixedOk(t *testing.T) {
require.NoError(t, err)
assert.Equal(t, []*ResourceAction{{Name: "sample", Disabled: false}}, actions.Actions)
_, err = client.RunResourceAction(t.Context(), &applicationpkg.ResourceActionRunRequest{
_, err = client.RunResourceActionV2(t.Context(), &applicationpkg.ResourceActionRunRequestV2{
Name: &app.Name,
Group: ptr.To("batch"),
Kind: ptr.To("CronJob"),
@@ -1507,7 +1507,7 @@ func assertResourceActions(t *testing.T, appName string, successful bool) {
})
assertError(err, expectedError)
_, err = cdClient.RunResourceAction(t.Context(), &applicationpkg.ResourceActionRunRequest{
_, err = cdClient.RunResourceActionV2(t.Context(), &applicationpkg.ResourceActionRunRequestV2{
Name: &appName,
ResourceName: ptr.To("guestbook-ui"),
Namespace: ptr.To(fixture.DeploymentNamespace()),

View File

@@ -347,7 +347,7 @@ export class ApplicationsService {
resourceActionParameters: models.ResourceActionParam[]
): Promise<models.ResourceAction[]> {
return requests
.post(`/applications/${name}/resource/actions`)
.post(`/applications/${name}/resource/actions/v2`)
.send(
JSON.stringify({
appNamespace,
@@ -547,7 +547,7 @@ export class ApplicationsService {
public async getApplicationSet(name: string, namespace: string): Promise<models.ApplicationSet> {
return requests
.get(`/applicationsets/${name}`)
.query({namespace})
.query({appsetNamespace: namespace})
.then(res => res.body as models.ApplicationSet);
}
}

View File

@@ -790,7 +790,7 @@ func (m *nativeGitClient) RevisionMetadata(revision string) (*RevisionMetadata,
if err != nil {
return nil, fmt.Errorf("failed to interpret trailers for revision %q in repo %q: %w", revision, m.repoURL, err)
}
relatedCommits := getReferences(log.WithFields(log.Fields{"repo": m.repoURL, "revision": revision}), out)
relatedCommits, _ := GetReferences(log.WithFields(log.Fields{"repo": m.repoURL, "revision": revision}), out)
out, err = m.runCmd("tag", "--points-at", revision)
if err != nil {
@@ -816,65 +816,23 @@ func truncate(str string) string {
var shaRegex = regexp.MustCompile(`^[0-9a-f]{5,40}$`)
// getReferences extracts related commit metadata from the commit message trailers. If referenced commit
// GetReferences extracts related commit metadata from the commit message trailers. If referenced commit
// metadata is present, we return a slice containing a single metadata object. If no related commit metadata is found,
// we return a nil slice.
//
// If a trailer fails validation, we log an error and skip that trailer. We truncate the trailer values to 100
// characters to avoid excessively long log messages.
func getReferences(logCtx *log.Entry, commitMessageBody string) []RevisionReference {
//
// We also return the commit message body with all valid Argocd-reference-commit-* trailers removed.
func GetReferences(logCtx *log.Entry, commitMessageBody string) ([]RevisionReference, string) {
unrelatedLines := strings.Builder{}
var relatedCommit CommitMetadata
scanner := bufio.NewScanner(strings.NewReader(commitMessageBody))
for scanner.Scan() {
line := scanner.Text()
if !strings.HasPrefix(line, "Argocd-reference-commit-") {
continue
}
parts := strings.SplitN(line, ": ", 2)
if len(parts) != 2 {
continue
}
trailerKey := parts[0]
trailerValue := parts[1]
switch trailerKey {
case "Argocd-reference-commit-repourl":
_, err := url.Parse(trailerValue)
if err != nil {
logCtx.Errorf("failed to parse repo URL %q: %v", truncate(trailerValue), err)
continue
}
relatedCommit.RepoURL = trailerValue
case "Argocd-reference-commit-author":
address, err := mail.ParseAddress(trailerValue)
if err != nil || address == nil {
logCtx.Errorf("failed to parse author email %q: %v", truncate(trailerValue), err)
continue
}
relatedCommit.Author = *address
case "Argocd-reference-commit-date":
// Validate that it's the correct date format.
t, err := time.Parse(time.RFC3339, trailerValue)
if err != nil {
logCtx.Errorf("failed to parse date %q with RFC3339 format: %v", truncate(trailerValue), err)
continue
}
relatedCommit.Date = t.Format(time.RFC3339)
case "Argocd-reference-commit-subject":
relatedCommit.Subject = trailerValue
case "Argocd-reference-commit-body":
body := ""
err := json.Unmarshal([]byte(trailerValue), &body)
if err != nil {
logCtx.Errorf("failed to parse body %q as JSON: %v", truncate(trailerValue), err)
continue
}
relatedCommit.Body = body
case "Argocd-reference-commit-sha":
if !shaRegex.MatchString(trailerValue) {
logCtx.Errorf("invalid commit SHA %q in trailer %s: must be a lowercase hex string 5-40 characters long", truncate(trailerValue), trailerKey)
continue
}
relatedCommit.SHA = trailerValue
updated := updateCommitMetadata(logCtx, &relatedCommit, line)
if !updated {
unrelatedLines.WriteString(line + "\n")
}
}
var relatedCommits []RevisionReference
@@ -883,7 +841,64 @@ func getReferences(logCtx *log.Entry, commitMessageBody string) []RevisionRefere
Commit: &relatedCommit,
})
}
return relatedCommits
return relatedCommits, unrelatedLines.String()
}
// updateCommitMetadata checks if the line is a valid Argocd-reference-commit-* trailer. If so, it updates
// the relatedCommit object and returns true. If the line is not a valid trailer, it returns false.
func updateCommitMetadata(logCtx *log.Entry, relatedCommit *CommitMetadata, line string) bool {
if !strings.HasPrefix(line, "Argocd-reference-commit-") {
return false
}
parts := strings.SplitN(line, ": ", 2)
if len(parts) != 2 {
return false
}
trailerKey := parts[0]
trailerValue := parts[1]
switch trailerKey {
case "Argocd-reference-commit-repourl":
_, err := url.Parse(trailerValue)
if err != nil {
logCtx.Errorf("failed to parse repo URL %q: %v", truncate(trailerValue), err)
return false
}
relatedCommit.RepoURL = trailerValue
case "Argocd-reference-commit-author":
address, err := mail.ParseAddress(trailerValue)
if err != nil || address == nil {
logCtx.Errorf("failed to parse author email %q: %v", truncate(trailerValue), err)
return false
}
relatedCommit.Author = *address
case "Argocd-reference-commit-date":
// Validate that it's the correct date format.
t, err := time.Parse(time.RFC3339, trailerValue)
if err != nil {
logCtx.Errorf("failed to parse date %q with RFC3339 format: %v", truncate(trailerValue), err)
return false
}
relatedCommit.Date = t.Format(time.RFC3339)
case "Argocd-reference-commit-subject":
relatedCommit.Subject = trailerValue
case "Argocd-reference-commit-body":
body := ""
err := json.Unmarshal([]byte(trailerValue), &body)
if err != nil {
logCtx.Errorf("failed to parse body %q as JSON: %v", truncate(trailerValue), err)
return false
}
relatedCommit.Body = body
case "Argocd-reference-commit-sha":
if !shaRegex.MatchString(trailerValue) {
logCtx.Errorf("invalid commit SHA %q in trailer %s: must be a lowercase hex string 5-40 characters long", truncate(trailerValue), trailerKey)
return false
}
relatedCommit.SHA = trailerValue
default:
return false
}
return true
}
// VerifyCommitSignature Runs verify-commit on a given revision and returns the output

View File

@@ -1103,20 +1103,22 @@ func (m *mockCreds) GetUserInfo(_ context.Context) (string, string, error) {
return "", "", nil
}
func Test_getReferences(t *testing.T) {
func Test_GetReferences(t *testing.T) {
t.Parallel()
now := time.Now()
tests := []struct {
name string
input string
expected []RevisionReference
name string
input string
expectedReferences []RevisionReference
expectedMessage string
}{
{
name: "No trailers",
input: "This is a commit message without trailers.",
expected: nil,
name: "No trailers",
input: "This is a commit message without trailers.",
expectedReferences: nil,
expectedMessage: "This is a commit message without trailers.\n",
},
{
name: "Invalid trailers",
@@ -1126,25 +1128,36 @@ Argocd-reference-commit-sha: xyz123
Argocd-reference-commit-body: this isn't json
Argocd-reference-commit-author: % not email %
Argocd-reference-commit-bogus:`,
expected: nil,
expectedReferences: nil,
expectedMessage: `Argocd-reference-commit-repourl: % invalid %
Argocd-reference-commit-date: invalid-date
Argocd-reference-commit-sha: xyz123
Argocd-reference-commit-body: this isn't json
Argocd-reference-commit-author: % not email %
Argocd-reference-commit-bogus:
`,
},
{
name: "Unknown trailers",
input: "Argocd-reference-commit-unknown: foobar",
expected: nil,
name: "Unknown trailers",
input: "Argocd-reference-commit-unknown: foobar",
expectedReferences: nil,
expectedMessage: "Argocd-reference-commit-unknown: foobar\n",
},
{
name: "Some valid and Invalid trailers",
input: `Argocd-reference-commit-sha: abc123
Argocd-reference-commit-repourl: % invalid %
Argocd-reference-commit-date: invalid-date`,
expected: []RevisionReference{
expectedReferences: []RevisionReference{
{
Commit: &CommitMetadata{
SHA: "abc123",
},
},
},
expectedMessage: `Argocd-reference-commit-repourl: % invalid %
Argocd-reference-commit-date: invalid-date
`,
},
{
name: "Valid trailers",
@@ -1154,7 +1167,7 @@ Argocd-reference-commit-date: %s
Argocd-reference-commit-subject: Fix bug
Argocd-reference-commit-body: "Fix bug\n\nSome: trailer"
Argocd-reference-commit-sha: abc123`, now.Format(time.RFC3339)),
expected: []RevisionReference{
expectedReferences: []RevisionReference{
{
Commit: &CommitMetadata{
Author: mail.Address{
@@ -1169,18 +1182,20 @@ Argocd-reference-commit-sha: abc123`, now.Format(time.RFC3339)),
},
},
},
expectedMessage: "",
},
{
name: "Duplicate trailers",
input: `Argocd-reference-commit-repourl: https://github.com/org/repo.git
Argocd-reference-commit-repourl: https://github.com/another/repo.git`,
expected: []RevisionReference{
expectedReferences: []RevisionReference{
{
Commit: &CommitMetadata{
RepoURL: "https://github.com/another/repo.git",
},
},
},
expectedMessage: "",
},
}
@@ -1189,8 +1204,9 @@ Argocd-reference-commit-repourl: https://github.com/another/repo.git`,
t.Parallel()
logCtx := log.WithFields(log.Fields{})
result := getReferences(logCtx, tt.input)
assert.Equal(t, tt.expected, result)
result, message := GetReferences(logCtx, tt.input)
assert.Equal(t, tt.expectedReferences, result)
assert.Equal(t, tt.expectedMessage, message)
})
}
}

View File

@@ -15,6 +15,8 @@ import (
"github.com/Masterminds/semver/v3"
"sigs.k8s.io/yaml"
"github.com/argoproj/argo-cd/v3/util/io"
"github.com/argoproj/gitops-engine/pkg/utils/kube"
log "github.com/sirupsen/logrus"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
@@ -24,8 +26,6 @@ import (
executil "github.com/argoproj/argo-cd/v3/util/exec"
"github.com/argoproj/argo-cd/v3/util/git"
"github.com/argoproj/argo-cd/v3/util/proxy"
securejoin "github.com/cyphar/filepath-securejoin"
)
// Image represents a Docker image in the format NAME[:TAG].
@@ -346,12 +346,18 @@ func (k *kustomize) Build(opts *v1alpha1.ApplicationSourceKustomize, kustomizeOp
foundComponents := opts.Components
if opts.IgnoreMissingComponents {
foundComponents = make([]string, 0)
root, err := os.OpenRoot(k.repoRoot)
defer io.Close(root)
if err != nil {
return nil, nil, nil, fmt.Errorf("failed to open the repo folder: %w", err)
}
for _, c := range opts.Components {
resolvedPath, err := securejoin.SecureJoin(k.path, c)
resolvedPath, err := filepath.Rel(k.repoRoot, filepath.Join(k.path, c))
if err != nil {
return nil, nil, nil, fmt.Errorf("Kustomize components path failed: %w", err)
return nil, nil, nil, fmt.Errorf("kustomize components path failed: %w", err)
}
_, err = os.Stat(resolvedPath)
_, err = root.Stat(resolvedPath)
if err != nil {
log.Debugf("%s component directory does not exist", resolvedPath)
continue

View File

@@ -25,6 +25,7 @@ const (
kustomization6 = "kustomization_yaml_components"
kustomization7 = "label_without_selector"
kustomization8 = "kustomization_yaml_patches_empty"
kustomization9 = "kustomization_yaml_components_monorepo"
)
func testDataDir(tb testing.TB, testData string) (string, error) {
@@ -512,6 +513,31 @@ func TestKustomizeBuildComponents(t *testing.T) {
assert.Equal(t, int64(3), replicas)
}
func TestKustomizeBuildComponentsMonoRepo(t *testing.T) {
rootPath, err := testDataDir(t, kustomization9)
require.NoError(t, err)
appPath := path.Join(rootPath, "envs/inseng-pdx-egert-sandbox/namespaces/inst-system/apps/hello-world")
kustomize := NewKustomizeApp(rootPath, appPath, git.NopCreds{}, "", "", "", "")
kustomizeSource := v1alpha1.ApplicationSourceKustomize{
Components: []string{"../../../../../../kustomize/components/all"},
IgnoreMissingComponents: true,
}
objs, _, _, err := kustomize.Build(&kustomizeSource, nil, nil, nil)
require.NoError(t, err)
obj := objs[2]
require.Equal(t, "hello-world-kustomize", obj.GetName())
require.Equal(t, map[string]string{
"app.kubernetes.io/name": "hello-world-kustomize",
"app.kubernetes.io/owner": "fire-team",
}, obj.GetLabels())
replicas, ok, err := unstructured.NestedSlice(obj.Object, "spec", "template", "spec", "tolerations")
require.NoError(t, err)
require.True(t, ok)
require.Len(t, replicas, 1)
require.Equal(t, "my-special-toleration", replicas[0].(map[string]any)["key"])
require.Equal(t, "Exists", replicas[0].(map[string]any)["operator"])
}
func TestKustomizeBuildPatches(t *testing.T) {
appPath, err := testDataDir(t, kustomization5)
require.NoError(t, err)

View File

@@ -0,0 +1,3 @@
---
kustomize:
componentsPath: ../../../../../../kustomize/components

View File

@@ -0,0 +1,33 @@
---
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
# All the members of this group are meant be populated from the
# same nonproduction overlay of the matching app
resources:
- ../../../../../../kustomize/apps/hello-world/base
nameSuffix: -kustomize
labels:
- pairs:
app.kubernetes.io/name: hello-world-kustomize
includeSelectors: true
includeTemplates: true
patches:
# Adjusting the serviceAccount ref
- patch: |-
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-world
spec:
template:
spec:
serviceAccountName: hello-world-kustomize
# Container image versions across the members
images:
- name: hello-world
newTag: 1.17.0

View File

@@ -0,0 +1,34 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-world
labels:
app.kubernetes.io/name: hello-world
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: hello-world
template:
metadata:
labels:
app.kubernetes.io/name: hello-world
spec:
serviceAccountName: hello-world
containers:
- name: hello-world
image: "nginx:1.16.0"
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
protocol: TCP
livenessProbe:
httpGet:
path: /
port: http
readinessProbe:
httpGet:
path: /
port: http
tolerations: []

View File

@@ -0,0 +1,8 @@
---
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml
- serviceaccount.yaml

View File

@@ -0,0 +1,16 @@
---
apiVersion: v1
kind: Service
metadata:
name: hello-world
labels:
app.kubernetes.io/name: hello-world
spec:
type: ClusterIP
ports:
- port: 80
targetPort: http
protocol: TCP
name: http
selector:
app.kubernetes.io/name: hello-world

View File

@@ -0,0 +1,7 @@
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: hello-world
labels:
app.kubernetes.io/name: hello-world

View File

@@ -0,0 +1,19 @@
---
apiVersion: kustomize.config.k8s.io/v1alpha1
kind: Component
labels:
- pairs:
app.kubernetes.io/owner: fire-team
includeSelectors: false
includeTemplates: false
patches:
- target:
kind: Deployment
patch: |-
- op: add
path: /spec/template/spec/tolerations/-
value:
key: my-special-toleration
operator: Exists

View File

@@ -295,6 +295,11 @@ func (c *nativeOCIClient) DigestMetadata(ctx context.Context, digest string) (*i
func (c *nativeOCIClient) ResolveRevision(ctx context.Context, revision string, noCache bool) (string, error) {
digest, err := c.resolveDigest(ctx, revision) // Lookup explicit revision
if err != nil {
// If the revision is not a semver constraint, just return the error
if !versions.IsConstraint(revision) {
return digest, err
}
tags, err := c.GetTags(ctx, noCache)
if err != nil {
return "", fmt.Errorf("error fetching tags: %w", err)

View File

@@ -374,7 +374,7 @@ func Test_nativeOCIClient_ResolveRevision(t *testing.T) {
fields: fields{repo: store, tagsFunc: func(context.Context, string) (tags []string, err error) {
return []string{"1.0.0", "1.1.0", "1.2.0", "2.0.0"}, nil
}},
expectedError: errors.New("no version for constraints: failed to determine semver constraint: improper constraint: sha256:abc123"),
expectedError: errors.New("cannot get digest for revision sha256:abc123: sha256:abc123: not found"),
},
{
name: "resolve latest tag",

View File

@@ -62,3 +62,12 @@ func MaxVersion(revision string, tags []string) (string, error) {
log.Debugf("Semver constraint '%s' resolved to version '%s'", constraints.String(), maxVersion.Original())
return maxVersion.Original(), nil
}
// Returns true if the given revision is not an exact semver and can be parsed as a semver constraint
func IsConstraint(revision string) bool {
if _, err := semver.NewVersion(revision); err == nil {
return false
}
_, err := semver.NewConstraint(revision)
return err == nil
}

View File

@@ -65,3 +65,27 @@ func TestTags_MaxVersion(t *testing.T) {
require.Error(t, err)
})
}
func TestTags_IsConstraint(t *testing.T) {
t.Run("Exact", func(t *testing.T) {
assert.False(t, IsConstraint("0.5.3"))
})
t.Run("Exact nonsemver", func(t *testing.T) {
assert.False(t, IsConstraint("2024.03-LTS-RC19"))
})
t.Run("Constraint", func(t *testing.T) {
assert.True(t, IsConstraint("= 0.5.3"))
})
t.Run("Constraint", func(t *testing.T) {
assert.True(t, IsConstraint("> 0.5.3"))
})
t.Run("Constraint", func(t *testing.T) {
assert.True(t, IsConstraint(">0.5.0,<0.7.0"))
})
t.Run("Constraint", func(t *testing.T) {
assert.True(t, IsConstraint("0.7.*"))
})
t.Run("Constraint", func(t *testing.T) {
assert.True(t, IsConstraint("*"))
})
}

View File

@@ -1,12 +1,7 @@
package workloadidentity
import (
"context"
"time"
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
)
const (
@@ -22,34 +17,9 @@ type TokenProvider interface {
GetToken(scope string) (*Token, error)
}
type WorkloadIdentityTokenProvider struct {
tokenCredential azcore.TokenCredential
}
// Used to propagate initialization error if any
var initError error
func NewWorkloadIdentityTokenProvider() TokenProvider {
cred, err := azidentity.NewDefaultAzureCredential(&azidentity.DefaultAzureCredentialOptions{})
initError = err
return WorkloadIdentityTokenProvider{tokenCredential: cred}
}
func (c WorkloadIdentityTokenProvider) GetToken(scope string) (*Token, error) {
if initError != nil {
return nil, initError
}
token, err := c.tokenCredential.GetToken(context.Background(), policy.TokenRequestOptions{
Scopes: []string{scope},
})
if err != nil {
return nil, err
}
return &Token{AccessToken: token.Token, ExpiresOn: token.ExpiresOn}, nil
}
func CalculateCacheExpiryBasedOnTokenExpiry(tokenExpiry time.Time) time.Duration {
// Calculate the cache expiry as 5 minutes before the token expires
cacheExpiry := time.Until(tokenExpiry) - time.Minute*5

View File

@@ -0,0 +1,36 @@
//go:build !darwin || (cgo && darwin)
package workloadidentity
import (
"context"
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
)
type WorkloadIdentityTokenProvider struct {
tokenCredential azcore.TokenCredential
}
func NewWorkloadIdentityTokenProvider() TokenProvider {
cred, err := azidentity.NewDefaultAzureCredential(&azidentity.DefaultAzureCredentialOptions{})
initError = err
return WorkloadIdentityTokenProvider{tokenCredential: cred}
}
func (c WorkloadIdentityTokenProvider) GetToken(scope string) (*Token, error) {
if initError != nil {
return nil, initError
}
token, err := c.tokenCredential.GetToken(context.Background(), policy.TokenRequestOptions{
Scopes: []string{scope},
})
if err != nil {
return nil, err
}
return &Token{AccessToken: token.Token, ExpiresOn: token.ExpiresOn}, nil
}

View File

@@ -0,0 +1,25 @@
//go:build darwin && !cgo
// Package workloadidentity
// This file is used when the GOOS is darwin and CGO is not enabled.
// It provides a no-op implementation of the WorkloadIdentityTokenProvider to allow goreleaser to build
// a darwin binary on a linux machine.
package workloadidentity
import (
"errors"
)
type WorkloadIdentityTokenProvider struct {
}
const CGOError = "CGO is not enabled, cannot use workload identity token provider"
// Code that does not require CGO
func NewWorkloadIdentityTokenProvider() TokenProvider {
panic(CGOError)
}
func (c WorkloadIdentityTokenProvider) GetToken(scope string) (*Token, error) {
return nil, errors.New(CGOError)
}