mirror of
https://github.com/argoproj/argo-cd.git
synced 2026-04-09 02:08:49 +02:00
Compare commits
83 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d16bc2610b | ||
|
|
a443ab06e0 | ||
|
|
d5ba03b5f2 | ||
|
|
71d7bb67a4 | ||
|
|
6f0b7cb1a4 | ||
|
|
2b15397479 | ||
|
|
999132d9e8 | ||
|
|
eb34149e7a | ||
|
|
970329f99b | ||
|
|
fbf49f72e7 | ||
|
|
cc56e70718 | ||
|
|
8d758733ad | ||
|
|
0432c40a85 | ||
|
|
09d1a1356d | ||
|
|
343cc02339 | ||
|
|
84f935a615 | ||
|
|
3aa3b5c778 | ||
|
|
201513d1c9 | ||
|
|
cea6f80266 | ||
|
|
deddacf6cc | ||
|
|
bd7bd4b18c | ||
|
|
95587118a1 | ||
|
|
0d93b20796 | ||
|
|
1f6174eebb | ||
|
|
4261d08b29 | ||
|
|
966919792f | ||
|
|
2bb1587333 | ||
|
|
f685ee61e1 | ||
|
|
2883620bb0 | ||
|
|
261e665bd9 | ||
|
|
b05386d8b7 | ||
|
|
ce87bf951e | ||
|
|
6ecb081ac8 | ||
|
|
4c4fa201a3 | ||
|
|
3c94817fb2 | ||
|
|
a05a3eef80 | ||
|
|
1974b8a2bf | ||
|
|
a117187138 | ||
|
|
5456570f8d | ||
|
|
aa7a849859 | ||
|
|
969c68c2b3 | ||
|
|
c508244cf8 | ||
|
|
f3d159f2a8 | ||
|
|
690524e93c | ||
|
|
52497ce0fb | ||
|
|
ce5de62fc5 | ||
|
|
77be41caba | ||
|
|
bba517dda0 | ||
|
|
c53bfedacd | ||
|
|
500504849c | ||
|
|
69c22df5e2 | ||
|
|
4761611390 | ||
|
|
86c831a042 | ||
|
|
697fd7c9a3 | ||
|
|
d194eaa6a2 | ||
|
|
b7fedfa497 | ||
|
|
34094a2d04 | ||
|
|
df200b044b | ||
|
|
7449f26e8b | ||
|
|
9ce19c6c80 | ||
|
|
9aaade6981 | ||
|
|
9adc9159e6 | ||
|
|
75eeb6dbb6 | ||
|
|
89051845c1 | ||
|
|
c145657347 | ||
|
|
0ee904746a | ||
|
|
3f1e7d401e | ||
|
|
85838126fc | ||
|
|
822788f0f9 | ||
|
|
8bc460fe28 | ||
|
|
814b2367c8 | ||
|
|
92ced542b8 | ||
|
|
0d579a0ec1 | ||
|
|
9c685cf021 | ||
|
|
37e24408a8 | ||
|
|
fdcbfade20 | ||
|
|
cf02b10d01 | ||
|
|
46dc70b6c6 | ||
|
|
d7e4ada9af | ||
|
|
292e69f97f | ||
|
|
618bd14c09 | ||
|
|
a047d72688 | ||
|
|
472d4eb16d |
4
.github/workflows/ci-build.yaml
vendored
4
.github/workflows/ci-build.yaml
vendored
@@ -13,7 +13,7 @@ on:
|
||||
|
||||
env:
|
||||
# Golang version to use across CI steps
|
||||
GOLANG_VERSION: '1.19.7'
|
||||
GOLANG_VERSION: '1.19.10'
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
@@ -425,7 +425,7 @@ jobs:
|
||||
git config --global user.email "john.doe@example.com"
|
||||
- name: Pull Docker image required for tests
|
||||
run: |
|
||||
docker pull ghcr.io/dexidp/dex:v2.36.0
|
||||
docker pull ghcr.io/dexidp/dex:v2.37.0
|
||||
docker pull argoproj/argo-cd-ci-builder:v1.0.0
|
||||
docker pull redis:7.0.11-alpine
|
||||
- name: Create target directory for binaries in the build-process
|
||||
|
||||
2
.github/workflows/image.yaml
vendored
2
.github/workflows/image.yaml
vendored
@@ -10,7 +10,7 @@ on:
|
||||
types: [ labeled, unlabeled, opened, synchronize, reopened ]
|
||||
|
||||
env:
|
||||
GOLANG_VERSION: '1.19.7'
|
||||
GOLANG_VERSION: '1.19.10'
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
|
||||
10
.github/workflows/release.yaml
vendored
10
.github/workflows/release.yaml
vendored
@@ -12,7 +12,7 @@ on:
|
||||
- "!release-v0*"
|
||||
|
||||
env:
|
||||
GOLANG_VERSION: '1.19.7'
|
||||
GOLANG_VERSION: '1.19.10'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -266,6 +266,14 @@ jobs:
|
||||
body: ${{ steps.release-notes.outputs.content }}
|
||||
if: ${{ env.DRY_RUN == 'true' }}
|
||||
|
||||
# Based on this suggestion: https://github.com/actions/runner-images/issues/2840#issuecomment-1284059930
|
||||
- name: Free Up Disk Space
|
||||
id: free-up-disk-space
|
||||
run: |
|
||||
df -h
|
||||
sudo rm -rf /usr/share/dotnet
|
||||
df -h
|
||||
|
||||
- name: Generate SBOM (spdx)
|
||||
id: spdx-builder
|
||||
env:
|
||||
|
||||
@@ -4,7 +4,7 @@ ARG BASE_IMAGE=docker.io/library/ubuntu:22.04
|
||||
# Initial stage which pulls prepares build dependencies and CLI tooling we need for our final image
|
||||
# Also used as the image in CI jobs so needs all dependencies
|
||||
####################################################################################################
|
||||
FROM docker.io/library/golang:1.19.7 AS builder
|
||||
FROM docker.io/library/golang:1.19.10@sha256:83f9f840072d05ad4d90ce4ac7cb2427632d6b89d5ffc558f18f9577ec8188c0 AS builder
|
||||
|
||||
RUN echo 'deb http://deb.debian.org/debian buster-backports main' >> /etc/apt/sources.list
|
||||
|
||||
@@ -99,7 +99,7 @@ RUN HOST_ARCH=$TARGETARCH NODE_ENV='production' NODE_ONLINE_ENV='online' NODE_OP
|
||||
####################################################################################################
|
||||
# Argo CD Build stage which performs the actual build of Argo CD binaries
|
||||
####################################################################################################
|
||||
FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.19.7 AS argocd-build
|
||||
FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.19.10@sha256:83f9f840072d05ad4d90ce4ac7cb2427632d6b89d5ffc558f18f9577ec8188c0 AS argocd-build
|
||||
|
||||
WORKDIR /go/src/github.com/argoproj/argo-cd
|
||||
|
||||
|
||||
@@ -35,9 +35,7 @@ impact on Argo CD before opening an issue at least roughly.
|
||||
|
||||
## Supported Versions
|
||||
|
||||
We currently support the most recent release (`N`, e.g. `1.8`) and the release
|
||||
previous to the most recent one (`N-1`, e.g. `1.7`). With the release of
|
||||
`N+1`, `N-1` drops out of support and `N` becomes `N-1`.
|
||||
We currently support the last 3 minor versions of Argo CD with security and bug fixes.
|
||||
|
||||
We regularly perform patch releases (e.g. `1.8.5` and `1.7.12`) for the
|
||||
supported versions, which will contain fixes for security vulnerabilities and
|
||||
|
||||
4
USERS.md
4
USERS.md
@@ -23,6 +23,7 @@ Currently, the following organizations are **officially** using Argo CD:
|
||||
1. [Arctiq Inc.](https://www.arctiq.ca)
|
||||
1. [ARZ Allgemeines Rechenzentrum GmbH](https://www.arz.at/)
|
||||
1. [Axual B.V.](https://axual.com)
|
||||
1. [Back Market](https://www.backmarket.com)
|
||||
1. [Baloise](https://www.baloise.com)
|
||||
1. [BCDevExchange DevOps Platform](https://bcdevexchange.org/DevOpsPlatform)
|
||||
1. [Beat](https://thebeat.co/en/)
|
||||
@@ -89,6 +90,7 @@ Currently, the following organizations are **officially** using Argo CD:
|
||||
1. [gloat](https://gloat.com/)
|
||||
1. [GLOBIS](https://globis.com)
|
||||
1. [Glovo](https://www.glovoapp.com)
|
||||
1. [GlueOps](https://glueops.dev)
|
||||
1. [GMETRI](https://gmetri.com/)
|
||||
1. [Gojek](https://www.gojek.io/)
|
||||
1. [Greenpass](https://www.greenpass.com.br/)
|
||||
@@ -202,6 +204,7 @@ Currently, the following organizations are **officially** using Argo CD:
|
||||
1. [SI Analytics](https://si-analytics.ai)
|
||||
1. [Skit](https://skit.ai/)
|
||||
1. [Skyscanner](https://www.skyscanner.net/)
|
||||
1. [Smart Pension](https://www.smartpension.co.uk/)
|
||||
1. [Smilee.io](https://smilee.io)
|
||||
1. [Snapp](https://snapp.ir/)
|
||||
1. [Snyk](https://snyk.io/)
|
||||
@@ -239,6 +242,7 @@ Currently, the following organizations are **officially** using Argo CD:
|
||||
1. [ungleich.ch](https://ungleich.ch/)
|
||||
1. [Unifonic Inc](https://www.unifonic.com/)
|
||||
1. [Universidad Mesoamericana](https://www.umes.edu.gt/)
|
||||
1. [Urbantz](https://urbantz.com/)
|
||||
1. [Viaduct](https://www.viaduct.ai/)
|
||||
1. [Vinted](https://vinted.com/)
|
||||
1. [Virtuo](https://www.govirtuo.com/)
|
||||
|
||||
@@ -1028,7 +1028,12 @@ func (r *ApplicationSetReconciler) updateApplicationSetApplicationStatus(ctx con
|
||||
}
|
||||
|
||||
if currentAppStatus.Status == "Pending" {
|
||||
if operationPhaseString == "Succeeded" && app.Status.OperationState.StartedAt.After(currentAppStatus.LastTransitionTime.Time) {
|
||||
// check for successful syncs started less than 10s before the Application transitioned to Pending
|
||||
// this covers race conditions where syncs initiated by RollingSync miraculously have a sync time before the transition to Pending state occurred (could be a few seconds)
|
||||
if operationPhaseString == "Succeeded" && app.Status.OperationState.StartedAt.Add(time.Duration(10)*time.Second).After(currentAppStatus.LastTransitionTime.Time) {
|
||||
if !app.Status.OperationState.StartedAt.After(currentAppStatus.LastTransitionTime.Time) {
|
||||
log.Warnf("Application %v was synced less than 10s prior to entering Pending status, we'll assume the AppSet controller triggered this sync and update its status to Progressing", app.Name)
|
||||
}
|
||||
log.Infof("Application %v has completed a sync successfully, updating its ApplicationSet status to Progressing", app.Name)
|
||||
currentAppStatus.LastTransitionTime = &now
|
||||
currentAppStatus.Status = "Progressing"
|
||||
|
||||
@@ -3996,6 +3996,63 @@ func TestUpdateApplicationSetApplicationStatus(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "progresses a pending application with a successful sync <1s ago to progressing",
|
||||
appSet: v1alpha1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "name",
|
||||
Namespace: "argocd",
|
||||
},
|
||||
Spec: v1alpha1.ApplicationSetSpec{
|
||||
Strategy: &v1alpha1.ApplicationSetStrategy{
|
||||
Type: "RollingSync",
|
||||
RollingSync: &v1alpha1.ApplicationSetRolloutStrategy{},
|
||||
},
|
||||
},
|
||||
Status: v1alpha1.ApplicationSetStatus{
|
||||
ApplicationStatus: []v1alpha1.ApplicationSetApplicationStatus{
|
||||
{
|
||||
Application: "app1",
|
||||
LastTransitionTime: &metav1.Time{
|
||||
Time: time.Now(),
|
||||
},
|
||||
Message: "",
|
||||
Status: "Pending",
|
||||
Step: "1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
apps: []v1alpha1.Application{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "app1",
|
||||
},
|
||||
Status: v1alpha1.ApplicationStatus{
|
||||
Health: v1alpha1.HealthStatus{
|
||||
Status: health.HealthStatusDegraded,
|
||||
},
|
||||
OperationState: &v1alpha1.OperationState{
|
||||
Phase: common.OperationSucceeded,
|
||||
StartedAt: metav1.Time{
|
||||
Time: time.Now().Add(time.Duration(-1) * time.Second),
|
||||
},
|
||||
},
|
||||
Sync: v1alpha1.SyncStatus{
|
||||
Status: v1alpha1.SyncStatusCodeSynced,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedAppStatus: []v1alpha1.ApplicationSetApplicationStatus{
|
||||
{
|
||||
Application: "app1",
|
||||
Message: "Application resource completed a sync successfully, updating status from Pending to Progressing.",
|
||||
Status: "Progressing",
|
||||
Step: "1",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "does not progresses a pending application with an old successful sync to progressing",
|
||||
appSet: argov1alpha1.ApplicationSet{
|
||||
@@ -4014,7 +4071,7 @@ func TestUpdateApplicationSetApplicationStatus(t *testing.T) {
|
||||
{
|
||||
Application: "app1",
|
||||
LastTransitionTime: &metav1.Time{
|
||||
Time: time.Now().Add(time.Duration(-1) * time.Minute),
|
||||
Time: time.Now(),
|
||||
},
|
||||
Message: "Application moved to Pending status, watching for the Application resource to start Progressing.",
|
||||
Status: "Pending",
|
||||
@@ -4035,7 +4092,7 @@ func TestUpdateApplicationSetApplicationStatus(t *testing.T) {
|
||||
OperationState: &argov1alpha1.OperationState{
|
||||
Phase: common.OperationSucceeded,
|
||||
StartedAt: metav1.Time{
|
||||
Time: time.Now().Add(time.Duration(-2) * time.Minute),
|
||||
Time: time.Now().Add(time.Duration(-11) * time.Second),
|
||||
},
|
||||
},
|
||||
Sync: argov1alpha1.SyncStatus{
|
||||
|
||||
@@ -5,8 +5,8 @@ import (
|
||||
"reflect"
|
||||
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/utils"
|
||||
"github.com/jeremywohl/flatten"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
|
||||
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
@@ -26,7 +26,10 @@ type TransformResult struct {
|
||||
|
||||
// Transform a spec generator to list of paramSets and a template
|
||||
func Transform(requestedGenerator argoprojiov1alpha1.ApplicationSetGenerator, allGenerators map[string]Generator, baseTemplate argoprojiov1alpha1.ApplicationSetTemplate, appSet *argoprojiov1alpha1.ApplicationSet, genParams map[string]interface{}) ([]TransformResult, error) {
|
||||
selector, err := metav1.LabelSelectorAsSelector(requestedGenerator.Selector)
|
||||
// This is a custom version of the `LabelSelectorAsSelector` that is in k8s.io/apimachinery. This has been copied
|
||||
// verbatim from that package, with the difference that we do not have any restrictions on label values. This is done
|
||||
// so that, among other things, we can match on cluster urls.
|
||||
selector, err := utils.LabelSelectorAsSelector(requestedGenerator.Selector)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error parsing label selector: %w", err)
|
||||
}
|
||||
@@ -71,8 +74,17 @@ func Transform(requestedGenerator argoprojiov1alpha1.ApplicationSetGenerator, al
|
||||
}
|
||||
var filterParams []map[string]interface{}
|
||||
for _, param := range params {
|
||||
flatParam, err := flattenParameters(param)
|
||||
if err != nil {
|
||||
log.WithError(err).WithField("generator", g).
|
||||
Error("error flattening params")
|
||||
if firstError == nil {
|
||||
firstError = err
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if requestedGenerator.Selector != nil && !selector.Matches(labels.Set(keepOnlyStringValues(param))) {
|
||||
if requestedGenerator.Selector != nil && !selector.Matches(labels.Set(flatParam)) {
|
||||
continue
|
||||
}
|
||||
filterParams = append(filterParams, param)
|
||||
@@ -87,18 +99,6 @@ func Transform(requestedGenerator argoprojiov1alpha1.ApplicationSetGenerator, al
|
||||
return res, firstError
|
||||
}
|
||||
|
||||
func keepOnlyStringValues(in map[string]interface{}) map[string]string {
|
||||
var out map[string]string = map[string]string{}
|
||||
|
||||
for key, value := range in {
|
||||
if _, ok := value.(string); ok {
|
||||
out[key] = value.(string)
|
||||
}
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func GetRelevantGenerators(requestedGenerator *argoprojiov1alpha1.ApplicationSetGenerator, generators map[string]Generator) []Generator {
|
||||
var res []Generator
|
||||
|
||||
@@ -121,6 +121,20 @@ func GetRelevantGenerators(requestedGenerator *argoprojiov1alpha1.ApplicationSet
|
||||
return res
|
||||
}
|
||||
|
||||
func flattenParameters(in map[string]interface{}) (map[string]string, error) {
|
||||
flat, err := flatten.Flatten(in, "", flatten.DotStyle)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
out := make(map[string]string, len(flat))
|
||||
for k, v := range flat {
|
||||
out[k] = fmt.Sprintf("%v", v)
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func mergeGeneratorTemplate(g Generator, requestedGenerator *argoprojiov1alpha1.ApplicationSetGenerator, applicationSetTemplate argoprojiov1alpha1.ApplicationSetTemplate) (argoprojiov1alpha1.ApplicationSetTemplate, error) {
|
||||
// Make a copy of the value from `GetTemplate()` before merge, rather than copying directly into
|
||||
// the provided parameter (which will touch the original resource object returned by client-go)
|
||||
|
||||
@@ -94,8 +94,160 @@ func TestMatchValues(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func emptyTemplate() argoprojiov1alpha1.ApplicationSetTemplate {
|
||||
return argoprojiov1alpha1.ApplicationSetTemplate{
|
||||
func TestMatchValuesGoTemplate(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
elements []apiextensionsv1.JSON
|
||||
selector *metav1.LabelSelector
|
||||
expected []map[string]interface{}
|
||||
}{
|
||||
{
|
||||
name: "no filter",
|
||||
elements: []apiextensionsv1.JSON{{Raw: []byte(`{"cluster": "cluster","url": "url"}`)}},
|
||||
selector: &metav1.LabelSelector{},
|
||||
expected: []map[string]interface{}{{"cluster": "cluster", "url": "url"}},
|
||||
},
|
||||
{
|
||||
name: "nil",
|
||||
elements: []apiextensionsv1.JSON{{Raw: []byte(`{"cluster": "cluster","url": "url"}`)}},
|
||||
selector: nil,
|
||||
expected: []map[string]interface{}{{"cluster": "cluster", "url": "url"}},
|
||||
},
|
||||
{
|
||||
name: "values.foo should be foo but is ignore element",
|
||||
elements: []apiextensionsv1.JSON{{Raw: []byte(`{"cluster": "cluster","url": "url","values":{"foo":"bar"}}`)}},
|
||||
selector: &metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{
|
||||
"values.foo": "foo",
|
||||
},
|
||||
},
|
||||
expected: []map[string]interface{}{},
|
||||
},
|
||||
{
|
||||
name: "values.foo should be bar",
|
||||
elements: []apiextensionsv1.JSON{{Raw: []byte(`{"cluster": "cluster","url": "url","values":{"foo":"bar"}}`)}},
|
||||
selector: &metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{
|
||||
"values.foo": "bar",
|
||||
},
|
||||
},
|
||||
expected: []map[string]interface{}{{"cluster": "cluster", "url": "url", "values": map[string]interface{}{"foo": "bar"}}},
|
||||
},
|
||||
{
|
||||
name: "values.0 should be bar",
|
||||
elements: []apiextensionsv1.JSON{{Raw: []byte(`{"cluster": "cluster","url": "url","values":["bar"]}`)}},
|
||||
selector: &metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{
|
||||
"values.0": "bar",
|
||||
},
|
||||
},
|
||||
expected: []map[string]interface{}{{"cluster": "cluster", "url": "url", "values": []interface{}{"bar"}}},
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
var listGenerator = NewListGenerator()
|
||||
var data = map[string]Generator{
|
||||
"List": listGenerator,
|
||||
}
|
||||
|
||||
applicationSetInfo := argov1alpha1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "set",
|
||||
},
|
||||
Spec: argov1alpha1.ApplicationSetSpec{
|
||||
GoTemplate: true,
|
||||
},
|
||||
}
|
||||
|
||||
results, err := Transform(argov1alpha1.ApplicationSetGenerator{
|
||||
Selector: testCase.selector,
|
||||
List: &argov1alpha1.ListGenerator{
|
||||
Elements: testCase.elements,
|
||||
Template: emptyTemplate(),
|
||||
}},
|
||||
data,
|
||||
emptyTemplate(),
|
||||
&applicationSetInfo, nil)
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.ElementsMatch(t, testCase.expected, results[0].Params)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTransForm(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
selector *metav1.LabelSelector
|
||||
expected []map[string]interface{}
|
||||
}{
|
||||
{
|
||||
name: "server filter",
|
||||
selector: &metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{"server": "https://production-01.example.com"},
|
||||
},
|
||||
expected: []map[string]interface{}{{
|
||||
"metadata.annotations.foo.argoproj.io": "production",
|
||||
"metadata.labels.argocd.argoproj.io/secret-type": "cluster",
|
||||
"metadata.labels.environment": "production",
|
||||
"metadata.labels.org": "bar",
|
||||
"name": "production_01/west",
|
||||
"nameNormalized": "production-01-west",
|
||||
"server": "https://production-01.example.com",
|
||||
}},
|
||||
},
|
||||
{
|
||||
name: "server filter with long url",
|
||||
selector: &metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{"server": "https://some-really-long-url-that-will-exceed-63-characters.com"},
|
||||
},
|
||||
expected: []map[string]interface{}{{
|
||||
"metadata.annotations.foo.argoproj.io": "production",
|
||||
"metadata.labels.argocd.argoproj.io/secret-type": "cluster",
|
||||
"metadata.labels.environment": "production",
|
||||
"metadata.labels.org": "bar",
|
||||
"name": "some-really-long-server-url",
|
||||
"nameNormalized": "some-really-long-server-url",
|
||||
"server": "https://some-really-long-url-that-will-exceed-63-characters.com",
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
testGenerators := map[string]Generator{
|
||||
"Clusters": getMockClusterGenerator(),
|
||||
}
|
||||
|
||||
applicationSetInfo := argov1alpha1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "set",
|
||||
},
|
||||
Spec: argov1alpha1.ApplicationSetSpec{},
|
||||
}
|
||||
|
||||
results, err := Transform(
|
||||
argov1alpha1.ApplicationSetGenerator{
|
||||
Selector: testCase.selector,
|
||||
Clusters: &argov1alpha1.ClusterGenerator{
|
||||
Selector: metav1.LabelSelector{},
|
||||
Template: argov1alpha1.ApplicationSetTemplate{},
|
||||
Values: nil,
|
||||
}},
|
||||
testGenerators,
|
||||
emptyTemplate(),
|
||||
&applicationSetInfo, nil)
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.ElementsMatch(t, testCase.expected, results[0].Params)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func emptyTemplate() argov1alpha1.ApplicationSetTemplate {
|
||||
return argov1alpha1.ApplicationSetTemplate{
|
||||
Spec: argov1alpha1.ApplicationSpec{
|
||||
Project: "project",
|
||||
},
|
||||
@@ -152,8 +304,35 @@ func getMockClusterGenerator() Generator {
|
||||
},
|
||||
Type: corev1.SecretType("Opaque"),
|
||||
},
|
||||
&corev1.Secret{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "Secret",
|
||||
APIVersion: "v1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "some-really-long-server-url",
|
||||
Namespace: "namespace",
|
||||
Labels: map[string]string{
|
||||
"argocd.argoproj.io/secret-type": "cluster",
|
||||
"environment": "production",
|
||||
"org": "bar",
|
||||
},
|
||||
Annotations: map[string]string{
|
||||
"foo.argoproj.io": "production",
|
||||
},
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"config": []byte("{}"),
|
||||
"name": []byte("some-really-long-server-url"),
|
||||
"server": []byte("https://some-really-long-url-that-will-exceed-63-characters.com"),
|
||||
},
|
||||
Type: corev1.SecretType("Opaque"),
|
||||
},
|
||||
}
|
||||
runtimeClusters := []runtime.Object{}
|
||||
for _, clientCluster := range clusters {
|
||||
runtimeClusters = append(runtimeClusters, clientCluster)
|
||||
}
|
||||
appClientset := kubefake.NewSimpleClientset(runtimeClusters...)
|
||||
|
||||
fakeClient := fake.NewClientBuilder().WithObjects(clusters...).Build()
|
||||
|
||||
261
applicationset/utils/selector.go
Normal file
261
applicationset/utils/selector.go
Normal file
@@ -0,0 +1,261 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/selection"
|
||||
"k8s.io/apimachinery/pkg/util/validation"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
"k8s.io/klog/v2"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
unaryOperators = []string{
|
||||
string(selection.Exists), string(selection.DoesNotExist),
|
||||
}
|
||||
binaryOperators = []string{
|
||||
string(selection.In), string(selection.NotIn),
|
||||
string(selection.Equals), string(selection.DoubleEquals), string(selection.NotEquals),
|
||||
string(selection.GreaterThan), string(selection.LessThan),
|
||||
}
|
||||
validRequirementOperators = append(binaryOperators, unaryOperators...)
|
||||
)
|
||||
|
||||
// Selector represents a label selector.
|
||||
type Selector interface {
|
||||
// Matches returns true if this selector matches the given set of labels.
|
||||
Matches(labels.Labels) bool
|
||||
|
||||
// Add adds requirements to the Selector
|
||||
Add(r ...Requirement) Selector
|
||||
}
|
||||
|
||||
type internalSelector []Requirement
|
||||
|
||||
// ByKey sorts requirements by key to obtain deterministic parser
|
||||
type ByKey []Requirement
|
||||
|
||||
func (a ByKey) Len() int { return len(a) }
|
||||
|
||||
func (a ByKey) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
|
||||
func (a ByKey) Less(i, j int) bool { return a[i].key < a[j].key }
|
||||
|
||||
// Matches for a internalSelector returns true if all
|
||||
// its Requirements match the input Labels. If any
|
||||
// Requirement does not match, false is returned.
|
||||
func (s internalSelector) Matches(l labels.Labels) bool {
|
||||
for ix := range s {
|
||||
if matches := s[ix].Matches(l); !matches {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Add adds requirements to the selector. It copies the current selector returning a new one
|
||||
func (s internalSelector) Add(reqs ...Requirement) Selector {
|
||||
ret := make(internalSelector, 0, len(s)+len(reqs))
|
||||
ret = append(ret, s...)
|
||||
ret = append(ret, reqs...)
|
||||
sort.Sort(ByKey(ret))
|
||||
return ret
|
||||
}
|
||||
|
||||
type nothingSelector struct{}
|
||||
|
||||
func (n nothingSelector) Matches(l labels.Labels) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (n nothingSelector) Add(r ...Requirement) Selector {
|
||||
return n
|
||||
}
|
||||
|
||||
// Nothing returns a selector that matches no labels
|
||||
func nothing() Selector {
|
||||
return nothingSelector{}
|
||||
}
|
||||
|
||||
// Everything returns a selector that matches all labels.
|
||||
func everything() Selector {
|
||||
return internalSelector{}
|
||||
}
|
||||
|
||||
// LabelSelectorAsSelector converts the LabelSelector api type into a struct that implements
|
||||
// labels.Selector
|
||||
// Note: This function should be kept in sync with the selector methods in pkg/labels/selector.go
|
||||
func LabelSelectorAsSelector(ps *v1.LabelSelector) (Selector, error) {
|
||||
if ps == nil {
|
||||
return nothing(), nil
|
||||
}
|
||||
if len(ps.MatchLabels)+len(ps.MatchExpressions) == 0 {
|
||||
return everything(), nil
|
||||
}
|
||||
requirements := make([]Requirement, 0, len(ps.MatchLabels)+len(ps.MatchExpressions))
|
||||
for k, v := range ps.MatchLabels {
|
||||
r, err := newRequirement(k, selection.Equals, []string{v})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
requirements = append(requirements, *r)
|
||||
}
|
||||
for _, expr := range ps.MatchExpressions {
|
||||
var op selection.Operator
|
||||
switch expr.Operator {
|
||||
case v1.LabelSelectorOpIn:
|
||||
op = selection.In
|
||||
case v1.LabelSelectorOpNotIn:
|
||||
op = selection.NotIn
|
||||
case v1.LabelSelectorOpExists:
|
||||
op = selection.Exists
|
||||
case v1.LabelSelectorOpDoesNotExist:
|
||||
op = selection.DoesNotExist
|
||||
default:
|
||||
return nil, fmt.Errorf("%q is not a valid pod selector operator", expr.Operator)
|
||||
}
|
||||
r, err := newRequirement(expr.Key, op, append([]string(nil), expr.Values...))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
requirements = append(requirements, *r)
|
||||
}
|
||||
selector := newSelector()
|
||||
selector = selector.Add(requirements...)
|
||||
return selector, nil
|
||||
}
|
||||
|
||||
// NewSelector returns a nil selector
|
||||
func newSelector() Selector {
|
||||
return internalSelector(nil)
|
||||
}
|
||||
|
||||
func validateLabelKey(k string, path *field.Path) *field.Error {
|
||||
if errs := validation.IsQualifiedName(k); len(errs) != 0 {
|
||||
return field.Invalid(path, k, strings.Join(errs, "; "))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewRequirement is the constructor for a Requirement.
|
||||
// If any of these rules is violated, an error is returned:
|
||||
// (1) The operator can only be In, NotIn, Equals, DoubleEquals, Gt, Lt, NotEquals, Exists, or DoesNotExist.
|
||||
// (2) If the operator is In or NotIn, the values set must be non-empty.
|
||||
// (3) If the operator is Equals, DoubleEquals, or NotEquals, the values set must contain one value.
|
||||
// (4) If the operator is Exists or DoesNotExist, the value set must be empty.
|
||||
// (5) If the operator is Gt or Lt, the values set must contain only one value, which will be interpreted as an integer.
|
||||
// (6) The key is invalid due to its length, or sequence
|
||||
//
|
||||
// of characters. See validateLabelKey for more details.
|
||||
//
|
||||
// The empty string is a valid value in the input values set.
|
||||
// Returned error, if not nil, is guaranteed to be an aggregated field.ErrorList
|
||||
func newRequirement(key string, op selection.Operator, vals []string, opts ...field.PathOption) (*Requirement, error) {
|
||||
var allErrs field.ErrorList
|
||||
path := field.ToPath(opts...)
|
||||
if err := validateLabelKey(key, path.Child("key")); err != nil {
|
||||
allErrs = append(allErrs, err)
|
||||
}
|
||||
|
||||
valuePath := path.Child("values")
|
||||
switch op {
|
||||
case selection.In, selection.NotIn:
|
||||
if len(vals) == 0 {
|
||||
allErrs = append(allErrs, field.Invalid(valuePath, vals, "for 'in', 'notin' operators, values set can't be empty"))
|
||||
}
|
||||
case selection.Equals, selection.DoubleEquals, selection.NotEquals:
|
||||
if len(vals) != 1 {
|
||||
allErrs = append(allErrs, field.Invalid(valuePath, vals, "exact-match compatibility requires one single value"))
|
||||
}
|
||||
case selection.Exists, selection.DoesNotExist:
|
||||
if len(vals) != 0 {
|
||||
allErrs = append(allErrs, field.Invalid(valuePath, vals, "values set must be empty for exists and does not exist"))
|
||||
}
|
||||
case selection.GreaterThan, selection.LessThan:
|
||||
if len(vals) != 1 {
|
||||
allErrs = append(allErrs, field.Invalid(valuePath, vals, "for 'Gt', 'Lt' operators, exactly one value is required"))
|
||||
}
|
||||
for i := range vals {
|
||||
if _, err := strconv.ParseInt(vals[i], 10, 64); err != nil {
|
||||
allErrs = append(allErrs, field.Invalid(valuePath.Index(i), vals[i], "for 'Gt', 'Lt' operators, the value must be an integer"))
|
||||
}
|
||||
}
|
||||
default:
|
||||
allErrs = append(allErrs, field.NotSupported(path.Child("operator"), op, validRequirementOperators))
|
||||
}
|
||||
|
||||
return &Requirement{key: key, operator: op, strValues: vals}, allErrs.ToAggregate()
|
||||
}
|
||||
|
||||
// Requirement contains values, a key, and an operator that relates the key and values.
|
||||
// The zero value of Requirement is invalid.
|
||||
// Requirement implements both set based match and exact match
|
||||
// Requirement should be initialized via NewRequirement constructor for creating a valid Requirement.
|
||||
// +k8s:deepcopy-gen=true
|
||||
type Requirement struct {
|
||||
key string
|
||||
operator selection.Operator
|
||||
// In the majority of cases we have at most one value here.
|
||||
// It is generally faster to operate on a single-element slice
|
||||
// than on a single-element map, so we have a slice here.
|
||||
strValues []string
|
||||
}
|
||||
|
||||
func (r *Requirement) hasValue(value string) bool {
|
||||
for i := range r.strValues {
|
||||
if r.strValues[i] == value {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (r *Requirement) Matches(ls labels.Labels) bool {
|
||||
switch r.operator {
|
||||
case selection.In, selection.Equals, selection.DoubleEquals:
|
||||
if !ls.Has(r.key) {
|
||||
return false
|
||||
}
|
||||
return r.hasValue(ls.Get(r.key))
|
||||
case selection.NotIn, selection.NotEquals:
|
||||
if !ls.Has(r.key) {
|
||||
return true
|
||||
}
|
||||
return !r.hasValue(ls.Get(r.key))
|
||||
case selection.Exists:
|
||||
return ls.Has(r.key)
|
||||
case selection.DoesNotExist:
|
||||
return !ls.Has(r.key)
|
||||
case selection.GreaterThan, selection.LessThan:
|
||||
if !ls.Has(r.key) {
|
||||
return false
|
||||
}
|
||||
lsValue, err := strconv.ParseInt(ls.Get(r.key), 10, 64)
|
||||
if err != nil {
|
||||
klog.V(10).Infof("ParseInt failed for value %+v in label %+v, %+v", ls.Get(r.key), ls, err)
|
||||
return false
|
||||
}
|
||||
|
||||
// There should be only one strValue in r.strValues, and can be converted to an integer.
|
||||
if len(r.strValues) != 1 {
|
||||
klog.V(10).Infof("Invalid values count %+v of requirement %#v, for 'Gt', 'Lt' operators, exactly one value is required", len(r.strValues), r)
|
||||
return false
|
||||
}
|
||||
|
||||
var rValue int64
|
||||
for i := range r.strValues {
|
||||
rValue, err = strconv.ParseInt(r.strValues[i], 10, 64)
|
||||
if err != nil {
|
||||
klog.V(10).Infof("ParseInt failed for value %+v in requirement %#v, for 'Gt', 'Lt' operators, the value must be an integer", r.strValues[i], r)
|
||||
return false
|
||||
}
|
||||
}
|
||||
return (r.operator == selection.GreaterThan && lsValue > rValue) || (r.operator == selection.LessThan && lsValue < rValue)
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -267,7 +267,10 @@ func (r *Render) Replace(tmpl string, replaceMap map[string]interface{}, useGoTe
|
||||
return tmpl, nil
|
||||
}
|
||||
|
||||
fstTmpl := fasttemplate.New(tmpl, "{{", "}}")
|
||||
fstTmpl, err := fasttemplate.NewTemplate(tmpl, "{{", "}}")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("invalid template: %w", err)
|
||||
}
|
||||
replacedTmpl := fstTmpl.ExecuteFuncString(func(w io.Writer, tag string) (int, error) {
|
||||
trimmedTag := strings.TrimSpace(tag)
|
||||
replacement, ok := replaceMap[trimmedTag].(string)
|
||||
|
||||
@@ -464,6 +464,14 @@ func TestRenderTemplateParamsGoTemplate(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Render_Replace_no_panic_on_missing_closing_brace(t *testing.T) {
|
||||
r := &Render{}
|
||||
assert.NotPanics(t, func() {
|
||||
_, err := r.Replace("{{properly.closed}} {{improperly.closed}", nil, false)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRenderTemplateKeys(t *testing.T) {
|
||||
t.Run("fasttemplate", func(t *testing.T) {
|
||||
application := &argoappsv1.Application{
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
log "github.com/sirupsen/logrus"
|
||||
@@ -373,6 +374,9 @@ func resolveRBACResourceName(name string) string {
|
||||
|
||||
// isValidRBACAction checks whether a given action is a valid RBAC action
|
||||
func isValidRBACAction(action string) bool {
|
||||
if strings.HasPrefix(action, rbacpolicy.ActionAction+"/") {
|
||||
return true
|
||||
}
|
||||
_, ok := validRBACActions[action]
|
||||
return ok
|
||||
}
|
||||
|
||||
@@ -27,6 +27,11 @@ func Test_isValidRBACAction(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func Test_isValidRBACAction_ActionAction(t *testing.T) {
|
||||
ok := isValidRBACAction("action/apps/Deployment/restart")
|
||||
assert.True(t, ok)
|
||||
}
|
||||
|
||||
func Test_isValidRBACResource(t *testing.T) {
|
||||
for k := range validRBACResources {
|
||||
t.Run(k, func(t *testing.T) {
|
||||
|
||||
@@ -1003,7 +1003,7 @@ func findandPrintDiff(ctx context.Context, app *argoappv1.Application, resources
|
||||
unstructureds = append(unstructureds, obj)
|
||||
}
|
||||
groupedObjs := groupObjsByKey(unstructureds, liveObjs, app.Spec.Destination.Namespace)
|
||||
items = groupObjsForDiff(resources, groupedObjs, items, argoSettings, app.Name)
|
||||
items = groupObjsForDiff(resources, groupedObjs, items, argoSettings, app.InstanceName(argoSettings.ControllerNamespace))
|
||||
} else if diffOptions.serversideRes != nil {
|
||||
var unstructureds []*unstructured.Unstructured
|
||||
for _, mfst := range diffOptions.serversideRes.Manifests {
|
||||
@@ -1012,7 +1012,7 @@ func findandPrintDiff(ctx context.Context, app *argoappv1.Application, resources
|
||||
unstructureds = append(unstructureds, obj)
|
||||
}
|
||||
groupedObjs := groupObjsByKey(unstructureds, liveObjs, app.Spec.Destination.Namespace)
|
||||
items = groupObjsForDiff(resources, groupedObjs, items, argoSettings, app.Name)
|
||||
items = groupObjsForDiff(resources, groupedObjs, items, argoSettings, app.InstanceName(argoSettings.ControllerNamespace))
|
||||
} else {
|
||||
for i := range resources.Items {
|
||||
res := resources.Items[i]
|
||||
@@ -1446,7 +1446,7 @@ func NewApplicationWaitCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
|
||||
}
|
||||
}
|
||||
for _, appName := range appNames {
|
||||
_, err := waitOnApplicationStatus(ctx, acdClient, appName, timeout, watch, selectedResources)
|
||||
_, _, err := waitOnApplicationStatus(ctx, acdClient, appName, timeout, watch, selectedResources)
|
||||
errors.CheckError(err)
|
||||
}
|
||||
},
|
||||
@@ -1607,8 +1607,15 @@ func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
|
||||
errors.CheckError(err)
|
||||
|
||||
if app.Spec.HasMultipleSources() {
|
||||
log.Fatal("argocd cli does not work on multi-source app")
|
||||
return
|
||||
if revision != "" {
|
||||
log.Fatal("argocd cli does not work on multi-source app with --revision flag")
|
||||
return
|
||||
}
|
||||
|
||||
if local != "" {
|
||||
log.Fatal("argocd cli does not work on multi-source app with --local flag")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if local != "" {
|
||||
@@ -1712,15 +1719,15 @@ func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
|
||||
errors.CheckError(err)
|
||||
|
||||
if !async {
|
||||
app, err := waitOnApplicationStatus(ctx, acdClient, appQualifiedName, timeout, watchOpts{operation: true}, selectedResources)
|
||||
app, opState, err := waitOnApplicationStatus(ctx, acdClient, appQualifiedName, timeout, watchOpts{operation: true}, selectedResources)
|
||||
errors.CheckError(err)
|
||||
|
||||
if !dryRun {
|
||||
if !app.Status.OperationState.Phase.Successful() {
|
||||
log.Fatalf("Operation has completed with phase: %s", app.Status.OperationState.Phase)
|
||||
if !opState.Phase.Successful() {
|
||||
log.Fatalf("Operation has completed with phase: %s", opState.Phase)
|
||||
} else if len(selectedResources) == 0 && app.Status.Sync.Status != argoappv1.SyncStatusCodeSynced {
|
||||
// Only get resources to be pruned if sync was application-wide and final status is not synced
|
||||
pruningRequired := app.Status.OperationState.SyncResult.Resources.PruningRequired()
|
||||
pruningRequired := opState.SyncResult.Resources.PruningRequired()
|
||||
if pruningRequired > 0 {
|
||||
log.Fatalf("%d resources require pruning", pruningRequired)
|
||||
}
|
||||
@@ -1920,7 +1927,10 @@ func checkResourceStatus(watch watchOpts, healthStatus string, syncStatus string
|
||||
|
||||
const waitFormatString = "%s\t%5s\t%10s\t%10s\t%20s\t%8s\t%7s\t%10s\t%s\n"
|
||||
|
||||
func waitOnApplicationStatus(ctx context.Context, acdClient argocdclient.Client, appName string, timeout uint, watch watchOpts, selectedResources []*argoappv1.SyncOperationResource) (*argoappv1.Application, error) {
|
||||
// waitOnApplicationStatus watches an application and blocks until either the desired watch conditions
|
||||
// are fulfiled or we reach the timeout. Returns the app once desired conditions have been filled.
|
||||
// Additionally return the operationState at time of fulfilment (which may be different than returned app).
|
||||
func waitOnApplicationStatus(ctx context.Context, acdClient argocdclient.Client, appName string, timeout uint, watch watchOpts, selectedResources []*argoappv1.SyncOperationResource) (*argoappv1.Application, *argoappv1.OperationState, error) {
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
@@ -1978,10 +1988,20 @@ func waitOnApplicationStatus(ctx context.Context, acdClient argocdclient.Client,
|
||||
AppNamespace: &appNs,
|
||||
})
|
||||
errors.CheckError(err)
|
||||
|
||||
// printFinalStatus() will refresh and update the app object, potentially causing the app's
|
||||
// status.operationState to be different than the version when we break out of the event loop.
|
||||
// This means the app.status is unreliable for determining the final state of the operation.
|
||||
// finalOperationState captures the operationState as it was seen when we met the conditions of
|
||||
// the wait, so the caller can rely on it to determine the outcome of the operation.
|
||||
// See: https://github.com/argoproj/argo-cd/issues/5592
|
||||
finalOperationState := app.Status.OperationState
|
||||
|
||||
appEventCh := acdClient.WatchApplicationWithRetry(ctx, appName, app.ResourceVersion)
|
||||
for appEvent := range appEventCh {
|
||||
app = &appEvent.Application
|
||||
|
||||
finalOperationState = app.Status.OperationState
|
||||
operationInProgress := false
|
||||
// consider the operation is in progress
|
||||
if app.Operation != nil {
|
||||
@@ -2019,7 +2039,7 @@ func waitOnApplicationStatus(ctx context.Context, acdClient argocdclient.Client,
|
||||
|
||||
if selectedResourcesAreReady && (!operationInProgress || !watch.operation) {
|
||||
app = printFinalStatus(app)
|
||||
return app, nil
|
||||
return app, finalOperationState, nil
|
||||
}
|
||||
|
||||
newStates := groupResourceStates(app, selectedResources)
|
||||
@@ -2029,7 +2049,7 @@ func waitOnApplicationStatus(ctx context.Context, acdClient argocdclient.Client,
|
||||
if prevState, found := prevStates[stateKey]; found {
|
||||
if watch.health && prevState.Health != string(health.HealthStatusUnknown) && prevState.Health != string(health.HealthStatusDegraded) && newState.Health == string(health.HealthStatusDegraded) {
|
||||
_ = printFinalStatus(app)
|
||||
return nil, fmt.Errorf("application '%s' health state has transitioned from %s to %s", appName, prevState.Health, newState.Health)
|
||||
return nil, finalOperationState, fmt.Errorf("application '%s' health state has transitioned from %s to %s", appName, prevState.Health, newState.Health)
|
||||
}
|
||||
doPrint = prevState.Merge(newState)
|
||||
} else {
|
||||
@@ -2043,7 +2063,7 @@ func waitOnApplicationStatus(ctx context.Context, acdClient argocdclient.Client,
|
||||
_ = w.Flush()
|
||||
}
|
||||
_ = printFinalStatus(app)
|
||||
return nil, fmt.Errorf("timed out (%ds) waiting for app %q match desired state", timeout, appName)
|
||||
return nil, finalOperationState, fmt.Errorf("timed out (%ds) waiting for app %q match desired state", timeout, appName)
|
||||
}
|
||||
|
||||
// setParameterOverrides updates an existing or appends a new parameter override in the application
|
||||
@@ -2199,7 +2219,7 @@ func NewApplicationRollbackCommand(clientOpts *argocdclient.ClientOptions) *cobr
|
||||
})
|
||||
errors.CheckError(err)
|
||||
|
||||
_, err = waitOnApplicationStatus(ctx, acdClient, app.QualifiedName(), timeout, watchOpts{
|
||||
_, _, err = waitOnApplicationStatus(ctx, acdClient, app.QualifiedName(), timeout, watchOpts{
|
||||
operation: true,
|
||||
}, nil)
|
||||
errors.CheckError(err)
|
||||
|
||||
@@ -3,6 +3,7 @@ package commands
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"text/tabwriter"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
@@ -250,15 +251,12 @@ func printRepoTable(repos appsv1.Repositories) {
|
||||
_, _ = fmt.Fprintf(w, "TYPE\tNAME\tREPO\tINSECURE\tOCI\tLFS\tCREDS\tSTATUS\tMESSAGE\tPROJECT\n")
|
||||
for _, r := range repos {
|
||||
var hasCreds string
|
||||
if !r.HasCredentials() {
|
||||
hasCreds = "false"
|
||||
if r.InheritedCreds {
|
||||
hasCreds = "inherited"
|
||||
} else {
|
||||
if r.InheritedCreds {
|
||||
hasCreds = "inherited"
|
||||
} else {
|
||||
hasCreds = "true"
|
||||
}
|
||||
hasCreds = strconv.FormatBool(r.HasCredentials())
|
||||
}
|
||||
|
||||
_, _ = fmt.Fprintf(w, "%s\t%s\t%s\t%v\t%v\t%v\t%s\t%s\t%s\t%s\n", r.Type, r.Name, r.Repo, r.IsInsecure(), r.EnableOCI, r.EnableLFS, hasCreds, r.ConnectionState.Status, r.ConnectionState.Message, r.Project)
|
||||
}
|
||||
_ = w.Flush()
|
||||
|
||||
@@ -24,6 +24,7 @@ import (
|
||||
"github.com/argoproj/argo-cd/v2/util/io/files"
|
||||
|
||||
"github.com/argoproj/gitops-engine/pkg/utils/kube"
|
||||
"github.com/cyphar/filepath-securejoin"
|
||||
"github.com/mattn/go-zglob"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
@@ -96,6 +97,14 @@ func runCommand(ctx context.Context, command Command, path string, env []string)
|
||||
<-ctx.Done()
|
||||
// Kill by group ID to make sure child processes are killed. The - tells `kill` that it's a group ID.
|
||||
// Since we didn't set Pgid in SysProcAttr, the group ID is the same as the process ID. https://pkg.go.dev/syscall#SysProcAttr
|
||||
|
||||
// Sending a TERM signal first to allow any potential cleanup if needed, and then sending a KILL signal
|
||||
_ = sysCallTerm(-cmd.Process.Pid)
|
||||
|
||||
// modify cleanup timeout to allow process to cleanup
|
||||
cleanupTimeout := 5 * time.Second
|
||||
time.Sleep(cleanupTimeout)
|
||||
|
||||
_ = sysCallKill(-cmd.Process.Pid)
|
||||
}()
|
||||
|
||||
@@ -176,7 +185,7 @@ func getTempDirMustCleanup(baseDir string) (workDir string, cleanup func(), err
|
||||
if err := os.RemoveAll(workDir); err != nil {
|
||||
log.WithFields(map[string]interface{}{
|
||||
common.SecurityField: common.SecurityHigh,
|
||||
common.SecurityCWEField: 459,
|
||||
common.SecurityCWEField: common.SecurityCWEIncompleteCleanup,
|
||||
}).Errorf("Failed to clean up temp directory: %s", err)
|
||||
}
|
||||
}
|
||||
@@ -296,7 +305,7 @@ func (s *Service) matchRepositoryGeneric(stream MatchRepositoryStream) error {
|
||||
return fmt.Errorf("match repository error receiving stream: %w", err)
|
||||
}
|
||||
|
||||
isSupported, isDiscoveryEnabled, err := s.matchRepository(bufferedCtx, workDir, metadata.GetEnv())
|
||||
isSupported, isDiscoveryEnabled, err := s.matchRepository(bufferedCtx, workDir, metadata.GetEnv(), metadata.GetAppRelPath())
|
||||
if err != nil {
|
||||
return fmt.Errorf("match repository error: %w", err)
|
||||
}
|
||||
@@ -309,12 +318,20 @@ func (s *Service) matchRepositoryGeneric(stream MatchRepositoryStream) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) matchRepository(ctx context.Context, workdir string, envEntries []*apiclient.EnvEntry) (isSupported bool, isDiscoveryEnabled bool, err error) {
|
||||
func (s *Service) matchRepository(ctx context.Context, workdir string, envEntries []*apiclient.EnvEntry, appRelPath string) (isSupported bool, isDiscoveryEnabled bool, err error) {
|
||||
config := s.initConstants.PluginConfig
|
||||
|
||||
appPath, err := securejoin.SecureJoin(workdir, appRelPath)
|
||||
if err != nil {
|
||||
log.WithFields(map[string]interface{}{
|
||||
common.SecurityField: common.SecurityHigh,
|
||||
common.SecurityCWEField: common.SecurityCWEIncompleteCleanup,
|
||||
}).Errorf("error joining workdir %q and appRelPath %q: %v", workdir, appRelPath, err)
|
||||
}
|
||||
|
||||
if config.Spec.Discover.FileName != "" {
|
||||
log.Debugf("config.Spec.Discover.FileName is provided")
|
||||
pattern := filepath.Join(workdir, config.Spec.Discover.FileName)
|
||||
pattern := filepath.Join(appPath, config.Spec.Discover.FileName)
|
||||
matches, err := filepath.Glob(pattern)
|
||||
if err != nil {
|
||||
e := fmt.Errorf("error finding filename match for pattern %q: %w", pattern, err)
|
||||
@@ -326,7 +343,7 @@ func (s *Service) matchRepository(ctx context.Context, workdir string, envEntrie
|
||||
|
||||
if config.Spec.Discover.Find.Glob != "" {
|
||||
log.Debugf("config.Spec.Discover.Find.Glob is provided")
|
||||
pattern := filepath.Join(workdir, config.Spec.Discover.Find.Glob)
|
||||
pattern := filepath.Join(appPath, config.Spec.Discover.Find.Glob)
|
||||
// filepath.Glob doesn't have '**' support hence selecting third-party lib
|
||||
// https://github.com/golang/go/issues/11862
|
||||
matches, err := zglob.Glob(pattern)
|
||||
@@ -342,7 +359,7 @@ func (s *Service) matchRepository(ctx context.Context, workdir string, envEntrie
|
||||
if len(config.Spec.Discover.Find.Command.Command) > 0 {
|
||||
log.Debugf("Going to try runCommand.")
|
||||
env := append(os.Environ(), environ(envEntries)...)
|
||||
find, err := runCommand(ctx, config.Spec.Discover.Find.Command, workdir, env)
|
||||
find, err := runCommand(ctx, config.Spec.Discover.Find.Command, appPath, env)
|
||||
if err != nil {
|
||||
return false, true, fmt.Errorf("error running find command: %w", err)
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ func TestMatchRepository(t *testing.T) {
|
||||
f := setup(t, withDiscover(d))
|
||||
|
||||
// when
|
||||
match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env)
|
||||
match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env, ".")
|
||||
|
||||
// then
|
||||
assert.NoError(t, err)
|
||||
@@ -115,7 +115,7 @@ func TestMatchRepository(t *testing.T) {
|
||||
f := setup(t, withDiscover(d))
|
||||
|
||||
// when
|
||||
match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env)
|
||||
match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env, ".")
|
||||
|
||||
// then
|
||||
assert.NoError(t, err)
|
||||
@@ -130,7 +130,7 @@ func TestMatchRepository(t *testing.T) {
|
||||
f := setup(t, withDiscover(d))
|
||||
|
||||
// when
|
||||
_, _, err := f.service.matchRepository(context.Background(), f.path, f.env)
|
||||
_, _, err := f.service.matchRepository(context.Background(), f.path, f.env, ".")
|
||||
|
||||
// then
|
||||
assert.ErrorContains(t, err, "syntax error")
|
||||
@@ -145,7 +145,7 @@ func TestMatchRepository(t *testing.T) {
|
||||
f := setup(t, withDiscover(d))
|
||||
|
||||
// when
|
||||
match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env)
|
||||
match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env, ".")
|
||||
|
||||
// then
|
||||
assert.NoError(t, err)
|
||||
@@ -162,7 +162,7 @@ func TestMatchRepository(t *testing.T) {
|
||||
f := setup(t, withDiscover(d))
|
||||
|
||||
// when
|
||||
match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env)
|
||||
match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env, ".")
|
||||
|
||||
// then
|
||||
assert.NoError(t, err)
|
||||
@@ -179,7 +179,7 @@ func TestMatchRepository(t *testing.T) {
|
||||
f := setup(t, withDiscover(d))
|
||||
|
||||
// when
|
||||
_, _, err := f.service.matchRepository(context.Background(), f.path, f.env)
|
||||
_, _, err := f.service.matchRepository(context.Background(), f.path, f.env, ".")
|
||||
|
||||
// then
|
||||
assert.ErrorContains(t, err, "error finding glob match for pattern")
|
||||
@@ -196,7 +196,7 @@ func TestMatchRepository(t *testing.T) {
|
||||
f := setup(t, withDiscover(d))
|
||||
|
||||
// when
|
||||
match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env)
|
||||
match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env, ".")
|
||||
|
||||
// then
|
||||
assert.NoError(t, err)
|
||||
@@ -215,7 +215,7 @@ func TestMatchRepository(t *testing.T) {
|
||||
f := setup(t, withDiscover(d))
|
||||
|
||||
// when
|
||||
match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env)
|
||||
match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env, ".")
|
||||
// then
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, match)
|
||||
@@ -233,7 +233,7 @@ func TestMatchRepository(t *testing.T) {
|
||||
f := setup(t, withDiscover(d))
|
||||
|
||||
// when
|
||||
match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env)
|
||||
match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env, ".")
|
||||
|
||||
// then
|
||||
assert.NoError(t, err)
|
||||
@@ -253,7 +253,7 @@ func TestMatchRepository(t *testing.T) {
|
||||
f := setup(t, withDiscover(d))
|
||||
|
||||
// when
|
||||
match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env)
|
||||
match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env, ".")
|
||||
|
||||
// then
|
||||
assert.NoError(t, err)
|
||||
@@ -272,7 +272,7 @@ func TestMatchRepository(t *testing.T) {
|
||||
f := setup(t, withDiscover(d))
|
||||
|
||||
// when
|
||||
match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env)
|
||||
match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env, ".")
|
||||
|
||||
// then
|
||||
assert.Error(t, err)
|
||||
@@ -285,7 +285,7 @@ func TestMatchRepository(t *testing.T) {
|
||||
f := setup(t, withDiscover(d))
|
||||
|
||||
// when
|
||||
match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env)
|
||||
match, discovery, err := f.service.matchRepository(context.Background(), f.path, f.env, ".")
|
||||
|
||||
// then
|
||||
assert.NoError(t, err)
|
||||
@@ -369,6 +369,28 @@ func TestRunCommandEmptyCommand(t *testing.T) {
|
||||
assert.ErrorContains(t, err, "Command is empty")
|
||||
}
|
||||
|
||||
// TestRunCommandContextTimeoutWithGracefulTermination makes sure that the process is given enough time to cleanup before sending SIGKILL.
|
||||
func TestRunCommandContextTimeoutWithCleanup(t *testing.T) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 900*time.Millisecond)
|
||||
defer cancel()
|
||||
|
||||
// Use a subshell so there's a child command.
|
||||
// This command sleeps for 4 seconds which is currently less than the 5 second delay between SIGTERM and SIGKILL signal and then exits successfully.
|
||||
command := Command{
|
||||
Command: []string{"sh", "-c"},
|
||||
Args: []string{`(trap 'echo "cleanup completed"; exit' TERM; sleep 4)`},
|
||||
}
|
||||
|
||||
before := time.Now()
|
||||
output, err := runCommand(ctx, command, "", []string{})
|
||||
after := time.Now()
|
||||
|
||||
assert.Error(t, err) // The command should time out, causing an error.
|
||||
assert.Less(t, after.Sub(before), 1*time.Second)
|
||||
// The command should still have completed the cleanup after termination.
|
||||
assert.Contains(t, output, "cleanup completed")
|
||||
}
|
||||
|
||||
func Test_getParametersAnnouncement_empty_command(t *testing.T) {
|
||||
staticYAML := `
|
||||
- name: static-a
|
||||
|
||||
@@ -14,3 +14,7 @@ func newSysProcAttr(setpgid bool) *syscall.SysProcAttr {
|
||||
func sysCallKill(pid int) error {
|
||||
return syscall.Kill(pid, syscall.SIGKILL)
|
||||
}
|
||||
|
||||
func sysCallTerm(pid int) error {
|
||||
return syscall.Kill(pid, syscall.SIGTERM)
|
||||
}
|
||||
|
||||
@@ -14,3 +14,7 @@ func newSysProcAttr(setpgid bool) *syscall.SysProcAttr {
|
||||
func sysCallKill(pid int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func sysCallTerm(pid int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -305,13 +305,16 @@ const (
|
||||
|
||||
// Security severity logging
|
||||
const (
|
||||
SecurityField = "security"
|
||||
SecurityCWEField = "CWE"
|
||||
SecurityEmergency = 5 // Indicates unmistakably malicious events that should NEVER occur accidentally and indicates an active attack (i.e. brute forcing, DoS)
|
||||
SecurityCritical = 4 // Indicates any malicious or exploitable event that had a side effect (i.e. secrets being left behind on the filesystem)
|
||||
SecurityHigh = 3 // Indicates likely malicious events but one that had no side effects or was blocked (i.e. out of bounds symlinks in repos)
|
||||
SecurityMedium = 2 // Could indicate malicious events, but has a high likelihood of being user/system error (i.e. access denied)
|
||||
SecurityLow = 1 // Unexceptional entries (i.e. successful access logs)
|
||||
SecurityField = "security"
|
||||
// SecurityCWEField is the logs field for the CWE associated with a log line. CWE stands for Common Weakness Enumeration. See https://cwe.mitre.org/
|
||||
SecurityCWEField = "CWE"
|
||||
SecurityCWEIncompleteCleanup = 459
|
||||
SecurityCWEMissingReleaseOfFileDescriptor = 775
|
||||
SecurityEmergency = 5 // Indicates unmistakably malicious events that should NEVER occur accidentally and indicates an active attack (i.e. brute forcing, DoS)
|
||||
SecurityCritical = 4 // Indicates any malicious or exploitable event that had a side effect (i.e. secrets being left behind on the filesystem)
|
||||
SecurityHigh = 3 // Indicates likely malicious events but one that had no side effects or was blocked (i.e. out of bounds symlinks in repos)
|
||||
SecurityMedium = 2 // Could indicate malicious events, but has a high likelihood of being user/system error (i.e. access denied)
|
||||
SecurityLow = 1 // Unexceptional entries (i.e. successful access logs)
|
||||
)
|
||||
|
||||
// Common error messages
|
||||
|
||||
@@ -50,6 +50,7 @@ type namespacedResource struct {
|
||||
type fakeData struct {
|
||||
apps []runtime.Object
|
||||
manifestResponse *apiclient.ManifestResponse
|
||||
manifestResponses []*apiclient.ManifestResponse
|
||||
managedLiveObjs map[kube.ResourceKey]*unstructured.Unstructured
|
||||
namespacedResources map[kube.ResourceKey]namespacedResource
|
||||
configMapData map[string]string
|
||||
@@ -65,7 +66,15 @@ func newFakeController(data *fakeData) *ApplicationController {
|
||||
|
||||
// Mock out call to GenerateManifest
|
||||
mockRepoClient := mockrepoclient.RepoServerServiceClient{}
|
||||
mockRepoClient.On("GenerateManifest", mock.Anything, mock.Anything).Return(data.manifestResponse, nil)
|
||||
|
||||
if len(data.manifestResponses) > 0 {
|
||||
for _, response := range data.manifestResponses {
|
||||
mockRepoClient.On("GenerateManifest", mock.Anything, mock.Anything).Return(response, nil).Once()
|
||||
}
|
||||
} else {
|
||||
mockRepoClient.On("GenerateManifest", mock.Anything, mock.Anything).Return(data.manifestResponse, nil)
|
||||
}
|
||||
|
||||
mockRepoClientset := mockrepoclient.Clientset{RepoServerServiceClient: &mockRepoClient}
|
||||
|
||||
secret := corev1.Secret{
|
||||
@@ -223,9 +232,14 @@ spec:
|
||||
project: default
|
||||
sources:
|
||||
- path: some/path
|
||||
helm:
|
||||
valueFiles:
|
||||
- $values_test/values.yaml
|
||||
repoURL: https://github.com/argoproj/argocd-example-apps.git
|
||||
- path: some/other/path
|
||||
repoURL: https://github.com/argoproj/argocd-example-apps-fake.git
|
||||
- ref: values_test
|
||||
repoURL: https://github.com/argoproj/argocd-example-apps-fake-ref.git
|
||||
syncPolicy:
|
||||
automated: {}
|
||||
status:
|
||||
@@ -237,6 +251,7 @@ status:
|
||||
revisions:
|
||||
- HEAD
|
||||
- HEAD
|
||||
- HEAD
|
||||
phase: Succeeded
|
||||
startedAt: 2018-09-21T23:50:25Z
|
||||
syncResult:
|
||||
@@ -251,11 +266,14 @@ status:
|
||||
revisions:
|
||||
- aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
- bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
||||
- cccccccccccccccccccccccccccccccccccccccc
|
||||
sources:
|
||||
- path: some/path
|
||||
repoURL: https://github.com/argoproj/argocd-example-apps.git
|
||||
- path: some/other/path
|
||||
repoURL: https://github.com/argoproj/argocd-example-apps-fake.git
|
||||
- path: some/other/path
|
||||
repoURL: https://github.com/argoproj/argocd-example-apps-fake-ref.git
|
||||
`
|
||||
|
||||
var fakeAppWithDestName = `
|
||||
|
||||
6
controller/cache/cache.go
vendored
6
controller/cache/cache.go
vendored
@@ -702,12 +702,14 @@ func (c *liveStateCache) handleModEvent(oldCluster *appv1.Cluster, newCluster *a
|
||||
}
|
||||
|
||||
func (c *liveStateCache) handleDeleteEvent(clusterServer string) {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
c.lock.RLock()
|
||||
cluster, ok := c.clusters[clusterServer]
|
||||
c.lock.RUnlock()
|
||||
if ok {
|
||||
cluster.Invalidate()
|
||||
c.lock.Lock()
|
||||
delete(c.clusters, clusterServer)
|
||||
c.lock.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
97
controller/cache/cache_test.go
vendored
97
controller/cache/cache_test.go
vendored
@@ -1,10 +1,13 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net"
|
||||
"net/url"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
apierr "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
@@ -14,8 +17,10 @@ import (
|
||||
"github.com/argoproj/gitops-engine/pkg/cache"
|
||||
"github.com/argoproj/gitops-engine/pkg/cache/mocks"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"k8s.io/client-go/kubernetes/fake"
|
||||
|
||||
appv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
argosettings "github.com/argoproj/argo-cd/v2/util/settings"
|
||||
)
|
||||
|
||||
type netError string
|
||||
@@ -106,6 +111,98 @@ func TestHandleAddEvent_ClusterExcluded(t *testing.T) {
|
||||
assert.Len(t, clustersCache.clusters, 0)
|
||||
}
|
||||
|
||||
func TestHandleDeleteEvent_CacheDeadlock(t *testing.T) {
|
||||
testCluster := &appv1.Cluster{
|
||||
Server: "https://mycluster",
|
||||
Config: appv1.ClusterConfig{Username: "bar"},
|
||||
}
|
||||
fakeClient := fake.NewSimpleClientset()
|
||||
settingsMgr := argosettings.NewSettingsManager(context.TODO(), fakeClient, "argocd")
|
||||
externalLockRef := sync.RWMutex{}
|
||||
gitopsEngineClusterCache := &mocks.ClusterCache{}
|
||||
clustersCache := liveStateCache{
|
||||
clusters: map[string]cache.ClusterCache{
|
||||
testCluster.Server: gitopsEngineClusterCache,
|
||||
},
|
||||
clusterFilter: func(cluster *appv1.Cluster) bool {
|
||||
return true
|
||||
},
|
||||
settingsMgr: settingsMgr,
|
||||
// Set the lock here so we can reference it later
|
||||
// nolint We need to overwrite here to have access to the lock
|
||||
lock: externalLockRef,
|
||||
}
|
||||
channel := make(chan string)
|
||||
// Mocked lock held by the gitops-engine cluster cache
|
||||
mockMutex := sync.RWMutex{}
|
||||
// Locks to force trigger condition during test
|
||||
// Condition order:
|
||||
// EnsuredSynced -> Locks gitops-engine
|
||||
// handleDeleteEvent -> Locks liveStateCache
|
||||
// EnsureSynced via sync, newResource, populateResourceInfoHandler -> attempts to Lock liveStateCache
|
||||
// handleDeleteEvent via cluster.Invalidate -> attempts to Lock gitops-engine
|
||||
handleDeleteWasCalled := sync.Mutex{}
|
||||
engineHoldsLock := sync.Mutex{}
|
||||
handleDeleteWasCalled.Lock()
|
||||
engineHoldsLock.Lock()
|
||||
gitopsEngineClusterCache.On("EnsureSynced").Run(func(args mock.Arguments) {
|
||||
// Held by EnsureSync calling into sync and watchEvents
|
||||
mockMutex.Lock()
|
||||
defer mockMutex.Unlock()
|
||||
// Continue Execution of timer func
|
||||
engineHoldsLock.Unlock()
|
||||
// Wait for handleDeleteEvent to be called triggering the lock
|
||||
// on the liveStateCache
|
||||
handleDeleteWasCalled.Lock()
|
||||
t.Logf("handleDelete was called, EnsureSynced continuing...")
|
||||
handleDeleteWasCalled.Unlock()
|
||||
// Try and obtain the lock on the liveStateCache
|
||||
alreadyFailed := !externalLockRef.TryLock()
|
||||
if alreadyFailed {
|
||||
channel <- "DEADLOCKED -- EnsureSynced could not obtain lock on liveStateCache"
|
||||
return
|
||||
}
|
||||
externalLockRef.Lock()
|
||||
t.Logf("EnsureSynce was able to lock liveStateCache")
|
||||
externalLockRef.Unlock()
|
||||
}).Return(nil).Once()
|
||||
gitopsEngineClusterCache.On("Invalidate").Run(func(args mock.Arguments) {
|
||||
// If deadlock is fixed should be able to acquire lock here
|
||||
alreadyFailed := !mockMutex.TryLock()
|
||||
if alreadyFailed {
|
||||
channel <- "DEADLOCKED -- Invalidate could not obtain lock on gitops-engine"
|
||||
return
|
||||
}
|
||||
mockMutex.Lock()
|
||||
t.Logf("Invalidate was able to lock gitops-engine cache")
|
||||
mockMutex.Unlock()
|
||||
}).Return()
|
||||
go func() {
|
||||
// Start the gitops-engine lock holds
|
||||
go func() {
|
||||
err := gitopsEngineClusterCache.EnsureSynced()
|
||||
if err != nil {
|
||||
assert.Fail(t, err.Error())
|
||||
}
|
||||
}()
|
||||
// Wait for EnsureSynced to grab the lock for gitops-engine
|
||||
engineHoldsLock.Lock()
|
||||
t.Log("EnsureSynced has obtained lock on gitops-engine")
|
||||
engineHoldsLock.Unlock()
|
||||
// Run in background
|
||||
go clustersCache.handleDeleteEvent(testCluster.Server)
|
||||
// Allow execution to continue on clusters cache call to trigger lock
|
||||
handleDeleteWasCalled.Unlock()
|
||||
channel <- "PASSED"
|
||||
}()
|
||||
select {
|
||||
case str := <-channel:
|
||||
assert.Equal(t, "PASSED", str, str)
|
||||
case <-time.After(5 * time.Second):
|
||||
assert.Fail(t, "Ended up in deadlock")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsRetryableError(t *testing.T) {
|
||||
var (
|
||||
tlsHandshakeTimeoutErr net.Error = netError("net/http: TLS handshake timeout")
|
||||
|
||||
@@ -107,7 +107,7 @@ type appStateManager struct {
|
||||
persistResourceHealth bool
|
||||
}
|
||||
|
||||
func (m *appStateManager) getRepoObjs(app *v1alpha1.Application, sources []v1alpha1.ApplicationSource, appLabelKey string, revisions []string, noCache, noRevisionCache, verifySignature bool, proj *v1alpha1.AppProject) ([]*unstructured.Unstructured, map[*v1alpha1.ApplicationSource]*apiclient.ManifestResponse, error) {
|
||||
func (m *appStateManager) getRepoObjs(app *v1alpha1.Application, sources []v1alpha1.ApplicationSource, appLabelKey string, revisions []string, noCache, noRevisionCache, verifySignature bool, proj *v1alpha1.AppProject) ([]*unstructured.Unstructured, []*apiclient.ManifestResponse, error) {
|
||||
|
||||
ts := stats.NewTimingStats()
|
||||
helmRepos, err := m.db.ListHelmRepositories(context.Background())
|
||||
@@ -164,7 +164,7 @@ func (m *appStateManager) getRepoObjs(app *v1alpha1.Application, sources []v1alp
|
||||
}
|
||||
defer io.Close(conn)
|
||||
|
||||
manifestInfoMap := make(map[*v1alpha1.ApplicationSource]*apiclient.ManifestResponse)
|
||||
manifestInfos := make([]*apiclient.ManifestResponse, 0)
|
||||
targetObjs := make([]*unstructured.Unstructured, 0)
|
||||
|
||||
// Store the map of all sources having ref field into a map for applications with sources field
|
||||
@@ -215,20 +215,14 @@ func (m *appStateManager) getRepoObjs(app *v1alpha1.Application, sources []v1alp
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// GenerateManifest can return empty ManifestResponse without error if app has multiple sources
|
||||
// and if any of the source does not have path and chart field not specified.
|
||||
// In that scenario, we continue to the next source
|
||||
if app.Spec.HasMultipleSources() && len(manifestInfo.Manifests) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
targetObj, err := unmarshalManifests(manifestInfo.Manifests)
|
||||
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
targetObjs = append(targetObjs, targetObj...)
|
||||
manifestInfoMap[&source] = manifestInfo
|
||||
|
||||
manifestInfos = append(manifestInfos, manifestInfo)
|
||||
}
|
||||
|
||||
ts.AddCheckpoint("unmarshal_ms")
|
||||
@@ -238,7 +232,7 @@ func (m *appStateManager) getRepoObjs(app *v1alpha1.Application, sources []v1alp
|
||||
}
|
||||
logCtx = logCtx.WithField("time_ms", time.Since(ts.StartTime).Milliseconds())
|
||||
logCtx.Info("getRepoObjs stats")
|
||||
return targetObjs, manifestInfoMap, nil
|
||||
return targetObjs, manifestInfos, nil
|
||||
}
|
||||
|
||||
func unmarshalManifests(manifests []string) ([]*unstructured.Unstructured, error) {
|
||||
@@ -399,7 +393,7 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap
|
||||
var targetObjs []*unstructured.Unstructured
|
||||
now := metav1.Now()
|
||||
|
||||
var manifestInfoMap map[*v1alpha1.ApplicationSource]*apiclient.ManifestResponse
|
||||
var manifestInfos []*apiclient.ManifestResponse
|
||||
|
||||
if len(localManifests) == 0 {
|
||||
// If the length of revisions is not same as the length of sources,
|
||||
@@ -411,7 +405,7 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap
|
||||
}
|
||||
}
|
||||
|
||||
targetObjs, manifestInfoMap, err = m.getRepoObjs(app, sources, appLabelKey, revisions, noCache, noRevisionCache, verifySignature, project)
|
||||
targetObjs, manifestInfos, err = m.getRepoObjs(app, sources, appLabelKey, revisions, noCache, noRevisionCache, verifySignature, project)
|
||||
if err != nil {
|
||||
targetObjs = make([]*unstructured.Unstructured, 0)
|
||||
conditions = append(conditions, v1alpha1.ApplicationCondition{Type: v1alpha1.ApplicationConditionComparisonError, Message: err.Error(), LastTransitionTime: &now})
|
||||
@@ -434,9 +428,7 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap
|
||||
}
|
||||
}
|
||||
// empty out manifestInfoMap
|
||||
for as := range manifestInfoMap {
|
||||
delete(manifestInfoMap, as)
|
||||
}
|
||||
manifestInfos = make([]*apiclient.ManifestResponse, 0)
|
||||
}
|
||||
ts.AddCheckpoint("git_ms")
|
||||
|
||||
@@ -516,12 +508,12 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap
|
||||
}
|
||||
manifestRevisions := make([]string, 0)
|
||||
|
||||
for _, manifestInfo := range manifestInfoMap {
|
||||
for _, manifestInfo := range manifestInfos {
|
||||
manifestRevisions = append(manifestRevisions, manifestInfo.Revision)
|
||||
}
|
||||
|
||||
// restore comparison using cached diff result if previous comparison was performed for the same revision
|
||||
revisionChanged := len(manifestInfoMap) != len(sources) || !reflect.DeepEqual(app.Status.Sync.Revisions, manifestRevisions)
|
||||
revisionChanged := len(manifestInfos) != len(sources) || !reflect.DeepEqual(app.Status.Sync.Revisions, manifestRevisions)
|
||||
specChanged := !reflect.DeepEqual(app.Status.Sync.ComparedTo, appv1.ComparedTo{Source: app.Spec.GetSource(), Destination: app.Spec.Destination, Sources: sources})
|
||||
|
||||
_, refreshRequested := app.IsRefreshRequested()
|
||||
@@ -688,7 +680,7 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap
|
||||
// Git has already performed the signature verification via its GPG interface, and the result is available
|
||||
// in the manifest info received from the repository server. We now need to form our opinion about the result
|
||||
// and stop processing if we do not agree about the outcome.
|
||||
for _, manifestInfo := range manifestInfoMap {
|
||||
for _, manifestInfo := range manifestInfos {
|
||||
if gpg.IsGPGEnabled() && verifySignature && manifestInfo != nil {
|
||||
conditions = append(conditions, verifyGnuPGSignature(manifestInfo.Revision, project, manifestInfo)...)
|
||||
}
|
||||
@@ -705,11 +697,11 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap
|
||||
}
|
||||
|
||||
if hasMultipleSources {
|
||||
for _, manifestInfo := range manifestInfoMap {
|
||||
for _, manifestInfo := range manifestInfos {
|
||||
compRes.appSourceTypes = append(compRes.appSourceTypes, appv1.ApplicationSourceType(manifestInfo.SourceType))
|
||||
}
|
||||
} else {
|
||||
for _, manifestInfo := range manifestInfoMap {
|
||||
for _, manifestInfo := range manifestInfos {
|
||||
compRes.appSourceType = v1alpha1.ApplicationSourceType(manifestInfo.SourceType)
|
||||
break
|
||||
}
|
||||
|
||||
@@ -233,6 +233,74 @@ func TestCompareAppStateExtraHook(t *testing.T) {
|
||||
assert.Equal(t, 0, len(app.Status.Conditions))
|
||||
}
|
||||
|
||||
// TestAppRevisions tests that revisions are properly propagated for a single source app
|
||||
func TestAppRevisionsSingleSource(t *testing.T) {
|
||||
obj1 := NewPod()
|
||||
obj1.SetNamespace(test.FakeDestNamespace)
|
||||
data := fakeData{
|
||||
manifestResponse: &apiclient.ManifestResponse{
|
||||
Manifests: []string{toJSON(t, obj1)},
|
||||
Namespace: test.FakeDestNamespace,
|
||||
Server: test.FakeClusterURL,
|
||||
Revision: "abc123",
|
||||
},
|
||||
managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured),
|
||||
}
|
||||
ctrl := newFakeController(&data)
|
||||
|
||||
app := newFakeApp()
|
||||
revisions := make([]string, 0)
|
||||
revisions = append(revisions, "")
|
||||
compRes := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, app.Spec.GetSources(), false, false, nil, app.Spec.HasMultipleSources())
|
||||
assert.NotNil(t, compRes)
|
||||
assert.NotNil(t, compRes.syncStatus)
|
||||
assert.NotEmpty(t, compRes.syncStatus.Revision)
|
||||
assert.Len(t, compRes.syncStatus.Revisions, 0)
|
||||
|
||||
}
|
||||
|
||||
// TestAppRevisions tests that revisions are properly propagated for a multi source app
|
||||
func TestAppRevisionsMultiSource(t *testing.T) {
|
||||
obj1 := NewPod()
|
||||
obj1.SetNamespace(test.FakeDestNamespace)
|
||||
data := fakeData{
|
||||
manifestResponses: []*apiclient.ManifestResponse{
|
||||
{
|
||||
Manifests: []string{toJSON(t, obj1)},
|
||||
Namespace: test.FakeDestNamespace,
|
||||
Server: test.FakeClusterURL,
|
||||
Revision: "abc123",
|
||||
},
|
||||
{
|
||||
Manifests: []string{toJSON(t, obj1)},
|
||||
Namespace: test.FakeDestNamespace,
|
||||
Server: test.FakeClusterURL,
|
||||
Revision: "def456",
|
||||
},
|
||||
{
|
||||
Manifests: []string{},
|
||||
Namespace: test.FakeDestNamespace,
|
||||
Server: test.FakeClusterURL,
|
||||
Revision: "ghi789",
|
||||
},
|
||||
},
|
||||
managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured),
|
||||
}
|
||||
ctrl := newFakeController(&data)
|
||||
|
||||
app := newFakeMultiSourceApp()
|
||||
revisions := make([]string, 0)
|
||||
revisions = append(revisions, "")
|
||||
compRes := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, app.Spec.GetSources(), false, false, nil, app.Spec.HasMultipleSources())
|
||||
assert.NotNil(t, compRes)
|
||||
assert.NotNil(t, compRes.syncStatus)
|
||||
assert.Empty(t, compRes.syncStatus.Revision)
|
||||
assert.Len(t, compRes.syncStatus.Revisions, 3)
|
||||
assert.Equal(t, "abc123", compRes.syncStatus.Revisions[0])
|
||||
assert.Equal(t, "def456", compRes.syncStatus.Revisions[1])
|
||||
assert.Equal(t, "ghi789", compRes.syncStatus.Revisions[2])
|
||||
}
|
||||
|
||||
func toJSON(t *testing.T, obj *unstructured.Unstructured) string {
|
||||
data, err := json.Marshal(obj)
|
||||
assert.NoError(t, err)
|
||||
|
||||
@@ -9,12 +9,7 @@ To test:
|
||||
```bash
|
||||
make serve-docs
|
||||
```
|
||||
|
||||
Check for broken external links:
|
||||
|
||||
```bash
|
||||
make lint-docs
|
||||
```
|
||||
Once running, you can view your locally built documentation at [http://0.0.0.0:8000/](http://0.0.0.0:8000/).
|
||||
|
||||
## Deploying
|
||||
|
||||
|
||||
@@ -6,7 +6,10 @@ metadata:
|
||||
namespace: argocd
|
||||
# Add this finalizer ONLY if you want these to cascade delete.
|
||||
finalizers:
|
||||
# The default behaviour is foreground cascading deletion
|
||||
- resources-finalizer.argocd.argoproj.io
|
||||
# Alternatively, you can use background cascading deletion
|
||||
# - resources-finalizer.argocd.argoproj.io/background
|
||||
# Add labels to your application object.
|
||||
labels:
|
||||
name: guestbook
|
||||
@@ -163,6 +166,7 @@ spec:
|
||||
- CreateNamespace=true # Namespace Auto-Creation ensures that namespace specified as the application destination exists in the destination cluster.
|
||||
- PrunePropagationPolicy=foreground # Supported policies are background, foreground and orphan.
|
||||
- PruneLast=true # Allow the ability for resource pruning to happen as a final, implicit wave of a sync operation
|
||||
- RespectIgnoreDifferences=true # When syncing changes, respect fields ignored by the ignoreDifferences configuration
|
||||
managedNamespaceMetadata: # Sets the metadata for the application namespace. Only valid if CreateNamespace=true (see above), otherwise it's a no-op.
|
||||
labels: # The labels to set on the application namespace
|
||||
any: label
|
||||
@@ -181,7 +185,7 @@ spec:
|
||||
maxDuration: 3m # the maximum amount of time allowed for the backoff strategy
|
||||
|
||||
# Will ignore differences between live and desired states during the diff. Note that these configurations are not
|
||||
# used during the sync process.
|
||||
# used during the sync process unless the `RespectIgnoreDifferences=true` sync option is enabled.
|
||||
ignoreDifferences:
|
||||
# for the specified json pointers
|
||||
- group: apps
|
||||
@@ -193,6 +197,9 @@ spec:
|
||||
kind: "*"
|
||||
managedFieldsManagers:
|
||||
- kube-controller-manager
|
||||
# Name and namespace are optional. If specified, they must match exactly, these are not glob patterns.
|
||||
name: my-deployment
|
||||
namespace: my-namespace
|
||||
|
||||
# RevisionHistoryLimit limits the number of items kept in the application's revision history, which is used for
|
||||
# informational purposes as well as for rollbacks to previous versions. This should only be changed in exceptional
|
||||
|
||||
@@ -153,7 +153,7 @@ Or, a shorter way (using [path.Match](https://golang.org/pkg/path/#Match) syntax
|
||||
|
||||
```yaml
|
||||
- path: /d/*
|
||||
- path: /d/[f|g]
|
||||
- path: /d/[fg]
|
||||
exclude: true
|
||||
```
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ Generators are primarily based on the data source that they use to generate the
|
||||
|
||||
As of this writing there are eight generators:
|
||||
|
||||
- [List generator](Generators-List.md): The List generator allows you to target Argo CD Applications to clusters based on a fixed list of cluster name/URL values.
|
||||
- [List generator](Generators-List.md): The List generator allows you to target Argo CD Applications to clusters based on a fixed list of any chosen key/value element pairs.
|
||||
- [Cluster generator](Generators-Cluster.md): The Cluster generator allows you to target Argo CD Applications to clusters, based on the list of clusters defined within (and managed by) Argo CD (which includes automatically responding to cluster addition/removal events from Argo CD).
|
||||
- [Git generator](Generators-Git.md): The Git generator allows you to create Applications based on files within a Git repository, or based on the directory structure of a Git repository.
|
||||
- [Matrix generator](Generators-Matrix.md): The Matrix generator may be used to combine the generated parameters of two separate generators.
|
||||
|
||||
@@ -87,6 +87,10 @@ By activating Go Templating, `{{ .path }}` becomes an object. Therefore, some ch
|
||||
generators' templating:
|
||||
|
||||
- `{{ path }}` becomes `{{ .path.path }}`
|
||||
- `{{ path.basename }}` becomes `{{ .path.basename }}`
|
||||
- `{{ path.basenameNormalized }}` becomes `{{ .path.basenameNormalized }}`
|
||||
- `{{ path.filename }}` becomes `{{ .path.filename }}`
|
||||
- `{{ path.filenameNormalized }}` becomes `{{ .path.filenameNormalized }}`
|
||||
- `{{ path[n] }}` becomes `{{ index .path.segments n }}`
|
||||
|
||||
Here is an example:
|
||||
|
||||
@@ -15,7 +15,7 @@ As an experimental feature, progressive syncs must be explicitly enabled, in one
|
||||
|
||||
1. Pass `--enable-progressive-syncs` to the ApplicationSet controller args.
|
||||
1. Set `ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_PROGRESSIVE_SYNCS=true` in the ApplicationSet controller environment variables.
|
||||
1. Set `applicationsetcontroller.enable.progressive.syncs: true` in the Argo CD ConfigMap.
|
||||
1. Set `applicationsetcontroller.enable.progressive.syncs: true` in the Argo CD `argocd-cmd-params-cm` ConfigMap.
|
||||
|
||||
## Strategies
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ metadata:
|
||||
name: argocd-ssh-known-hosts-cm
|
||||
data:
|
||||
ssh_known_hosts: |
|
||||
bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kNvEcqTKl/VqLat/MaB33pZy0y3rJZtnqwR2qOOvbwKZYKiEO1O6VqNEBxKvJJelCq0dTXWT5pbO2gDXC6h6QDXCaHo6pOHGPUy+YBaGQRGuSusMEASYiWunYN0vCAI8QaXnWMXNMdFP3jHAJH0eDsoiGnLPBlBp4TNm6rYI74nMzgz3B9IikW4WVK+dc8KZJZWYjAuORU3jc1c/NPskD2ASinf8v3xnfXeukU0sJ5N6m5E8VLjObPEO+mN2t/FZTMZLiFqPWc/ALSqnMnnhwrNi2rbfg/rd/IpL8Le3pSBne8+seeFVBoGqzHM9yXw==
|
||||
bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDQeJzhupRu0u0cdegZIa8e86EG2qOCsIsD1Xw0xSeiPDlCr7kq97NLmMbpKTX6Esc30NuoqEEHCuc7yWtwp8dI76EEEB1VqY9QJq6vk+aySyboD5QF61I/1WeTwu+deCbgKMGbUijeXhtfbxSxm6JwGrXrhBdofTsbKRUsrN1WoNgUa8uqN1Vx6WAJw1JHPhglEGGHea6QICwJOAr/6mrui/oB7pkaWKHj3z7d1IC4KWLtY47elvjbaTlkN04Kc/5LFEirorGYVbt15kAUlqGM65pk6ZBxtaO3+30LVlORZkxOh+LKL/BvbZ/iRNhItLqNyieoQj/uh/7Iv4uyH/cV/0b4WDSd3DptigWq84lJubb9t/DnZlrJazxyDCulTmKdOR7vs9gMTo+uoIrPSb8ScTtvw65+odKAlBj59dhnVp9zd7QUojOpXlL62Aw56U4oO+FALuevvMjiWeavKhJqlR7i5n9srYcrNV7ttmDw7kf/97P5zauIhxcjX+xHv4M=
|
||||
github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==
|
||||
gitlab.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QlYWrOLXBpQ6KWjbjTDTdDkoohFzgbEY=
|
||||
gitlab.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf
|
||||
|
||||
@@ -54,7 +54,7 @@ spec:
|
||||
command: [sh]
|
||||
args: [-c, 'echo "Initializing..."']
|
||||
# The generate command runs in the Application source directory each time manifests are generated. Standard output
|
||||
# must be ONLY valid YAML manifests. A non-zero exit code will fail manifest generation.
|
||||
# must be ONLY valid Kubernetes Objects in either YAML or JSON. A non-zero exit code will fail manifest generation.
|
||||
# Error output will be sent to the UI, so avoid printing sensitive information (such as secrets).
|
||||
generate:
|
||||
command: [sh, -c]
|
||||
@@ -67,8 +67,8 @@ spec:
|
||||
# Only one of fileName, find.glob, or find.command should be specified. If multiple are specified then only the
|
||||
# first (in that order) is evaluated.
|
||||
discover:
|
||||
# fileName is a glob pattern (https://pkg.go.dev/path/filepath#Glob) that is applied to the repository's root
|
||||
# directory (not the Application source directory). If there is a match, this plugin may be used for the repository.
|
||||
# fileName is a glob pattern (https://pkg.go.dev/path/filepath#Glob) that is applied to the Application's source
|
||||
# directory. If there is a match, this plugin may be used for the Application.
|
||||
fileName: "./subdir/s*.yaml"
|
||||
find:
|
||||
# This does the same thing as fileName, but it supports double-start (nested directory) glob patterns.
|
||||
@@ -123,7 +123,7 @@ spec:
|
||||
While the ConfigManagementPlugin _looks like_ a Kubernetes object, it is not actually a custom resource.
|
||||
It only follows kubernetes-style spec conventions.
|
||||
|
||||
The `generate` command must print a valid YAML stream to stdout. Both `init` and `generate` commands are executed inside the application source directory.
|
||||
The `generate` command must print a valid Kubernetes YAML or JSON object stream to stdout. Both `init` and `generate` commands are executed inside the application source directory.
|
||||
|
||||
The `discover.fileName` is used as [glob](https://pkg.go.dev/path/filepath#Glob) pattern to determine whether an
|
||||
application repository is supported by the plugin or not.
|
||||
@@ -420,7 +420,7 @@ data:
|
||||
init: # Optional command to initialize application source directory
|
||||
command: ["sample command"]
|
||||
args: ["sample args"]
|
||||
generate: # Command to generate manifests YAML
|
||||
generate: # Command to generate Kubernetes Objects in either YAML or JSON
|
||||
command: ["sample command"]
|
||||
args: ["sample args"]
|
||||
lockRepo: true # Defaults to false. See below.
|
||||
@@ -437,7 +437,7 @@ spec:
|
||||
init: # Optional command to initialize application source directory
|
||||
command: ["sample command"]
|
||||
args: ["sample args"]
|
||||
generate: # Command to generate manifests YAML
|
||||
generate: # Command to generate Kubernetes Objects in either YAML or JSON
|
||||
command: ["sample command"]
|
||||
args: ["sample args"]
|
||||
```
|
||||
|
||||
@@ -416,9 +416,25 @@ data:
|
||||
|
||||
### SSH known host public keys
|
||||
|
||||
If you are connecting repositories via SSH, Argo CD will need to know the SSH known hosts public key of the repository servers. You can manage the SSH known hosts data in the ConfigMap named `argocd-ssh-known-hosts-cm`. This ConfigMap contains a single key/value pair, with `ssh_known_hosts` as the key and the actual public keys of the SSH servers as data. As opposed to TLS configuration, the public key(s) of each single repository server Argo CD will connect via SSH must be configured, otherwise the connections to the repository will fail. There is no fallback. The data can be copied from any existing `ssh_known_hosts` file, or from the output of the `ssh-keyscan` utility. The basic format is `<servername> <keydata>`, one entry per line.
|
||||
If you are configuring repositories to use SSH, Argo CD will need to know their SSH public keys. In order for Argo CD to connect via SSH the public key(s) for each repository server must be pre-configured in Argo CD (unlike TLS configuration), otherwise the connections to the repository will fail.
|
||||
|
||||
An example ConfigMap object:
|
||||
You can manage the SSH known hosts data in the `argocd-ssh-known-hosts-cm` ConfigMap. This ConfigMap contains a single entry, `ssh_known_hosts`, with the public keys of the SSH servers as its value. The value can be filled in from any existing `ssh_known_hosts` file, or from the output of the `ssh-keyscan` utility (which is part of OpenSSH's client package). The basic format is `<server_name> <keytype> <base64-encoded_key>`, one entry per line.
|
||||
|
||||
Here is an example of running `ssh-keyscan`:
|
||||
```bash
|
||||
$ for host in bitbucket.org github.com gitlab.com ssh.dev.azure.com vs-ssh.visualstudio.com ; do ssh-keyscan $host 2> /dev/null ; done
|
||||
bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDQeJzhupRu0u0cdegZIa8e86EG2qOCsIsD1Xw0xSeiPDlCr7kq97NLmMbpKTX6Esc30NuoqEEHCuc7yWtwp8dI76EEEB1VqY9QJq6vk+aySyboD5QF61I/1WeTwu+deCbgKMGbUijeXhtfbxSxm6JwGrXrhBdofTsbKRUsrN1WoNgUa8uqN1Vx6WAJw1JHPhglEGGHea6QICwJOAr/6mrui/oB7pkaWKHj3z7d1IC4KWLtY47elvjbaTlkN04Kc/5LFEirorGYVbt15kAUlqGM65pk6ZBxtaO3+30LVlORZkxOh+LKL/BvbZ/iRNhItLqNyieoQj/uh/7Iv4uyH/cV/0b4WDSd3DptigWq84lJubb9t/DnZlrJazxyDCulTmKdOR7vs9gMTo+uoIrPSb8ScTtvw65+odKAlBj59dhnVp9zd7QUojOpXlL62Aw56U4oO+FALuevvMjiWeavKhJqlR7i5n9srYcrNV7ttmDw7kf/97P5zauIhxcjX+xHv4M=
|
||||
github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl
|
||||
github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk=
|
||||
github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg=
|
||||
gitlab.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QlYWrOLXBpQ6KWjbjTDTdDkoohFzgbEY=
|
||||
gitlab.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf
|
||||
gitlab.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsj2bNKTBSpIYDEGk9KxsGh3mySTRgMtXL583qmBpzeQ+jqCMRgBqB98u3z++J1sKlXHWfM9dyhSevkMwSbhoR8XIq/U0tCNyokEi/ueaBMCvbcTHhO7FcwzY92WK4Yt0aGROY5qX2UKSeOvuP4D6TPqKF1onrSzH9bx9XUf2lEdWT/ia1NEKjunUqu1xOB/StKDHMoX4/OKyIzuS0q/T1zOATthvasJFoPrAjkohTyaDUz2LN5JoH839hViyEG82yB+MjcFV5MU3N1l1QL3cVUCh93xSaua1N85qivl+siMkPGbO5xR/En4iEY6K2XPASUEMaieWVNTRCtJ4S8H+9
|
||||
ssh.dev.azure.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H
|
||||
vs-ssh.visualstudio.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H
|
||||
```
|
||||
|
||||
Here is an example `ConfigMap` object using the output from `ssh-keyscan` above:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
@@ -431,7 +447,7 @@ metadata:
|
||||
app.kubernetes.io/part-of: argocd
|
||||
data:
|
||||
ssh_known_hosts: |
|
||||
bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kNvEcqTKl/VqLat/MaB33pZy0y3rJZtnqwR2qOOvbwKZYKiEO1O6VqNEBxKvJJelCq0dTXWT5pbO2gDXC6h6QDXCaHo6pOHGPUy+YBaGQRGuSusMEASYiWunYN0vCAI8QaXnWMXNMdFP3jHAJH0eDsoiGnLPBlBp4TNm6rYI74nMzgz3B9IikW4WVK+dc8KZJZWYjAuORU3jc1c/NPskD2ASinf8v3xnfXeukU0sJ5N6m5E8VLjObPEO+mN2t/FZTMZLiFqPWc/ALSqnMnnhwrNi2rbfg/rd/IpL8Le3pSBne8+seeFVBoGqzHM9yXw==
|
||||
bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDQeJzhupRu0u0cdegZIa8e86EG2qOCsIsD1Xw0xSeiPDlCr7kq97NLmMbpKTX6Esc30NuoqEEHCuc7yWtwp8dI76EEEB1VqY9QJq6vk+aySyboD5QF61I/1WeTwu+deCbgKMGbUijeXhtfbxSxm6JwGrXrhBdofTsbKRUsrN1WoNgUa8uqN1Vx6WAJw1JHPhglEGGHea6QICwJOAr/6mrui/oB7pkaWKHj3z7d1IC4KWLtY47elvjbaTlkN04Kc/5LFEirorGYVbt15kAUlqGM65pk6ZBxtaO3+30LVlORZkxOh+LKL/BvbZ/iRNhItLqNyieoQj/uh/7Iv4uyH/cV/0b4WDSd3DptigWq84lJubb9t/DnZlrJazxyDCulTmKdOR7vs9gMTo+uoIrPSb8ScTtvw65+odKAlBj59dhnVp9zd7QUojOpXlL62Aw56U4oO+FALuevvMjiWeavKhJqlR7i5n9srYcrNV7ttmDw7kf/97P5zauIhxcjX+xHv4M=
|
||||
github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==
|
||||
gitlab.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QlYWrOLXBpQ6KWjbjTDTdDkoohFzgbEY=
|
||||
gitlab.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf
|
||||
|
||||
@@ -15,13 +15,13 @@ export VERSION=v1.0.1
|
||||
Export to a backup:
|
||||
|
||||
```bash
|
||||
docker run -v ~/.kube:/home/argocd/.kube --rm argoproj/argocd:$VERSION argocd admin export > backup.yaml
|
||||
docker run -v ~/.kube:/home/argocd/.kube --rm quay.io/argoproj/argocd:$VERSION argocd admin export > backup.yaml
|
||||
```
|
||||
|
||||
Import from a backup:
|
||||
|
||||
```bash
|
||||
docker run -i -v ~/.kube:/home/argocd/.kube --rm argoproj/argocd:$VERSION argocd admin import - < backup.yaml
|
||||
docker run -i -v ~/.kube:/home/argocd/.kube --rm quay.io/argoproj/argocd:$VERSION argocd admin import - < backup.yaml
|
||||
```
|
||||
|
||||
!!! note
|
||||
|
||||
@@ -538,15 +538,15 @@ spec:
|
||||
- secretName: secret-yourdomain-com
|
||||
rules:
|
||||
- host: argocd.yourdomain.com
|
||||
http:
|
||||
paths:
|
||||
- pathType: ImplementationSpecific
|
||||
path: "/*" # "*" is needed. Without this, the UI Javascript and CSS will not load properly
|
||||
backend:
|
||||
service:
|
||||
name: argocd-server
|
||||
port:
|
||||
number: 80
|
||||
http:
|
||||
paths:
|
||||
- pathType: ImplementationSpecific
|
||||
path: "/*" # "*" is needed. Without this, the UI Javascript and CSS will not load properly
|
||||
backend:
|
||||
service:
|
||||
name: argocd-server
|
||||
port:
|
||||
number: 80
|
||||
```
|
||||
|
||||
If you use the version `1.21.3-gke.1600` or later, you should use the following Ingress resource:
|
||||
@@ -563,15 +563,15 @@ spec:
|
||||
- secretName: secret-yourdomain-com
|
||||
rules:
|
||||
- host: argocd.yourdomain.com
|
||||
http:
|
||||
paths:
|
||||
- pathType: Prefix
|
||||
path: "/"
|
||||
backend:
|
||||
service:
|
||||
name: argocd-server
|
||||
port:
|
||||
number: 80
|
||||
http:
|
||||
paths:
|
||||
- pathType: Prefix
|
||||
path: "/"
|
||||
backend:
|
||||
service:
|
||||
name: argocd-server
|
||||
port:
|
||||
number: 80
|
||||
```
|
||||
|
||||
As you may know already, it can take some minutes to deploy the load balancer and become ready to accept connections. Once it's ready, get the public IP address for your Load Balancer, go to your DNS server (Google or third party) and point your domain or subdomain (i.e. argocd.yourdomain.com) to that IP address.
|
||||
|
||||
@@ -17,8 +17,9 @@ kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/st
|
||||
* Add Email username and password token to `argocd-notifications-secret` secret
|
||||
|
||||
```bash
|
||||
export EMAIL_USER=<your-username>
|
||||
export PASSWORD=<your-password>
|
||||
EMAIL_USER=<your-username>
|
||||
PASSWORD=<your-password>
|
||||
|
||||
kubectl apply -n argocd -f - << EOF
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
|
||||
@@ -86,3 +86,8 @@ spec:
|
||||
clusters:
|
||||
- in-cluster
|
||||
- cluster1
|
||||
|
||||
# By default, apps may sync to any cluster specified under the `destinations` field, even if they are not
|
||||
# scoped to this project. Set the following field to `true` to restrict apps in this cluster to only clusters
|
||||
# scoped to this project.
|
||||
permitOnlyProjectScopedClusters: false
|
||||
|
||||
@@ -197,3 +197,8 @@ response and will therefore fail to create/update the Application.
|
||||
To solve the issue, upgrade the CLI to at least 2.5.16, or 2.6.7.
|
||||
|
||||
CLIs older than 2.5.0-rc1 are unaffected.
|
||||
|
||||
## Golang upgrade in 2.5.20
|
||||
|
||||
In 2.5.20, we upgrade the Golang version used to build Argo CD from 1.18 to 1.19. If you use Argo CD as a library, you
|
||||
may need to upgrade your Go version.
|
||||
|
||||
@@ -19,7 +19,7 @@ metadata:
|
||||
spec:
|
||||
accessTokenSkewMillis: 120000
|
||||
accessTokenTimeToLive: 1200000
|
||||
authChainName: LoginService
|
||||
authChainName: login-service
|
||||
clientId: argocd
|
||||
codeLastMileKeyName: lastmile-oidc
|
||||
codeTokenSkewMilis: 60000
|
||||
|
||||
26
docs/user-guide/annotations-and-labels.md
Normal file
26
docs/user-guide/annotations-and-labels.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# Annotations and Labels used by Argo CD
|
||||
|
||||
## Annotations
|
||||
|
||||
| Annotation key | Target resource(es) | Possible values | Description |
|
||||
|--------------------------------------------|---------------------|---------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| argocd.argoproj.io/application-set-refresh | ApplicationSet | `"true"` | Added when an ApplicationSet is requested to be refreshed by a webhook. The ApplicationSet controller will remove this annotation at the end of reconciliation. |
|
||||
| argocd.argoproj.io/compare-options | any | [see compare options docs](compare-options.md) | Configures how an app's current state is compared to its desired state. |
|
||||
| argocd.argoproj.io/hook | any | [see resource hooks docs](resource_hooks.md) | Used to configure [resource hooks](resource_hooks.md). |
|
||||
| argocd.argoproj.io/hook-delete-policy | any | [see resource hooks docs](resource_hooks.md#hook-deletion-policies) | Used to set a [resource hook's deletion policy](resource_hooks.md#hook-deletion-policies). |
|
||||
| argocd.argoproj.io/manifest-generate-paths | Application | [see scaling docs](../operator-manual/high_availability.md#webhook-and-manifest-paths-annotation) | Used to avoid unnecessary Application refreshes, especially in mono-repos. |
|
||||
| argocd.argoproj.io/refresh | Application | `normal`, `hard` | Indicates that app needs to be refreshed. Removed by application controller after app is refreshed. Value `"hard"` means manifest cache and target cluster state cache should be invalidated before refresh. |
|
||||
| argocd.argoproj.io/skip-reconcile | Application | `"true"` | Indicates to the Argo CD application controller that the Application should not be reconciled. See the [skip reconcile documentation](skip_reconcile.md) for use cases. |
|
||||
| argocd.argoproj.io/sync-options | any | [see sync options docs](sync-options.md) | Provides a variety of settings to determine how an Application's resources are synced. |
|
||||
| argocd.argoproj.io/sync-wave | any | [see sync waves docs](sync-waves.md) | |
|
||||
| argocd.argoproj.io/tracking-id | any | any | Used by Argo CD to track resources it manages. See [resource tracking docs](resource_tracking.md) for details. |
|
||||
| link.argocd.argoproj.io/{some link name} | any | An http(s) URL | Adds a link to the Argo CD UI for the resource. See [external URL docs](external-url.md) for details. |
|
||||
| pref.argocd.argoproj.io/default-pod-sort | Application | [see UI customization docs](../operator-manual/ui-customization.md) | Sets the Application's default grouping mechanism. |
|
||||
| pref.argocd.argoproj.io/default-view | Application | [see UI customization docs](../operator-manual/ui-customization.md) | Sets the Application's default view mode (e.g. "tree" or "list") |
|
||||
|
||||
## Labels
|
||||
|
||||
| Label key | Target resource(es) | Possible values | Description |
|
||||
|--------------------------------|---------------------|---------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| argocd.argoproj.io/instance | Application | any | Recommended tracking label to [avoid conflicts with other tools which use `app.kubernetes.io/instance`](../faq.md#why-is-my-app-out-of-sync-even-after-syncing. |
|
||||
| argocd.argoproj.io/secret-type | Secret | `cluster`, `repository`, `repo-creds` | Identifies certain types of Secrets used by Argo CD. See the [Declarative Setup docs](../operator-manual/declarative-setup.md) for details. |
|
||||
@@ -22,7 +22,7 @@ or
|
||||
argocd app delete APPNAME
|
||||
```
|
||||
|
||||
# Deletion Using `kubectl`
|
||||
## Deletion Using `kubectl`
|
||||
|
||||
To perform a non-cascade delete, make sure the finalizer is unset and then delete the app:
|
||||
|
||||
@@ -38,16 +38,23 @@ kubectl patch app APPNAME -p '{"metadata": {"finalizers": ["resources-finalizer
|
||||
kubectl delete app APPNAME
|
||||
```
|
||||
|
||||
# About The Deletion Finalizer
|
||||
## About The Deletion Finalizer
|
||||
|
||||
```yaml
|
||||
metadata:
|
||||
finalizers:
|
||||
# The default behaviour is foreground cascading deletion
|
||||
- resources-finalizer.argocd.argoproj.io
|
||||
# Alternatively, you can use background cascading deletion
|
||||
# - resources-finalizer.argocd.argoproj.io/background
|
||||
```
|
||||
|
||||
When deleting an Application with this finalizer, the Argo CD application controller will perform a cascading delete of the Application's resources.
|
||||
|
||||
Adding the finalizer enables cascading deletes when implementing [the App of Apps pattern](../operator-manual/cluster-bootstrapping.md#cascading-deletion).
|
||||
|
||||
The default propagation policy for cascading deletion is [foreground cascading deletion](https://kubernetes.io/docs/concepts/architecture/garbage-collection/#foreground-deletion).
|
||||
ArgoCD performs [background cascading deletion](https://kubernetes.io/docs/concepts/architecture/garbage-collection/#background-deletion) when `resources-finalizer.argocd.argoproj.io/background` is set.
|
||||
|
||||
When you invoke `argocd app delete` with `--cascade`, the finalizer is added automatically.
|
||||
You can set the propagation policy with `--propagation-policy <foreground|background>`.
|
||||
|
||||
@@ -60,8 +60,8 @@ To ignore fields owned by specific managers defined in your live resources:
|
||||
```yaml
|
||||
spec:
|
||||
ignoreDifferences:
|
||||
- group: *
|
||||
kind: *
|
||||
- group: "*"
|
||||
kind: "*"
|
||||
managedFieldsManagers:
|
||||
- kube-controller-manager
|
||||
```
|
||||
|
||||
@@ -48,6 +48,29 @@ source:
|
||||
- values-production.yaml
|
||||
```
|
||||
|
||||
## Values
|
||||
|
||||
Argo CD supports the equivalent of a values file directly in the Application manifest using the `source.helm.values` key.
|
||||
|
||||
```
|
||||
source:
|
||||
helm:
|
||||
values: |
|
||||
ingress:
|
||||
enabled: true
|
||||
path: /
|
||||
hosts:
|
||||
- mydomain.example.com
|
||||
annotations:
|
||||
kubernetes.io/ingress.class: nginx
|
||||
kubernetes.io/tls-acme: "true"
|
||||
labels: {}
|
||||
tls:
|
||||
- secretName: mydomain-tls
|
||||
hosts:
|
||||
- mydomain.example.com
|
||||
```
|
||||
|
||||
## Helm Parameters
|
||||
|
||||
Helm has the ability to set parameter values, which override any values in
|
||||
@@ -120,6 +143,9 @@ Argo CD supports many (most?) Helm hooks by mapping the Helm annotations onto Ar
|
||||
|
||||
Unsupported hooks are ignored. In Argo CD, hooks are created by using `kubectl apply`, rather than `kubectl create`. This means that if the hook is named and already exists, it will not change unless you have annotated it with `before-hook-creation`.
|
||||
|
||||
!!! warning "Helm hooks + ArgoCD hooks"
|
||||
If you define some Argo CD hooks in addition to the Helm ones, the Helm hooks will be ignored.
|
||||
|
||||
!!! warning "'install' vs 'upgrade' vs 'sync'"
|
||||
Argo CD cannot know if it is running a first-time "install" or an "upgrade" - every operation is a "sync'. This means that, by default, apps that have `pre-install` and `pre-upgrade` will have those hooks run at the same time.
|
||||
|
||||
|
||||
@@ -303,7 +303,7 @@ You can list all configured SSH known host entries using the `argocd cert list`
|
||||
```bash
|
||||
$ argocd cert list --cert-type ssh
|
||||
HOSTNAME TYPE SUBTYPE FINGERPRINT/SUBJECT
|
||||
bitbucket.org ssh ssh-rsa SHA256:zzXQOXSRBEiUtuE8AikJYKwbHaxvSc0ojez9YXaGp1A
|
||||
bitbucket.org ssh ssh-rsa SHA256:46OSHA1Rmj8E8ERTC6xkNcmGOw9oFxYr0WF6zWW8l1E
|
||||
github.com ssh ssh-rsa SHA256:nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8
|
||||
gitlab.com ssh ecdsa-sha2-nistp256 SHA256:HbW3g8zUjNSksFbqTiUWPWg2Bq1x8xdGUrliXFzSnUw
|
||||
gitlab.com ssh ssh-ed25519 SHA256:eUXGGm1YGsMAS7vkcx6JOJdOGHPem5gQp4taiCfCLB8
|
||||
|
||||
@@ -7,6 +7,12 @@ metadata:
|
||||
app.kubernetes.io/component: server
|
||||
name: argocd-server-cluster-apps
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- events
|
||||
verbs:
|
||||
- create
|
||||
- apiGroups:
|
||||
- "argoproj.io"
|
||||
resources:
|
||||
|
||||
33
go.mod
33
go.mod
@@ -11,14 +11,15 @@ require (
|
||||
github.com/antonmedv/expr v1.9.0
|
||||
github.com/argoproj/gitops-engine v0.7.1-0.20230512020822-b4dd8b8c3976
|
||||
github.com/argoproj/notifications-engine v0.4.1-0.20230228182525-f754726f03da
|
||||
github.com/argoproj/pkg v0.13.7-0.20221221191914-44694015343d
|
||||
github.com/aws/aws-sdk-go v1.44.164
|
||||
github.com/argoproj/pkg v0.13.7-0.20230627120311-a4dd357b057e
|
||||
github.com/aws/aws-sdk-go v1.44.290
|
||||
github.com/bombsimon/logrusr/v2 v2.0.1
|
||||
github.com/bradleyfalzon/ghinstallation/v2 v2.1.0
|
||||
github.com/casbin/casbin/v2 v2.60.0
|
||||
github.com/chai2010/gettext-go v0.0.0-20170215093142-bf70f2a70fb1 // indirect
|
||||
github.com/coreos/go-oidc v2.2.1+incompatible
|
||||
github.com/dustin/go-humanize v1.0.0
|
||||
github.com/cyphar/filepath-securejoin v0.2.3
|
||||
github.com/dustin/go-humanize v1.0.1
|
||||
github.com/evanphx/json-patch v5.6.0+incompatible
|
||||
github.com/fsnotify/fsnotify v1.5.1
|
||||
github.com/ghodss/yaml v1.0.0
|
||||
@@ -64,21 +65,21 @@ require (
|
||||
github.com/prometheus/client_golang v1.14.0
|
||||
github.com/r3labs/diff v1.1.0
|
||||
github.com/rs/cors v1.8.0 // indirect
|
||||
github.com/sirupsen/logrus v1.9.0
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/skratchdot/open-golang v0.0.0-20160302144031-75fb7ed4208c
|
||||
github.com/soheilhy/cmux v0.1.5
|
||||
github.com/spf13/cobra v1.6.1
|
||||
github.com/spf13/cobra v1.7.0
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/stretchr/testify v1.8.1
|
||||
github.com/stretchr/testify v1.8.4
|
||||
github.com/valyala/fasttemplate v1.2.2
|
||||
github.com/whilp/git-urls v0.0.0-20191001220047-6db9661140c0
|
||||
github.com/xanzy/go-gitlab v0.60.0
|
||||
github.com/yuin/gopher-lua v0.0.0-20220504180219-658193537a64
|
||||
golang.org/x/crypto v0.3.0
|
||||
golang.org/x/net v0.7.0 // indirect
|
||||
golang.org/x/crypto v0.10.0
|
||||
golang.org/x/net v0.11.0 // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4
|
||||
golang.org/x/term v0.5.0
|
||||
golang.org/x/sync v0.1.0
|
||||
golang.org/x/term v0.9.0
|
||||
google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368
|
||||
google.golang.org/grpc v1.51.0
|
||||
google.golang.org/protobuf v1.28.1
|
||||
@@ -180,7 +181,7 @@ require (
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-version v1.2.1 // indirect
|
||||
github.com/huandu/xstrings v1.3.3 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.1 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/itchyny/timefmt-go v0.1.4 // indirect
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
@@ -188,7 +189,7 @@ require (
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect
|
||||
github.com/klauspost/compress v1.15.9 // indirect
|
||||
github.com/klauspost/compress v1.16.5 // indirect
|
||||
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.13 // indirect
|
||||
@@ -229,11 +230,11 @@ require (
|
||||
go.opentelemetry.io/proto/otlp v0.19.0 // indirect
|
||||
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect
|
||||
golang.org/x/exp v0.0.0-20210901193431-a062eea981d2 // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
||||
golang.org/x/sys v0.5.0 // indirect
|
||||
golang.org/x/text v0.7.0 // indirect
|
||||
golang.org/x/mod v0.8.0 // indirect
|
||||
golang.org/x/sys v0.9.0 // indirect
|
||||
golang.org/x/text v0.10.0 // indirect
|
||||
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect
|
||||
golang.org/x/tools v0.1.12 // indirect
|
||||
golang.org/x/tools v0.6.0 // indirect
|
||||
gomodules.xyz/envconfig v1.3.1-0.20190308184047-426f31af0d45 // indirect
|
||||
gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
|
||||
gomodules.xyz/notify v0.1.1 // indirect
|
||||
|
||||
76
go.sum
76
go.sum
@@ -136,8 +136,8 @@ github.com/argoproj/gitops-engine v0.7.1-0.20230512020822-b4dd8b8c3976 h1:8i12dO
|
||||
github.com/argoproj/gitops-engine v0.7.1-0.20230512020822-b4dd8b8c3976/go.mod h1:WpA/B7tgwfz+sdNE3LqrTrb7ArEY1FOPI2pAGI0hfPc=
|
||||
github.com/argoproj/notifications-engine v0.4.1-0.20230228182525-f754726f03da h1:Vf9xvHcXn4TP/nLIfWn+TaC521V9fpz/DwRP6uEeVR8=
|
||||
github.com/argoproj/notifications-engine v0.4.1-0.20230228182525-f754726f03da/go.mod h1:05koR0gE/O0i5YDbidg1dpr76XitK4DJveh+dIAq6e8=
|
||||
github.com/argoproj/pkg v0.13.7-0.20221221191914-44694015343d h1:7fXEKF3OQ9i1PrgieA6FLrXOL3UAKyiotomn0RHevds=
|
||||
github.com/argoproj/pkg v0.13.7-0.20221221191914-44694015343d/go.mod h1:RKjj5FJ6KxtktOY49GJSG49qO6Z4lH7RnrVCaS3tf18=
|
||||
github.com/argoproj/pkg v0.13.7-0.20230627120311-a4dd357b057e h1:kuLQvJqwwRMQTheT4MFyKVM8Txncu21CHT4yBWUl1Mk=
|
||||
github.com/argoproj/pkg v0.13.7-0.20230627120311-a4dd357b057e/go.mod h1:xBN5PLx2MoK63dmPfMo/PGBvd77K1Y0m/rzZOe4cs1s=
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||
@@ -154,8 +154,8 @@ github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQ
|
||||
github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||
github.com/aws/aws-sdk-go v1.35.24/go.mod h1:tlPOdRjfxPBpNIwqDj61rmsnA85v9jc0Ps9+muhnW+k=
|
||||
github.com/aws/aws-sdk-go v1.38.49/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
|
||||
github.com/aws/aws-sdk-go v1.44.164 h1:qDj0RutF2Ut0HZYyUJxFdReLxpYrjupsu2JmDIgCvX8=
|
||||
github.com/aws/aws-sdk-go v1.44.164/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
|
||||
github.com/aws/aws-sdk-go v1.44.290 h1:Md4+os9DQtJjow0lWLMzeJljsimD+XS2xwwHDr5Z+Lk=
|
||||
github.com/aws/aws-sdk-go v1.44.290/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
|
||||
github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
|
||||
github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg=
|
||||
github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
|
||||
@@ -253,6 +253,7 @@ github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7Do
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw=
|
||||
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/cyphar/filepath-securejoin v0.2.3 h1:YX6ebbZCZP7VkM3scTTokDgBL2TY741X51MTk3ycuNI=
|
||||
github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
|
||||
github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@@ -273,8 +274,9 @@ github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5Xh
|
||||
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
|
||||
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
|
||||
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
|
||||
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
|
||||
@@ -650,8 +652,8 @@ github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK
|
||||
github.com/improbable-eng/grpc-web v0.0.0-20181111100011-16092bd1d58a h1:RweVA0vnEyStwtAelyGmnU8ENDnwd1Q7pQr7U3J/rXo=
|
||||
github.com/improbable-eng/grpc-web v0.0.0-20181111100011-16092bd1d58a/go.mod h1:6hRR09jOEG81ADP5wCQju1z71g6OL4eEvELdran/3cs=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc=
|
||||
github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
|
||||
github.com/ishidawataru/sctp v0.0.0-20190723014705-7c296d48a2b5/go.mod h1:DM4VvS+hD/kDi1U1QsX2fnZowwBhqD0Dk3bRPKF/Oc8=
|
||||
github.com/itchyny/gojq v0.12.9 h1:biKpbKwMxVYhCU1d6mR7qMr3f0Hn9F5k5YykCVb3gmM=
|
||||
@@ -705,11 +707,11 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
github.com/klauspost/compress v1.15.9 h1:wKRjX6JRtDdrE9qwa4b/Cip7ACOshUI4smpCQanqjSY=
|
||||
github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
|
||||
github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI=
|
||||
github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||
github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.1.0/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
|
||||
github.com/klauspost/cpuid/v2 v2.2.3/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
|
||||
github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
@@ -781,8 +783,8 @@ github.com/microsoft/azure-devops-go-api/azuredevops v1.0.0-b5/go.mod h1:PoGiBqK
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/mindprince/gonvml v0.0.0-20190828220739-9ebdce4bb989/go.mod h1:2eu9pRWp8mo84xCg6KswZ+USQHjwgRhNp06sozOdsTY=
|
||||
github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
|
||||
github.com/minio/minio-go/v7 v7.0.45/go.mod h1:nCrRzjoSUQh8hgKKtu3Y708OLvRLtuASMg2/nvmbarw=
|
||||
github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM=
|
||||
github.com/minio/minio-go/v7 v7.0.58/go.mod h1:NUDy4A4oXPq1l2yK6LTSvCEzAMeIcoz9lcj5dbzSrRE=
|
||||
github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8=
|
||||
github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4=
|
||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||
github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ=
|
||||
@@ -977,7 +979,7 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR
|
||||
github.com/rs/cors v1.8.0 h1:P2KMzcFwrPoSjkF1WLRPsp3UMLyql8L4v9hQpVeK5so=
|
||||
github.com/rs/cors v1.8.0/go.mod h1:EBwu+T5AvHOcXwvZIkQFjUN6s8Czyqw12GL/Y0tUyRM=
|
||||
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
|
||||
github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||
github.com/rs/zerolog v1.21.0/go.mod h1:ZPhntP/xmq1nnND05hhpAh2QMhSsA4UN3MGZ6O2J3hM=
|
||||
github.com/rubiojr/go-vhd v0.0.0-20200706105327-02e210299021/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto=
|
||||
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
|
||||
@@ -1002,8 +1004,9 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
|
||||
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/sirupsen/logrus v1.9.2/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/skratchdot/open-golang v0.0.0-20160302144031-75fb7ed4208c h1:fyKiXKO1/I/B6Y2U8T7WdQGWzwehOuGIrljPtt7YTTI=
|
||||
github.com/skratchdot/open-golang v0.0.0-20160302144031-75fb7ed4208c/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
|
||||
github.com/slack-go/slack v0.12.1 h1:X97b9g2hnITDtNsNe5GkGx6O2/Sz/uC20ejRZN6QxOw=
|
||||
@@ -1031,8 +1034,8 @@ github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHN
|
||||
github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo=
|
||||
github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk=
|
||||
github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g=
|
||||
github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA=
|
||||
github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY=
|
||||
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
|
||||
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
|
||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
||||
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
@@ -1064,8 +1067,9 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||
github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
|
||||
@@ -1220,9 +1224,10 @@ golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5y
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A=
|
||||
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
|
||||
golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM=
|
||||
golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
|
||||
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
@@ -1272,8 +1277,9 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.5.1-0.20210830214625-1b1db11ec8f4/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -1336,8 +1342,10 @@ golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
||||
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
|
||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.11.0 h1:Gi2tvZIJyBtO9SDr1q9h5hEQCp/4L2RQ+ar0qjx2oNU=
|
||||
golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ=
|
||||
golang.org/x/oauth2 v0.0.0-20180227000427-d7d64896b5ff/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -1372,8 +1380,9 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180224232135-f6cff0780e54/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -1484,14 +1493,18 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
|
||||
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||
golang.org/x/term v0.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.9.0 h1:GRRCnKYhdQrD8kfRAdQ6Zcw1P0OcELxGLKJvtjVMZ28=
|
||||
golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -1502,8 +1515,10 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58=
|
||||
golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
@@ -1585,8 +1600,9 @@ golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.10-0.20220218145154-897bd77cd717/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
|
||||
golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -1782,7 +1798,7 @@ gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ini.v1 v1.66.6/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
|
||||
gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||
gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI=
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# This file was automatically generated. DO NOT EDIT
|
||||
bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kNvEcqTKl/VqLat/MaB33pZy0y3rJZtnqwR2qOOvbwKZYKiEO1O6VqNEBxKvJJelCq0dTXWT5pbO2gDXC6h6QDXCaHo6pOHGPUy+YBaGQRGuSusMEASYiWunYN0vCAI8QaXnWMXNMdFP3jHAJH0eDsoiGnLPBlBp4TNm6rYI74nMzgz3B9IikW4WVK+dc8KZJZWYjAuORU3jc1c/NPskD2ASinf8v3xnfXeukU0sJ5N6m5E8VLjObPEO+mN2t/FZTMZLiFqPWc/ALSqnMnnhwrNi2rbfg/rd/IpL8Le3pSBne8+seeFVBoGqzHM9yXw==
|
||||
bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDQeJzhupRu0u0cdegZIa8e86EG2qOCsIsD1Xw0xSeiPDlCr7kq97NLmMbpKTX6Esc30NuoqEEHCuc7yWtwp8dI76EEEB1VqY9QJq6vk+aySyboD5QF61I/1WeTwu+deCbgKMGbUijeXhtfbxSxm6JwGrXrhBdofTsbKRUsrN1WoNgUa8uqN1Vx6WAJw1JHPhglEGGHea6QICwJOAr/6mrui/oB7pkaWKHj3z7d1IC4KWLtY47elvjbaTlkN04Kc/5LFEirorGYVbt15kAUlqGM65pk6ZBxtaO3+30LVlORZkxOh+LKL/BvbZ/iRNhItLqNyieoQj/uh/7Iv4uyH/cV/0b4WDSd3DptigWq84lJubb9t/DnZlrJazxyDCulTmKdOR7vs9gMTo+uoIrPSb8ScTtvw65+odKAlBj59dhnVp9zd7QUojOpXlL62Aw56U4oO+FALuevvMjiWeavKhJqlR7i5n9srYcrNV7ttmDw7kf/97P5zauIhxcjX+xHv4M=
|
||||
github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==
|
||||
gitlab.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QlYWrOLXBpQ6KWjbjTDTdDkoohFzgbEY=
|
||||
gitlab.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf
|
||||
|
||||
@@ -14,11 +14,11 @@ chmod 0644 $KNOWN_HOSTS_FILE
|
||||
# - bitbucket.org: https://confluence.atlassian.com/bitbucket/ssh-keys-935365775.html
|
||||
# - ssh.dev.azure.com, vs-ssh.visualstudio.com: https://docs.microsoft.com/en-us/azure/devops/repos/git/use-ssh-keys-to-authenticate?view=azure-devops
|
||||
diff - <(ssh-keygen -l -f $KNOWN_HOSTS_FILE | sort -k 3) <<EOF
|
||||
2048 SHA256:zzXQOXSRBEiUtuE8AikJYKwbHaxvSc0ojez9YXaGp1A bitbucket.org (RSA)
|
||||
2048 SHA256:46OSHA1Rmj8E8ERTC6xkNcmGOw9oFxYr0WF6zWW8l1E bitbucket.org (RSA)
|
||||
2048 SHA256:nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8 github.com (RSA)
|
||||
256 SHA256:HbW3g8zUjNSksFbqTiUWPWg2Bq1x8xdGUrliXFzSnUw gitlab.com (ECDSA)
|
||||
256 SHA256:eUXGGm1YGsMAS7vkcx6JOJdOGHPem5gQp4taiCfCLB8 gitlab.com (ED25519)
|
||||
2048 SHA256:ROQFvPThGrW4RuWLoL9tq9I9zJ42fK4XywyRtbOz/EQ gitlab.com (RSA)
|
||||
2048 SHA256:ohD8VZEXGWo6Ez8GSEJQ9WpafgLFsOfLOtGGQCQo6Og ssh.dev.azure.com (RSA)
|
||||
2048 SHA256:ohD8VZEXGWo6Ez8GSEJQ9WpafgLFsOfLOtGGQCQo6Og vs-ssh.visualstudio.com (RSA)
|
||||
EOF
|
||||
EOF
|
||||
|
||||
@@ -7,7 +7,7 @@ metadata:
|
||||
name: argocd-ssh-known-hosts-cm
|
||||
data:
|
||||
ssh_known_hosts: |
|
||||
bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kNvEcqTKl/VqLat/MaB33pZy0y3rJZtnqwR2qOOvbwKZYKiEO1O6VqNEBxKvJJelCq0dTXWT5pbO2gDXC6h6QDXCaHo6pOHGPUy+YBaGQRGuSusMEASYiWunYN0vCAI8QaXnWMXNMdFP3jHAJH0eDsoiGnLPBlBp4TNm6rYI74nMzgz3B9IikW4WVK+dc8KZJZWYjAuORU3jc1c/NPskD2ASinf8v3xnfXeukU0sJ5N6m5E8VLjObPEO+mN2t/FZTMZLiFqPWc/ALSqnMnnhwrNi2rbfg/rd/IpL8Le3pSBne8+seeFVBoGqzHM9yXw==
|
||||
bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDQeJzhupRu0u0cdegZIa8e86EG2qOCsIsD1Xw0xSeiPDlCr7kq97NLmMbpKTX6Esc30NuoqEEHCuc7yWtwp8dI76EEEB1VqY9QJq6vk+aySyboD5QF61I/1WeTwu+deCbgKMGbUijeXhtfbxSxm6JwGrXrhBdofTsbKRUsrN1WoNgUa8uqN1Vx6WAJw1JHPhglEGGHea6QICwJOAr/6mrui/oB7pkaWKHj3z7d1IC4KWLtY47elvjbaTlkN04Kc/5LFEirorGYVbt15kAUlqGM65pk6ZBxtaO3+30LVlORZkxOh+LKL/BvbZ/iRNhItLqNyieoQj/uh/7Iv4uyH/cV/0b4WDSd3DptigWq84lJubb9t/DnZlrJazxyDCulTmKdOR7vs9gMTo+uoIrPSb8ScTtvw65+odKAlBj59dhnVp9zd7QUojOpXlL62Aw56U4oO+FALuevvMjiWeavKhJqlR7i5n9srYcrNV7ttmDw7kf/97P5zauIhxcjX+xHv4M=
|
||||
github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==
|
||||
gitlab.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QlYWrOLXBpQ6KWjbjTDTdDkoohFzgbEY=
|
||||
gitlab.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf
|
||||
@@ -15,4 +15,4 @@ data:
|
||||
ssh.dev.azure.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H
|
||||
vs-ssh.visualstudio.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOfGJ4NakVyIzf1rXYd4d7wo6jBlkLvCA4odBlL0mDUyZ0/QUfTTqeu+tm22gOsv+VrVTMk6vwRU75gY/y9ut5Mb3bR5BV58dKXyq9A9UeB5Cakehn5Zgm6x1mKoVyf+FFn26iYqXJRgzIZZcZ5V6hrE0Qg39kZm4az48o0AUbf6Sp4SLdvnuMa2sVNwHBboS7EJkm57XQPVU3/QpyNLHbWDdzwtrlS+ez30S3AdYhLKEOxAG8weOnyrtLJAUen9mTkol8oII1edf7mWWbWVf0nBmly21+nZcmCTISQBtdcyPaEno7fFQMDD26/s0lfKob4Kw8H
|
||||
github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg=
|
||||
github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl
|
||||
github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl
|
||||
|
||||
@@ -37,7 +37,7 @@ spec:
|
||||
type: RuntimeDefault
|
||||
containers:
|
||||
- name: dex
|
||||
image: ghcr.io/dexidp/dex:v2.36.0
|
||||
image: ghcr.io/dexidp/dex:v2.37.0
|
||||
imagePullPolicy: Always
|
||||
command: [/shared/argocd-dex, rundex]
|
||||
env:
|
||||
|
||||
@@ -5,7 +5,7 @@ kind: Kustomization
|
||||
images:
|
||||
- name: quay.io/argoproj/argocd
|
||||
newName: quay.io/argoproj/argocd
|
||||
newTag: v2.6.8
|
||||
newTag: v2.6.14
|
||||
resources:
|
||||
- ./application-controller
|
||||
- ./dex
|
||||
|
||||
@@ -15362,8 +15362,8 @@ metadata:
|
||||
---
|
||||
apiVersion: v1
|
||||
data:
|
||||
ssh_known_hosts: |-
|
||||
bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kNvEcqTKl/VqLat/MaB33pZy0y3rJZtnqwR2qOOvbwKZYKiEO1O6VqNEBxKvJJelCq0dTXWT5pbO2gDXC6h6QDXCaHo6pOHGPUy+YBaGQRGuSusMEASYiWunYN0vCAI8QaXnWMXNMdFP3jHAJH0eDsoiGnLPBlBp4TNm6rYI74nMzgz3B9IikW4WVK+dc8KZJZWYjAuORU3jc1c/NPskD2ASinf8v3xnfXeukU0sJ5N6m5E8VLjObPEO+mN2t/FZTMZLiFqPWc/ALSqnMnnhwrNi2rbfg/rd/IpL8Le3pSBne8+seeFVBoGqzHM9yXw==
|
||||
ssh_known_hosts: |
|
||||
bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDQeJzhupRu0u0cdegZIa8e86EG2qOCsIsD1Xw0xSeiPDlCr7kq97NLmMbpKTX6Esc30NuoqEEHCuc7yWtwp8dI76EEEB1VqY9QJq6vk+aySyboD5QF61I/1WeTwu+deCbgKMGbUijeXhtfbxSxm6JwGrXrhBdofTsbKRUsrN1WoNgUa8uqN1Vx6WAJw1JHPhglEGGHea6QICwJOAr/6mrui/oB7pkaWKHj3z7d1IC4KWLtY47elvjbaTlkN04Kc/5LFEirorGYVbt15kAUlqGM65pk6ZBxtaO3+30LVlORZkxOh+LKL/BvbZ/iRNhItLqNyieoQj/uh/7Iv4uyH/cV/0b4WDSd3DptigWq84lJubb9t/DnZlrJazxyDCulTmKdOR7vs9gMTo+uoIrPSb8ScTtvw65+odKAlBj59dhnVp9zd7QUojOpXlL62Aw56U4oO+FALuevvMjiWeavKhJqlR7i5n9srYcrNV7ttmDw7kf/97P5zauIhxcjX+xHv4M=
|
||||
github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==
|
||||
gitlab.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QlYWrOLXBpQ6KWjbjTDTdDkoohFzgbEY=
|
||||
gitlab.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf
|
||||
@@ -15557,7 +15557,7 @@ spec:
|
||||
key: applicationsetcontroller.enable.progressive.syncs
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.6.8
|
||||
image: quay.io/argoproj/argocd:v2.6.14
|
||||
imagePullPolicy: Always
|
||||
name: argocd-applicationset-controller
|
||||
ports:
|
||||
@@ -15821,7 +15821,7 @@ spec:
|
||||
value: /helm-working-dir
|
||||
- name: HELM_DATA_HOME
|
||||
value: /helm-working-dir
|
||||
image: quay.io/argoproj/argocd:v2.6.8
|
||||
image: quay.io/argoproj/argocd:v2.6.14
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -15873,7 +15873,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /var/run/argocd/argocd-cmp-server
|
||||
image: quay.io/argoproj/argocd:v2.6.8
|
||||
image: quay.io/argoproj/argocd:v2.6.14
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -16080,7 +16080,7 @@ spec:
|
||||
key: application.namespaces
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.6.8
|
||||
image: quay.io/argoproj/argocd:v2.6.14
|
||||
imagePullPolicy: Always
|
||||
name: argocd-application-controller
|
||||
ports:
|
||||
|
||||
@@ -12,4 +12,4 @@ resources:
|
||||
images:
|
||||
- name: quay.io/argoproj/argocd
|
||||
newName: quay.io/argoproj/argocd
|
||||
newTag: v2.6.8
|
||||
newTag: v2.6.14
|
||||
|
||||
@@ -11,7 +11,7 @@ patchesStrategicMerge:
|
||||
images:
|
||||
- name: quay.io/argoproj/argocd
|
||||
newName: quay.io/argoproj/argocd
|
||||
newTag: v2.6.8
|
||||
newTag: v2.6.14
|
||||
resources:
|
||||
- ../../base/application-controller
|
||||
- ../../base/applicationset-controller
|
||||
|
||||
@@ -1071,7 +1071,7 @@ spec:
|
||||
topologyKey: kubernetes.io/hostname
|
||||
initContainers:
|
||||
- name: config-init
|
||||
image: haproxy:2.6.12-alpine
|
||||
image: haproxy:2.6.14-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
resources:
|
||||
{}
|
||||
@@ -1089,7 +1089,7 @@ spec:
|
||||
mountPath: /data
|
||||
containers:
|
||||
- name: haproxy
|
||||
image: haproxy:2.6.12-alpine
|
||||
image: haproxy:2.6.14-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
securityContext:
|
||||
null
|
||||
|
||||
@@ -11,7 +11,7 @@ redis-ha:
|
||||
IPv6:
|
||||
enabled: false
|
||||
image:
|
||||
tag: 2.6.12-alpine
|
||||
tag: 2.6.14-alpine
|
||||
containerSecurityContext: null
|
||||
timeout:
|
||||
server: 6m
|
||||
|
||||
@@ -16376,8 +16376,8 @@ metadata:
|
||||
---
|
||||
apiVersion: v1
|
||||
data:
|
||||
ssh_known_hosts: |-
|
||||
bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kNvEcqTKl/VqLat/MaB33pZy0y3rJZtnqwR2qOOvbwKZYKiEO1O6VqNEBxKvJJelCq0dTXWT5pbO2gDXC6h6QDXCaHo6pOHGPUy+YBaGQRGuSusMEASYiWunYN0vCAI8QaXnWMXNMdFP3jHAJH0eDsoiGnLPBlBp4TNm6rYI74nMzgz3B9IikW4WVK+dc8KZJZWYjAuORU3jc1c/NPskD2ASinf8v3xnfXeukU0sJ5N6m5E8VLjObPEO+mN2t/FZTMZLiFqPWc/ALSqnMnnhwrNi2rbfg/rd/IpL8Le3pSBne8+seeFVBoGqzHM9yXw==
|
||||
ssh_known_hosts: |
|
||||
bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDQeJzhupRu0u0cdegZIa8e86EG2qOCsIsD1Xw0xSeiPDlCr7kq97NLmMbpKTX6Esc30NuoqEEHCuc7yWtwp8dI76EEEB1VqY9QJq6vk+aySyboD5QF61I/1WeTwu+deCbgKMGbUijeXhtfbxSxm6JwGrXrhBdofTsbKRUsrN1WoNgUa8uqN1Vx6WAJw1JHPhglEGGHea6QICwJOAr/6mrui/oB7pkaWKHj3z7d1IC4KWLtY47elvjbaTlkN04Kc/5LFEirorGYVbt15kAUlqGM65pk6ZBxtaO3+30LVlORZkxOh+LKL/BvbZ/iRNhItLqNyieoQj/uh/7Iv4uyH/cV/0b4WDSd3DptigWq84lJubb9t/DnZlrJazxyDCulTmKdOR7vs9gMTo+uoIrPSb8ScTtvw65+odKAlBj59dhnVp9zd7QUojOpXlL62Aw56U4oO+FALuevvMjiWeavKhJqlR7i5n9srYcrNV7ttmDw7kf/97P5zauIhxcjX+xHv4M=
|
||||
github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==
|
||||
gitlab.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QlYWrOLXBpQ6KWjbjTDTdDkoohFzgbEY=
|
||||
gitlab.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf
|
||||
@@ -16758,7 +16758,7 @@ spec:
|
||||
key: applicationsetcontroller.enable.progressive.syncs
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.6.8
|
||||
image: quay.io/argoproj/argocd:v2.6.14
|
||||
imagePullPolicy: Always
|
||||
name: argocd-applicationset-controller
|
||||
ports:
|
||||
@@ -16839,7 +16839,7 @@ spec:
|
||||
key: dexserver.disable.tls
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: ghcr.io/dexidp/dex:v2.36.0
|
||||
image: ghcr.io/dexidp/dex:v2.37.0
|
||||
imagePullPolicy: Always
|
||||
name: dex
|
||||
ports:
|
||||
@@ -16868,7 +16868,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /shared/argocd-dex
|
||||
image: quay.io/argoproj/argocd:v2.6.8
|
||||
image: quay.io/argoproj/argocd:v2.6.14
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
securityContext:
|
||||
@@ -16921,7 +16921,7 @@ spec:
|
||||
containers:
|
||||
- command:
|
||||
- argocd-notifications
|
||||
image: quay.io/argoproj/argocd:v2.6.8
|
||||
image: quay.io/argoproj/argocd:v2.6.14
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
@@ -16992,7 +16992,7 @@ spec:
|
||||
app.kubernetes.io/name: argocd-redis-ha-haproxy
|
||||
topologyKey: kubernetes.io/hostname
|
||||
containers:
|
||||
- image: haproxy:2.6.12-alpine
|
||||
- image: haproxy:2.6.14-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
lifecycle: {}
|
||||
livenessProbe:
|
||||
@@ -17028,7 +17028,7 @@ spec:
|
||||
- /readonly/haproxy_init.sh
|
||||
command:
|
||||
- sh
|
||||
image: haproxy:2.6.12-alpine
|
||||
image: haproxy:2.6.14-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: config-init
|
||||
securityContext:
|
||||
@@ -17224,7 +17224,7 @@ spec:
|
||||
value: /helm-working-dir
|
||||
- name: HELM_DATA_HOME
|
||||
value: /helm-working-dir
|
||||
image: quay.io/argoproj/argocd:v2.6.8
|
||||
image: quay.io/argoproj/argocd:v2.6.14
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -17276,7 +17276,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /var/run/argocd/argocd-cmp-server
|
||||
image: quay.io/argoproj/argocd:v2.6.8
|
||||
image: quay.io/argoproj/argocd:v2.6.14
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -17555,7 +17555,7 @@ spec:
|
||||
key: server.enable.proxy.extension
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.6.8
|
||||
image: quay.io/argoproj/argocd:v2.6.14
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -17791,7 +17791,7 @@ spec:
|
||||
key: application.namespaces
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.6.8
|
||||
image: quay.io/argoproj/argocd:v2.6.14
|
||||
imagePullPolicy: Always
|
||||
name: argocd-application-controller
|
||||
ports:
|
||||
|
||||
@@ -1180,8 +1180,8 @@ metadata:
|
||||
---
|
||||
apiVersion: v1
|
||||
data:
|
||||
ssh_known_hosts: |-
|
||||
bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kNvEcqTKl/VqLat/MaB33pZy0y3rJZtnqwR2qOOvbwKZYKiEO1O6VqNEBxKvJJelCq0dTXWT5pbO2gDXC6h6QDXCaHo6pOHGPUy+YBaGQRGuSusMEASYiWunYN0vCAI8QaXnWMXNMdFP3jHAJH0eDsoiGnLPBlBp4TNm6rYI74nMzgz3B9IikW4WVK+dc8KZJZWYjAuORU3jc1c/NPskD2ASinf8v3xnfXeukU0sJ5N6m5E8VLjObPEO+mN2t/FZTMZLiFqPWc/ALSqnMnnhwrNi2rbfg/rd/IpL8Le3pSBne8+seeFVBoGqzHM9yXw==
|
||||
ssh_known_hosts: |
|
||||
bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDQeJzhupRu0u0cdegZIa8e86EG2qOCsIsD1Xw0xSeiPDlCr7kq97NLmMbpKTX6Esc30NuoqEEHCuc7yWtwp8dI76EEEB1VqY9QJq6vk+aySyboD5QF61I/1WeTwu+deCbgKMGbUijeXhtfbxSxm6JwGrXrhBdofTsbKRUsrN1WoNgUa8uqN1Vx6WAJw1JHPhglEGGHea6QICwJOAr/6mrui/oB7pkaWKHj3z7d1IC4KWLtY47elvjbaTlkN04Kc/5LFEirorGYVbt15kAUlqGM65pk6ZBxtaO3+30LVlORZkxOh+LKL/BvbZ/iRNhItLqNyieoQj/uh/7Iv4uyH/cV/0b4WDSd3DptigWq84lJubb9t/DnZlrJazxyDCulTmKdOR7vs9gMTo+uoIrPSb8ScTtvw65+odKAlBj59dhnVp9zd7QUojOpXlL62Aw56U4oO+FALuevvMjiWeavKhJqlR7i5n9srYcrNV7ttmDw7kf/97P5zauIhxcjX+xHv4M=
|
||||
github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==
|
||||
gitlab.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QlYWrOLXBpQ6KWjbjTDTdDkoohFzgbEY=
|
||||
gitlab.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf
|
||||
@@ -1562,7 +1562,7 @@ spec:
|
||||
key: applicationsetcontroller.enable.progressive.syncs
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.6.8
|
||||
image: quay.io/argoproj/argocd:v2.6.14
|
||||
imagePullPolicy: Always
|
||||
name: argocd-applicationset-controller
|
||||
ports:
|
||||
@@ -1643,7 +1643,7 @@ spec:
|
||||
key: dexserver.disable.tls
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: ghcr.io/dexidp/dex:v2.36.0
|
||||
image: ghcr.io/dexidp/dex:v2.37.0
|
||||
imagePullPolicy: Always
|
||||
name: dex
|
||||
ports:
|
||||
@@ -1672,7 +1672,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /shared/argocd-dex
|
||||
image: quay.io/argoproj/argocd:v2.6.8
|
||||
image: quay.io/argoproj/argocd:v2.6.14
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
securityContext:
|
||||
@@ -1725,7 +1725,7 @@ spec:
|
||||
containers:
|
||||
- command:
|
||||
- argocd-notifications
|
||||
image: quay.io/argoproj/argocd:v2.6.8
|
||||
image: quay.io/argoproj/argocd:v2.6.14
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
@@ -1796,7 +1796,7 @@ spec:
|
||||
app.kubernetes.io/name: argocd-redis-ha-haproxy
|
||||
topologyKey: kubernetes.io/hostname
|
||||
containers:
|
||||
- image: haproxy:2.6.12-alpine
|
||||
- image: haproxy:2.6.14-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
lifecycle: {}
|
||||
livenessProbe:
|
||||
@@ -1832,7 +1832,7 @@ spec:
|
||||
- /readonly/haproxy_init.sh
|
||||
command:
|
||||
- sh
|
||||
image: haproxy:2.6.12-alpine
|
||||
image: haproxy:2.6.14-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: config-init
|
||||
securityContext:
|
||||
@@ -2028,7 +2028,7 @@ spec:
|
||||
value: /helm-working-dir
|
||||
- name: HELM_DATA_HOME
|
||||
value: /helm-working-dir
|
||||
image: quay.io/argoproj/argocd:v2.6.8
|
||||
image: quay.io/argoproj/argocd:v2.6.14
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -2080,7 +2080,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /var/run/argocd/argocd-cmp-server
|
||||
image: quay.io/argoproj/argocd:v2.6.8
|
||||
image: quay.io/argoproj/argocd:v2.6.14
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -2359,7 +2359,7 @@ spec:
|
||||
key: server.enable.proxy.extension
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.6.8
|
||||
image: quay.io/argoproj/argocd:v2.6.14
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -2595,7 +2595,7 @@ spec:
|
||||
key: application.namespaces
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.6.8
|
||||
image: quay.io/argoproj/argocd:v2.6.14
|
||||
imagePullPolicy: Always
|
||||
name: argocd-application-controller
|
||||
ports:
|
||||
|
||||
@@ -15598,8 +15598,8 @@ metadata:
|
||||
---
|
||||
apiVersion: v1
|
||||
data:
|
||||
ssh_known_hosts: |-
|
||||
bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kNvEcqTKl/VqLat/MaB33pZy0y3rJZtnqwR2qOOvbwKZYKiEO1O6VqNEBxKvJJelCq0dTXWT5pbO2gDXC6h6QDXCaHo6pOHGPUy+YBaGQRGuSusMEASYiWunYN0vCAI8QaXnWMXNMdFP3jHAJH0eDsoiGnLPBlBp4TNm6rYI74nMzgz3B9IikW4WVK+dc8KZJZWYjAuORU3jc1c/NPskD2ASinf8v3xnfXeukU0sJ5N6m5E8VLjObPEO+mN2t/FZTMZLiFqPWc/ALSqnMnnhwrNi2rbfg/rd/IpL8Le3pSBne8+seeFVBoGqzHM9yXw==
|
||||
ssh_known_hosts: |
|
||||
bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDQeJzhupRu0u0cdegZIa8e86EG2qOCsIsD1Xw0xSeiPDlCr7kq97NLmMbpKTX6Esc30NuoqEEHCuc7yWtwp8dI76EEEB1VqY9QJq6vk+aySyboD5QF61I/1WeTwu+deCbgKMGbUijeXhtfbxSxm6JwGrXrhBdofTsbKRUsrN1WoNgUa8uqN1Vx6WAJw1JHPhglEGGHea6QICwJOAr/6mrui/oB7pkaWKHj3z7d1IC4KWLtY47elvjbaTlkN04Kc/5LFEirorGYVbt15kAUlqGM65pk6ZBxtaO3+30LVlORZkxOh+LKL/BvbZ/iRNhItLqNyieoQj/uh/7Iv4uyH/cV/0b4WDSd3DptigWq84lJubb9t/DnZlrJazxyDCulTmKdOR7vs9gMTo+uoIrPSb8ScTtvw65+odKAlBj59dhnVp9zd7QUojOpXlL62Aw56U4oO+FALuevvMjiWeavKhJqlR7i5n9srYcrNV7ttmDw7kf/97P5zauIhxcjX+xHv4M=
|
||||
github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==
|
||||
gitlab.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QlYWrOLXBpQ6KWjbjTDTdDkoohFzgbEY=
|
||||
gitlab.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf
|
||||
@@ -15877,7 +15877,7 @@ spec:
|
||||
key: applicationsetcontroller.enable.progressive.syncs
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.6.8
|
||||
image: quay.io/argoproj/argocd:v2.6.14
|
||||
imagePullPolicy: Always
|
||||
name: argocd-applicationset-controller
|
||||
ports:
|
||||
@@ -15958,7 +15958,7 @@ spec:
|
||||
key: dexserver.disable.tls
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: ghcr.io/dexidp/dex:v2.36.0
|
||||
image: ghcr.io/dexidp/dex:v2.37.0
|
||||
imagePullPolicy: Always
|
||||
name: dex
|
||||
ports:
|
||||
@@ -15987,7 +15987,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /shared/argocd-dex
|
||||
image: quay.io/argoproj/argocd:v2.6.8
|
||||
image: quay.io/argoproj/argocd:v2.6.14
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
securityContext:
|
||||
@@ -16040,7 +16040,7 @@ spec:
|
||||
containers:
|
||||
- command:
|
||||
- argocd-notifications
|
||||
image: quay.io/argoproj/argocd:v2.6.8
|
||||
image: quay.io/argoproj/argocd:v2.6.14
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
@@ -16299,7 +16299,7 @@ spec:
|
||||
value: /helm-working-dir
|
||||
- name: HELM_DATA_HOME
|
||||
value: /helm-working-dir
|
||||
image: quay.io/argoproj/argocd:v2.6.8
|
||||
image: quay.io/argoproj/argocd:v2.6.14
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -16351,7 +16351,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /var/run/argocd/argocd-cmp-server
|
||||
image: quay.io/argoproj/argocd:v2.6.8
|
||||
image: quay.io/argoproj/argocd:v2.6.14
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -16626,7 +16626,7 @@ spec:
|
||||
key: server.enable.proxy.extension
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.6.8
|
||||
image: quay.io/argoproj/argocd:v2.6.14
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -16860,7 +16860,7 @@ spec:
|
||||
key: application.namespaces
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.6.8
|
||||
image: quay.io/argoproj/argocd:v2.6.14
|
||||
imagePullPolicy: Always
|
||||
name: argocd-application-controller
|
||||
ports:
|
||||
|
||||
@@ -402,8 +402,8 @@ metadata:
|
||||
---
|
||||
apiVersion: v1
|
||||
data:
|
||||
ssh_known_hosts: |-
|
||||
bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kNvEcqTKl/VqLat/MaB33pZy0y3rJZtnqwR2qOOvbwKZYKiEO1O6VqNEBxKvJJelCq0dTXWT5pbO2gDXC6h6QDXCaHo6pOHGPUy+YBaGQRGuSusMEASYiWunYN0vCAI8QaXnWMXNMdFP3jHAJH0eDsoiGnLPBlBp4TNm6rYI74nMzgz3B9IikW4WVK+dc8KZJZWYjAuORU3jc1c/NPskD2ASinf8v3xnfXeukU0sJ5N6m5E8VLjObPEO+mN2t/FZTMZLiFqPWc/ALSqnMnnhwrNi2rbfg/rd/IpL8Le3pSBne8+seeFVBoGqzHM9yXw==
|
||||
ssh_known_hosts: |
|
||||
bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDQeJzhupRu0u0cdegZIa8e86EG2qOCsIsD1Xw0xSeiPDlCr7kq97NLmMbpKTX6Esc30NuoqEEHCuc7yWtwp8dI76EEEB1VqY9QJq6vk+aySyboD5QF61I/1WeTwu+deCbgKMGbUijeXhtfbxSxm6JwGrXrhBdofTsbKRUsrN1WoNgUa8uqN1Vx6WAJw1JHPhglEGGHea6QICwJOAr/6mrui/oB7pkaWKHj3z7d1IC4KWLtY47elvjbaTlkN04Kc/5LFEirorGYVbt15kAUlqGM65pk6ZBxtaO3+30LVlORZkxOh+LKL/BvbZ/iRNhItLqNyieoQj/uh/7Iv4uyH/cV/0b4WDSd3DptigWq84lJubb9t/DnZlrJazxyDCulTmKdOR7vs9gMTo+uoIrPSb8ScTtvw65+odKAlBj59dhnVp9zd7QUojOpXlL62Aw56U4oO+FALuevvMjiWeavKhJqlR7i5n9srYcrNV7ttmDw7kf/97P5zauIhxcjX+xHv4M=
|
||||
github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==
|
||||
gitlab.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QlYWrOLXBpQ6KWjbjTDTdDkoohFzgbEY=
|
||||
gitlab.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf
|
||||
@@ -681,7 +681,7 @@ spec:
|
||||
key: applicationsetcontroller.enable.progressive.syncs
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.6.8
|
||||
image: quay.io/argoproj/argocd:v2.6.14
|
||||
imagePullPolicy: Always
|
||||
name: argocd-applicationset-controller
|
||||
ports:
|
||||
@@ -762,7 +762,7 @@ spec:
|
||||
key: dexserver.disable.tls
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: ghcr.io/dexidp/dex:v2.36.0
|
||||
image: ghcr.io/dexidp/dex:v2.37.0
|
||||
imagePullPolicy: Always
|
||||
name: dex
|
||||
ports:
|
||||
@@ -791,7 +791,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /shared/argocd-dex
|
||||
image: quay.io/argoproj/argocd:v2.6.8
|
||||
image: quay.io/argoproj/argocd:v2.6.14
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
securityContext:
|
||||
@@ -844,7 +844,7 @@ spec:
|
||||
containers:
|
||||
- command:
|
||||
- argocd-notifications
|
||||
image: quay.io/argoproj/argocd:v2.6.8
|
||||
image: quay.io/argoproj/argocd:v2.6.14
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
@@ -1103,7 +1103,7 @@ spec:
|
||||
value: /helm-working-dir
|
||||
- name: HELM_DATA_HOME
|
||||
value: /helm-working-dir
|
||||
image: quay.io/argoproj/argocd:v2.6.8
|
||||
image: quay.io/argoproj/argocd:v2.6.14
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -1155,7 +1155,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /var/run/argocd/argocd-cmp-server
|
||||
image: quay.io/argoproj/argocd:v2.6.8
|
||||
image: quay.io/argoproj/argocd:v2.6.14
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -1430,7 +1430,7 @@ spec:
|
||||
key: server.enable.proxy.extension
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.6.8
|
||||
image: quay.io/argoproj/argocd:v2.6.14
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -1664,7 +1664,7 @@ spec:
|
||||
key: application.namespaces
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.6.8
|
||||
image: quay.io/argoproj/argocd:v2.6.14
|
||||
imagePullPolicy: Always
|
||||
name: argocd-application-controller
|
||||
ports:
|
||||
|
||||
@@ -163,6 +163,7 @@ nav:
|
||||
- user-guide/external-url.md
|
||||
- user-guide/extra_info.md
|
||||
- Notification subscriptions: user-guide/subscriptions.md
|
||||
- user-guide/annotations-and-labels.md
|
||||
- Command Reference: user-guide/commands/argocd.md
|
||||
- Developer Guide:
|
||||
- developer-guide/index.md
|
||||
|
||||
@@ -450,6 +450,7 @@ type ApplicationSourceKustomize struct {
|
||||
func (k *ApplicationSourceKustomize) AllowsConcurrentProcessing() bool {
|
||||
return len(k.Images) == 0 &&
|
||||
len(k.CommonLabels) == 0 &&
|
||||
len(k.CommonAnnotations) == 0 &&
|
||||
k.NamePrefix == "" &&
|
||||
k.NameSuffix == ""
|
||||
}
|
||||
|
||||
@@ -2880,11 +2880,21 @@ func TestRetryStrategy_NextRetryAtCustomBackoff(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSourceAllowsConcurrentProcessing_KustomizeParams(t *testing.T) {
|
||||
src := ApplicationSource{Path: ".", Kustomize: &ApplicationSourceKustomize{
|
||||
NameSuffix: "test",
|
||||
}}
|
||||
t.Run("Has NameSuffix", func(t *testing.T) {
|
||||
src := ApplicationSource{Path: ".", Kustomize: &ApplicationSourceKustomize{
|
||||
NameSuffix: "test",
|
||||
}}
|
||||
|
||||
assert.False(t, src.AllowsConcurrentProcessing())
|
||||
assert.False(t, src.AllowsConcurrentProcessing())
|
||||
})
|
||||
|
||||
t.Run("Has CommonAnnotations", func(t *testing.T) {
|
||||
src := ApplicationSource{Path: ".", Kustomize: &ApplicationSourceKustomize{
|
||||
CommonAnnotations: map[string]string{"foo": "bar"},
|
||||
}}
|
||||
|
||||
assert.False(t, src.AllowsConcurrentProcessing())
|
||||
})
|
||||
}
|
||||
|
||||
func TestUnSetCascadedDeletion(t *testing.T) {
|
||||
|
||||
@@ -302,6 +302,7 @@ func (s *Service) runRepoOperation(
|
||||
var helmClient helm.Client
|
||||
var err error
|
||||
revision = textutils.FirstNonEmpty(revision, source.TargetRevision)
|
||||
unresolvedRevision := revision
|
||||
if source.IsHelm() {
|
||||
helmClient, revision, err = s.newHelmClientResolveRevision(repo, revision, source.Chart, settings.noCache || settings.noRevisionCache)
|
||||
if err != nil {
|
||||
@@ -336,14 +337,6 @@ func (s *Service) runRepoOperation(
|
||||
defer settings.sem.Release(1)
|
||||
}
|
||||
|
||||
// do not generate manifests if Path and Chart fields are not set for a source in Multiple Sources
|
||||
if hasMultipleSources && source.Path == "" && source.Chart == "" {
|
||||
log.WithFields(map[string]interface{}{
|
||||
"source": source,
|
||||
}).Debugf("not generating manifests as path and chart fields are empty")
|
||||
return nil
|
||||
}
|
||||
|
||||
if source.IsHelm() {
|
||||
if settings.noCache {
|
||||
err = helmClient.CleanChartCache(source.Chart, revision)
|
||||
@@ -426,7 +419,16 @@ func (s *Service) runRepoOperation(
|
||||
return operation(gitClient.Root(), commitSHA, revision, func() (*operationContext, error) {
|
||||
var signature string
|
||||
if verifyCommit {
|
||||
signature, err = gitClient.VerifyCommitSignature(revision)
|
||||
// When the revision is an annotated tag, we need to pass the unresolved revision (i.e. the tag name)
|
||||
// to the verification routine. For everything else, we work with the SHA that the target revision is
|
||||
// pointing to (i.e. the resolved revision).
|
||||
var rev string
|
||||
if gitClient.IsAnnotatedTag(revision) {
|
||||
rev = unresolvedRevision
|
||||
} else {
|
||||
rev = revision
|
||||
}
|
||||
signature, err = gitClient.VerifyCommitSignature(rev)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -500,6 +502,17 @@ func (s *Service) GenerateManifest(ctx context.Context, q *apiclient.ManifestReq
|
||||
var promise *ManifestResponsePromise
|
||||
|
||||
operation := func(repoRoot, commitSHA, cacheKey string, ctxSrc operationContextSrc) error {
|
||||
// do not generate manifests if Path and Chart fields are not set for a source in Multiple Sources
|
||||
if q.HasMultipleSources && q.ApplicationSource.Path == "" && q.ApplicationSource.Chart == "" {
|
||||
log.WithFields(map[string]interface{}{
|
||||
"source": q.ApplicationSource,
|
||||
}).Debugf("not generating manifests as path and chart fields are empty")
|
||||
res = &apiclient.ManifestResponse{
|
||||
Revision: commitSHA,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
promise = s.runManifestGen(ctx, repoRoot, commitSHA, cacheKey, ctxSrc, q)
|
||||
// The fist channel to send the message will resume this operation.
|
||||
// The main purpose for using channels here is to be able to unlock
|
||||
@@ -532,10 +545,6 @@ func (s *Service) GenerateManifest(ctx context.Context, q *apiclient.ManifestReq
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if q.HasMultipleSources && err == nil && res == nil {
|
||||
res = &apiclient.ManifestResponse{}
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
|
||||
@@ -920,12 +929,52 @@ func (s *Service) getManifestCacheEntry(cacheKey string, q *apiclient.ManifestRe
|
||||
return false, nil, nil
|
||||
}
|
||||
|
||||
func getHelmRepos(repositories []*v1alpha1.Repository) []helm.HelmRepository {
|
||||
repos := make([]helm.HelmRepository, 0)
|
||||
func getHelmRepos(appPath string, repositories []*v1alpha1.Repository, helmRepoCreds []*v1alpha1.RepoCreds) ([]helm.HelmRepository, error) {
|
||||
dependencies, err := getHelmDependencyRepos(appPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
reposByName := make(map[string]*v1alpha1.Repository)
|
||||
reposByUrl := make(map[string]*v1alpha1.Repository)
|
||||
for _, repo := range repositories {
|
||||
reposByUrl[repo.Repo] = repo
|
||||
if repo.Name != "" {
|
||||
reposByName[repo.Name] = repo
|
||||
}
|
||||
}
|
||||
|
||||
repos := make([]helm.HelmRepository, 0)
|
||||
for _, dep := range dependencies {
|
||||
// find matching repo credentials by URL or name
|
||||
repo, ok := reposByUrl[dep.Repo]
|
||||
if !ok && dep.Name != "" {
|
||||
repo, ok = reposByName[dep.Name]
|
||||
}
|
||||
if !ok {
|
||||
// if no matching repo credentials found, use the repo creds from the credential list
|
||||
repo = &v1alpha1.Repository{Repo: dep.Repo, Name: dep.Name, EnableOCI: dep.EnableOCI}
|
||||
if repositoryCredential := getRepoCredential(helmRepoCreds, dep.Repo); repositoryCredential != nil {
|
||||
repo.EnableOCI = repositoryCredential.EnableOCI
|
||||
repo.Password = repositoryCredential.Password
|
||||
repo.Username = repositoryCredential.Username
|
||||
repo.SSHPrivateKey = repositoryCredential.SSHPrivateKey
|
||||
repo.TLSClientCertData = repositoryCredential.TLSClientCertData
|
||||
repo.TLSClientCertKey = repositoryCredential.TLSClientCertKey
|
||||
} else if repo.EnableOCI {
|
||||
// finally if repo is OCI and no credentials found, use the first OCI credential matching by hostname
|
||||
// see https://github.com/argoproj/argo-cd/issues/14636
|
||||
for _, cred := range repositories {
|
||||
if depURL, err := url.Parse("oci://" + dep.Repo); err == nil && cred.EnableOCI && depURL.Host == cred.Repo {
|
||||
repo.Username = cred.Username
|
||||
repo.Password = cred.Password
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
repos = append(repos, helm.HelmRepository{Name: repo.Name, Repo: repo.Repo, Creds: repo.GetHelmCreds(), EnableOci: repo.EnableOCI})
|
||||
}
|
||||
return repos
|
||||
return repos, nil
|
||||
}
|
||||
|
||||
type dependencies struct {
|
||||
@@ -949,9 +998,14 @@ func getHelmDependencyRepos(appPath string) ([]*v1alpha1.Repository, error) {
|
||||
}
|
||||
|
||||
for _, r := range d.Dependencies {
|
||||
if u, err := url.Parse(r.Repository); err == nil && (u.Scheme == "https" || u.Scheme == "oci") {
|
||||
if strings.HasPrefix(r.Repository, "@") {
|
||||
repos = append(repos, &v1alpha1.Repository{
|
||||
Name: r.Repository[1:],
|
||||
})
|
||||
} else if u, err := url.Parse(r.Repository); err == nil && (u.Scheme == "https" || u.Scheme == "oci") {
|
||||
repo := &v1alpha1.Repository{
|
||||
Repo: r.Repository,
|
||||
// trimming oci:// prefix since it is currently not supported by Argo CD (OCI repos just have no scheme)
|
||||
Repo: strings.TrimPrefix(r.Repository, "oci://"),
|
||||
Name: sanitizeRepoName(r.Repository),
|
||||
EnableOCI: u.Scheme == "oci",
|
||||
}
|
||||
@@ -966,15 +1020,6 @@ func sanitizeRepoName(repoName string) string {
|
||||
return strings.ReplaceAll(repoName, "/", "-")
|
||||
}
|
||||
|
||||
func repoExists(repo string, repos []*v1alpha1.Repository) bool {
|
||||
for _, r := range repos {
|
||||
if strings.TrimPrefix(repo, ociPrefix) == strings.TrimPrefix(r.Repo, ociPrefix) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func isConcurrencyAllowed(appPath string) bool {
|
||||
if _, err := os.Stat(path.Join(appPath, allowConcurrencyFile)); err == nil {
|
||||
return true
|
||||
@@ -1010,32 +1055,6 @@ func runHelmBuild(appPath string, h helm.Helm) error {
|
||||
return os.WriteFile(markerFile, []byte("marker"), 0644)
|
||||
}
|
||||
|
||||
func populateRequestRepos(appPath string, q *apiclient.ManifestRequest) error {
|
||||
repos, err := getHelmDependencyRepos(appPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, r := range repos {
|
||||
if !repoExists(r.Repo, q.Repos) {
|
||||
repositoryCredential := getRepoCredential(q.HelmRepoCreds, r.Repo)
|
||||
if repositoryCredential != nil {
|
||||
if repositoryCredential.EnableOCI {
|
||||
r.Repo = strings.TrimPrefix(r.Repo, ociPrefix)
|
||||
}
|
||||
r.EnableOCI = repositoryCredential.EnableOCI
|
||||
r.Password = repositoryCredential.Password
|
||||
r.Username = repositoryCredential.Username
|
||||
r.SSHPrivateKey = repositoryCredential.SSHPrivateKey
|
||||
r.TLSClientCertData = repositoryCredential.TLSClientCertData
|
||||
r.TLSClientCertKey = repositoryCredential.TLSClientCertKey
|
||||
}
|
||||
q.Repos = append(q.Repos, r)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func helmTemplate(appPath string, repoRoot string, env *v1alpha1.Env, q *apiclient.ManifestRequest, isLocal bool, gitRepoPaths io.TempPaths) ([]*unstructured.Unstructured, error) {
|
||||
concurrencyAllowed := isConcurrencyAllowed(appPath)
|
||||
if !concurrencyAllowed {
|
||||
@@ -1123,16 +1142,16 @@ func helmTemplate(appPath string, repoRoot string, env *v1alpha1.Env, q *apiclie
|
||||
templateOpts.SetString[i] = env.Envsubst(j)
|
||||
}
|
||||
|
||||
if err := populateRequestRepos(appPath, q); err != nil {
|
||||
return nil, fmt.Errorf("failed parsing dependencies: %v", err)
|
||||
}
|
||||
|
||||
var proxy string
|
||||
if q.Repo != nil {
|
||||
proxy = q.Repo.Proxy
|
||||
}
|
||||
|
||||
h, err := helm.NewHelmApp(appPath, getHelmRepos(q.Repos), isLocal, version, proxy, passCredentials)
|
||||
helmRepos, err := getHelmRepos(appPath, q.Repos, q.HelmRepoCreds)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
h, err := helm.NewHelmApp(appPath, helmRepos, isLocal, version, proxy, passCredentials)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -2034,7 +2053,11 @@ func populateHelmAppDetails(res *apiclient.RepoAppDetailsResponse, appPath strin
|
||||
}
|
||||
passCredentials = q.Source.Helm.PassCredentials
|
||||
}
|
||||
h, err := helm.NewHelmApp(appPath, getHelmRepos(q.Repos), false, version, q.Repo.Proxy, passCredentials)
|
||||
helmRepos, err := getHelmRepos(appPath, q.Repos, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
h, err := helm.NewHelmApp(appPath, helmRepos, false, version, q.Repo.Proxy, passCredentials)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -63,6 +63,7 @@ func newServiceWithMocks(root string, signed bool) (*Service, *gitmocks.Client)
|
||||
gitClient.On("LsRemote", mock.Anything).Return(mock.Anything, nil)
|
||||
gitClient.On("CommitSHA").Return(mock.Anything, nil)
|
||||
gitClient.On("Root").Return(root)
|
||||
gitClient.On("IsAnnotatedTag").Return(false)
|
||||
if signed {
|
||||
gitClient.On("VerifyCommitSignature", mock.Anything).Return(testSignature, nil)
|
||||
} else {
|
||||
@@ -1276,6 +1277,7 @@ func TestListApps(t *testing.T) {
|
||||
"oci-dependencies": "Helm",
|
||||
"out-of-bounds-values-file-link": "Helm",
|
||||
"values-files": "Helm",
|
||||
"helm-with-dependencies": "Helm",
|
||||
}
|
||||
assert.Equal(t, expectedApps, res.Apps)
|
||||
}
|
||||
@@ -2602,19 +2604,35 @@ func Test_populateHelmAppDetails_values_symlinks(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestOCIDependencies(t *testing.T) {
|
||||
func TestGetHelmRepos_OCIDependencies(t *testing.T) {
|
||||
src := argoappv1.ApplicationSource{Path: "."}
|
||||
q := apiclient.ManifestRequest{Repo: &argoappv1.Repository{}, ApplicationSource: &src, HelmRepoCreds: []*argoappv1.RepoCreds{
|
||||
{URL: "example.com", Username: "test", Password: "test", EnableOCI: true},
|
||||
}}
|
||||
|
||||
err := populateRequestRepos("./testdata/oci-dependencies", &q)
|
||||
helmRepos, err := getHelmRepos("./testdata/oci-dependencies", q.Repos, q.HelmRepoCreds)
|
||||
assert.Nil(t, err)
|
||||
|
||||
assert.Equal(t, len(q.Repos), 1)
|
||||
assert.Equal(t, q.Repos[0].Username, "test")
|
||||
assert.Equal(t, q.Repos[0].EnableOCI, true)
|
||||
assert.Equal(t, q.Repos[0].Repo, "example.com")
|
||||
assert.Equal(t, len(helmRepos), 1)
|
||||
assert.Equal(t, helmRepos[0].Username, "test")
|
||||
assert.Equal(t, helmRepos[0].EnableOci, true)
|
||||
assert.Equal(t, helmRepos[0].Repo, "example.com/myrepo")
|
||||
}
|
||||
|
||||
func TestGetHelmRepo_NamedRepos(t *testing.T) {
|
||||
src := argoappv1.ApplicationSource{Path: "."}
|
||||
q := apiclient.ManifestRequest{Repo: &argoappv1.Repository{}, ApplicationSource: &src, Repos: []*argoappv1.Repository{{
|
||||
Name: "custom-repo",
|
||||
Repo: "https://example.com",
|
||||
Username: "test",
|
||||
}}}
|
||||
|
||||
helmRepos, err := getHelmRepos("./testdata/helm-with-dependencies", q.Repos, q.HelmRepoCreds)
|
||||
assert.Nil(t, err)
|
||||
|
||||
assert.Equal(t, len(helmRepos), 1)
|
||||
assert.Equal(t, helmRepos[0].Username, "test")
|
||||
assert.Equal(t, helmRepos[0].Repo, "https://example.com")
|
||||
}
|
||||
|
||||
func Test_getResolvedValueFiles(t *testing.T) {
|
||||
|
||||
7
reposerver/repository/testdata/helm-with-dependencies/Chart.yaml
vendored
Normal file
7
reposerver/repository/testdata/helm-with-dependencies/Chart.yaml
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
apiVersion: v2
|
||||
name: helm-with-dependencies
|
||||
version: v1.0.0
|
||||
dependencies:
|
||||
- name: helm
|
||||
repository: "@custom-repo"
|
||||
version: v1.0.0
|
||||
@@ -2,5 +2,5 @@ name: my-chart
|
||||
version: 1.1.0
|
||||
dependencies:
|
||||
- name: my-dependency
|
||||
repository: oci://example.com
|
||||
repository: oci://example.com/myrepo
|
||||
version: '*'
|
||||
@@ -1387,7 +1387,7 @@ func (s *Server) ManagedResources(ctx context.Context, q *application.ResourcesQ
|
||||
res := &application.ManagedResourcesResponse{}
|
||||
for i := range items {
|
||||
item := items[i]
|
||||
if isMatchingResource(q, kube.ResourceKey{Name: item.Name, Namespace: item.Namespace, Kind: item.Kind, Group: item.Group}) {
|
||||
if !item.Hook && isMatchingResource(q, kube.ResourceKey{Name: item.Name, Namespace: item.Namespace, Kind: item.Kind, Group: item.Group}) {
|
||||
res.Items = append(res.Items, item)
|
||||
}
|
||||
}
|
||||
@@ -1789,7 +1789,7 @@ func (s *Server) Rollback(ctx context.Context, rollbackReq *application.Applicat
|
||||
}
|
||||
|
||||
func (s *Server) ListLinks(ctx context.Context, req *application.ListAppLinksRequest) (*application.LinksResponse, error) {
|
||||
a, err := s.getApplicationEnforceRBACClient(ctx, rbacpolicy.ActionSync, req.GetNamespace(), req.GetName(), "")
|
||||
a, err := s.getApplicationEnforceRBACClient(ctx, rbacpolicy.ActionGet, req.GetNamespace(), req.GetName(), "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
util_session "github.com/argoproj/argo-cd/v2/util/session"
|
||||
"github.com/argoproj/gitops-engine/pkg/utils/kube"
|
||||
log "github.com/sirupsen/logrus"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
@@ -37,11 +38,12 @@ type terminalHandler struct {
|
||||
allowedShells []string
|
||||
namespace string
|
||||
enabledNamespaces []string
|
||||
sessionManager util_session.SessionManager
|
||||
}
|
||||
|
||||
// NewHandler returns a new terminal handler.
|
||||
func NewHandler(appLister applisters.ApplicationLister, namespace string, enabledNamespaces []string, db db.ArgoDB, enf *rbac.Enforcer, cache *servercache.Cache,
|
||||
appResourceTree AppResourceTreeFn, allowedShells []string) *terminalHandler {
|
||||
appResourceTree AppResourceTreeFn, allowedShells []string, sessionManager util_session.SessionManager) *terminalHandler {
|
||||
return &terminalHandler{
|
||||
appLister: appLister,
|
||||
db: db,
|
||||
@@ -51,6 +53,7 @@ func NewHandler(appLister applisters.ApplicationLister, namespace string, enable
|
||||
allowedShells: allowedShells,
|
||||
namespace: namespace,
|
||||
enabledNamespaces: enabledNamespaces,
|
||||
sessionManager: sessionManager,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -253,7 +256,7 @@ func (s *terminalHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
fieldLog.Info("terminal session starting")
|
||||
|
||||
session, err := newTerminalSession(w, r, nil)
|
||||
session, err := newTerminalSession(w, r, nil, s.sessionManager)
|
||||
if err != nil {
|
||||
http.Error(w, "Failed to start terminal session", http.StatusBadRequest)
|
||||
return
|
||||
@@ -309,6 +312,11 @@ type TerminalMessage struct {
|
||||
Cols uint16 `json:"cols"`
|
||||
}
|
||||
|
||||
// TerminalCommand is the struct for websocket commands,For example you need ask client to reconnect
|
||||
type TerminalCommand struct {
|
||||
Code int
|
||||
}
|
||||
|
||||
// startProcess executes specified commands in the container and connects it up with the ptyHandler (a session)
|
||||
func startProcess(k8sClient kubernetes.Interface, cfg *rest.Config, namespace, podName, containerName string, cmd []string, ptyHandler PtyHandler) error {
|
||||
req := k8sClient.CoreV1().RESTClient().Post().
|
||||
|
||||
@@ -3,6 +3,9 @@ package application
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/argoproj/argo-cd/v2/common"
|
||||
httputil "github.com/argoproj/argo-cd/v2/util/http"
|
||||
util_session "github.com/argoproj/argo-cd/v2/util/session"
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -12,6 +15,11 @@ import (
|
||||
"k8s.io/client-go/tools/remotecommand"
|
||||
)
|
||||
|
||||
const (
|
||||
ReconnectCode = 1
|
||||
ReconnectMessage = "\nReconnect because the token was refreshed...\n"
|
||||
)
|
||||
|
||||
var upgrader = func() websocket.Upgrader {
|
||||
upgrader := websocket.Upgrader{}
|
||||
upgrader.HandshakeTimeout = time.Second * 2
|
||||
@@ -23,25 +31,40 @@ var upgrader = func() websocket.Upgrader {
|
||||
|
||||
// terminalSession implements PtyHandler
|
||||
type terminalSession struct {
|
||||
wsConn *websocket.Conn
|
||||
sizeChan chan remotecommand.TerminalSize
|
||||
doneChan chan struct{}
|
||||
tty bool
|
||||
readLock sync.Mutex
|
||||
writeLock sync.Mutex
|
||||
wsConn *websocket.Conn
|
||||
sizeChan chan remotecommand.TerminalSize
|
||||
doneChan chan struct{}
|
||||
tty bool
|
||||
readLock sync.Mutex
|
||||
writeLock sync.Mutex
|
||||
sessionManager util_session.SessionManager
|
||||
token *string
|
||||
}
|
||||
|
||||
// getToken get auth token from web socket request
|
||||
func getToken(r *http.Request) (string, error) {
|
||||
cookies := r.Cookies()
|
||||
return httputil.JoinCookies(common.AuthCookieName, cookies)
|
||||
}
|
||||
|
||||
// newTerminalSession create terminalSession
|
||||
func newTerminalSession(w http.ResponseWriter, r *http.Request, responseHeader http.Header) (*terminalSession, error) {
|
||||
func newTerminalSession(w http.ResponseWriter, r *http.Request, responseHeader http.Header, sessionManager util_session.SessionManager) (*terminalSession, error) {
|
||||
token, err := getToken(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
conn, err := upgrader.Upgrade(w, r, responseHeader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
session := &terminalSession{
|
||||
wsConn: conn,
|
||||
tty: true,
|
||||
sizeChan: make(chan remotecommand.TerminalSize),
|
||||
doneChan: make(chan struct{}),
|
||||
wsConn: conn,
|
||||
tty: true,
|
||||
sizeChan: make(chan remotecommand.TerminalSize),
|
||||
doneChan: make(chan struct{}),
|
||||
sessionManager: sessionManager,
|
||||
token: &token,
|
||||
}
|
||||
return session, nil
|
||||
}
|
||||
@@ -61,8 +84,40 @@ func (t *terminalSession) Next() *remotecommand.TerminalSize {
|
||||
}
|
||||
}
|
||||
|
||||
// reconnect send reconnect code to client and ask them init new ws session
|
||||
func (t *terminalSession) reconnect() (int, error) {
|
||||
reconnectCommand, _ := json.Marshal(TerminalCommand{
|
||||
Code: ReconnectCode,
|
||||
})
|
||||
reconnectMessage, _ := json.Marshal(TerminalMessage{
|
||||
Operation: "stdout",
|
||||
Data: ReconnectMessage,
|
||||
})
|
||||
t.writeLock.Lock()
|
||||
err := t.wsConn.WriteMessage(websocket.TextMessage, reconnectMessage)
|
||||
if err != nil {
|
||||
log.Errorf("write message err: %v", err)
|
||||
return 0, err
|
||||
}
|
||||
err = t.wsConn.WriteMessage(websocket.TextMessage, reconnectCommand)
|
||||
if err != nil {
|
||||
log.Errorf("write message err: %v", err)
|
||||
return 0, err
|
||||
}
|
||||
t.writeLock.Unlock()
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// Read called in a loop from remotecommand as long as the process is running
|
||||
func (t *terminalSession) Read(p []byte) (int, error) {
|
||||
// check if token still valid
|
||||
_, newToken, err := t.sessionManager.VerifyToken(*t.token)
|
||||
// err in case if token is revoked, newToken in case if refresh happened
|
||||
if err != nil || newToken != "" {
|
||||
// need to send reconnect code in case if token was refreshed
|
||||
return t.reconnect()
|
||||
}
|
||||
|
||||
t.readLock.Lock()
|
||||
_, message, err := t.wsConn.ReadMessage()
|
||||
t.readLock.Unlock()
|
||||
|
||||
46
server/application/websocket_test.go
Normal file
46
server/application/websocket_test.go
Normal file
@@ -0,0 +1,46 @@
|
||||
package application
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func reconnect(w http.ResponseWriter, r *http.Request) {
|
||||
var upgrader = websocket.Upgrader{}
|
||||
c, err := upgrader.Upgrade(w, r, nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
ts := terminalSession{wsConn: c}
|
||||
_, _ = ts.reconnect()
|
||||
}
|
||||
|
||||
func TestReconnect(t *testing.T) {
|
||||
|
||||
s := httptest.NewServer(http.HandlerFunc(reconnect))
|
||||
defer s.Close()
|
||||
|
||||
u := "ws" + strings.TrimPrefix(s.URL, "http")
|
||||
|
||||
// Connect to the server
|
||||
ws, _, err := websocket.DefaultDialer.Dial(u, nil)
|
||||
assert.NoError(t, err)
|
||||
|
||||
defer ws.Close()
|
||||
|
||||
_, p, _ := ws.ReadMessage()
|
||||
|
||||
var message TerminalMessage
|
||||
|
||||
err = json.Unmarshal(p, &message)
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, message.Data, ReconnectMessage)
|
||||
|
||||
}
|
||||
@@ -160,6 +160,7 @@ func (s *Server) Get(ctx context.Context, q *repositorypkg.RepoQuery) (*appsv1.R
|
||||
GitHubAppEnterpriseBaseURL: repo.GitHubAppEnterpriseBaseURL,
|
||||
Proxy: repo.Proxy,
|
||||
Project: repo.Project,
|
||||
InheritedCreds: repo.InheritedCreds,
|
||||
}
|
||||
|
||||
item.ConnectionState = s.getConnectionState(ctx, item.Repo, q.ForceRefresh)
|
||||
@@ -193,6 +194,7 @@ func (s *Server) ListRepositories(ctx context.Context, q *repositorypkg.RepoQuer
|
||||
Proxy: repo.Proxy,
|
||||
Project: repo.Project,
|
||||
ForceHttpBasicAuth: repo.ForceHttpBasicAuth,
|
||||
InheritedCreds: repo.InheritedCreds,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +86,18 @@ var (
|
||||
Destinations: []appsv1.ApplicationDestination{{Server: "*", Namespace: "*"}},
|
||||
},
|
||||
}
|
||||
|
||||
fakeRepo = appsv1.Repository{
|
||||
Repo: "https://test",
|
||||
Type: "test",
|
||||
Name: "test",
|
||||
Username: "argo",
|
||||
Insecure: false,
|
||||
EnableLFS: false,
|
||||
EnableOCI: false,
|
||||
Proxy: "test",
|
||||
Project: "argocd",
|
||||
InheritedCreds: true,
|
||||
}
|
||||
guestbookApp = &appsv1.Application{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "Application",
|
||||
@@ -196,6 +207,33 @@ func TestRepositoryServer(t *testing.T) {
|
||||
assert.Equal(t, repo.Repo, url)
|
||||
})
|
||||
|
||||
t.Run("Test_GetInherited", func(t *testing.T) {
|
||||
repoServerClient := mocks.RepoServerServiceClient{}
|
||||
repoServerClient.On("TestRepository", mock.Anything, mock.Anything).Return(&apiclient.TestRepositoryResponse{}, nil)
|
||||
repoServerClientset := mocks.Clientset{RepoServerServiceClient: &repoServerClient}
|
||||
|
||||
url := "https://test"
|
||||
db := &dbmocks.ArgoDB{}
|
||||
testRepo := &appsv1.Repository{
|
||||
Repo: url,
|
||||
Type: "git",
|
||||
Username: "foo",
|
||||
InheritedCreds: true,
|
||||
}
|
||||
db.On("GetRepository", context.TODO(), url).Return(testRepo, nil)
|
||||
db.On("RepositoryExists", context.TODO(), url).Return(true, nil)
|
||||
|
||||
s := NewServer(&repoServerClientset, db, enforcer, newFixtures().Cache, appLister, projLister, settingsMgr)
|
||||
repo, err := s.Get(context.TODO(), &repository.RepoQuery{
|
||||
Repo: url,
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
|
||||
testRepo.ConnectionState = repo.ConnectionState // overwrite connection state on our test object to simplify comparison below
|
||||
|
||||
assert.Equal(t, testRepo, repo)
|
||||
})
|
||||
|
||||
t.Run("Test_GetWithErrorShouldReturn403", func(t *testing.T) {
|
||||
repoServerClient := mocks.RepoServerServiceClient{}
|
||||
repoServerClientset := mocks.Clientset{RepoServerServiceClient: &repoServerClient}
|
||||
@@ -279,6 +317,23 @@ func TestRepositoryServer(t *testing.T) {
|
||||
assert.Equal(t, repo.Repo, "test")
|
||||
})
|
||||
|
||||
t.Run("Test_ListRepositories", func(t *testing.T) {
|
||||
repoServerClient := mocks.RepoServerServiceClient{}
|
||||
repoServerClient.On("TestRepository", mock.Anything, mock.Anything).Return(&apiclient.TestRepositoryResponse{}, nil)
|
||||
repoServerClientset := mocks.Clientset{RepoServerServiceClient: &repoServerClient}
|
||||
enforcer := newEnforcer(kubeclientset)
|
||||
|
||||
url := "https://test"
|
||||
db := &dbmocks.ArgoDB{}
|
||||
db.On("GetRepository", context.TODO(), url).Return(nil, nil)
|
||||
db.On("ListHelmRepositories", context.TODO(), mock.Anything).Return(nil, nil)
|
||||
db.On("ListRepositories", context.TODO()).Return([]*appsv1.Repository{&fakeRepo, &fakeRepo}, nil)
|
||||
|
||||
s := NewServer(&repoServerClientset, db, enforcer, newFixtures().Cache, appLister, projLister, settingsMgr)
|
||||
resp, err := s.ListRepositories(context.TODO(), &repository.RepoQuery{})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 2, len(resp.Items))
|
||||
})
|
||||
}
|
||||
|
||||
func TestRepositoryServerListApps(t *testing.T) {
|
||||
|
||||
@@ -24,6 +24,8 @@ import (
|
||||
|
||||
// nolint:staticcheck
|
||||
golang_proto "github.com/golang/protobuf/proto"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/selection"
|
||||
|
||||
"github.com/argoproj/notifications-engine/pkg/api"
|
||||
"github.com/argoproj/pkg/sync"
|
||||
@@ -291,7 +293,9 @@ func NewServer(ctx context.Context, opts ArgoCDServerOpts) *ArgoCDServer {
|
||||
|
||||
apiFactory := api.NewFactory(settings_notif.GetFactorySettings(argocdService, "argocd-notifications-secret", "argocd-notifications-cm"), opts.Namespace, secretInformer, configMapInformer)
|
||||
|
||||
return &ArgoCDServer{
|
||||
dbInstance := db.NewDB(opts.Namespace, settingsMgr, opts.KubeClientset)
|
||||
|
||||
a := &ArgoCDServer{
|
||||
ArgoCDServerOpts: opts,
|
||||
log: log.NewEntry(log.StandardLogger()),
|
||||
settings: settings,
|
||||
@@ -307,11 +311,19 @@ func NewServer(ctx context.Context, opts ArgoCDServerOpts) *ArgoCDServer {
|
||||
policyEnforcer: policyEnf,
|
||||
userStateStorage: userStateStorage,
|
||||
staticAssets: http.FS(staticFS),
|
||||
db: db.NewDB(opts.Namespace, settingsMgr, opts.KubeClientset),
|
||||
db: dbInstance,
|
||||
apiFactory: apiFactory,
|
||||
secretInformer: secretInformer,
|
||||
configMapInformer: configMapInformer,
|
||||
}
|
||||
|
||||
err = a.logInClusterWarnings()
|
||||
if err != nil {
|
||||
// Just log. It's not critical.
|
||||
log.Warnf("Failed to log in-cluster warnings: %v", err)
|
||||
}
|
||||
|
||||
return a
|
||||
}
|
||||
|
||||
const (
|
||||
@@ -358,6 +370,47 @@ func (l *Listeners) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// logInClusterWarnings checks the in-cluster configuration and prints out any warnings.
|
||||
func (a *ArgoCDServer) logInClusterWarnings() error {
|
||||
labelSelector := labels.NewSelector()
|
||||
req, err := labels.NewRequirement(common.LabelKeySecretType, selection.Equals, []string{common.LabelValueSecretTypeCluster})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to construct cluster-type label selector: %w", err)
|
||||
}
|
||||
labelSelector = labelSelector.Add(*req)
|
||||
secretsLister, err := a.settingsMgr.GetSecretsLister()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get secrets lister: %w", err)
|
||||
}
|
||||
clusterSecrets, err := secretsLister.Secrets(a.ArgoCDServerOpts.Namespace).List(labelSelector)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to list cluster secrets: %w", err)
|
||||
}
|
||||
var inClusterSecrets []string
|
||||
for _, clusterSecret := range clusterSecrets {
|
||||
cluster, err := db.SecretToCluster(clusterSecret)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not unmarshal cluster secret %q: %w", clusterSecret.Name, err)
|
||||
}
|
||||
if cluster.Server == v1alpha1.KubernetesInternalAPIServerAddr {
|
||||
inClusterSecrets = append(inClusterSecrets, clusterSecret.Name)
|
||||
}
|
||||
}
|
||||
if len(inClusterSecrets) > 0 {
|
||||
// Don't make this call unless we actually have in-cluster secrets, to save time.
|
||||
dbSettings, err := a.settingsMgr.GetSettings()
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not get DB settings: %w", err)
|
||||
}
|
||||
if !dbSettings.InClusterEnabled {
|
||||
for _, clusterName := range inClusterSecrets {
|
||||
log.Warnf("cluster %q uses in-cluster server address but it's disabled in Argo CD settings", clusterName)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func startListener(host string, port int) (net.Listener, error) {
|
||||
var conn net.Listener
|
||||
var realErr error
|
||||
@@ -460,12 +513,12 @@ func (a *ArgoCDServer) Run(ctx context.Context, listeners *Listeners) {
|
||||
var httpL net.Listener
|
||||
var httpsL net.Listener
|
||||
if !a.useTLS() {
|
||||
httpL = tcpm.Match(cmux.HTTP1Fast())
|
||||
httpL = tcpm.Match(cmux.HTTP1Fast("PATCH"))
|
||||
grpcL = tcpm.MatchWithWriters(cmux.HTTP2MatchHeaderFieldSendSettings("content-type", "application/grpc"))
|
||||
|
||||
} else {
|
||||
// We first match on HTTP 1.1 methods.
|
||||
httpL = tcpm.Match(cmux.HTTP1Fast())
|
||||
httpL = tcpm.Match(cmux.HTTP1Fast("PATCH"))
|
||||
|
||||
// If not matched, we assume that its TLS.
|
||||
tlsl := tcpm.Match(cmux.Any())
|
||||
@@ -480,7 +533,7 @@ func (a *ArgoCDServer) Run(ctx context.Context, listeners *Listeners) {
|
||||
|
||||
// Now, we build another mux recursively to match HTTPS and gRPC.
|
||||
tlsm = cmux.New(tlsl)
|
||||
httpsL = tlsm.Match(cmux.HTTP1Fast())
|
||||
httpsL = tlsm.Match(cmux.HTTP1Fast("PATCH"))
|
||||
grpcL = tlsm.MatchWithWriters(cmux.HTTP2MatchHeaderFieldSendSettings("content-type", "application/grpc"))
|
||||
}
|
||||
|
||||
@@ -910,7 +963,7 @@ func (a *ArgoCDServer) newHTTPServer(ctx context.Context, port int, grpcWebHandl
|
||||
}
|
||||
mux.Handle("/api/", handler)
|
||||
|
||||
terminal := application.NewHandler(a.appLister, a.Namespace, a.ApplicationNamespaces, a.db, a.enf, a.Cache, appResourceTreeFn, a.settings.ExecShells).
|
||||
terminal := application.NewHandler(a.appLister, a.Namespace, a.ApplicationNamespaces, a.db, a.enf, a.Cache, appResourceTreeFn, a.settings.ExecShells, *a.sessionMgr).
|
||||
WithFeatureFlagMiddleware(a.settingsMgr.GetSettings)
|
||||
th := util_session.WithAuthMiddleware(a.DisableAuth, a.sessionMgr, terminal)
|
||||
mux.Handle("/terminal", th)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# This file was automatically generated. DO NOT EDIT
|
||||
bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kNvEcqTKl/VqLat/MaB33pZy0y3rJZtnqwR2qOOvbwKZYKiEO1O6VqNEBxKvJJelCq0dTXWT5pbO2gDXC6h6QDXCaHo6pOHGPUy+YBaGQRGuSusMEASYiWunYN0vCAI8QaXnWMXNMdFP3jHAJH0eDsoiGnLPBlBp4TNm6rYI74nMzgz3B9IikW4WVK+dc8KZJZWYjAuORU3jc1c/NPskD2ASinf8v3xnfXeukU0sJ5N6m5E8VLjObPEO+mN2t/FZTMZLiFqPWc/ALSqnMnnhwrNi2rbfg/rd/IpL8Le3pSBne8+seeFVBoGqzHM9yXw==
|
||||
bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDQeJzhupRu0u0cdegZIa8e86EG2qOCsIsD1Xw0xSeiPDlCr7kq97NLmMbpKTX6Esc30NuoqEEHCuc7yWtwp8dI76EEEB1VqY9QJq6vk+aySyboD5QF61I/1WeTwu+deCbgKMGbUijeXhtfbxSxm6JwGrXrhBdofTsbKRUsrN1WoNgUa8uqN1Vx6WAJw1JHPhglEGGHea6QICwJOAr/6mrui/oB7pkaWKHj3z7d1IC4KWLtY47elvjbaTlkN04Kc/5LFEirorGYVbt15kAUlqGM65pk6ZBxtaO3+30LVlORZkxOh+LKL/BvbZ/iRNhItLqNyieoQj/uh/7Iv4uyH/cV/0b4WDSd3DptigWq84lJubb9t/DnZlrJazxyDCulTmKdOR7vs9gMTo+uoIrPSb8ScTtvw65+odKAlBj59dhnVp9zd7QUojOpXlL62Aw56U4oO+FALuevvMjiWeavKhJqlR7i5n9srYcrNV7ttmDw7kf/97P5zauIhxcjX+xHv4M=
|
||||
github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==
|
||||
gitlab.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QlYWrOLXBpQ6KWjbjTDTdDkoohFzgbEY=
|
||||
gitlab.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
controller: [ "$BIN_MODE" = 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_SSH_DATA_PATH=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} ARGOCD_BINARY_NAME=argocd-application-controller $COMMAND --loglevel debug --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081} --application-namespaces=${ARGOCD_APPLICATION_NAMESPACES:-''}"
|
||||
api-server: [ "$BIN_MODE" = 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_BINARY_NAME=argocd-server $COMMAND --loglevel debug --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --disable-auth=${ARGOCD_E2E_DISABLE_AUTH:-'true'} --insecure --dex-server http://localhost:${ARGOCD_E2E_DEX_PORT:-5556} --repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081} --port ${ARGOCD_E2E_APISERVER_PORT:-8080} --application-namespaces=${ARGOCD_APPLICATION_NAMESPACES:-''} "
|
||||
dex: sh -c "test $ARGOCD_IN_CI = true && exit 0; ARGOCD_BINARY_NAME=argocd-dex go run github.com/argoproj/argo-cd/cmd gendexcfg -o `pwd`/dist/dex.yaml && docker run --rm -p ${ARGOCD_E2E_DEX_PORT:-5556}:${ARGOCD_E2E_DEX_PORT:-5556} -v `pwd`/dist/dex.yaml:/dex.yaml ghcr.io/dexidp/dex:v2.36.0 serve /dex.yaml"
|
||||
dex: sh -c "test $ARGOCD_IN_CI = true && exit 0; ARGOCD_BINARY_NAME=argocd-dex go run github.com/argoproj/argo-cd/cmd gendexcfg -o `pwd`/dist/dex.yaml && docker run --rm -p ${ARGOCD_E2E_DEX_PORT:-5556}:${ARGOCD_E2E_DEX_PORT:-5556} -v `pwd`/dist/dex.yaml:/dex.yaml ghcr.io/dexidp/dex:v2.37.0 serve /dex.yaml"
|
||||
redis: sh -c "/usr/local/bin/redis-server --save "" --appendonly no --port ${ARGOCD_E2E_REDIS_PORT:-6379}"
|
||||
repo-server: [ "$BIN_MODE" == 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_GNUPGHOME=${ARGOCD_GNUPGHOME:-/tmp/argocd-local/gpg/keys} ARGOCD_PLUGINSOCKFILEPATH=${ARGOCD_PLUGINSOCKFILEPATH:-./test/cmp} ARGOCD_GPG_DATA_PATH=${ARGOCD_GPG_DATA_PATH:-/tmp/argocd-local/gpg/source} ARGOCD_BINARY_NAME=argocd-repo-server $COMMAND --loglevel debug --port ${ARGOCD_E2E_REPOSERVER_PORT:-8081} --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379}"
|
||||
ui: sh -c "test $ARGOCD_IN_CI = true && exit 0; cd ui && ARGOCD_E2E_YARN_HOST=0.0.0.0 ${ARGOCD_E2E_YARN_CMD:-yarn} start"
|
||||
|
||||
@@ -249,7 +249,7 @@ func TestSyncToSignedCommitWithoutKnownKey(t *testing.T) {
|
||||
Expect(HealthIs(health.HealthStatusMissing))
|
||||
}
|
||||
|
||||
func TestSyncToSignedCommitKeyWithKnownKey(t *testing.T) {
|
||||
func TestSyncToSignedCommitWithKnownKey(t *testing.T) {
|
||||
SkipOnEnv(t, "GPG")
|
||||
Given(t).
|
||||
Project("gpg").
|
||||
@@ -267,6 +267,117 @@ func TestSyncToSignedCommitKeyWithKnownKey(t *testing.T) {
|
||||
Expect(HealthIs(health.HealthStatusHealthy))
|
||||
}
|
||||
|
||||
func TestSyncToSignedBranchWithKnownKey(t *testing.T) {
|
||||
SkipOnEnv(t, "GPG")
|
||||
Given(t).
|
||||
Project("gpg").
|
||||
Path(guestbookPath).
|
||||
Revision("master").
|
||||
GPGPublicKeyAdded().
|
||||
Sleep(2).
|
||||
When().
|
||||
AddSignedFile("test.yaml", "null").
|
||||
IgnoreErrors().
|
||||
CreateApp().
|
||||
Sync().
|
||||
Then().
|
||||
Expect(OperationPhaseIs(OperationSucceeded)).
|
||||
Expect(SyncStatusIs(SyncStatusCodeSynced)).
|
||||
Expect(HealthIs(health.HealthStatusHealthy))
|
||||
}
|
||||
|
||||
func TestSyncToSignedBranchWithUnknownKey(t *testing.T) {
|
||||
SkipOnEnv(t, "GPG")
|
||||
Given(t).
|
||||
Project("gpg").
|
||||
Path(guestbookPath).
|
||||
Revision("master").
|
||||
Sleep(2).
|
||||
When().
|
||||
AddSignedFile("test.yaml", "null").
|
||||
IgnoreErrors().
|
||||
CreateApp().
|
||||
Sync().
|
||||
Then().
|
||||
Expect(OperationPhaseIs(OperationError)).
|
||||
Expect(SyncStatusIs(SyncStatusCodeOutOfSync)).
|
||||
Expect(HealthIs(health.HealthStatusMissing))
|
||||
}
|
||||
|
||||
func TestSyncToUnsignedBranch(t *testing.T) {
|
||||
SkipOnEnv(t, "GPG")
|
||||
Given(t).
|
||||
Project("gpg").
|
||||
Revision("master").
|
||||
Path(guestbookPath).
|
||||
GPGPublicKeyAdded().
|
||||
Sleep(2).
|
||||
When().
|
||||
IgnoreErrors().
|
||||
CreateApp().
|
||||
Sync().
|
||||
Then().
|
||||
Expect(OperationPhaseIs(OperationError)).
|
||||
Expect(SyncStatusIs(SyncStatusCodeOutOfSync)).
|
||||
Expect(HealthIs(health.HealthStatusMissing))
|
||||
}
|
||||
|
||||
func TestSyncToSignedTagWithKnownKey(t *testing.T) {
|
||||
SkipOnEnv(t, "GPG")
|
||||
Given(t).
|
||||
Project("gpg").
|
||||
Revision("signed-tag").
|
||||
Path(guestbookPath).
|
||||
GPGPublicKeyAdded().
|
||||
Sleep(2).
|
||||
When().
|
||||
AddSignedTag("signed-tag").
|
||||
IgnoreErrors().
|
||||
CreateApp().
|
||||
Sync().
|
||||
Then().
|
||||
Expect(OperationPhaseIs(OperationSucceeded)).
|
||||
Expect(SyncStatusIs(SyncStatusCodeSynced)).
|
||||
Expect(HealthIs(health.HealthStatusHealthy))
|
||||
}
|
||||
|
||||
func TestSyncToSignedTagWithUnknownKey(t *testing.T) {
|
||||
SkipOnEnv(t, "GPG")
|
||||
Given(t).
|
||||
Project("gpg").
|
||||
Revision("signed-tag").
|
||||
Path(guestbookPath).
|
||||
Sleep(2).
|
||||
When().
|
||||
AddSignedTag("signed-tag").
|
||||
IgnoreErrors().
|
||||
CreateApp().
|
||||
Sync().
|
||||
Then().
|
||||
Expect(OperationPhaseIs(OperationError)).
|
||||
Expect(SyncStatusIs(SyncStatusCodeOutOfSync)).
|
||||
Expect(HealthIs(health.HealthStatusMissing))
|
||||
}
|
||||
|
||||
func TestSyncToUnsignedTag(t *testing.T) {
|
||||
SkipOnEnv(t, "GPG")
|
||||
Given(t).
|
||||
Project("gpg").
|
||||
Revision("unsigned-tag").
|
||||
Path(guestbookPath).
|
||||
GPGPublicKeyAdded().
|
||||
Sleep(2).
|
||||
When().
|
||||
AddTag("unsigned-tag").
|
||||
IgnoreErrors().
|
||||
CreateApp().
|
||||
Sync().
|
||||
Then().
|
||||
Expect(OperationPhaseIs(OperationError)).
|
||||
Expect(SyncStatusIs(SyncStatusCodeOutOfSync)).
|
||||
Expect(HealthIs(health.HealthStatusMissing))
|
||||
}
|
||||
|
||||
func TestAppCreation(t *testing.T) {
|
||||
ctx := Given(t)
|
||||
ctx.
|
||||
@@ -361,6 +472,24 @@ func TestDeleteAppResource(t *testing.T) {
|
||||
Expect(HealthIs(health.HealthStatusMissing))
|
||||
}
|
||||
|
||||
// Fix for issue #2677, support PATCH in HTTP service
|
||||
func TestPatchHttp(t *testing.T) {
|
||||
ctx := Given(t)
|
||||
|
||||
ctx.
|
||||
Path(guestbookPath).
|
||||
When().
|
||||
CreateApp().
|
||||
Sync().
|
||||
PatchAppHttp(`{"metadata": {"labels": { "test": "patch" }, "annotations": { "test": "patch" }}}`).
|
||||
Then().
|
||||
And(func(app *Application) {
|
||||
assert.Equal(t, "patch", app.Labels["test"])
|
||||
assert.Equal(t, "patch", app.Annotations["test"])
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
// demonstrate that we cannot use a standard sync when an immutable field is changed, we must use "force"
|
||||
func TestImmutableChange(t *testing.T) {
|
||||
SkipOnEnv(t, "OPENSHIFT")
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
client "github.com/argoproj/argo-cd/v2/pkg/apiclient/application"
|
||||
. "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/v2/test/e2e/fixture"
|
||||
"github.com/argoproj/argo-cd/v2/util/errors"
|
||||
@@ -64,6 +66,18 @@ func (a *Actions) AddSignedFile(fileName, fileContents string) *Actions {
|
||||
return a
|
||||
}
|
||||
|
||||
func (a *Actions) AddSignedTag(name string) *Actions {
|
||||
a.context.t.Helper()
|
||||
fixture.AddSignedTag(name)
|
||||
return a
|
||||
}
|
||||
|
||||
func (a *Actions) AddTag(name string) *Actions {
|
||||
a.context.t.Helper()
|
||||
fixture.AddTag(name)
|
||||
return a
|
||||
}
|
||||
|
||||
func (a *Actions) CreateFromPartialFile(data string, flags ...string) *Actions {
|
||||
a.context.t.Helper()
|
||||
tmpFile, err := os.CreateTemp("", "")
|
||||
@@ -277,6 +291,28 @@ func (a *Actions) PatchApp(patch string) *Actions {
|
||||
return a
|
||||
}
|
||||
|
||||
func (a *Actions) PatchAppHttp(patch string) *Actions {
|
||||
a.context.t.Helper()
|
||||
var application Application
|
||||
var patchType = "merge"
|
||||
var appName = a.context.AppQualifiedName()
|
||||
var appNamespace = a.context.AppNamespace()
|
||||
patchRequest := &client.ApplicationPatchRequest{
|
||||
Name: &appName,
|
||||
PatchType: &patchType,
|
||||
Patch: &patch,
|
||||
AppNamespace: &appNamespace,
|
||||
}
|
||||
jsonBytes, err := json.MarshalIndent(patchRequest, "", " ")
|
||||
errors.CheckError(err)
|
||||
err = fixture.DoHttpJsonRequest("PATCH",
|
||||
fmt.Sprintf("/api/v1/applications/%v", appName),
|
||||
&application,
|
||||
jsonBytes...)
|
||||
errors.CheckError(err)
|
||||
return a
|
||||
}
|
||||
|
||||
func (a *Actions) AppSet(flags ...string) *Actions {
|
||||
a.context.t.Helper()
|
||||
args := []string{"app", "set", a.context.AppQualifiedName()}
|
||||
|
||||
@@ -92,6 +92,7 @@ type ACL struct {
|
||||
const (
|
||||
RepoURLTypeFile = "file"
|
||||
RepoURLTypeHTTPS = "https"
|
||||
RepoURLTypeHTTPSOrg = "https-org"
|
||||
RepoURLTypeHTTPSClientCert = "https-cc"
|
||||
RepoURLTypeHTTPSSubmodule = "https-sub"
|
||||
RepoURLTypeHTTPSSubmoduleParent = "https-par"
|
||||
@@ -103,6 +104,8 @@ const (
|
||||
RepoURLTypeHelmOCI = "helm-oci"
|
||||
GitUsername = "admin"
|
||||
GitPassword = "password"
|
||||
GithubAppID = "2978632978"
|
||||
GithubAppInstallationID = "7893789433789"
|
||||
GpgGoodKeyID = "D56C4FCA57A46444"
|
||||
HelmOCIRegistryURL = "localhost:5000/myrepo"
|
||||
)
|
||||
@@ -251,6 +254,7 @@ const (
|
||||
EnvRepoURLTypeSSHSubmodule = "ARGOCD_E2E_REPO_SSH_SUBMODULE"
|
||||
EnvRepoURLTypeSSHSubmoduleParent = "ARGOCD_E2E_REPO_SSH_SUBMODULE_PARENT"
|
||||
EnvRepoURLTypeHTTPS = "ARGOCD_E2E_REPO_HTTPS"
|
||||
EnvRepoURLTypeHTTPSOrg = "ARGOCD_E2E_REPO_HTTPS_ORG"
|
||||
EnvRepoURLTypeHTTPSClientCert = "ARGOCD_E2E_REPO_HTTPS_CLIENT_CERT"
|
||||
EnvRepoURLTypeHTTPSSubmodule = "ARGOCD_E2E_REPO_HTTPS_SUBMODULE"
|
||||
EnvRepoURLTypeHTTPSSubmoduleParent = "ARGOCD_E2E_REPO_HTTPS_SUBMODULE_PARENT"
|
||||
@@ -272,6 +276,9 @@ func RepoURL(urlType RepoURLType) string {
|
||||
// Git server via HTTPS
|
||||
case RepoURLTypeHTTPS:
|
||||
return GetEnvWithDefault(EnvRepoURLTypeHTTPS, "https://localhost:9443/argo-e2e/testdata.git")
|
||||
// Git "organisation" via HTTPS
|
||||
case RepoURLTypeHTTPSOrg:
|
||||
return GetEnvWithDefault(EnvRepoURLTypeHTTPSOrg, "https://localhost:9443/argo-e2e")
|
||||
// Git server via HTTPS - Client Cert protected
|
||||
case RepoURLTypeHTTPSClientCert:
|
||||
return GetEnvWithDefault(EnvRepoURLTypeHTTPSClientCert, "https://localhost:9444/argo-e2e/testdata.git")
|
||||
@@ -770,6 +777,26 @@ func AddSignedFile(path, contents string) {
|
||||
}
|
||||
}
|
||||
|
||||
func AddSignedTag(name string) {
|
||||
prevGnuPGHome := os.Getenv("GNUPGHOME")
|
||||
os.Setenv("GNUPGHOME", TmpDir+"/gpg")
|
||||
defer os.Setenv("GNUPGHOME", prevGnuPGHome)
|
||||
FailOnErr(Run(repoDirectory(), "git", "-c", fmt.Sprintf("user.signingkey=%s", GpgGoodKeyID), "tag", "-sm", "add signed tag", name))
|
||||
if IsRemote() {
|
||||
FailOnErr(Run(repoDirectory(), "git", "push", "--tags", "-f", "origin", "master"))
|
||||
}
|
||||
}
|
||||
|
||||
func AddTag(name string) {
|
||||
prevGnuPGHome := os.Getenv("GNUPGHOME")
|
||||
os.Setenv("GNUPGHOME", TmpDir+"/gpg")
|
||||
defer os.Setenv("GNUPGHOME", prevGnuPGHome)
|
||||
FailOnErr(Run(repoDirectory(), "git", "tag", name))
|
||||
if IsRemote() {
|
||||
FailOnErr(Run(repoDirectory(), "git", "push", "--tags", "-f", "origin", "master"))
|
||||
}
|
||||
}
|
||||
|
||||
// create the resource by creating using "kubectl apply", with bonus templating
|
||||
func Declarative(filename string, values interface{}) (string, error) {
|
||||
|
||||
|
||||
@@ -7,9 +7,11 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
repositorypkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/repository"
|
||||
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/v2/test/e2e/fixture"
|
||||
"github.com/argoproj/argo-cd/v2/test/e2e/fixture/app"
|
||||
"github.com/argoproj/argo-cd/v2/test/e2e/fixture/repos"
|
||||
. "github.com/argoproj/argo-cd/v2/util/errors"
|
||||
argoio "github.com/argoproj/argo-cd/v2/util/io"
|
||||
"github.com/argoproj/argo-cd/v2/util/settings"
|
||||
)
|
||||
@@ -52,6 +54,38 @@ func TestAddRemovePublicRepo(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetRepoWithInheritedCreds(t *testing.T) {
|
||||
app.Given(t).And(func() {
|
||||
// create repo credentials
|
||||
FailOnErr(fixture.RunCli("repocreds", "add", fixture.RepoURL(fixture.RepoURLTypeHTTPSOrg), "--github-app-id", fixture.GithubAppID, "--github-app-installation-id", fixture.GithubAppInstallationID, "--github-app-private-key-path", repos.CertKeyPath))
|
||||
|
||||
repoUrl := fixture.RepoURL(fixture.RepoURLTypeHTTPS)
|
||||
|
||||
// Hack: First we need to create repo with valid credentials
|
||||
FailOnErr(fixture.RunCli("repo", "add", repoUrl, "--username", fixture.GitUsername, "--password", fixture.GitPassword, "--insecure-skip-server-verification"))
|
||||
|
||||
// Then, we remove username/password so that the repo inherits the credentials from our repocreds
|
||||
conn, repoClient, err := fixture.ArgoCDClientset.NewRepoClient()
|
||||
assert.NoError(t, err)
|
||||
defer argoio.Close(conn)
|
||||
|
||||
_, err = repoClient.UpdateRepository(context.Background(), &repositorypkg.RepoUpdateRequest{
|
||||
Repo: &v1alpha1.Repository{
|
||||
Repo: repoUrl,
|
||||
},
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
|
||||
// CLI output should indicate that repo has inherited credentials
|
||||
out, err := fixture.RunCli("repo", "get", repoUrl)
|
||||
assert.NoError(t, err)
|
||||
assert.Contains(t, out, "inherited")
|
||||
|
||||
_, err = fixture.RunCli("repo", "rm", repoUrl)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestUpsertExistingRepo(t *testing.T) {
|
||||
app.Given(t).And(func() {
|
||||
fixture.SetRepos(settings.RepositoryCredentials{URL: fixture.RepoURL(fixture.RepoURLTypeFile)})
|
||||
|
||||
2
test/e2e/testdata/cmp-fileName/plugin.yaml
vendored
2
test/e2e/testdata/cmp-fileName/plugin.yaml
vendored
@@ -7,4 +7,4 @@ spec:
|
||||
generate:
|
||||
command: [sh, -c, 'echo "{\"kind\": \"ConfigMap\", \"apiVersion\": \"v1\", \"metadata\": { \"name\": \"$ARGOCD_APP_NAME\", \"namespace\": \"$ARGOCD_APP_NAMESPACE\", \"annotations\": {\"Foo\": \"$FOO\", \"KubeVersion\": \"$KUBE_VERSION\", \"KubeApiVersion\": \"$KUBE_API_VERSIONS\",\"Bar\": \"baz\"}}}"']
|
||||
discover:
|
||||
fileName: "cmp-fileName/subdir/s*.yaml"
|
||||
fileName: "subdir/s*.yaml"
|
||||
|
||||
@@ -108,15 +108,24 @@ export const ApplicationCreatePanel = (props: {
|
||||
const [explicitPathType, setExplicitPathType] = React.useState<{path: string; type: models.AppSourceType}>(null);
|
||||
const [destFormat, setDestFormat] = React.useState('URL');
|
||||
const [retry, setRetry] = React.useState(false);
|
||||
const app = deepMerge(DEFAULT_APP, props.app || {});
|
||||
|
||||
React.useEffect(() => {
|
||||
if (app?.spec?.destination?.name && app.spec.destination.name !== '') {
|
||||
setDestFormat('NAME');
|
||||
} else {
|
||||
setDestFormat('URL');
|
||||
}
|
||||
}, []);
|
||||
|
||||
function normalizeTypeFields(formApi: FormApi, type: models.AppSourceType) {
|
||||
const app = formApi.getFormState().values;
|
||||
const appToNormalize = formApi.getFormState().values;
|
||||
for (const item of appTypes) {
|
||||
if (item.type !== type) {
|
||||
delete app.spec.source[item.field];
|
||||
delete appToNormalize.spec.source[item.field];
|
||||
}
|
||||
}
|
||||
formApi.setAllValues(app);
|
||||
formApi.setAllValues(appToNormalize);
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -132,7 +141,6 @@ export const ApplicationCreatePanel = (props: {
|
||||
}>
|
||||
{({projects, clusters, reposInfo}) => {
|
||||
const repos = reposInfo.map(info => info.repo).sort();
|
||||
const app = deepMerge(DEFAULT_APP, props.app || {});
|
||||
const repoInfo = reposInfo.find(info => info.repo === app.spec.source.repoURL);
|
||||
if (repoInfo) {
|
||||
normalizeAppSource(app, repoInfo.type || 'git');
|
||||
|
||||
@@ -319,7 +319,7 @@ export const ApplicationSummary = (props: ApplicationSummaryProps) => {
|
||||
{
|
||||
title: 'LINKS',
|
||||
view: (
|
||||
<DataLoader load={() => services.applications.getLinks(app.metadata.name)} input={app} key='appLinks'>
|
||||
<DataLoader load={() => services.applications.getLinks(app.metadata.name, app.metadata.namespace)} input={app} key='appLinks'>
|
||||
{(links: models.LinksResponse) => <DeepLinks links={links.items} />}
|
||||
</DataLoader>
|
||||
)
|
||||
|
||||
@@ -72,7 +72,13 @@ export const PodTerminalViewer: React.FC<PodTerminalViewerProps> = ({
|
||||
|
||||
const onConnectionMessage = (e: MessageEvent) => {
|
||||
const msg = JSON.parse(e.data);
|
||||
connSubject.next(msg);
|
||||
if (!msg?.Code) {
|
||||
connSubject.next(msg);
|
||||
} else {
|
||||
// Do reconnect due to refresh token event
|
||||
onConnectionClose();
|
||||
setupConnection();
|
||||
}
|
||||
};
|
||||
|
||||
const onConnectionOpen = () => {
|
||||
|
||||
@@ -35,7 +35,7 @@ test('gitlab.com', () => {
|
||||
'git@gitlab.com:alex_collins/private-repo.git',
|
||||
'b1fe9426ead684d7af16958920968342ee295c1f',
|
||||
'https://gitlab.com/alex_collins/private-repo',
|
||||
'https://gitlab.com/alex_collins/private-repo/commit/b1fe9426ead684d7af16958920968342ee295c1f');
|
||||
'https://gitlab.com/alex_collins/private-repo/-/commit/b1fe9426ead684d7af16958920968342ee295c1f');
|
||||
});
|
||||
|
||||
test('bitbucket.org', () => {
|
||||
|
||||
@@ -39,6 +39,12 @@ export function revisionUrl(url: string, revision: string, forPath: boolean): st
|
||||
urlSubPath = isSHA(revision) && !forPath ? 'commits' : 'src';
|
||||
}
|
||||
|
||||
// Gitlab changed the way urls to commit look like
|
||||
// Ref: https://docs.gitlab.com/ee/update/deprecations.html#legacy-urls-replaced-or-removed
|
||||
if (parsed.source === 'gitlab.com') {
|
||||
urlSubPath = '-/' + urlSubPath;
|
||||
}
|
||||
|
||||
if (!supportedSource(parsed)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ export class VersionPanel extends React.Component<VersionPanelProps, {copyState:
|
||||
}
|
||||
|
||||
private async onCopy(version: VersionMessage): Promise<void> {
|
||||
const stringifiedVersion = JSON.stringify(version, undefined, 4);
|
||||
const stringifiedVersion = JSON.stringify(version, undefined, 4) + '\n';
|
||||
try {
|
||||
await navigator.clipboard.writeText(stringifiedVersion);
|
||||
this.setState({copyState: 'success'});
|
||||
|
||||
@@ -101,13 +101,14 @@ export class ApplicationsService {
|
||||
public getManifest(name: string, appNamespace: string, revision: string): Promise<models.ManifestResponse> {
|
||||
return requests
|
||||
.get(`/applications/${name}/manifests`)
|
||||
.query({name, revision})
|
||||
.query({name, revision, appNamespace})
|
||||
.then(res => res.body as models.ManifestResponse);
|
||||
}
|
||||
|
||||
public updateSpec(appName: string, appNamespace: string, spec: models.ApplicationSpec): Promise<models.ApplicationSpec> {
|
||||
return requests
|
||||
.put(`/applications/${appName}/spec`)
|
||||
.query({appNamespace})
|
||||
.send(spec)
|
||||
.then(res => res.body as models.ApplicationSpec);
|
||||
}
|
||||
@@ -322,11 +323,12 @@ export class ApplicationsService {
|
||||
.then(res => (res.body.actions as models.ResourceAction[]) || []);
|
||||
}
|
||||
|
||||
public patchResource(name: string, appNamspace: string, resource: models.ResourceNode, patch: string, patchType: string): Promise<models.State> {
|
||||
public patchResource(name: string, appNamespace: string, resource: models.ResourceNode, patch: string, patchType: string): Promise<models.State> {
|
||||
return requests
|
||||
.post(`/applications/${name}/resource`)
|
||||
.query({
|
||||
name: resource.name,
|
||||
appNamespace,
|
||||
namespace: resource.namespace,
|
||||
resourceName: resource.name,
|
||||
version: resource.version,
|
||||
@@ -394,9 +396,10 @@ export class ApplicationsService {
|
||||
.then(() => true);
|
||||
}
|
||||
|
||||
public getLinks(applicationName: string): Promise<models.LinksResponse> {
|
||||
public getLinks(applicationName: string, namespace: string): Promise<models.LinksResponse> {
|
||||
return requests
|
||||
.get(`/applications/${applicationName}/links`)
|
||||
.query({namespace})
|
||||
.send()
|
||||
.then(res => res.body as models.LinksResponse);
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ func DetectConfigManagementPlugin(ctx context.Context, appPath, repoPath, plugin
|
||||
pluginSockFilePath := common.GetPluginSockFilePath()
|
||||
log.WithFields(log.Fields{
|
||||
common.SecurityField: common.SecurityLow,
|
||||
common.SecurityCWEField: 775,
|
||||
common.SecurityCWEField: common.SecurityCWEMissingReleaseOfFileDescriptor,
|
||||
}).Debugf("pluginSockFilePath is: %s", pluginSockFilePath)
|
||||
|
||||
if pluginName != "" {
|
||||
@@ -155,7 +155,7 @@ func cmpSupports(ctx context.Context, pluginSockFilePath, appPath, repoPath, fil
|
||||
if err != nil {
|
||||
log.WithFields(log.Fields{
|
||||
common.SecurityField: common.SecurityMedium,
|
||||
common.SecurityCWEField: 775,
|
||||
common.SecurityCWEField: common.SecurityCWEMissingReleaseOfFileDescriptor,
|
||||
}).Errorf("error dialing to cmp-server for plugin %s, %v", fileName, err)
|
||||
return nil, nil, false
|
||||
}
|
||||
@@ -164,7 +164,7 @@ func cmpSupports(ctx context.Context, pluginSockFilePath, appPath, repoPath, fil
|
||||
if err != nil {
|
||||
log.WithFields(log.Fields{
|
||||
common.SecurityField: common.SecurityMedium,
|
||||
common.SecurityCWEField: 775,
|
||||
common.SecurityCWEField: common.SecurityCWEMissingReleaseOfFileDescriptor,
|
||||
}).Errorf("repository %s is not the match because %v", repoPath, err)
|
||||
io.Close(conn)
|
||||
return nil, nil, false
|
||||
@@ -177,7 +177,7 @@ func cmpSupports(ctx context.Context, pluginSockFilePath, appPath, repoPath, fil
|
||||
}
|
||||
log.WithFields(log.Fields{
|
||||
common.SecurityField: common.SecurityLow,
|
||||
common.SecurityCWEField: 775,
|
||||
common.SecurityCWEField: common.SecurityCWEMissingReleaseOfFileDescriptor,
|
||||
}).Debugf("Reponse from socket file %s does not support %v", fileName, repoPath)
|
||||
io.Close(conn)
|
||||
return nil, nil, false
|
||||
|
||||
@@ -135,7 +135,7 @@ func ParseTLSCertificatesFromPath(sourceFile string) ([]string, error) {
|
||||
if err = fileHandle.Close(); err != nil {
|
||||
log.WithFields(log.Fields{
|
||||
common.SecurityField: common.SecurityMedium,
|
||||
common.SecurityCWEField: 775,
|
||||
common.SecurityCWEField: common.SecurityCWEMissingReleaseOfFileDescriptor,
|
||||
}).Errorf("error closing file %q: %v", fileHandle.Name(), err)
|
||||
}
|
||||
}()
|
||||
@@ -199,7 +199,7 @@ func ParseSSHKnownHostsFromPath(sourceFile string) ([]string, error) {
|
||||
if err = fileHandle.Close(); err != nil {
|
||||
log.WithFields(log.Fields{
|
||||
common.SecurityField: common.SecurityMedium,
|
||||
common.SecurityCWEField: 775,
|
||||
common.SecurityCWEField: common.SecurityCWEMissingReleaseOfFileDescriptor,
|
||||
}).Errorf("error closing file %q: %v", fileHandle.Name(), err)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -176,7 +176,7 @@ XWyb96wrUlv+E8I=
|
||||
// Taken from hack/ssh_known_hosts
|
||||
const Test_ValidSSHKnownHostsData = `
|
||||
# BitBucket
|
||||
bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kNvEcqTKl/VqLat/MaB33pZy0y3rJZtnqwR2qOOvbwKZYKiEO1O6VqNEBxKvJJelCq0dTXWT5pbO2gDXC6h6QDXCaHo6pOHGPUy+YBaGQRGuSusMEASYiWunYN0vCAI8QaXnWMXNMdFP3jHAJH0eDsoiGnLPBlBp4TNm6rYI74nMzgz3B9IikW4WVK+dc8KZJZWYjAuORU3jc1c/NPskD2ASinf8v3xnfXeukU0sJ5N6m5E8VLjObPEO+mN2t/FZTMZLiFqPWc/ALSqnMnnhwrNi2rbfg/rd/IpL8Le3pSBne8+seeFVBoGqzHM9yXw==
|
||||
bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDQeJzhupRu0u0cdegZIa8e86EG2qOCsIsD1Xw0xSeiPDlCr7kq97NLmMbpKTX6Esc30NuoqEEHCuc7yWtwp8dI76EEEB1VqY9QJq6vk+aySyboD5QF61I/1WeTwu+deCbgKMGbUijeXhtfbxSxm6JwGrXrhBdofTsbKRUsrN1WoNgUa8uqN1Vx6WAJw1JHPhglEGGHea6QICwJOAr/6mrui/oB7pkaWKHj3z7d1IC4KWLtY47elvjbaTlkN04Kc/5LFEirorGYVbt15kAUlqGM65pk6ZBxtaO3+30LVlORZkxOh+LKL/BvbZ/iRNhItLqNyieoQj/uh/7Iv4uyH/cV/0b4WDSd3DptigWq84lJubb9t/DnZlrJazxyDCulTmKdOR7vs9gMTo+uoIrPSb8ScTtvw65+odKAlBj59dhnVp9zd7QUojOpXlL62Aw56U4oO+FALuevvMjiWeavKhJqlR7i5n9srYcrNV7ttmDw7kf/97P5zauIhxcjX+xHv4M=
|
||||
# GitHub
|
||||
github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==
|
||||
# GitLab
|
||||
@@ -189,7 +189,7 @@ vs-ssh.visualstudio.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOf
|
||||
`
|
||||
|
||||
const Test_InvalidSSHKnownHostsData = `
|
||||
bitbucket.org AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kNvEcqTKl/VqLat/MaB33pZy0y3rJZtnqwR2qOOvbwKZYKiEO1O6VqNEBxKvJJelCq0dTXWT5pbO2gDXC6h6QDXCaHo6pOHGPUy+YBaGQRGuSusMEASYiWunYN0vCAI8QaXnWMXNMdFP3jHAJH0eDsoiGnLPBlBp4TNm6rYI74nMzgz3B9IikW4WVK+dc8KZJZWYjAuORU3jc1c/NPskD2ASinf8v3xnfXeukU0sJ5N6m5E8VLjObPEO+mN2t/FZTMZLiFqPWc/ALSqnMnnhwrNi2rbfg/rd/IpL8Le3pSBne8+seeFVBoGqzHM9yXw==
|
||||
bitbucket.org AAAAB3NzaC1yc2EAAAADAQABAAABgQDQeJzhupRu0u0cdegZIa8e86EG2qOCsIsD1Xw0xSeiPDlCr7kq97NLmMbpKTX6Esc30NuoqEEHCuc7yWtwp8dI76EEEB1VqY9QJq6vk+aySyboD5QF61I/1WeTwu+deCbgKMGbUijeXhtfbxSxm6JwGrXrhBdofTsbKRUsrN1WoNgUa8uqN1Vx6WAJw1JHPhglEGGHea6QICwJOAr/6mrui/oB7pkaWKHj3z7d1IC4KWLtY47elvjbaTlkN04Kc/5LFEirorGYVbt15kAUlqGM65pk6ZBxtaO3+30LVlORZkxOh+LKL/BvbZ/iRNhItLqNyieoQj/uh/7Iv4uyH/cV/0b4WDSd3DptigWq84lJubb9t/DnZlrJazxyDCulTmKdOR7vs9gMTo+uoIrPSb8ScTtvw65+odKAlBj59dhnVp9zd7QUojOpXlL62Aw56U4oO+FALuevvMjiWeavKhJqlR7i5n9srYcrNV7ttmDw7kf/97P5zauIhxcjX+xHv4M=
|
||||
# GitHub
|
||||
github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==
|
||||
# GitLab
|
||||
@@ -322,7 +322,7 @@ func Test_MatchHostName(t *testing.T) {
|
||||
func Test_SSHFingerprintSHA256(t *testing.T) {
|
||||
// actual SHA256 fingerprints for keys defined above
|
||||
fingerprints := [...]string{
|
||||
"zzXQOXSRBEiUtuE8AikJYKwbHaxvSc0ojez9YXaGp1A",
|
||||
"46OSHA1Rmj8E8ERTC6xkNcmGOw9oFxYr0WF6zWW8l1E",
|
||||
"nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8",
|
||||
"HbW3g8zUjNSksFbqTiUWPWg2Bq1x8xdGUrliXFzSnUw",
|
||||
"eUXGGm1YGsMAS7vkcx6JOJdOGHPem5gQp4taiCfCLB8",
|
||||
@@ -344,7 +344,7 @@ func Test_SSHFingerprintSHA256(t *testing.T) {
|
||||
func Test_SSHFingerPrintSHA256FromString(t *testing.T) {
|
||||
// actual SHA256 fingerprints for keys defined above
|
||||
fingerprints := [...]string{
|
||||
"zzXQOXSRBEiUtuE8AikJYKwbHaxvSc0ojez9YXaGp1A",
|
||||
"46OSHA1Rmj8E8ERTC6xkNcmGOw9oFxYr0WF6zWW8l1E",
|
||||
"nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8",
|
||||
"HbW3g8zUjNSksFbqTiUWPWg2Bq1x8xdGUrliXFzSnUw",
|
||||
"eUXGGm1YGsMAS7vkcx6JOJdOGHPem5gQp4taiCfCLB8",
|
||||
|
||||
@@ -185,7 +185,7 @@ XWyb96wrUlv+E8I=
|
||||
// Taken from hack/ssh_known_hosts
|
||||
const Test_ValidSSHKnownHostsData = `
|
||||
# BitBucket
|
||||
bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kNvEcqTKl/VqLat/MaB33pZy0y3rJZtnqwR2qOOvbwKZYKiEO1O6VqNEBxKvJJelCq0dTXWT5pbO2gDXC6h6QDXCaHo6pOHGPUy+YBaGQRGuSusMEASYiWunYN0vCAI8QaXnWMXNMdFP3jHAJH0eDsoiGnLPBlBp4TNm6rYI74nMzgz3B9IikW4WVK+dc8KZJZWYjAuORU3jc1c/NPskD2ASinf8v3xnfXeukU0sJ5N6m5E8VLjObPEO+mN2t/FZTMZLiFqPWc/ALSqnMnnhwrNi2rbfg/rd/IpL8Le3pSBne8+seeFVBoGqzHM9yXw==
|
||||
bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDQeJzhupRu0u0cdegZIa8e86EG2qOCsIsD1Xw0xSeiPDlCr7kq97NLmMbpKTX6Esc30NuoqEEHCuc7yWtwp8dI76EEEB1VqY9QJq6vk+aySyboD5QF61I/1WeTwu+deCbgKMGbUijeXhtfbxSxm6JwGrXrhBdofTsbKRUsrN1WoNgUa8uqN1Vx6WAJw1JHPhglEGGHea6QICwJOAr/6mrui/oB7pkaWKHj3z7d1IC4KWLtY47elvjbaTlkN04Kc/5LFEirorGYVbt15kAUlqGM65pk6ZBxtaO3+30LVlORZkxOh+LKL/BvbZ/iRNhItLqNyieoQj/uh/7Iv4uyH/cV/0b4WDSd3DptigWq84lJubb9t/DnZlrJazxyDCulTmKdOR7vs9gMTo+uoIrPSb8ScTtvw65+odKAlBj59dhnVp9zd7QUojOpXlL62Aw56U4oO+FALuevvMjiWeavKhJqlR7i5n9srYcrNV7ttmDw7kf/97P5zauIhxcjX+xHv4M=
|
||||
# GitHub
|
||||
github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==
|
||||
# GitLab
|
||||
@@ -198,7 +198,7 @@ vs-ssh.visualstudio.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC7Hr1oTWqNqOlzGJOf
|
||||
`
|
||||
|
||||
const Test_InvalidSSHKnownHostsData = `
|
||||
bitbucket.org AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kNvEcqTKl/VqLat/MaB33pZy0y3rJZtnqwR2qOOvbwKZYKiEO1O6VqNEBxKvJJelCq0dTXWT5pbO2gDXC6h6QDXCaHo6pOHGPUy+YBaGQRGuSusMEASYiWunYN0vCAI8QaXnWMXNMdFP3jHAJH0eDsoiGnLPBlBp4TNm6rYI74nMzgz3B9IikW4WVK+dc8KZJZWYjAuORU3jc1c/NPskD2ASinf8v3xnfXeukU0sJ5N6m5E8VLjObPEO+mN2t/FZTMZLiFqPWc/ALSqnMnnhwrNi2rbfg/rd/IpL8Le3pSBne8+seeFVBoGqzHM9yXw==
|
||||
bitbucket.org AAAAB3NzaC1yc2EAAAADAQABAAABgQDQeJzhupRu0u0cdegZIa8e86EG2qOCsIsD1Xw0xSeiPDlCr7kq97NLmMbpKTX6Esc30NuoqEEHCuc7yWtwp8dI76EEEB1VqY9QJq6vk+aySyboD5QF61I/1WeTwu+deCbgKMGbUijeXhtfbxSxm6JwGrXrhBdofTsbKRUsrN1WoNgUa8uqN1Vx6WAJw1JHPhglEGGHea6QICwJOAr/6mrui/oB7pkaWKHj3z7d1IC4KWLtY47elvjbaTlkN04Kc/5LFEirorGYVbt15kAUlqGM65pk6ZBxtaO3+30LVlORZkxOh+LKL/BvbZ/iRNhItLqNyieoQj/uh/7Iv4uyH/cV/0b4WDSd3DptigWq84lJubb9t/DnZlrJazxyDCulTmKdOR7vs9gMTo+uoIrPSb8ScTtvw65+odKAlBj59dhnVp9zd7QUojOpXlL62Aw56U4oO+FALuevvMjiWeavKhJqlR7i5n9srYcrNV7ttmDw7kf/97P5zauIhxcjX+xHv4M=
|
||||
# GitHub
|
||||
github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==
|
||||
# GitLab
|
||||
|
||||
@@ -68,7 +68,7 @@ func (db *db) ListClusters(ctx context.Context) (*appv1.ClusterList, error) {
|
||||
inClusterEnabled := settings.InClusterEnabled
|
||||
hasInClusterCredentials := false
|
||||
for _, clusterSecret := range clusterSecrets {
|
||||
cluster, err := secretToCluster(clusterSecret)
|
||||
cluster, err := SecretToCluster(clusterSecret)
|
||||
if err != nil {
|
||||
log.Errorf("could not unmarshal cluster secret %s", clusterSecret.Name)
|
||||
continue
|
||||
@@ -77,8 +77,6 @@ func (db *db) ListClusters(ctx context.Context) (*appv1.ClusterList, error) {
|
||||
if inClusterEnabled {
|
||||
hasInClusterCredentials = true
|
||||
clusterList.Items = append(clusterList.Items, *cluster)
|
||||
} else {
|
||||
log.Errorf("failed to add cluster %q to cluster list: in-cluster server address is disabled in Argo CD settings", cluster.Name)
|
||||
}
|
||||
} else {
|
||||
clusterList.Items = append(clusterList.Items, *cluster)
|
||||
@@ -122,7 +120,7 @@ func (db *db) CreateCluster(ctx context.Context, c *appv1.Cluster) (*appv1.Clust
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cluster, err := secretToCluster(clusterSecret)
|
||||
cluster, err := SecretToCluster(clusterSecret)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "could not unmarshal cluster secret %s", clusterSecret.Name)
|
||||
}
|
||||
@@ -150,7 +148,7 @@ func (db *db) WatchClusters(ctx context.Context,
|
||||
common.LabelValueSecretTypeCluster,
|
||||
|
||||
func(secret *apiv1.Secret) {
|
||||
cluster, err := secretToCluster(secret)
|
||||
cluster, err := SecretToCluster(secret)
|
||||
if err != nil {
|
||||
log.Errorf("could not unmarshal cluster secret %s", secret.Name)
|
||||
return
|
||||
@@ -165,12 +163,12 @@ func (db *db) WatchClusters(ctx context.Context,
|
||||
},
|
||||
|
||||
func(oldSecret *apiv1.Secret, newSecret *apiv1.Secret) {
|
||||
oldCluster, err := secretToCluster(oldSecret)
|
||||
oldCluster, err := SecretToCluster(oldSecret)
|
||||
if err != nil {
|
||||
log.Errorf("could not unmarshal cluster secret %s", oldSecret.Name)
|
||||
return
|
||||
}
|
||||
newCluster, err := secretToCluster(newSecret)
|
||||
newCluster, err := SecretToCluster(newSecret)
|
||||
if err != nil {
|
||||
log.Errorf("could not unmarshal cluster secret %s", newSecret.Name)
|
||||
return
|
||||
@@ -220,7 +218,7 @@ func (db *db) GetCluster(_ context.Context, server string) (*appv1.Cluster, erro
|
||||
return nil, err
|
||||
}
|
||||
if len(res) > 0 {
|
||||
return secretToCluster(res[0].(*apiv1.Secret))
|
||||
return SecretToCluster(res[0].(*apiv1.Secret))
|
||||
}
|
||||
if server == appv1.KubernetesInternalAPIServerAddr {
|
||||
return db.getLocalCluster(), nil
|
||||
@@ -241,7 +239,7 @@ func (db *db) GetProjectClusters(ctx context.Context, project string) ([]*appv1.
|
||||
}
|
||||
var res []*appv1.Cluster
|
||||
for i := range secrets {
|
||||
cluster, err := secretToCluster(secrets[i].(*apiv1.Secret))
|
||||
cluster, err := SecretToCluster(secrets[i].(*apiv1.Secret))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -295,7 +293,7 @@ func (db *db) UpdateCluster(ctx context.Context, c *appv1.Cluster) (*appv1.Clust
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cluster, err := secretToCluster(clusterSecret)
|
||||
cluster, err := SecretToCluster(clusterSecret)
|
||||
if err != nil {
|
||||
log.Errorf("could not unmarshal cluster secret %s", clusterSecret.Name)
|
||||
return nil, err
|
||||
@@ -362,8 +360,8 @@ func clusterToSecret(c *appv1.Cluster, secret *apiv1.Secret) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// secretToCluster converts a secret into a Cluster object
|
||||
func secretToCluster(s *apiv1.Secret) (*appv1.Cluster, error) {
|
||||
// SecretToCluster converts a secret into a Cluster object
|
||||
func SecretToCluster(s *apiv1.Secret) (*appv1.Cluster, error) {
|
||||
var config appv1.ClusterConfig
|
||||
if len(s.Data["config"]) > 0 {
|
||||
err := json.Unmarshal(s.Data["config"], &config)
|
||||
|
||||
@@ -43,7 +43,7 @@ func Test_secretToCluster(t *testing.T) {
|
||||
"config": []byte("{\"username\":\"foo\"}"),
|
||||
},
|
||||
}
|
||||
cluster, err := secretToCluster(secret)
|
||||
cluster, err := SecretToCluster(secret)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, *cluster, v1alpha1.Cluster{
|
||||
Name: "test",
|
||||
@@ -89,7 +89,7 @@ func Test_secretToCluster_NoConfig(t *testing.T) {
|
||||
"server": []byte("http://mycluster"),
|
||||
},
|
||||
}
|
||||
cluster, err := secretToCluster(secret)
|
||||
cluster, err := SecretToCluster(secret)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, *cluster, v1alpha1.Cluster{
|
||||
Name: "test",
|
||||
@@ -111,7 +111,7 @@ func Test_secretToCluster_InvalidConfig(t *testing.T) {
|
||||
"config": []byte("{'tlsClientConfig':{'insecure':false}}"),
|
||||
},
|
||||
}
|
||||
cluster, err := secretToCluster(secret)
|
||||
cluster, err := SecretToCluster(secret)
|
||||
require.Error(t, err)
|
||||
assert.Nil(t, cluster)
|
||||
}
|
||||
|
||||
@@ -151,7 +151,7 @@ func replaceListSecrets(obj []interface{}, secretValues map[string]string) []int
|
||||
// https://dexidp.io/docs/connectors/
|
||||
func needsRedirectURI(connectorType string) bool {
|
||||
switch connectorType {
|
||||
case "oidc", "saml", "microsoft", "linkedin", "gitlab", "github", "bitbucket-cloud", "openshift":
|
||||
case "oidc", "saml", "microsoft", "linkedin", "gitlab", "github", "bitbucket-cloud", "openshift", "gitea", "google", "oauth":
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user