mirror of
https://github.com/argoproj/argo-cd.git
synced 2026-03-06 00:18:48 +01:00
Compare commits
70 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
19ec34e134 | ||
|
|
5f74aa5c24 | ||
|
|
b350c11935 | ||
|
|
c271f1a6c1 | ||
|
|
e6bd9469f8 | ||
|
|
2bb180b3d9 | ||
|
|
216b10e6d8 | ||
|
|
fc8f57a0b5 | ||
|
|
56c2e3c81d | ||
|
|
83931b8515 | ||
|
|
712df99420 | ||
|
|
41f54aa556 | ||
|
|
540fe1b762 | ||
|
|
66ebec630a | ||
|
|
a6b5aa2766 | ||
|
|
1ac264e9a1 | ||
|
|
128a261513 | ||
|
|
8552cc3f07 | ||
|
|
cb05b8fb4a | ||
|
|
2ca18ab5fe | ||
|
|
e8d2d3a7e0 | ||
|
|
6d348ce4a1 | ||
|
|
3c2683dfe9 | ||
|
|
8aa4df6f17 | ||
|
|
7db5c5c589 | ||
|
|
3d9e9f2f95 | ||
|
|
ca7d83f645 | ||
|
|
e59f4889a4 | ||
|
|
fea6197af4 | ||
|
|
5b576acf5d | ||
|
|
2ccc17afcb | ||
|
|
e7521ed7b8 | ||
|
|
f83bed0d4b | ||
|
|
88274b6870 | ||
|
|
431ee12282 | ||
|
|
3b17121d44 | ||
|
|
f071b29b5f | ||
|
|
5ed749e827 | ||
|
|
1ba9008536 | ||
|
|
2b873f0b3a | ||
|
|
3fdb6ae960 | ||
|
|
d40ebce7b3 | ||
|
|
d945e9f256 | ||
|
|
fb75ada4c2 | ||
|
|
05c9ba27e3 | ||
|
|
77c972d27e | ||
|
|
7e0ee5c449 | ||
|
|
164284e329 | ||
|
|
ac2c1618b2 | ||
|
|
4ee796604a | ||
|
|
118d4d3c58 | ||
|
|
912fe33009 | ||
|
|
844f79eb9d | ||
|
|
ecfa0da491 | ||
|
|
fac8466e86 | ||
|
|
ac34ff23c4 | ||
|
|
a85d88d479 | ||
|
|
40075da70c | ||
|
|
779e383f64 | ||
|
|
3e523dbab7 | ||
|
|
4df892fecf | ||
|
|
670a1756d7 | ||
|
|
5721f559f0 | ||
|
|
e23178a8d1 | ||
|
|
918e5eadf4 | ||
|
|
55de2b9dab | ||
|
|
c48004f944 | ||
|
|
f7b6a38041 | ||
|
|
91eb9925ef | ||
|
|
6190964899 |
4
.github/workflows/ci-build.yaml
vendored
4
.github/workflows/ci-build.yaml
vendored
@@ -405,9 +405,9 @@ jobs:
|
||||
git config --global user.email "john.doe@example.com"
|
||||
- name: Pull Docker image required for tests
|
||||
run: |
|
||||
docker pull quay.io/dexidp/dex:v2.25.0
|
||||
docker pull ghcr.io/dexidp/dex:v2.35.0-distroless
|
||||
docker pull argoproj/argo-cd-ci-builder:v1.0.0
|
||||
docker pull redis:7.0.0-alpine
|
||||
docker pull redis:7.0.4-alpine
|
||||
- name: Create target directory for binaries in the build-process
|
||||
run: |
|
||||
mkdir -p dist
|
||||
|
||||
@@ -13,9 +13,13 @@ commands, and helps to troubleshoot the application state.
|
||||
Argo CD is used to manage the critical infrastructure of multiple organizations, which makes security the top priority of the project. We've listened to
|
||||
your feedback and introduced additional access control settings that control access to Kubernetes Pod logs and the new Web Terminal feature.
|
||||
|
||||
#### Known UI Issue for Pod Logs Access
|
||||
#### Pod Logs UI
|
||||
|
||||
Currently, upon pressing the "LOGS" tab in pod view by users who don't have an explicit allow get logs policy, the red "unable to load data: Internal error" is received in the bottom of the screen, and "Failed to load data, please try again" is displayed.
|
||||
Since 2.4.9, the LOGS tab in pod view is visible in the UI only for users with explicit allow get logs policy.
|
||||
|
||||
#### Known pod logs UI issue prior to 2.4.9
|
||||
|
||||
Upon pressing the "LOGS" tab in pod view by users who don't have an explicit allow get logs policy, the red "unable to load data: Internal error" is received in the bottom of the screen, and "Failed to load data, please try again" is displayed.
|
||||
|
||||
### OpenTelemetry Tracing Integration
|
||||
|
||||
|
||||
@@ -92,12 +92,13 @@ COPY ["ui/", "."]
|
||||
|
||||
ARG ARGO_VERSION=latest
|
||||
ENV ARGO_VERSION=$ARGO_VERSION
|
||||
RUN HOST_ARCH='amd64' NODE_ENV='production' NODE_ONLINE_ENV='online' NODE_OPTIONS=--max_old_space_size=8192 yarn build
|
||||
ARG TARGETARCH
|
||||
RUN HOST_ARCH=$TARGETARCH NODE_ENV='production' NODE_ONLINE_ENV='online' NODE_OPTIONS=--max_old_space_size=8192 yarn build
|
||||
|
||||
####################################################################################################
|
||||
# Argo CD Build stage which performs the actual build of Argo CD binaries
|
||||
####################################################################################################
|
||||
FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.18 AS argocd-build
|
||||
FROM --platform=$BUILDPLATFORM docker.io/library/golang:1.18 AS argocd-build
|
||||
|
||||
WORKDIR /go/src/github.com/argoproj/argo-cd
|
||||
|
||||
|
||||
@@ -20,11 +20,16 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
log "github.com/sirupsen/logrus"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
apierr "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/tools/record"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||
"sigs.k8s.io/controller-runtime/pkg/handler"
|
||||
"sigs.k8s.io/controller-runtime/pkg/source"
|
||||
@@ -33,18 +38,10 @@ import (
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/utils"
|
||||
"github.com/argoproj/argo-cd/v2/common"
|
||||
argov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/v2/util/db"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/applicationset/v1alpha1"
|
||||
appclientset "github.com/argoproj/argo-cd/v2/pkg/client/clientset/versioned"
|
||||
argoutil "github.com/argoproj/argo-cd/v2/util/argo"
|
||||
|
||||
apierr "k8s.io/apimachinery/pkg/api/errors"
|
||||
"github.com/argoproj/argo-cd/v2/util/db"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -55,6 +52,13 @@ const (
|
||||
ReconcileRequeueOnValidationError = time.Minute * 3
|
||||
)
|
||||
|
||||
var (
|
||||
preservedAnnotations = []string{
|
||||
NotifiedAnnotationKey,
|
||||
argov1alpha1.AnnotationKeyRefresh,
|
||||
}
|
||||
)
|
||||
|
||||
// ApplicationSetReconciler reconciles a ApplicationSet object
|
||||
type ApplicationSetReconciler struct {
|
||||
client.Client
|
||||
@@ -527,12 +531,16 @@ func (r *ApplicationSetReconciler) createOrUpdateInCluster(ctx context.Context,
|
||||
// Copy only the Application/ObjectMeta fields that are significant, from the generatedApp
|
||||
found.Spec = generatedApp.Spec
|
||||
|
||||
// Preserve argo cd notifications state (https://github.com/argoproj/applicationset/issues/180)
|
||||
if state, exists := found.ObjectMeta.Annotations[NotifiedAnnotationKey]; exists {
|
||||
if generatedApp.Annotations == nil {
|
||||
generatedApp.Annotations = map[string]string{}
|
||||
// Preserve specially treated argo cd annotations:
|
||||
// * https://github.com/argoproj/applicationset/issues/180
|
||||
// * https://github.com/argoproj/argo-cd/issues/10500
|
||||
for _, key := range preservedAnnotations {
|
||||
if state, exists := found.ObjectMeta.Annotations[key]; exists {
|
||||
if generatedApp.Annotations == nil {
|
||||
generatedApp.Annotations = map[string]string{}
|
||||
}
|
||||
generatedApp.Annotations[key] = state
|
||||
}
|
||||
generatedApp.Annotations[NotifiedAnnotationKey] = state
|
||||
}
|
||||
found.ObjectMeta.Annotations = generatedApp.Annotations
|
||||
|
||||
|
||||
@@ -13,9 +13,11 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
kubefake "k8s.io/client-go/kubernetes/fake"
|
||||
"k8s.io/client-go/tools/record"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
crtclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
@@ -25,10 +27,6 @@ import (
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/generators"
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/utils"
|
||||
argov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
|
||||
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
kubefake "k8s.io/client-go/kubernetes/fake"
|
||||
|
||||
"github.com/argoproj/argo-cd/v2/pkg/apis/applicationset/v1alpha1"
|
||||
argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/applicationset/v1alpha1"
|
||||
appclientset "github.com/argoproj/argo-cd/v2/pkg/client/clientset/versioned/fake"
|
||||
@@ -755,7 +753,7 @@ func TestCreateOrUpdateInCluster(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Ensure that argocd notifications state annotation is preserved from an existing app",
|
||||
name: "Ensure that argocd notifications state and refresh annotation is preserved from an existing app",
|
||||
appSet: argoprojiov1alpha1.ApplicationSet{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "name",
|
||||
@@ -781,8 +779,9 @@ func TestCreateOrUpdateInCluster(t *testing.T) {
|
||||
ResourceVersion: "2",
|
||||
Labels: map[string]string{"label-key": "label-value"},
|
||||
Annotations: map[string]string{
|
||||
"annot-key": "annot-value",
|
||||
NotifiedAnnotationKey: `{"b620d4600c771a6f4cxxxxxxx:on-deployed:[0].y7b5sbwa2Q329JYHxxxxxx-fBs:slack:slack-test":1617144614}`,
|
||||
"annot-key": "annot-value",
|
||||
NotifiedAnnotationKey: `{"b620d4600c771a6f4cxxxxxxx:on-deployed:[0].y7b5sbwa2Q329JYHxxxxxx-fBs:slack:slack-test":1617144614}`,
|
||||
argov1alpha1.AnnotationKeyRefresh: string(argov1alpha1.RefreshTypeNormal),
|
||||
},
|
||||
},
|
||||
Spec: argov1alpha1.ApplicationSpec{
|
||||
@@ -811,7 +810,8 @@ func TestCreateOrUpdateInCluster(t *testing.T) {
|
||||
Namespace: "namespace",
|
||||
ResourceVersion: "3",
|
||||
Annotations: map[string]string{
|
||||
NotifiedAnnotationKey: `{"b620d4600c771a6f4cxxxxxxx:on-deployed:[0].y7b5sbwa2Q329JYHxxxxxx-fBs:slack:slack-test":1617144614}`,
|
||||
NotifiedAnnotationKey: `{"b620d4600c771a6f4cxxxxxxx:on-deployed:[0].y7b5sbwa2Q329JYHxxxxxx-fBs:slack:slack-test":1617144614}`,
|
||||
argov1alpha1.AnnotationKeyRefresh: string(argov1alpha1.RefreshTypeNormal),
|
||||
},
|
||||
},
|
||||
Spec: argov1alpha1.ApplicationSpec{
|
||||
|
||||
@@ -2,13 +2,253 @@ package pull_request
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func giteaMockHandler(t *testing.T) func(http.ResponseWriter, *http.Request) {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
fmt.Println(r.RequestURI)
|
||||
switch r.RequestURI {
|
||||
case "/api/v1/version":
|
||||
_, err := io.WriteString(w, `{"version":"1.17.0+dev-452-g1f0541780"}`)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
case "/api/v1/repos/test-argocd/pr-test/pulls?limit=0&page=1&state=open":
|
||||
_, err := io.WriteString(w, `[{
|
||||
"id": 50721,
|
||||
"url": "https://gitea.com/test-argocd/pr-test/pulls/1",
|
||||
"number": 1,
|
||||
"user": {
|
||||
"id": 4476,
|
||||
"login": "graytshirt",
|
||||
"full_name": "Dan",
|
||||
"email": "graytshirt@noreply.gitea.io",
|
||||
"avatar_url": "https://secure.gravatar.com/avatar/2446c67bcd59d71f6ae3cf376ec2ae37?d=identicon",
|
||||
"language": "",
|
||||
"is_admin": false,
|
||||
"last_login": "0001-01-01T00:00:00Z",
|
||||
"created": "2020-04-07T01:14:36+08:00",
|
||||
"restricted": false,
|
||||
"active": false,
|
||||
"prohibit_login": false,
|
||||
"location": "",
|
||||
"website": "",
|
||||
"description": "",
|
||||
"visibility": "public",
|
||||
"followers_count": 0,
|
||||
"following_count": 4,
|
||||
"starred_repos_count": 1,
|
||||
"username": "graytshirt"
|
||||
},
|
||||
"title": "add an empty file",
|
||||
"body": "",
|
||||
"labels": [],
|
||||
"milestone": null,
|
||||
"assignee": null,
|
||||
"assignees": null,
|
||||
"state": "open",
|
||||
"is_locked": false,
|
||||
"comments": 0,
|
||||
"html_url": "https://gitea.com/test-argocd/pr-test/pulls/1",
|
||||
"diff_url": "https://gitea.com/test-argocd/pr-test/pulls/1.diff",
|
||||
"patch_url": "https://gitea.com/test-argocd/pr-test/pulls/1.patch",
|
||||
"mergeable": true,
|
||||
"merged": false,
|
||||
"merged_at": null,
|
||||
"merge_commit_sha": null,
|
||||
"merged_by": null,
|
||||
"base": {
|
||||
"label": "main",
|
||||
"ref": "main",
|
||||
"sha": "72687815ccba81ef014a96201cc2e846a68789d8",
|
||||
"repo_id": 21618,
|
||||
"repo": {
|
||||
"id": 21618,
|
||||
"owner": {
|
||||
"id": 31480,
|
||||
"login": "test-argocd",
|
||||
"full_name": "",
|
||||
"email": "",
|
||||
"avatar_url": "https://gitea.com/avatars/22d1b1d3f61abf95951c4a958731d848",
|
||||
"language": "",
|
||||
"is_admin": false,
|
||||
"last_login": "0001-01-01T00:00:00Z",
|
||||
"created": "2022-04-06T02:28:06+08:00",
|
||||
"restricted": false,
|
||||
"active": false,
|
||||
"prohibit_login": false,
|
||||
"location": "",
|
||||
"website": "",
|
||||
"description": "",
|
||||
"visibility": "public",
|
||||
"followers_count": 0,
|
||||
"following_count": 0,
|
||||
"starred_repos_count": 0,
|
||||
"username": "test-argocd"
|
||||
},
|
||||
"name": "pr-test",
|
||||
"full_name": "test-argocd/pr-test",
|
||||
"description": "",
|
||||
"empty": false,
|
||||
"private": false,
|
||||
"fork": false,
|
||||
"template": false,
|
||||
"parent": null,
|
||||
"mirror": false,
|
||||
"size": 28,
|
||||
"language": "",
|
||||
"languages_url": "https://gitea.com/api/v1/repos/test-argocd/pr-test/languages",
|
||||
"html_url": "https://gitea.com/test-argocd/pr-test",
|
||||
"ssh_url": "git@gitea.com:test-argocd/pr-test.git",
|
||||
"clone_url": "https://gitea.com/test-argocd/pr-test.git",
|
||||
"original_url": "",
|
||||
"website": "",
|
||||
"stars_count": 0,
|
||||
"forks_count": 0,
|
||||
"watchers_count": 1,
|
||||
"open_issues_count": 0,
|
||||
"open_pr_counter": 1,
|
||||
"release_counter": 0,
|
||||
"default_branch": "main",
|
||||
"archived": false,
|
||||
"created_at": "2022-04-06T02:32:09+08:00",
|
||||
"updated_at": "2022-04-06T02:33:12+08:00",
|
||||
"permissions": {
|
||||
"admin": false,
|
||||
"push": false,
|
||||
"pull": true
|
||||
},
|
||||
"has_issues": true,
|
||||
"internal_tracker": {
|
||||
"enable_time_tracker": true,
|
||||
"allow_only_contributors_to_track_time": true,
|
||||
"enable_issue_dependencies": true
|
||||
},
|
||||
"has_wiki": true,
|
||||
"has_pull_requests": true,
|
||||
"has_projects": true,
|
||||
"ignore_whitespace_conflicts": false,
|
||||
"allow_merge_commits": true,
|
||||
"allow_rebase": true,
|
||||
"allow_rebase_explicit": true,
|
||||
"allow_squash_merge": true,
|
||||
"default_merge_style": "merge",
|
||||
"avatar_url": "",
|
||||
"internal": false,
|
||||
"mirror_interval": "",
|
||||
"mirror_updated": "0001-01-01T00:00:00Z",
|
||||
"repo_transfer": null
|
||||
}
|
||||
},
|
||||
"head": {
|
||||
"label": "test",
|
||||
"ref": "test",
|
||||
"sha": "7bbaf62d92ddfafd9cc8b340c619abaec32bc09f",
|
||||
"repo_id": 21618,
|
||||
"repo": {
|
||||
"id": 21618,
|
||||
"owner": {
|
||||
"id": 31480,
|
||||
"login": "test-argocd",
|
||||
"full_name": "",
|
||||
"email": "",
|
||||
"avatar_url": "https://gitea.com/avatars/22d1b1d3f61abf95951c4a958731d848",
|
||||
"language": "",
|
||||
"is_admin": false,
|
||||
"last_login": "0001-01-01T00:00:00Z",
|
||||
"created": "2022-04-06T02:28:06+08:00",
|
||||
"restricted": false,
|
||||
"active": false,
|
||||
"prohibit_login": false,
|
||||
"location": "",
|
||||
"website": "",
|
||||
"description": "",
|
||||
"visibility": "public",
|
||||
"followers_count": 0,
|
||||
"following_count": 0,
|
||||
"starred_repos_count": 0,
|
||||
"username": "test-argocd"
|
||||
},
|
||||
"name": "pr-test",
|
||||
"full_name": "test-argocd/pr-test",
|
||||
"description": "",
|
||||
"empty": false,
|
||||
"private": false,
|
||||
"fork": false,
|
||||
"template": false,
|
||||
"parent": null,
|
||||
"mirror": false,
|
||||
"size": 28,
|
||||
"language": "",
|
||||
"languages_url": "https://gitea.com/api/v1/repos/test-argocd/pr-test/languages",
|
||||
"html_url": "https://gitea.com/test-argocd/pr-test",
|
||||
"ssh_url": "git@gitea.com:test-argocd/pr-test.git",
|
||||
"clone_url": "https://gitea.com/test-argocd/pr-test.git",
|
||||
"original_url": "",
|
||||
"website": "",
|
||||
"stars_count": 0,
|
||||
"forks_count": 0,
|
||||
"watchers_count": 1,
|
||||
"open_issues_count": 0,
|
||||
"open_pr_counter": 1,
|
||||
"release_counter": 0,
|
||||
"default_branch": "main",
|
||||
"archived": false,
|
||||
"created_at": "2022-04-06T02:32:09+08:00",
|
||||
"updated_at": "2022-04-06T02:33:12+08:00",
|
||||
"permissions": {
|
||||
"admin": false,
|
||||
"push": false,
|
||||
"pull": true
|
||||
},
|
||||
"has_issues": true,
|
||||
"internal_tracker": {
|
||||
"enable_time_tracker": true,
|
||||
"allow_only_contributors_to_track_time": true,
|
||||
"enable_issue_dependencies": true
|
||||
},
|
||||
"has_wiki": true,
|
||||
"has_pull_requests": true,
|
||||
"has_projects": true,
|
||||
"ignore_whitespace_conflicts": false,
|
||||
"allow_merge_commits": true,
|
||||
"allow_rebase": true,
|
||||
"allow_rebase_explicit": true,
|
||||
"allow_squash_merge": true,
|
||||
"default_merge_style": "merge",
|
||||
"avatar_url": "",
|
||||
"internal": false,
|
||||
"mirror_interval": "",
|
||||
"mirror_updated": "0001-01-01T00:00:00Z",
|
||||
"repo_transfer": null
|
||||
}
|
||||
},
|
||||
"merge_base": "72687815ccba81ef014a96201cc2e846a68789d8",
|
||||
"due_date": null,
|
||||
"created_at": "2022-04-06T02:34:24+08:00",
|
||||
"updated_at": "2022-04-06T02:34:24+08:00",
|
||||
"closed_at": null
|
||||
}]`)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGiteaList(t *testing.T) {
|
||||
host, err := NewGiteaService(context.Background(), "", "https://gitea.com", "test-argocd", "pr-test", false)
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
giteaMockHandler(t)(w, r)
|
||||
}))
|
||||
host, err := NewGiteaService(context.Background(), "", ts.URL, "test-argocd", "pr-test", false)
|
||||
assert.Nil(t, err)
|
||||
prs, err := host.List(context.Background())
|
||||
assert.Nil(t, err)
|
||||
|
||||
@@ -19,8 +19,9 @@ type RepositoryDB interface {
|
||||
}
|
||||
|
||||
type argoCDService struct {
|
||||
repositoriesDB RepositoryDB
|
||||
storecreds git.CredsStore
|
||||
repositoriesDB RepositoryDB
|
||||
storecreds git.CredsStore
|
||||
submoduleEnabled bool
|
||||
}
|
||||
|
||||
type Repos interface {
|
||||
@@ -32,11 +33,12 @@ type Repos interface {
|
||||
GetDirectories(ctx context.Context, repoURL string, revision string) ([]string, error)
|
||||
}
|
||||
|
||||
func NewArgoCDService(db db.ArgoDB, gitCredStore git.CredsStore, repoServerAddress string) Repos {
|
||||
func NewArgoCDService(db db.ArgoDB, gitCredStore git.CredsStore, submoduleEnabled bool) Repos {
|
||||
|
||||
return &argoCDService{
|
||||
repositoriesDB: db.(RepositoryDB),
|
||||
storecreds: gitCredStore,
|
||||
repositoriesDB: db.(RepositoryDB),
|
||||
storecreds: gitCredStore,
|
||||
submoduleEnabled: submoduleEnabled,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +54,7 @@ func (a *argoCDService) GetFiles(ctx context.Context, repoURL string, revision s
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = checkoutRepo(gitRepoClient, revision)
|
||||
err = checkoutRepo(gitRepoClient, revision, a.submoduleEnabled)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -86,7 +88,7 @@ func (a *argoCDService) GetDirectories(ctx context.Context, repoURL string, revi
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = checkoutRepo(gitRepoClient, revision)
|
||||
err = checkoutRepo(gitRepoClient, revision, a.submoduleEnabled)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -128,7 +130,7 @@ func (a *argoCDService) GetDirectories(ctx context.Context, repoURL string, revi
|
||||
|
||||
}
|
||||
|
||||
func checkoutRepo(gitRepoClient git.Client, revision string) error {
|
||||
func checkoutRepo(gitRepoClient git.Client, revision string, submoduleEnabled bool) error {
|
||||
err := gitRepoClient.Init()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error during initializing repo: %w", err)
|
||||
@@ -143,7 +145,7 @@ func checkoutRepo(gitRepoClient git.Client, revision string) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error during fetching commitSHA: %w", err)
|
||||
}
|
||||
err = gitRepoClient.Checkout(commitSHA, true)
|
||||
err = gitRepoClient.Checkout(commitSHA, submoduleEnabled)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error during repo checkout: %w", err)
|
||||
}
|
||||
|
||||
@@ -2,13 +2,262 @@ package scm_provider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/services/scm_provider/testdata"
|
||||
"github.com/argoproj/argo-cd/v2/pkg/apis/applicationset/v1alpha1"
|
||||
)
|
||||
|
||||
func giteaMockHandler(t *testing.T) func(http.ResponseWriter, *http.Request) {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
switch r.RequestURI {
|
||||
case "/api/v1/version":
|
||||
_, err := io.WriteString(w, `{"version":"1.17.0+dev-452-g1f0541780"}`)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
case "/api/v1/orgs/test-argocd/repos?limit=0&page=1":
|
||||
_, err := io.WriteString(w, `[{
|
||||
"id": 21618,
|
||||
"owner": {
|
||||
"id": 31480,
|
||||
"login": "test-argocd",
|
||||
"full_name": "",
|
||||
"email": "",
|
||||
"avatar_url": "https://gitea.com/avatars/22d1b1d3f61abf95951c4a958731d848",
|
||||
"language": "",
|
||||
"is_admin": false,
|
||||
"last_login": "0001-01-01T00:00:00Z",
|
||||
"created": "2022-04-06T02:28:06+08:00",
|
||||
"restricted": false,
|
||||
"active": false,
|
||||
"prohibit_login": false,
|
||||
"location": "",
|
||||
"website": "",
|
||||
"description": "",
|
||||
"visibility": "public",
|
||||
"followers_count": 0,
|
||||
"following_count": 0,
|
||||
"starred_repos_count": 0,
|
||||
"username": "test-argocd"
|
||||
},
|
||||
"name": "pr-test",
|
||||
"full_name": "test-argocd/pr-test",
|
||||
"description": "",
|
||||
"empty": false,
|
||||
"private": false,
|
||||
"fork": false,
|
||||
"template": false,
|
||||
"parent": null,
|
||||
"mirror": false,
|
||||
"size": 28,
|
||||
"language": "",
|
||||
"languages_url": "https://gitea.com/api/v1/repos/test-argocd/pr-test/languages",
|
||||
"html_url": "https://gitea.com/test-argocd/pr-test",
|
||||
"ssh_url": "git@gitea.com:test-argocd/pr-test.git",
|
||||
"clone_url": "https://gitea.com/test-argocd/pr-test.git",
|
||||
"original_url": "",
|
||||
"website": "",
|
||||
"stars_count": 0,
|
||||
"forks_count": 0,
|
||||
"watchers_count": 1,
|
||||
"open_issues_count": 0,
|
||||
"open_pr_counter": 1,
|
||||
"release_counter": 0,
|
||||
"default_branch": "main",
|
||||
"archived": false,
|
||||
"created_at": "2022-04-06T02:32:09+08:00",
|
||||
"updated_at": "2022-04-06T02:33:12+08:00",
|
||||
"permissions": {
|
||||
"admin": false,
|
||||
"push": false,
|
||||
"pull": true
|
||||
},
|
||||
"has_issues": true,
|
||||
"internal_tracker": {
|
||||
"enable_time_tracker": true,
|
||||
"allow_only_contributors_to_track_time": true,
|
||||
"enable_issue_dependencies": true
|
||||
},
|
||||
"has_wiki": true,
|
||||
"has_pull_requests": true,
|
||||
"has_projects": true,
|
||||
"ignore_whitespace_conflicts": false,
|
||||
"allow_merge_commits": true,
|
||||
"allow_rebase": true,
|
||||
"allow_rebase_explicit": true,
|
||||
"allow_squash_merge": true,
|
||||
"default_merge_style": "merge",
|
||||
"avatar_url": "",
|
||||
"internal": false,
|
||||
"mirror_interval": "",
|
||||
"mirror_updated": "0001-01-01T00:00:00Z",
|
||||
"repo_transfer": null
|
||||
}]`)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
case "/api/v1/repos/test-argocd/pr-test/branches/main":
|
||||
_, err := io.WriteString(w, `{
|
||||
"name": "main",
|
||||
"commit": {
|
||||
"id": "72687815ccba81ef014a96201cc2e846a68789d8",
|
||||
"message": "initial commit\n",
|
||||
"url": "https://gitea.com/test-argocd/pr-test/commit/72687815ccba81ef014a96201cc2e846a68789d8",
|
||||
"author": {
|
||||
"name": "Dan Molik",
|
||||
"email": "dan@danmolik.com",
|
||||
"username": "graytshirt"
|
||||
},
|
||||
"committer": {
|
||||
"name": "Dan Molik",
|
||||
"email": "dan@danmolik.com",
|
||||
"username": "graytshirt"
|
||||
},
|
||||
"verification": {
|
||||
"verified": false,
|
||||
"reason": "gpg.error.no_gpg_keys_found",
|
||||
"signature": "-----BEGIN PGP SIGNATURE-----\n\niQEzBAABCAAdFiEEXYAkwEBRpXzXgHFWlgCr7m50zBMFAmJMiqUACgkQlgCr7m50\nzBPSmQgAiVVEIxC42tuks4iGFNURrtYvypZAEIc+hJgt2kBpmdCrAphYPeAj+Wtr\n9KT7dDscCZIba2wx39HEXO2S7wNCXESvAzrA8rdfbXjR4L2miZ1urfBkEoqK5i/F\noblWGuAyjurX4KPa2ARROd0H4AXxt6gNAXaFPgZO+xXCyNKZfad/lkEP1AiPRknD\nvTTMbEkIzFHK9iVwZ9DORGpfF1wnLzxWmMfhYatZnBgFNnoeJNtFhCJo05rHBgqc\nqVZWXt1iF7nysBoXSzyx1ZAsmBr/Qerkuj0nonh0aPVa6NKJsdmeJyPX4zXXoi6E\ne/jpxX2UQJkpFezg3IjUpvE5FvIiYg==\n=3Af2\n-----END PGP SIGNATURE-----\n",
|
||||
"signer": null,
|
||||
"payload": "tree 64d47c7fc6e31dcf00654223ec4ab749dd0a464e\nauthor Dan Molik \u003cdan@danmolik.com\u003e 1649183391 -0400\ncommitter Dan Molik \u003cdan@danmolik.com\u003e 1649183391 -0400\n\ninitial commit\n"
|
||||
},
|
||||
"timestamp": "2022-04-05T14:29:51-04:00",
|
||||
"added": null,
|
||||
"removed": null,
|
||||
"modified": null
|
||||
},
|
||||
"protected": false,
|
||||
"required_approvals": 0,
|
||||
"enable_status_check": false,
|
||||
"status_check_contexts": [],
|
||||
"user_can_push": false,
|
||||
"user_can_merge": false,
|
||||
"effective_branch_protection_name": ""
|
||||
}`)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
case "/api/v1/repos/test-argocd/pr-test/branches?limit=0&page=1":
|
||||
_, err := io.WriteString(w, `[{
|
||||
"name": "main",
|
||||
"commit": {
|
||||
"id": "72687815ccba81ef014a96201cc2e846a68789d8",
|
||||
"message": "initial commit\n",
|
||||
"url": "https://gitea.com/test-argocd/pr-test/commit/72687815ccba81ef014a96201cc2e846a68789d8",
|
||||
"author": {
|
||||
"name": "Dan Molik",
|
||||
"email": "dan@danmolik.com",
|
||||
"username": "graytshirt"
|
||||
},
|
||||
"committer": {
|
||||
"name": "Dan Molik",
|
||||
"email": "dan@danmolik.com",
|
||||
"username": "graytshirt"
|
||||
},
|
||||
"verification": {
|
||||
"verified": false,
|
||||
"reason": "gpg.error.no_gpg_keys_found",
|
||||
"signature": "-----BEGIN PGP SIGNATURE-----\n\niQEzBAABCAAdFiEEXYAkwEBRpXzXgHFWlgCr7m50zBMFAmJMiqUACgkQlgCr7m50\nzBPSmQgAiVVEIxC42tuks4iGFNURrtYvypZAEIc+hJgt2kBpmdCrAphYPeAj+Wtr\n9KT7dDscCZIba2wx39HEXO2S7wNCXESvAzrA8rdfbXjR4L2miZ1urfBkEoqK5i/F\noblWGuAyjurX4KPa2ARROd0H4AXxt6gNAXaFPgZO+xXCyNKZfad/lkEP1AiPRknD\nvTTMbEkIzFHK9iVwZ9DORGpfF1wnLzxWmMfhYatZnBgFNnoeJNtFhCJo05rHBgqc\nqVZWXt1iF7nysBoXSzyx1ZAsmBr/Qerkuj0nonh0aPVa6NKJsdmeJyPX4zXXoi6E\ne/jpxX2UQJkpFezg3IjUpvE5FvIiYg==\n=3Af2\n-----END PGP SIGNATURE-----\n",
|
||||
"signer": null,
|
||||
"payload": "tree 64d47c7fc6e31dcf00654223ec4ab749dd0a464e\nauthor Dan Molik \u003cdan@danmolik.com\u003e 1649183391 -0400\ncommitter Dan Molik \u003cdan@danmolik.com\u003e 1649183391 -0400\n\ninitial commit\n"
|
||||
},
|
||||
"timestamp": "2022-04-05T14:29:51-04:00",
|
||||
"added": null,
|
||||
"removed": null,
|
||||
"modified": null
|
||||
},
|
||||
"protected": false,
|
||||
"required_approvals": 0,
|
||||
"enable_status_check": false,
|
||||
"status_check_contexts": [],
|
||||
"user_can_push": false,
|
||||
"user_can_merge": false,
|
||||
"effective_branch_protection_name": ""
|
||||
}, {
|
||||
"name": "test",
|
||||
"commit": {
|
||||
"id": "7bbaf62d92ddfafd9cc8b340c619abaec32bc09f",
|
||||
"message": "add an empty file\n",
|
||||
"url": "https://gitea.com/test-argocd/pr-test/commit/7bbaf62d92ddfafd9cc8b340c619abaec32bc09f",
|
||||
"author": {
|
||||
"name": "Dan Molik",
|
||||
"email": "dan@danmolik.com",
|
||||
"username": "graytshirt"
|
||||
},
|
||||
"committer": {
|
||||
"name": "Dan Molik",
|
||||
"email": "dan@danmolik.com",
|
||||
"username": "graytshirt"
|
||||
},
|
||||
"verification": {
|
||||
"verified": false,
|
||||
"reason": "gpg.error.no_gpg_keys_found",
|
||||
"signature": "-----BEGIN PGP SIGNATURE-----\n\niQEzBAABCAAdFiEEXYAkwEBRpXzXgHFWlgCr7m50zBMFAmJMiugACgkQlgCr7m50\nzBN+7wgAkCHD3KfX3Ffkqv2qPwqgHNYM1bA6Hmffzhv0YeD9jWCI3tp0JulP4iFZ\ncQ7jqx9xP9tCQMSFCaijLRHaE6Js1xrVtf0OKRkbpdlvkyrIM3sQhqyQgAsISrDG\nLzSqeoQQjglzeWESYh2Tjn1CgqQNKjI6LLepSwvF1pIeV4pJpJobaEbIfTgStdzM\nWEk8o0I+EZaYqK0C0vU9N0LK/LR/jnlaHsb4OUjvk+S7lRjZwBkrsg7P/QsqtCVd\nw5nkxDiCx1J58zKMnQ7ZinJEK9A5WYdnMYc6aBn7ARgZrblXPPBkkKUhEv3ZSPeW\nKv9i4GQy838xkVSTFkHNj1+a5o6zEA==\n=JiFw\n-----END PGP SIGNATURE-----\n",
|
||||
"signer": null,
|
||||
"payload": "tree cdddf3e1d6a8a7e6899a044d0e1bc73bf798e2f5\nparent 72687815ccba81ef014a96201cc2e846a68789d8\nauthor Dan Molik \u003cdan@danmolik.com\u003e 1649183458 -0400\ncommitter Dan Molik \u003cdan@danmolik.com\u003e 1649183458 -0400\n\nadd an empty file\n"
|
||||
},
|
||||
"timestamp": "2022-04-05T14:30:58-04:00",
|
||||
"added": null,
|
||||
"removed": null,
|
||||
"modified": null
|
||||
},
|
||||
"protected": false,
|
||||
"required_approvals": 0,
|
||||
"enable_status_check": false,
|
||||
"status_check_contexts": [],
|
||||
"user_can_push": false,
|
||||
"user_can_merge": false,
|
||||
"effective_branch_protection_name": ""
|
||||
}]`)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
case "/api/v1/repos/gitea/go-sdk/contents/README.md?ref=master":
|
||||
_, err := io.WriteString(w, `{
|
||||
"name": "README.md",
|
||||
"path": "README.md",
|
||||
"sha": "3605625ef3f80dc092167b54e3f55eb0663d729f",
|
||||
"last_commit_sha": "6b6fdd91ce769bb4641084e15f76554fb841bf27",
|
||||
"type": "file",
|
||||
"size": 1673,
|
||||
"encoding": "base64",
|
||||
"content": "IyBHaXRlYSBTREsgZm9yIEdvCgpbIVtMaWNlbnNlOiBNSVRdKGh0dHBzOi8vaW1nLnNoaWVsZHMuaW8vYmFkZ2UvTGljZW5zZS1NSVQtYmx1ZS5zdmcpXShodHRwczovL29wZW5zb3VyY2Uub3JnL2xpY2Vuc2VzL01JVCkgWyFbUmVsZWFzZV0oaHR0cHM6Ly9yYXN0ZXIuc2hpZWxkcy5pby9iYWRnZS9keW5hbWljL2pzb24uc3ZnP2xhYmVsPXJlbGVhc2UmdXJsPWh0dHBzOi8vZ2l0ZWEuY29tL2FwaS92MS9yZXBvcy9naXRlYS9nby1zZGsvcmVsZWFzZXMmcXVlcnk9JFswXS50YWdfbmFtZSldKGh0dHBzOi8vZ2l0ZWEuY29tL2dpdGVhL2dvLXNkay9yZWxlYXNlcykgWyFbQnVpbGQgU3RhdHVzXShodHRwczovL2Ryb25lLmdpdGVhLmNvbS9hcGkvYmFkZ2VzL2dpdGVhL2dvLXNkay9zdGF0dXMuc3ZnKV0oaHR0cHM6Ly9kcm9uZS5naXRlYS5jb20vZ2l0ZWEvZ28tc2RrKSBbIVtKb2luIHRoZSBjaGF0IGF0IGh0dHBzOi8vaW1nLnNoaWVsZHMuaW8vZGlzY29yZC8zMjI1Mzg5NTQxMTkxODQzODQuc3ZnXShodHRwczovL2ltZy5zaGllbGRzLmlvL2Rpc2NvcmQvMzIyNTM4OTU0MTE5MTg0Mzg0LnN2ZyldKGh0dHBzOi8vZGlzY29yZC5nZy9HaXRlYSkgWyFbXShodHRwczovL2ltYWdlcy5taWNyb2JhZGdlci5jb20vYmFkZ2VzL2ltYWdlL2dpdGVhL2dpdGVhLnN2ZyldKGh0dHA6Ly9taWNyb2JhZGdlci5jb20vaW1hZ2VzL2dpdGVhL2dpdGVhICJHZXQgeW91ciBvd24gaW1hZ2UgYmFkZ2Ugb24gbWljcm9iYWRnZXIuY29tIikgWyFbR28gUmVwb3J0IENhcmRdKGh0dHBzOi8vZ29yZXBvcnRjYXJkLmNvbS9iYWRnZS9jb2RlLmdpdGVhLmlvL3NkayldKGh0dHBzOi8vZ29yZXBvcnRjYXJkLmNvbS9yZXBvcnQvY29kZS5naXRlYS5pby9zZGspIFshW0dvRG9jXShodHRwczovL2dvZG9jLm9yZy9jb2RlLmdpdGVhLmlvL3Nkay9naXRlYT9zdGF0dXMuc3ZnKV0oaHR0cHM6Ly9nb2RvYy5vcmcvY29kZS5naXRlYS5pby9zZGsvZ2l0ZWEpCgpUaGlzIHByb2plY3QgYWN0cyBhcyBhIGNsaWVudCBTREsgaW1wbGVtZW50YXRpb24gd3JpdHRlbiBpbiBHbyB0byBpbnRlcmFjdCB3aXRoIHRoZSBHaXRlYSBBUEkgaW1wbGVtZW50YXRpb24uIEZvciBmdXJ0aGVyIGluZm9ybWF0aW9ucyB0YWtlIGEgbG9vayBhdCB0aGUgY3VycmVudCBbZG9jdW1lbnRhdGlvbl0oaHR0cHM6Ly9nb2RvYy5vcmcvY29kZS5naXRlYS5pby9zZGsvZ2l0ZWEpLgoKTm90ZTogZnVuY3Rpb24gYXJndW1lbnRzIGFyZSBlc2NhcGVkIGJ5IHRoZSBTREsuCgojIyBVc2UgaXQKCmBgYGdvCmltcG9ydCAiY29kZS5naXRlYS5pby9zZGsvZ2l0ZWEiCmBgYAoKIyMgVmVyc2lvbiBSZXF1aXJlbWVudHMKICogZ28gPj0gMS4xMwogKiBnaXRlYSA+PSAxLjExCgojIyBDb250cmlidXRpbmcKCkZvcmsgLT4gUGF0Y2ggLT4gUHVzaCAtPiBQdWxsIFJlcXVlc3QKCiMjIEF1dGhvcnMKCiogW01haW50YWluZXJzXShodHRwczovL2dpdGh1Yi5jb20vb3Jncy9nby1naXRlYS9wZW9wbGUpCiogW0NvbnRyaWJ1dG9yc10oaHR0cHM6Ly9naXRodWIuY29tL2dvLWdpdGVhL2dvLXNkay9ncmFwaHMvY29udHJpYnV0b3JzKQoKIyMgTGljZW5zZQoKVGhpcyBwcm9qZWN0IGlzIHVuZGVyIHRoZSBNSVQgTGljZW5zZS4gU2VlIHRoZSBbTElDRU5TRV0oTElDRU5TRSkgZmlsZSBmb3IgdGhlIGZ1bGwgbGljZW5zZSB0ZXh0Lgo=",
|
||||
"target": null,
|
||||
"url": "https://gitea.com/api/v1/repos/gitea/go-sdk/contents/README.md?ref=master",
|
||||
"html_url": "https://gitea.com/gitea/go-sdk/src/branch/master/README.md",
|
||||
"git_url": "https://gitea.com/api/v1/repos/gitea/go-sdk/git/blobs/3605625ef3f80dc092167b54e3f55eb0663d729f",
|
||||
"download_url": "https://gitea.com/gitea/go-sdk/raw/branch/master/README.md",
|
||||
"submodule_git_url": null,
|
||||
"_links": {
|
||||
"self": "https://gitea.com/api/v1/repos/gitea/go-sdk/contents/README.md?ref=master",
|
||||
"git": "https://gitea.com/api/v1/repos/gitea/go-sdk/git/blobs/3605625ef3f80dc092167b54e3f55eb0663d729f",
|
||||
"html": "https://gitea.com/gitea/go-sdk/src/branch/master/README.md"
|
||||
}
|
||||
}
|
||||
`)
|
||||
require.NoError(t, err)
|
||||
case "/api/v1/repos/gitea/go-sdk/contents/gitea?ref=master":
|
||||
_, err := io.WriteString(w, testdata.ReposGiteaGoSdkContentsGiteaResponse)
|
||||
require.NoError(t, err)
|
||||
case "/api/v1/repos/gitea/go-sdk/contents/notathing?ref=master":
|
||||
w.WriteHeader(404)
|
||||
_, err := io.WriteString(w, `{"errors":["object does not exist [id: , rel_path: notathing]"],"message":"GetContentsOrList","url":"https://gitea.com/api/swagger"}`)
|
||||
require.NoError(t, err)
|
||||
default:
|
||||
_, err := io.WriteString(w, `[]`)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
func TestGiteaListRepos(t *testing.T) {
|
||||
cases := []struct {
|
||||
name, proto, url string
|
||||
@@ -17,28 +266,28 @@ func TestGiteaListRepos(t *testing.T) {
|
||||
filters []v1alpha1.SCMProviderGeneratorFilter
|
||||
}{
|
||||
{
|
||||
name: "blank protocol",
|
||||
name: "blank protocol",
|
||||
allBranches: false,
|
||||
url: "git@gitea.com:test-argocd/pr-test.git",
|
||||
branches: []string{"main"},
|
||||
url: "git@gitea.com:test-argocd/pr-test.git",
|
||||
branches: []string{"main"},
|
||||
},
|
||||
{
|
||||
name: "ssh protocol",
|
||||
name: "ssh protocol",
|
||||
allBranches: false,
|
||||
proto: "ssh",
|
||||
url: "git@gitea.com:test-argocd/pr-test.git",
|
||||
proto: "ssh",
|
||||
url: "git@gitea.com:test-argocd/pr-test.git",
|
||||
},
|
||||
{
|
||||
name: "https protocol",
|
||||
name: "https protocol",
|
||||
allBranches: false,
|
||||
proto: "https",
|
||||
url: "https://gitea.com/test-argocd/pr-test",
|
||||
proto: "https",
|
||||
url: "https://gitea.com/test-argocd/pr-test",
|
||||
},
|
||||
{
|
||||
name: "other protocol",
|
||||
name: "other protocol",
|
||||
allBranches: false,
|
||||
proto: "other",
|
||||
hasError: true,
|
||||
proto: "other",
|
||||
hasError: true,
|
||||
},
|
||||
{
|
||||
name: "all branches",
|
||||
@@ -47,15 +296,17 @@ func TestGiteaListRepos(t *testing.T) {
|
||||
branches: []string{"main"},
|
||||
},
|
||||
}
|
||||
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
giteaMockHandler(t)(w, r)
|
||||
}))
|
||||
defer ts.Close()
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
provider, _ := NewGiteaProvider(context.Background(), "test-argocd", "", "https://gitea.com/", c.allBranches, false)
|
||||
provider, _ := NewGiteaProvider(context.Background(), "test-argocd", "", ts.URL, c.allBranches, false)
|
||||
rawRepos, err := ListRepos(context.Background(), provider, c.filters, c.proto)
|
||||
if c.hasError {
|
||||
assert.NotNil(t, err)
|
||||
} else {
|
||||
checkRateLimit(t, err)
|
||||
assert.Nil(t, err)
|
||||
// Just check that this one project shows up. Not a great test but better thing nothing?
|
||||
repos := []*Repository{}
|
||||
@@ -77,22 +328,32 @@ func TestGiteaListRepos(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGiteaHasPath(t *testing.T) {
|
||||
host, _ := NewGiteaProvider(context.Background(), "gitea", "", "https://gitea.com/", false, false)
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
giteaMockHandler(t)(w, r)
|
||||
}))
|
||||
defer ts.Close()
|
||||
host, _ := NewGiteaProvider(context.Background(), "gitea", "", ts.URL, false, false)
|
||||
repo := &Repository{
|
||||
Organization: "gitea",
|
||||
Repository: "go-sdk",
|
||||
Branch: "master",
|
||||
}
|
||||
ok, err := host.RepoHasPath(context.Background(), repo, "README.md")
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, ok)
|
||||
|
||||
// directory
|
||||
ok, err = host.RepoHasPath(context.Background(), repo, "gitea")
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, ok)
|
||||
t.Run("file exists", func(t *testing.T) {
|
||||
ok, err := host.RepoHasPath(context.Background(), repo, "README.md")
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, ok)
|
||||
})
|
||||
|
||||
ok, err = host.RepoHasPath(context.Background(), repo, "notathing")
|
||||
assert.Nil(t, err)
|
||||
assert.False(t, ok)
|
||||
t.Run("directory exists", func(t *testing.T) {
|
||||
ok, err := host.RepoHasPath(context.Background(), repo, "gitea")
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, ok)
|
||||
})
|
||||
|
||||
t.Run("does not exists", func(t *testing.T) {
|
||||
ok, err := host.RepoHasPath(context.Background(), repo, "notathing")
|
||||
assert.Nil(t, err)
|
||||
assert.False(t, ok)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -2,8 +2,9 @@ package scm_provider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"strings"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -11,27 +12,192 @@ import (
|
||||
"github.com/argoproj/argo-cd/v2/pkg/apis/applicationset/v1alpha1"
|
||||
)
|
||||
|
||||
func checkRateLimit(t *testing.T, err error) {
|
||||
// Check if we've hit a rate limit, don't fail the test if so.
|
||||
if err != nil && (strings.Contains(err.Error(), "rate limit exceeded") ||
|
||||
(strings.Contains(err.Error(), "API rate limit") && strings.Contains(err.Error(), "still exceeded"))) {
|
||||
|
||||
// GitHub Actions add this environment variable to indicate branch ref you are running on
|
||||
githubRef := os.Getenv("GITHUB_REF")
|
||||
|
||||
// Only report rate limit errors as errors, when:
|
||||
// - We are running in a GitHub action
|
||||
// - AND, we are running that action on the 'master' or 'release-*' branch
|
||||
// (unfortunately, for PRs, we don't have access to GitHub secrets that would allow us to embed a token)
|
||||
failOnRateLimitErrors := os.Getenv("CI") != "" && (strings.Contains(githubRef, "/master") || strings.Contains(githubRef, "/release-"))
|
||||
|
||||
t.Logf("Got a rate limit error, consider setting $GITHUB_TOKEN to increase your GitHub API rate limit: %v\n", err)
|
||||
if failOnRateLimitErrors {
|
||||
t.FailNow()
|
||||
} else {
|
||||
t.SkipNow()
|
||||
func githubMockHandler(t *testing.T) func(http.ResponseWriter, *http.Request) {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
switch r.RequestURI {
|
||||
case "/api/v3/orgs/argoproj/repos?per_page=100":
|
||||
_, err := io.WriteString(w, `[
|
||||
{
|
||||
"id": 1296269,
|
||||
"node_id": "MDEwOlJlcG9zaXRvcnkxMjk2MjY5",
|
||||
"name": "argo-cd",
|
||||
"full_name": "argoproj/argo-cd",
|
||||
"owner": {
|
||||
"login": "argoproj",
|
||||
"id": 1,
|
||||
"node_id": "MDQ6VXNlcjE=",
|
||||
"avatar_url": "https://github.com/images/error/argoproj_happy.gif",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/argoproj",
|
||||
"html_url": "https://github.com/argoproj",
|
||||
"followers_url": "https://api.github.com/users/argoproj/followers",
|
||||
"following_url": "https://api.github.com/users/argoproj/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/argoproj/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/argoproj/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/argoproj/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/argoproj/orgs",
|
||||
"repos_url": "https://api.github.com/users/argoproj/repos",
|
||||
"events_url": "https://api.github.com/users/argoproj/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/argoproj/received_events",
|
||||
"type": "User",
|
||||
"site_admin": false
|
||||
},
|
||||
"private": false,
|
||||
"html_url": "https://github.com/argoproj/argo-cd",
|
||||
"description": "This your first repo!",
|
||||
"fork": false,
|
||||
"url": "https://api.github.com/repos/argoproj/argo-cd",
|
||||
"archive_url": "https://api.github.com/repos/argoproj/argo-cd/{archive_format}{/ref}",
|
||||
"assignees_url": "https://api.github.com/repos/argoproj/argo-cd/assignees{/user}",
|
||||
"blobs_url": "https://api.github.com/repos/argoproj/argo-cd/git/blobs{/sha}",
|
||||
"branches_url": "https://api.github.com/repos/argoproj/argo-cd/branches{/branch}",
|
||||
"collaborators_url": "https://api.github.com/repos/argoproj/argo-cd/collaborators{/collaborator}",
|
||||
"comments_url": "https://api.github.com/repos/argoproj/argo-cd/comments{/number}",
|
||||
"commits_url": "https://api.github.com/repos/argoproj/argo-cd/commits{/sha}",
|
||||
"compare_url": "https://api.github.com/repos/argoproj/argo-cd/compare/{base}...{head}",
|
||||
"contents_url": "https://api.github.com/repos/argoproj/argo-cd/contents/{path}",
|
||||
"contributors_url": "https://api.github.com/repos/argoproj/argo-cd/contributors",
|
||||
"deployments_url": "https://api.github.com/repos/argoproj/argo-cd/deployments",
|
||||
"downloads_url": "https://api.github.com/repos/argoproj/argo-cd/downloads",
|
||||
"events_url": "https://api.github.com/repos/argoproj/argo-cd/events",
|
||||
"forks_url": "https://api.github.com/repos/argoproj/argo-cd/forks",
|
||||
"git_commits_url": "https://api.github.com/repos/argoproj/argo-cd/git/commits{/sha}",
|
||||
"git_refs_url": "https://api.github.com/repos/argoproj/argo-cd/git/refs{/sha}",
|
||||
"git_tags_url": "https://api.github.com/repos/argoproj/argo-cd/git/tags{/sha}",
|
||||
"git_url": "git:github.com/argoproj/argo-cd.git",
|
||||
"issue_comment_url": "https://api.github.com/repos/argoproj/argo-cd/issues/comments{/number}",
|
||||
"issue_events_url": "https://api.github.com/repos/argoproj/argo-cd/issues/events{/number}",
|
||||
"issues_url": "https://api.github.com/repos/argoproj/argo-cd/issues{/number}",
|
||||
"keys_url": "https://api.github.com/repos/argoproj/argo-cd/keys{/key_id}",
|
||||
"labels_url": "https://api.github.com/repos/argoproj/argo-cd/labels{/name}",
|
||||
"languages_url": "https://api.github.com/repos/argoproj/argo-cd/languages",
|
||||
"merges_url": "https://api.github.com/repos/argoproj/argo-cd/merges",
|
||||
"milestones_url": "https://api.github.com/repos/argoproj/argo-cd/milestones{/number}",
|
||||
"notifications_url": "https://api.github.com/repos/argoproj/argo-cd/notifications{?since,all,participating}",
|
||||
"pulls_url": "https://api.github.com/repos/argoproj/argo-cd/pulls{/number}",
|
||||
"releases_url": "https://api.github.com/repos/argoproj/argo-cd/releases{/id}",
|
||||
"ssh_url": "git@github.com:argoproj/argo-cd.git",
|
||||
"stargazers_url": "https://api.github.com/repos/argoproj/argo-cd/stargazers",
|
||||
"statuses_url": "https://api.github.com/repos/argoproj/argo-cd/statuses/{sha}",
|
||||
"subscribers_url": "https://api.github.com/repos/argoproj/argo-cd/subscribers",
|
||||
"subscription_url": "https://api.github.com/repos/argoproj/argo-cd/subscription",
|
||||
"tags_url": "https://api.github.com/repos/argoproj/argo-cd/tags",
|
||||
"teams_url": "https://api.github.com/repos/argoproj/argo-cd/teams",
|
||||
"trees_url": "https://api.github.com/repos/argoproj/argo-cd/git/trees{/sha}",
|
||||
"clone_url": "https://github.com/argoproj/argo-cd.git",
|
||||
"mirror_url": "git:git.example.com/argoproj/argo-cd",
|
||||
"hooks_url": "https://api.github.com/repos/argoproj/argo-cd/hooks",
|
||||
"svn_url": "https://svn.github.com/argoproj/argo-cd",
|
||||
"homepage": "https://github.com",
|
||||
"language": null,
|
||||
"forks_count": 9,
|
||||
"stargazers_count": 80,
|
||||
"watchers_count": 80,
|
||||
"size": 108,
|
||||
"default_branch": "master",
|
||||
"open_issues_count": 0,
|
||||
"is_template": false,
|
||||
"topics": [
|
||||
"argoproj",
|
||||
"atom",
|
||||
"electron",
|
||||
"api"
|
||||
],
|
||||
"has_issues": true,
|
||||
"has_projects": true,
|
||||
"has_wiki": true,
|
||||
"has_pages": false,
|
||||
"has_downloads": true,
|
||||
"archived": false,
|
||||
"disabled": false,
|
||||
"visibility": "public",
|
||||
"pushed_at": "2011-01-26T19:06:43Z",
|
||||
"created_at": "2011-01-26T19:01:12Z",
|
||||
"updated_at": "2011-01-26T19:14:43Z",
|
||||
"permissions": {
|
||||
"admin": false,
|
||||
"push": false,
|
||||
"pull": true
|
||||
},
|
||||
"template_repository": null
|
||||
}
|
||||
]`)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
case "/api/v3/repos/argoproj/argo-cd/branches?per_page=100":
|
||||
_, err := io.WriteString(w, `[
|
||||
{
|
||||
"name": "master",
|
||||
"commit": {
|
||||
"sha": "c5b97d5ae6c19d5c5df71a34c7fbeeda2479ccbc",
|
||||
"url": "https://api.github.com/repos/argoproj/argo-cd/commits/c5b97d5ae6c19d5c5df71a34c7fbeeda2479ccbc"
|
||||
},
|
||||
"protected": true,
|
||||
"protection": {
|
||||
"required_status_checks": {
|
||||
"enforcement_level": "non_admins",
|
||||
"contexts": [
|
||||
"ci-test",
|
||||
"linter"
|
||||
]
|
||||
}
|
||||
},
|
||||
"protection_url": "https://api.github.com/repos/argoproj/hello-world/branches/master/protection"
|
||||
}
|
||||
]
|
||||
`)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
case "/api/v3/repos/argoproj/argo-cd/contents/pkg?ref=master":
|
||||
_, err := io.WriteString(w, `{
|
||||
"type": "file",
|
||||
"encoding": "base64",
|
||||
"size": 5362,
|
||||
"name": "pkg/",
|
||||
"path": "pkg/",
|
||||
"content": "encoded content ...",
|
||||
"sha": "3d21ec53a331a6f037a91c368710b99387d012c1",
|
||||
"url": "https://api.github.com/repos/octokit/octokit.rb/contents/README.md",
|
||||
"git_url": "https://api.github.com/repos/octokit/octokit.rb/git/blobs/3d21ec53a331a6f037a91c368710b99387d012c1",
|
||||
"html_url": "https://github.com/octokit/octokit.rb/blob/master/README.md",
|
||||
"download_url": "https://raw.githubusercontent.com/octokit/octokit.rb/master/README.md",
|
||||
"_links": {
|
||||
"git": "https://api.github.com/repos/octokit/octokit.rb/git/blobs/3d21ec53a331a6f037a91c368710b99387d012c1",
|
||||
"self": "https://api.github.com/repos/octokit/octokit.rb/contents/README.md",
|
||||
"html": "https://github.com/octokit/octokit.rb/blob/master/README.md"
|
||||
}
|
||||
}`)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
case "/api/v3/repos/argoproj/argo-cd/branches/master":
|
||||
_, err := io.WriteString(w, `{
|
||||
"name": "master",
|
||||
"commit": {
|
||||
"sha": "c5b97d5ae6c19d5c5df71a34c7fbeeda2479ccbc",
|
||||
"url": "https://api.github.com/repos/octocat/Hello-World/commits/c5b97d5ae6c19d5c5df71a34c7fbeeda2479ccbc"
|
||||
},
|
||||
"protected": true,
|
||||
"protection": {
|
||||
"required_status_checks": {
|
||||
"enforcement_level": "non_admins",
|
||||
"contexts": [
|
||||
"ci-test",
|
||||
"linter"
|
||||
]
|
||||
}
|
||||
},
|
||||
"protection_url": "https://api.github.com/repos/octocat/hello-world/branches/master/protection"
|
||||
}`)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
default:
|
||||
w.WriteHeader(404)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,18 +232,20 @@ func TestGithubListRepos(t *testing.T) {
|
||||
name: "all branches",
|
||||
allBranches: true,
|
||||
url: "git@github.com:argoproj/argo-cd.git",
|
||||
branches: []string{"master", "release-0.11"},
|
||||
branches: []string{"master"},
|
||||
},
|
||||
}
|
||||
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
githubMockHandler(t)(w, r)
|
||||
}))
|
||||
defer ts.Close()
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
provider, _ := NewGithubProvider(context.Background(), "argoproj", "", "", c.allBranches)
|
||||
provider, _ := NewGithubProvider(context.Background(), "argoproj", "", ts.URL, c.allBranches)
|
||||
rawRepos, err := ListRepos(context.Background(), provider, c.filters, c.proto)
|
||||
if c.hasError {
|
||||
assert.Error(t, err)
|
||||
} else {
|
||||
checkRateLimit(t, err)
|
||||
assert.NoError(t, err)
|
||||
// Just check that this one project shows up. Not a great test but better thing nothing?
|
||||
repos := []*Repository{}
|
||||
@@ -99,25 +267,31 @@ func TestGithubListRepos(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGithubHasPath(t *testing.T) {
|
||||
host, _ := NewGithubProvider(context.Background(), "argoproj", "", "", false)
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
githubMockHandler(t)(w, r)
|
||||
}))
|
||||
defer ts.Close()
|
||||
host, _ := NewGithubProvider(context.Background(), "argoproj", "", ts.URL, false)
|
||||
repo := &Repository{
|
||||
Organization: "argoproj",
|
||||
Repository: "argo-cd",
|
||||
Branch: "master",
|
||||
}
|
||||
ok, err := host.RepoHasPath(context.Background(), repo, "pkg/")
|
||||
checkRateLimit(t, err)
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, ok)
|
||||
|
||||
ok, err = host.RepoHasPath(context.Background(), repo, "notathing/")
|
||||
checkRateLimit(t, err)
|
||||
assert.Nil(t, err)
|
||||
assert.False(t, ok)
|
||||
}
|
||||
|
||||
func TestGithubGetBranches(t *testing.T) {
|
||||
host, _ := NewGithubProvider(context.Background(), "argoproj", "", "", false)
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
githubMockHandler(t)(w, r)
|
||||
}))
|
||||
defer ts.Close()
|
||||
host, _ := NewGithubProvider(context.Background(), "argoproj", "", ts.URL, false)
|
||||
repo := &Repository{
|
||||
Organization: "argoproj",
|
||||
Repository: "argo-cd",
|
||||
@@ -125,19 +299,26 @@ func TestGithubGetBranches(t *testing.T) {
|
||||
}
|
||||
repos, err := host.GetBranches(context.Background(), repo)
|
||||
if err != nil {
|
||||
checkRateLimit(t, err)
|
||||
assert.NoError(t, err)
|
||||
} else {
|
||||
assert.Equal(t, repos[0].Branch, "master")
|
||||
}
|
||||
// Get all branches
|
||||
//Branch Doesn't exists instead of error will return no error
|
||||
repo2 := &Repository{
|
||||
Organization: "argoproj",
|
||||
Repository: "applicationset",
|
||||
Branch: "main",
|
||||
}
|
||||
_, err = host.GetBranches(context.Background(), repo2)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Get all branches
|
||||
host.allBranches = true
|
||||
repos, err = host.GetBranches(context.Background(), repo)
|
||||
if err != nil {
|
||||
checkRateLimit(t, err)
|
||||
assert.NoError(t, err)
|
||||
} else {
|
||||
// considering master and one release branch to always exist.
|
||||
assert.Greater(t, len(repos), 1)
|
||||
// considering master branch to exist.
|
||||
assert.Equal(t, len(repos), 1)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,10 @@ package scm_provider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -9,6 +13,275 @@ import (
|
||||
"github.com/argoproj/argo-cd/v2/pkg/apis/applicationset/v1alpha1"
|
||||
)
|
||||
|
||||
func gitlabMockHandler(t *testing.T) func(http.ResponseWriter, *http.Request) {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
switch r.RequestURI {
|
||||
case "/api/v4":
|
||||
fmt.Println("here1")
|
||||
case "/api/v4/groups/test-argocd-proton/projects?include_subgroups=false&per_page=100":
|
||||
fmt.Println("here")
|
||||
_, err := io.WriteString(w, `[{
|
||||
"id": 27084533,
|
||||
"description": "",
|
||||
"name": "argocd",
|
||||
"name_with_namespace": "test argocd proton / argocd",
|
||||
"path": "argocd",
|
||||
"path_with_namespace": "test-argocd-proton/argocd",
|
||||
"created_at": "2021-06-01T17:30:44.724Z",
|
||||
"default_branch": "master",
|
||||
"tag_list": [],
|
||||
"topics": [],
|
||||
"ssh_url_to_repo": "git@gitlab.com:test-argocd-proton/argocd.git",
|
||||
"http_url_to_repo": "https://gitlab.com/test-argocd-proton/argocd.git",
|
||||
"web_url": "https://gitlab.com/test-argocd-proton/argocd",
|
||||
"readme_url": null,
|
||||
"avatar_url": null,
|
||||
"forks_count": 0,
|
||||
"star_count": 0,
|
||||
"last_activity_at": "2021-06-04T08:19:51.656Z",
|
||||
"namespace": {
|
||||
"id": 12258515,
|
||||
"name": "test argocd proton",
|
||||
"path": "test-argocd-proton",
|
||||
"kind": "gro* Connection #0 to host gitlab.com left intact up ",
|
||||
"full_path ": "test - argocd - proton ",
|
||||
"parent_id ": null,
|
||||
"avatar_url ": null,
|
||||
"web_url ": "https: //gitlab.com/groups/test-argocd-proton"
|
||||
},
|
||||
"container_registry_image_prefix": "registry.gitlab.com/test-argocd-proton/argocd",
|
||||
"_links": {
|
||||
"self": "https://gitlab.com/api/v4/projects/27084533",
|
||||
"issues": "https://gitlab.com/api/v4/projects/27084533/issues",
|
||||
"merge_requests": "https://gitlab.com/api/v4/projects/27084533/merge_requests",
|
||||
"repo_branches": "https://gitlab.com/api/v4/projects/27084533/repository/branches",
|
||||
"labels": "https://gitlab.com/api/v4/projects/27084533/labels",
|
||||
"events": "https://gitlab.com/api/v4/projects/27084533/events",
|
||||
"members": "https://gitlab.com/api/v4/projects/27084533/members",
|
||||
"cluster_agents": "https://gitlab.com/api/v4/projects/27084533/cluster_agents"
|
||||
},
|
||||
"packages_enabled": true,
|
||||
"empty_repo": false,
|
||||
"archived": false,
|
||||
"visibility": "public",
|
||||
"resolve_outdated_diff_discussions": false,
|
||||
"container_expiration_policy": {
|
||||
"cadence": "1d",
|
||||
"enabled": false,
|
||||
"keep_n": 10,
|
||||
"older_than": "90d",
|
||||
"name_regex": ".*",
|
||||
"name_regex_keep": null,
|
||||
"next_run_at": "2021-06-02T17:30:44.740Z"
|
||||
},
|
||||
"issues_enabled": true,
|
||||
"merge_requests_enabled": true,
|
||||
"wiki_enabled": true,
|
||||
"jobs_enabled": true,
|
||||
"snippets_enabled": true,
|
||||
"container_registry_enabled": true,
|
||||
"service_desk_enabled": true,
|
||||
"can_create_merge_request_in": false,
|
||||
"issues_access_level": "enabled",
|
||||
"repository_access_level": "enabled",
|
||||
"merge_requests_access_level": "enabled",
|
||||
"forking_access_level": "enabled",
|
||||
"wiki_access_level": "enabled",
|
||||
"builds_access_level": "enabled",
|
||||
"snippets_access_level": "enabled",
|
||||
"pages_access_level": "enabled",
|
||||
"operations_access_level": "enabled",
|
||||
"analytics_access_level": "enabled",
|
||||
"container_registry_access_level": "enabled",
|
||||
"security_and_compliance_access_level": "private",
|
||||
"emails_disabled": null,
|
||||
"shared_runners_enabled": true,
|
||||
"lfs_enabled": true,
|
||||
"creator_id": 2378866,
|
||||
"import_status": "none",
|
||||
"open_issues_count": 0,
|
||||
"ci_default_git_depth": 50,
|
||||
"ci_forward_deployment_enabled": true,
|
||||
"ci_job_token_scope_enabled": false,
|
||||
"public_jobs": true,
|
||||
"build_timeout": 3600,
|
||||
"auto_cancel_pending_pipelines": "enabled",
|
||||
"ci_config_path": "",
|
||||
"shared_with_groups": [],
|
||||
"only_allow_merge_if_pipeline_succeeds": false,
|
||||
"allow_merge_on_skipped_pipeline": null,
|
||||
"restrict_user_defined_variables": false,
|
||||
"request_access_enabled": true,
|
||||
"only_allow_merge_if_all_discussions_are_resolved": false,
|
||||
"remove_source_branch_after_merge": true,
|
||||
"printing_merge_request_link_enabled": true,
|
||||
"merge_method": "merge",
|
||||
"squash_option": "default_off",
|
||||
"suggestion_commit_message": null,
|
||||
"merge_commit_template": null,
|
||||
"squash_commit_template": null,
|
||||
"auto_devops_enabled": false,
|
||||
"auto_devops_deploy_strategy": "continuous",
|
||||
"autoclose_referenced_issues": true,
|
||||
"keep_latest_artifact": true,
|
||||
"runner_token_expiration_interval": null,
|
||||
"approvals_before_merge": 0,
|
||||
"mirror": false,
|
||||
"external_authorization_classification_label": "",
|
||||
"marked_for_deletion_at": null,
|
||||
"marked_for_deletion_on": null,
|
||||
"requirements_enabled": true,
|
||||
"requirements_access_level": "enabled",
|
||||
"security_and_compliance_enabled": false,
|
||||
"compliance_frameworks": [],
|
||||
"issues_template": null,
|
||||
"merge_requests_template": null,
|
||||
"merge_pipelines_enabled": false,
|
||||
"merge_trains_enabled": false
|
||||
}]`)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
case "/api/v4/projects/27084533/repository/branches/master":
|
||||
fmt.Println("returning")
|
||||
_, err := io.WriteString(w, `{
|
||||
"name": "master",
|
||||
"commit": {
|
||||
"id": "8898d7999fc99dd0fd578650b58b244fc63f6b53",
|
||||
"short_id": "8898d799",
|
||||
"created_at": "2021-06-04T08:24:44.000+00:00",
|
||||
"parent_ids": ["3c9d50be1ef949ad28674e238c7e12a17b1e9706", "56482e001731640b4123cf177e51c696f08a3005"],
|
||||
"title": "Merge branch 'pipeline-1317911429' into 'master'",
|
||||
"message": "Merge branch 'pipeline-1317911429' into 'master'\n\n[testapp-ci] manifests/demo/test-app.yaml: release v1.1.0\n\nSee merge request test-argocd-proton/argocd!3",
|
||||
"author_name": "Martin Vozník",
|
||||
"author_email": "martin@voznik.cz",
|
||||
"authored_date": "2021-06-04T08:24:44.000+00:00",
|
||||
"committer_name": "Martin Vozník",
|
||||
"committer_email": "martin@voznik.cz",
|
||||
"committed_date": "2021-06-04T08:24:44.000+00:00",
|
||||
"trailers": {},
|
||||
"web_url": "https://gitlab.com/test-argocd-proton/argocd/-/commit/8898d7999fc99dd0fd578650b58b244fc63f6b53"
|
||||
},
|
||||
"merged": false,
|
||||
"protected": true,
|
||||
"developers_can_push": false,
|
||||
"developers_can_merge": false,
|
||||
"can_push": false,
|
||||
"default": true,
|
||||
"web_url": "https://gitlab.com/test-argocd-proton/argocd/-/tree/master"
|
||||
}`)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
case "/api/v4/projects/27084533/repository/branches?per_page=100":
|
||||
_, err := io.WriteString(w, `[{
|
||||
"name": "master",
|
||||
"commit": {
|
||||
"id": "8898d7999fc99dd0fd578650b58b244fc63f6b53",
|
||||
"short_id": "8898d799",
|
||||
"created_at": "2021-06-04T08:24:44.000+00:00",
|
||||
"parent_ids": null,
|
||||
"title": "Merge branch 'pipeline-1317911429' into 'master'",
|
||||
"message": "Merge branch 'pipeline-1317911429' into 'master'",
|
||||
"author_name": "Martin Vozník",
|
||||
"author_email": "martin@voznik.cz",
|
||||
"authored_date": "2021-06-04T08:24:44.000+00:00",
|
||||
"committer_name": "Martin Vozník",
|
||||
"committer_email": "martin@voznik.cz",
|
||||
"committed_date": "2021-06-04T08:24:44.000+00:00",
|
||||
"trailers": null,
|
||||
"web_url": "https://gitlab.com/test-argocd-proton/argocd/-/commit/8898d7999fc99dd0fd578650b58b244fc63f6b53"
|
||||
},
|
||||
"merged": false,
|
||||
"protected": true,
|
||||
"developers_can_push": false,
|
||||
"developers_can_merge": false,
|
||||
"can_push": false,
|
||||
"default": true,
|
||||
"web_url": "https://gitlab.com/test-argocd-proton/argocd/-/tree/master"
|
||||
}, {
|
||||
"name": "pipeline-1310077506",
|
||||
"commit": {
|
||||
"id": "0f92540e5f396ba960adea4ed0aa905baf3f73d1",
|
||||
"short_id": "0f92540e",
|
||||
"created_at": "2021-06-01T18:39:59.000+00:00",
|
||||
"parent_ids": null,
|
||||
"title": "[testapp-ci] manifests/demo/test-app.yaml: release v1.0.1",
|
||||
"message": "[testapp-ci] manifests/demo/test-app.yaml: release v1.0.1",
|
||||
"author_name": "ci-test-app",
|
||||
"author_email": "mvoznik+cicd@protonmail.com",
|
||||
"authored_date": "2021-06-01T18:39:59.000+00:00",
|
||||
"committer_name": "ci-test-app",
|
||||
"committer_email": "mvoznik+cicd@protonmail.com",
|
||||
"committed_date": "2021-06-01T18:39:59.000+00:00",
|
||||
"trailers": null,
|
||||
"web_url": "https://gitlab.com/test-argocd-proton/argocd/-/commit/0f92540e5f396ba960adea4ed0aa905baf3f73d1"
|
||||
},
|
||||
"merged": false,
|
||||
"protected": false,
|
||||
"developers_can_push": false,
|
||||
"developers_can_merge": false,
|
||||
"can_push": false,
|
||||
"default": false,
|
||||
"web_url": "https://gitlab.com/test-argocd-proton/argocd/-/tree/pipeline-1310077506"
|
||||
}]`)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
case "/api/v4/projects/test-argocd-proton%2Fargocd":
|
||||
fmt.Println("auct")
|
||||
_, err := io.WriteString(w, `{
|
||||
"id": 27084533,
|
||||
"description": "",
|
||||
"name": "argocd",
|
||||
"name_with_namespace": "test argocd proton / argocd",
|
||||
"path": "argocd",
|
||||
"path_with_namespace": "test-argocd-proton/argocd",
|
||||
"created_at": "2021-06-01T17:30:44.724Z",
|
||||
"default_branch": "master",
|
||||
"tag_list": [],
|
||||
"topics": [],
|
||||
"ssh_url_to_repo": "git@gitlab.com:test-argocd-proton/argocd.git",
|
||||
"http_url_to_repo": "https://gitlab.com/test-argocd-proton/argocd.git",
|
||||
"web_url": "https://gitlab.com/test-argocd-proton/argocd",
|
||||
"readme_url": null,
|
||||
"avatar_url": null,
|
||||
"forks_count": 0,
|
||||
"star_count": 0,
|
||||
"last_activity_at": "2021-06-04T08:19:51.656Z",
|
||||
"namespace": {
|
||||
"id": 12258515,
|
||||
"name": "test argocd proton",
|
||||
"path": "test-argocd-proton",
|
||||
"kind": "group",
|
||||
"full_path": "test-argocd-proton",
|
||||
"parent_id": null,
|
||||
"avatar_url": null,
|
||||
"web_url": "https://gitlab.com/groups/test-argocd-proton"
|
||||
}
|
||||
}`)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
case "/api/v4/projects/27084533/repository/tree?path=argocd&ref=master":
|
||||
_, err := io.WriteString(w, `[{"id":"ca14f2a3718159c74572a5325fb4bfb0662a2d3e","name":"ingress.yaml","type":"blob","path":"argocd/ingress.yaml","mode":"100644"},{"id":"de2a53a73b1550b3e0f4d37ea0a6d878bf9c5096","name":"install.yaml","type":"blob","path":"argocd/install.yaml","mode":"100644"}]`)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
case "/api/v4/projects/27084533/repository/tree?path=.&ref=master":
|
||||
_, err := io.WriteString(w, `[{"id":"f2bf99fa8f7a27df9c43d2dffc8c8cd747f3181a","name":"argocd","type":"tree","path":"argocd","mode":"040000"},{"id":"68a3125232e01c1583a6a6299534ce10c5e7dd83","name":"manifests","type":"tree","path":"manifests","mode":"040000"}]`)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
default:
|
||||
_, err := io.WriteString(w, `[]`)
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
func TestGitlabListRepos(t *testing.T) {
|
||||
cases := []struct {
|
||||
name, proto, url string
|
||||
@@ -40,18 +313,19 @@ func TestGitlabListRepos(t *testing.T) {
|
||||
name: "all branches",
|
||||
allBranches: true,
|
||||
url: "git@gitlab.com:test-argocd-proton/argocd.git",
|
||||
branches: []string{"master", "pipeline-1310077506"},
|
||||
branches: []string{"master"},
|
||||
},
|
||||
}
|
||||
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
gitlabMockHandler(t)(w, r)
|
||||
}))
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
provider, _ := NewGitlabProvider(context.Background(), "test-argocd-proton", "", "", c.allBranches, c.includeSubgroups)
|
||||
provider, _ := NewGitlabProvider(context.Background(), "test-argocd-proton", "", ts.URL, c.allBranches, c.includeSubgroups)
|
||||
rawRepos, err := ListRepos(context.Background(), provider, c.filters, c.proto)
|
||||
if c.hasError {
|
||||
assert.NotNil(t, err)
|
||||
} else {
|
||||
checkRateLimit(t, err)
|
||||
assert.Nil(t, err)
|
||||
// Just check that this one project shows up. Not a great test but better thing nothing?
|
||||
repos := []*Repository{}
|
||||
@@ -73,7 +347,10 @@ func TestGitlabListRepos(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestGitlabHasPath(t *testing.T) {
|
||||
host, _ := NewGitlabProvider(context.Background(), "test-argocd-proton", "", "", false, true)
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
gitlabMockHandler(t)(w, r)
|
||||
}))
|
||||
host, _ := NewGitlabProvider(context.Background(), "test-argocd-proton", "", ts.URL, false, true)
|
||||
repo := &Repository{
|
||||
Organization: "test-argocd-proton",
|
||||
Repository: "argocd",
|
||||
|
||||
6
applicationset/services/scm_provider/testdata/data.go
vendored
Normal file
6
applicationset/services/scm_provider/testdata/data.go
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
package testdata
|
||||
|
||||
import _ "embed"
|
||||
|
||||
//go:embed repos_gitea_go-sdk_contents_gitea.json
|
||||
var ReposGiteaGoSdkContentsGiteaResponse string
|
||||
2039
applicationset/services/scm_provider/testdata/repos_gitea_go-sdk_contents_gitea.json
vendored
Normal file
2039
applicationset/services/scm_provider/testdata/repos_gitea_go-sdk_contents_gitea.json
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@@ -18,6 +18,7 @@ import (
|
||||
"github.com/argoproj/argo-cd/v2/applicationset/utils"
|
||||
"github.com/argoproj/argo-cd/v2/common"
|
||||
"github.com/argoproj/argo-cd/v2/reposerver/askpass"
|
||||
"github.com/argoproj/argo-cd/v2/util/env"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
@@ -37,6 +38,11 @@ import (
|
||||
argosettings "github.com/argoproj/argo-cd/v2/util/settings"
|
||||
)
|
||||
|
||||
// TODO: load this using Cobra. https://github.com/argoproj/argo-cd/issues/10157
|
||||
func getSubmoduleEnabled() bool {
|
||||
return env.ParseBoolFromEnv(common.EnvGitSubmoduleEnabled, true)
|
||||
}
|
||||
|
||||
func NewCommand() *cobra.Command {
|
||||
var (
|
||||
clientConfig clientcmd.ClientConfig
|
||||
@@ -136,7 +142,7 @@ func NewCommand() *cobra.Command {
|
||||
terminalGenerators := map[string]generators.Generator{
|
||||
"List": generators.NewListGenerator(),
|
||||
"Clusters": generators.NewClusterGenerator(mgr.GetClient(), context.Background(), k8sClient, namespace),
|
||||
"Git": generators.NewGitGenerator(services.NewArgoCDService(argoCDDB, askPassServer, argocdRepoServer)),
|
||||
"Git": generators.NewGitGenerator(services.NewArgoCDService(argoCDDB, askPassServer, getSubmoduleEnabled())),
|
||||
"SCMProvider": generators.NewSCMProviderGenerator(mgr.GetClient()),
|
||||
"ClusterDecisionResource": generators.NewDuckTypeGenerator(context.Background(), dynamicClient, k8sClient, namespace),
|
||||
"PullRequest": generators.NewPullRequestGenerator(mgr.GetClient()),
|
||||
|
||||
@@ -36,11 +36,12 @@ import (
|
||||
// NewLoginCommand returns a new instance of `argocd login` command
|
||||
func NewLoginCommand(globalClientOpts *argocdclient.ClientOptions) *cobra.Command {
|
||||
var (
|
||||
ctxName string
|
||||
username string
|
||||
password string
|
||||
sso bool
|
||||
ssoPort int
|
||||
ctxName string
|
||||
username string
|
||||
password string
|
||||
sso bool
|
||||
ssoPort int
|
||||
skipTestTLS bool
|
||||
)
|
||||
var command = &cobra.Command{
|
||||
Use: "login SERVER",
|
||||
@@ -68,22 +69,25 @@ argocd login cd.argoproj.io --core`,
|
||||
server = "kubernetes"
|
||||
} else {
|
||||
server = args[0]
|
||||
dialTime := 30 * time.Second
|
||||
tlsTestResult, err := grpc_util.TestTLS(server, dialTime)
|
||||
errors.CheckError(err)
|
||||
if !tlsTestResult.TLS {
|
||||
if !globalClientOpts.PlainText {
|
||||
if !cli.AskToProceed("WARNING: server is not configured with TLS. Proceed (y/n)? ") {
|
||||
os.Exit(1)
|
||||
|
||||
if !skipTestTLS {
|
||||
dialTime := 30 * time.Second
|
||||
tlsTestResult, err := grpc_util.TestTLS(server, dialTime)
|
||||
errors.CheckError(err)
|
||||
if !tlsTestResult.TLS {
|
||||
if !globalClientOpts.PlainText {
|
||||
if !cli.AskToProceed("WARNING: server is not configured with TLS. Proceed (y/n)? ") {
|
||||
os.Exit(1)
|
||||
}
|
||||
globalClientOpts.PlainText = true
|
||||
}
|
||||
globalClientOpts.PlainText = true
|
||||
}
|
||||
} else if tlsTestResult.InsecureErr != nil {
|
||||
if !globalClientOpts.Insecure {
|
||||
if !cli.AskToProceed(fmt.Sprintf("WARNING: server certificate had error: %s. Proceed insecurely (y/n)? ", tlsTestResult.InsecureErr)) {
|
||||
os.Exit(1)
|
||||
} else if tlsTestResult.InsecureErr != nil {
|
||||
if !globalClientOpts.Insecure {
|
||||
if !cli.AskToProceed(fmt.Sprintf("WARNING: server certificate had error: %s. Proceed insecurely (y/n)? ", tlsTestResult.InsecureErr)) {
|
||||
os.Exit(1)
|
||||
}
|
||||
globalClientOpts.Insecure = true
|
||||
}
|
||||
globalClientOpts.Insecure = true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -175,6 +179,8 @@ argocd login cd.argoproj.io --core`,
|
||||
command.Flags().StringVar(&password, "password", "", "the password of an account to authenticate")
|
||||
command.Flags().BoolVar(&sso, "sso", false, "perform SSO login")
|
||||
command.Flags().IntVar(&ssoPort, "sso-port", DefaultSSOLocalPort, "port to run local OAuth2 login application")
|
||||
command.Flags().
|
||||
BoolVar(&skipTestTLS, "skip-test-tls", false, "Skip testing whether the server is configured with TLS (this can help when the command hangs for no apparent reason)")
|
||||
return command
|
||||
}
|
||||
|
||||
@@ -190,7 +196,13 @@ func userDisplayName(claims jwt.MapClaims) string {
|
||||
|
||||
// oauth2Login opens a browser, runs a temporary HTTP server to delegate OAuth2 login flow and
|
||||
// returns the JWT token and a refresh token (if supported)
|
||||
func oauth2Login(ctx context.Context, port int, oidcSettings *settingspkg.OIDCConfig, oauth2conf *oauth2.Config, provider *oidc.Provider) (string, string) {
|
||||
func oauth2Login(
|
||||
ctx context.Context,
|
||||
port int,
|
||||
oidcSettings *settingspkg.OIDCConfig,
|
||||
oauth2conf *oauth2.Config,
|
||||
provider *oidc.Provider,
|
||||
) (string, string) {
|
||||
oauth2conf.RedirectURL = fmt.Sprintf("http://localhost:%d/auth/callback", port)
|
||||
oidcConf, err := oidcutil.ParseConfig(provider)
|
||||
errors.CheckError(err)
|
||||
@@ -216,7 +228,10 @@ func oauth2Login(ctx context.Context, port int, oidcSettings *settingspkg.OIDCCo
|
||||
}
|
||||
|
||||
// PKCE implementation of https://tools.ietf.org/html/rfc7636
|
||||
codeVerifier, err := rand.StringFromCharset(43, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~")
|
||||
codeVerifier, err := rand.StringFromCharset(
|
||||
43,
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~",
|
||||
)
|
||||
errors.CheckError(err)
|
||||
codeChallengeHash := sha256.Sum256([]byte(codeVerifier))
|
||||
codeChallenge := base64.RawURLEncoding.EncodeToString(codeChallengeHash[:])
|
||||
|
||||
2
cmd/argocd/commands/testdata/config
vendored
2
cmd/argocd/commands/testdata/config
vendored
@@ -28,4 +28,4 @@ current-context: localhost:8080
|
||||
users:
|
||||
- name: argocd1.example.com:443
|
||||
- name: argocd2.example.com:443
|
||||
- name: localhost:8080
|
||||
- name: localhost:8080
|
||||
@@ -691,10 +691,11 @@ func (m *appStateManager) isSelfReferencedObj(obj *unstructured.Unstructured, ap
|
||||
|
||||
// In order for us to assume obj to be managed by this application, the
|
||||
// values from the annotation have to match the properties from the live
|
||||
// object.
|
||||
// object. Cluster scoped objects carry the app's destination namespace
|
||||
// in the tracking annotation, but are unique in GVK + name combination.
|
||||
appInstance := m.resourceTracking.GetAppInstance(obj, appLabelKey, trackingMethod)
|
||||
if appInstance != nil {
|
||||
return obj.GetNamespace() == appInstance.Namespace &&
|
||||
return (obj.GetNamespace() == appInstance.Namespace || obj.GetNamespace() == "") &&
|
||||
obj.GetName() == appInstance.Name &&
|
||||
obj.GetObjectKind().GroupVersionKind().Group == appInstance.Group &&
|
||||
obj.GetObjectKind().GroupVersionKind().Kind == appInstance.Kind
|
||||
|
||||
@@ -205,6 +205,13 @@ func (m *appStateManager) SyncAppState(app *v1alpha1.Application, state *v1alpha
|
||||
reconciliationResult.Target = patchedTargets
|
||||
}
|
||||
|
||||
appLabelKey, err := m.settingsMgr.GetAppInstanceLabelKey()
|
||||
if err != nil {
|
||||
log.Errorf("Could not get appInstanceLabelKey: %v", err)
|
||||
return
|
||||
}
|
||||
trackingMethod := argo.GetTrackingMethod(m.settingsMgr)
|
||||
|
||||
syncCtx, cleanup, err := sync.NewSyncContext(
|
||||
compareResult.syncStatus.Revision,
|
||||
reconciliationResult,
|
||||
@@ -217,7 +224,7 @@ func (m *appStateManager) SyncAppState(app *v1alpha1.Application, state *v1alpha
|
||||
sync.WithHealthOverride(lua.ResourceHealthOverrides(resourceOverrides)),
|
||||
sync.WithPermissionValidator(func(un *unstructured.Unstructured, res *v1.APIResource) error {
|
||||
if !proj.IsGroupKindPermitted(un.GroupVersionKind().GroupKind(), res.Namespaced) {
|
||||
return fmt.Errorf("Resource %s:%s is not permitted in project %s.", un.GroupVersionKind().Group, un.GroupVersionKind().Kind, proj.Name)
|
||||
return fmt.Errorf("resource %s:%s is not permitted in project %s", un.GroupVersionKind().Group, un.GroupVersionKind().Kind, proj.Name)
|
||||
}
|
||||
if res.Namespaced && !proj.IsDestinationPermitted(v1alpha1.ApplicationDestination{Namespace: un.GetNamespace(), Server: app.Spec.Destination.Server, Name: app.Spec.Destination.Name}) {
|
||||
return fmt.Errorf("namespace %v is not permitted in project '%s'", un.GetNamespace(), proj.Name)
|
||||
@@ -227,7 +234,9 @@ func (m *appStateManager) SyncAppState(app *v1alpha1.Application, state *v1alpha
|
||||
sync.WithOperationSettings(syncOp.DryRun, syncOp.Prune, syncOp.SyncStrategy.Force(), syncOp.IsApplyStrategy() || len(syncOp.Resources) > 0),
|
||||
sync.WithInitialState(state.Phase, state.Message, initialResourcesRes, state.StartedAt),
|
||||
sync.WithResourcesFilter(func(key kube.ResourceKey, target *unstructured.Unstructured, live *unstructured.Unstructured) bool {
|
||||
return len(syncOp.Resources) == 0 || argo.ContainsSyncResource(key.Name, key.Namespace, schema.GroupVersionKind{Kind: key.Kind, Group: key.Group}, syncOp.Resources)
|
||||
return (len(syncOp.Resources) == 0 ||
|
||||
argo.ContainsSyncResource(key.Name, key.Namespace, schema.GroupVersionKind{Kind: key.Kind, Group: key.Group}, syncOp.Resources)) &&
|
||||
m.isSelfReferencedObj(live, appLabelKey, trackingMethod)
|
||||
}),
|
||||
sync.WithManifestValidation(!syncOp.SyncOptions.HasOption(common.SyncOptionsDisableValidation)),
|
||||
sync.WithNamespaceCreation(syncOp.SyncOptions.HasOption("CreateNamespace=true"), func(un *unstructured.Unstructured) bool {
|
||||
|
||||
64
docs/developer-guide/ui-extensions.md
Normal file
64
docs/developer-guide/ui-extensions.md
Normal file
@@ -0,0 +1,64 @@
|
||||
# UI Extensions
|
||||
|
||||
Argo CD web user interface can be extended with additional UI elements. Extensions should be delivered as a javascript file
|
||||
in the `argocd-server` Pods that are placed in the `/tmp/extensions` directory and starts with `extension` prefix ( matches to `^extension(.*)\.js$` regex ).
|
||||
|
||||
```
|
||||
/tmp/extensions
|
||||
├── example1
|
||||
│ └── extension-1.js
|
||||
└── example2
|
||||
└── extension-2.js
|
||||
```
|
||||
|
||||
Extensions are loaded during initial page rendering and should register themselves using API exposed in the `extensionsAPI` global variable. (See
|
||||
corresponding extension type details for additional information).
|
||||
|
||||
The extension should provide a React component that is responsible for rendering the UI element. Extension should not bundle the React library.
|
||||
Instead extension should use the `react` global variable. You can leverage `externals` setting if you are using webpack:
|
||||
|
||||
```js
|
||||
externals: {
|
||||
react: 'React'
|
||||
}
|
||||
```
|
||||
|
||||
## Resource Tab Extensions
|
||||
|
||||
Resource Tab extensions is an extension that provides an additional tab for the resource sliding panel at the Argo CD Application details page.
|
||||
|
||||
The resource tab extension should be registered using the `extensionsAPI.registerResourceExtension` method:
|
||||
|
||||
```typescript
|
||||
registerResourceExtension(component: ExtensionComponent, group: string, kind: string, tabTitle: string)
|
||||
```
|
||||
|
||||
* `component: ExtensionComponent` is a React component that receives the following properties:
|
||||
|
||||
* application: Application - Argo CD Application resource;
|
||||
* resource: State - the kubernetes resource object;
|
||||
* tree: ApplicationTree - includes list of all resources that comprise the application;
|
||||
|
||||
See properties interfaces in [models.ts](https://github.com/argoproj/argo-cd/blob/master/ui/src/app/shared/models.ts)
|
||||
|
||||
* `group: string` - the glob expression that matches the group of the resource; note: use globstar (`**`) to match all groups including empty string;
|
||||
* `kind: string` - the glob expression that matches the kind of the resource;
|
||||
* `tabTitle: string` - the extension tab title.
|
||||
* `opts: Object` - additional options:
|
||||
* `icon: string` - the class name the represents the icon from the [https://fontawesome.com/](https://fontawesome.com/) library (e.g. 'fa-calendar-alt');
|
||||
|
||||
Below is an example of a resource tab extension:
|
||||
|
||||
```javascript
|
||||
((window) => {
|
||||
const component = () => {
|
||||
return React.createElement( 'div', {}, 'Hello World' );
|
||||
};
|
||||
window.extensionsAPI.registerResourceExtension(component, '*', '*', 'Nice extension');
|
||||
})(window)
|
||||
```
|
||||
|
||||
## Application Tab Extensions
|
||||
|
||||
Since the Argo CD Application is a Kubernetes resource, application tabs can be the same as any other resource tab.
|
||||
Make sure to use 'argoproj.io'/'Application' as group/kind and an extension will be used to render the application-level tab.
|
||||
@@ -63,7 +63,7 @@ or a randomly generated password stored in a secret (Argo CD 1.9 and later).
|
||||
## How to disable admin user?
|
||||
|
||||
Add `admin.enabled: "false"` to the `argocd-cm` ConfigMap (
|
||||
see [user management](operator-manual/user-management/index.md)).
|
||||
see [user management](./operator-manual/user-management/index.md)).
|
||||
|
||||
## Argo CD cannot deploy Helm Chart based applications without internet access, how can I solve it?
|
||||
|
||||
@@ -189,7 +189,7 @@ argocd ... --insecure
|
||||
## I have configured Dex via `dex.config` in `argocd-cm`, it still says Dex is unconfigured. Why?
|
||||
|
||||
Most likely you forgot to set the `url` in `argocd-cm` to point to your ArgoCD as well. See also
|
||||
[the docs](/operator-manual/user-management/#2-configure-argo-cd-for-sso).
|
||||
[the docs](./operator-manual/user-management/index.md#2-configure-argo-cd-for-sso).
|
||||
|
||||
## Why are `SealedSecret` resources reporting a `Status`?
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/st
|
||||
This default installation will have a self-signed certificate and cannot be accessed without a bit of extra work.
|
||||
Do one of:
|
||||
|
||||
* Follow the [instructions to configure a certificate](./operator-manual/tls) (and ensure that the client OS trusts it).
|
||||
* Follow the [instructions to configure a certificate](operator-manual/tls.md) (and ensure that the client OS trusts it).
|
||||
* Configure the client OS to trust the self signed certificate.
|
||||
* Use the --insecure flag on all Argo CD CLI operations in this guide.
|
||||
|
||||
|
||||
@@ -69,11 +69,16 @@ spec:
|
||||
kustomize:
|
||||
# Optional kustomize version. Note: version must be configured in argocd-cm ConfigMap
|
||||
version: v3.5.4
|
||||
# Optional image name prefix
|
||||
# Supported kustomize transformers. https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/
|
||||
namePrefix: prod-
|
||||
# Optional images passed to "kustomize edit set image".
|
||||
nameSuffix: -some-suffix
|
||||
commonLabels:
|
||||
foo: bar
|
||||
commonAnnotations:
|
||||
beep: boop
|
||||
images:
|
||||
- gcr.io/heptio-images/ks-guestbook-demo:0.2
|
||||
- my-app=gcr.io/my-repo/my-app:0.1
|
||||
|
||||
# directory
|
||||
directory:
|
||||
|
||||
@@ -107,32 +107,33 @@ Finally, the Matrix generator will combine both sets of outputs, and produce:
|
||||
## Restrictions
|
||||
|
||||
1. The Matrix generator currently only supports combining the outputs of only two child generators (eg does not support generating combinations for 3 or more).
|
||||
|
||||
1. You should specify only a single generator per array entry, eg this is not valid:
|
||||
```yaml
|
||||
- matrix:
|
||||
generators:
|
||||
- list: # (...)
|
||||
git: # (...)
|
||||
```
|
||||
|
||||
- matrix:
|
||||
generators:
|
||||
- list: # (...)
|
||||
git: # (...)
|
||||
|
||||
- While this *will* be accepted by Kubernetes API validation, the controller will report an error on generation. Each generator should be specified in a separate array element, as in the examples above.
|
||||
|
||||
1. The Matrix generator does not currently support [`template` overrides](Template.md#generator-templates) specified on child generators, eg this `template` will not be processed:
|
||||
```yaml
|
||||
- matrix:
|
||||
generators:
|
||||
- list:
|
||||
elements:
|
||||
- # (...)
|
||||
template: { } # Not processed
|
||||
```
|
||||
|
||||
- matrix:
|
||||
generators:
|
||||
- list:
|
||||
elements:
|
||||
- # (...)
|
||||
template: { } # Not processed
|
||||
|
||||
1. Combination-type generators (matrix or merge) can only be nested once. For example, this will not work:
|
||||
```yaml
|
||||
- matrix:
|
||||
generators:
|
||||
- matrix:
|
||||
generators:
|
||||
- matrix: # This third level is invalid.
|
||||
generators:
|
||||
- list:
|
||||
elements:
|
||||
- # (...)
|
||||
```
|
||||
|
||||
- matrix:
|
||||
generators:
|
||||
- matrix:
|
||||
generators:
|
||||
- matrix: # This third level is invalid.
|
||||
generators:
|
||||
- list:
|
||||
elements:
|
||||
- # (...)
|
||||
|
||||
@@ -114,31 +114,31 @@ When merged with the updated base parameters, the `values.redis` value for the p
|
||||
## Restrictions
|
||||
|
||||
1. You should specify only a single generator per array entry. This is not valid:
|
||||
```yaml
|
||||
- merge:
|
||||
generators:
|
||||
- list: # (...)
|
||||
git: # (...)
|
||||
```
|
||||
|
||||
- merge:
|
||||
generators:
|
||||
- list: # (...)
|
||||
git: # (...)
|
||||
|
||||
- While this *will* be accepted by Kubernetes API validation, the controller will report an error on generation. Each generator should be specified in a separate array element, as in the examples above.
|
||||
|
||||
1. The Merge generator does not support [`template` overrides](Template.md#generator-templates) specified on child generators. This `template` will not be processed:
|
||||
```yaml
|
||||
- merge:
|
||||
generators:
|
||||
- list:
|
||||
elements:
|
||||
- # (...)
|
||||
template: { } # Not processed
|
||||
```
|
||||
|
||||
- merge:
|
||||
generators:
|
||||
- list:
|
||||
elements:
|
||||
- # (...)
|
||||
template: { } # Not processed
|
||||
|
||||
1. Combination-type generators (Matrix or Merge) can only be nested once. For example, this will not work:
|
||||
```yaml
|
||||
- merge:
|
||||
generators:
|
||||
- merge:
|
||||
generators:
|
||||
- merge: # This third level is invalid.
|
||||
generators:
|
||||
- list:
|
||||
elements:
|
||||
- # (...)
|
||||
```
|
||||
|
||||
- merge:
|
||||
generators:
|
||||
- merge:
|
||||
generators:
|
||||
- merge: # This third level is invalid.
|
||||
generators:
|
||||
- list:
|
||||
elements:
|
||||
- # (...)
|
||||
|
||||
@@ -47,7 +47,7 @@ spec:
|
||||
# Labels is used to filter the PRs that you want to target. (optional)
|
||||
labels:
|
||||
- preview
|
||||
requeueAfterSeconds: 1800
|
||||
requeueAfterSeconds: 1800
|
||||
template:
|
||||
# ...
|
||||
```
|
||||
@@ -83,7 +83,7 @@ spec:
|
||||
key: token
|
||||
# many gitea deployments use TLS, but many are self-hosted and self-signed certificates
|
||||
insecure: true
|
||||
requeueAfterSeconds: 1800
|
||||
requeueAfterSeconds: 1800
|
||||
template:
|
||||
# ...
|
||||
```
|
||||
|
||||
@@ -27,7 +27,7 @@ spec:
|
||||
|
||||
## GitHub
|
||||
|
||||
The GitHub mode uses the GitHub API to scan and organization in either github.com or GitHub Enterprise.
|
||||
The GitHub mode uses the GitHub API to scan an organization in either github.com or GitHub Enterprise.
|
||||
|
||||
```yaml
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
@@ -76,7 +76,7 @@ spec:
|
||||
gitlab:
|
||||
# The base GitLab group to scan. You can either use the group id or the full namespaced path.
|
||||
group: "8675309"
|
||||
# For GitLab Enterprise:
|
||||
# For self-hosted GitLab:
|
||||
api: https://gitlab.example.com/
|
||||
# If true, scan every branch of every repository. If false, scan only the default branch. Defaults to false.
|
||||
allBranches: true
|
||||
@@ -91,7 +91,7 @@ spec:
|
||||
```
|
||||
|
||||
* `group`: Required name of the base GitLab group to scan. If you have multiple base groups, use multiple generators.
|
||||
* `api`: If using GitHub Enterprise, the URL to access it.
|
||||
* `api`: If using self-hosted GitLab, the URL to access it.
|
||||
* `allBranches`: By default (false) the template will only be evaluated for the default branch of each repo. If this is true, every branch of every repository will be passed to the filters. If using this flag, you likely want to use a `branchMatch` filter.
|
||||
* `includeSubgroups`: By default (false) the controller will only search for repos directly in the base group. If this is true, it will recurse through all the subgroups searching for repos to scan.
|
||||
* `tokenRef`: A `Secret` name and key containing the GitLab access token to use for requests. If not specified, will make anonymous requests which have a lower rate limit and can only see public repositories.
|
||||
|
||||
@@ -4,7 +4,7 @@ Generators are responsible for generating *parameters*, which are then rendered
|
||||
|
||||
Generators are primarily based on the data source that they use to generate the template parameters. For example: the List generator provides a set of parameters from a *literal list*, the Cluster generator uses the *Argo CD cluster list* as a source, the Git generator uses files/directories from a *Git repository*, and so.
|
||||
|
||||
As of this writing there are seven generators:
|
||||
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.
|
||||
- [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).
|
||||
|
||||
@@ -11,8 +11,8 @@ resources of Argo CD itself (like the RBAC ConfigMap).
|
||||
ApplicationSets can also quickly create an arbitrary number of Applications and just as quickly delete them.
|
||||
|
||||
Finally, ApplicationSets can reveal privileged information. For example, the [git generator](./Generators-Git.md) can
|
||||
read Secrets in the Argo CD namespace and send them to arbitrary URLs as auth headers. (This functionality is intended
|
||||
for authorizing requests to SCM providers like GitHub, but it could be abused by a malicious user.)
|
||||
read Secrets in the Argo CD namespace and send them to arbitrary URLs (e.g. URL provided for the `api` field) as auth headers.
|
||||
(This functionality is intended for authorizing requests to SCM providers like GitHub, but it could be abused by a malicious user.)
|
||||
|
||||
For these reasons, **only admins** may be given permission (via Kubernetes RBAC or any other mechanism) to create,
|
||||
update, or delete ApplicationSets.
|
||||
|
||||
@@ -36,8 +36,9 @@ data:
|
||||
help.chatUrl: "https://mycorp.slack.com/argo-cd"
|
||||
# the text for getting chat help, defaults to "Chat now!"
|
||||
help.chatText: "Chat now!"
|
||||
# The URLs to download additional ArgoCD binaries (besides the Linux amd64 binary included by default)
|
||||
# The URLs to download additional ArgoCD binaries (besides the Linux with current platform binary included by default)
|
||||
# for different OS architectures. If provided, additional download buttons will be displayed on the help page.
|
||||
help.download.linux-amd64: "path-or-url-to-download"
|
||||
help.download.linux-arm64: "path-or-url-to-download"
|
||||
help.download.linux-ppc64le: "path-or-url-to-download"
|
||||
help.download.linux-s390x: "path-or-url-to-download"
|
||||
|
||||
@@ -489,6 +489,7 @@ The secret data must include following fields:
|
||||
* `name` - cluster name
|
||||
* `server` - cluster api server url
|
||||
* `namespaces` - optional comma-separated list of namespaces which are accessible in that cluster. Cluster level resources would be ignored if namespace list is not empty.
|
||||
* `clusterResources` - optional boolean string (`"true"` or `"false"`) determining whether Argo CD can manage cluster-level resources on this cluster. This setting is used only if the list of managed namespaces is not empty.
|
||||
* `config` - JSON representation of following data structure:
|
||||
|
||||
```yaml
|
||||
|
||||
@@ -119,7 +119,7 @@ If the manifest generation has no side effects then requests are processed in pa
|
||||
* **Multiple Helm based applications pointing to the same directory in one Git repository:** ensure that your Helm chart don't have conditional
|
||||
[dependencies](https://helm.sh/docs/chart_best_practices/dependencies/#conditions-and-tags) and create `.argocd-allow-concurrency` file in chart directory.
|
||||
|
||||
* **Multiple Custom plugin based applications:** avoid creating temporal files during manifest generation and create `.argocd-allow-concurrency` file in app directory.
|
||||
* **Multiple Custom plugin based applications:** avoid creating temporal files during manifest generation and create `.argocd-allow-concurrency` file in app directory, or use the sidecar plugin option, which processes each application using a temporary copy of the repository.
|
||||
|
||||
* **Multiple Kustomize applications in same repository with [parameter overrides](../user-guide/parameters.md):** sorry, no workaround for now.
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ There are several ways how Ingress can be configured.
|
||||
|
||||
The Ambassador Edge Stack can be used as a Kubernetes ingress controller with [automatic TLS termination](https://www.getambassador.io/docs/latest/topics/running/tls/#host) and routing capabilities for both the CLI and the UI.
|
||||
|
||||
The API server should be run with TLS disabled. Edit the `argocd-server` deployment to add the `--insecure` flag to the argocd-server command. Given the `argocd` CLI includes the port number in the request `host` header, 2 Mappings are required.
|
||||
The API server should be run with TLS disabled. Edit the `argocd-server` deployment to add the `--insecure` flag to the argocd-server command, or simply set `server.insecure: "true"` in the `argocd-cmd-params-cm` ConfigMap [as described here](server-commands/additional-configuration-method.md). Given the `argocd` CLI includes the port number in the request `host` header, 2 Mappings are required.
|
||||
|
||||
### Option 1: Mapping CRD for Host-based Routing
|
||||
```yaml
|
||||
@@ -72,7 +72,7 @@ argocd login <host>:<port> --grpc-web-root-path /argo-cd
|
||||
## [Contour](https://projectcontour.io/)
|
||||
The Contour ingress controller can terminate TLS ingress traffic at the edge.
|
||||
|
||||
The Argo CD API server should be run with TLS disabled. Edit the `argocd-server` Deployment to add the `--insecure` flag to the argocd-server container command.
|
||||
The Argo CD API server should be run with TLS disabled. Edit the `argocd-server` Deployment to add the `--insecure` flag to the argocd-server container command, or simply set `server.insecure: "true"` in the `argocd-cmd-params-cm` ConfigMap [as described here](server-commands/additional-configuration-method.md).
|
||||
|
||||
It is also possible to provide an internal-only ingress path and an external-only ingress path by deploying two instances of Contour: one behind a private-subnet LoadBalancer service and one behind a public-subnet LoadBalancer service. The private Contour deployment will pick up Ingresses annotated with `kubernetes.io/ingress.class: contour-internal` and the public Contour deployment will pick up Ingresses annotated with `kubernetes.io/ingress.class: contour-external`.
|
||||
|
||||
@@ -164,20 +164,7 @@ spec:
|
||||
The argocd-server Service needs to be annotated with `projectcontour.io/upstream-protocol.h2c: "https,443"` to wire up the gRPC protocol proxying.
|
||||
|
||||
The API server should then be run with TLS disabled. Edit the `argocd-server` deployment to add the
|
||||
`--insecure` flag to the argocd-server command:
|
||||
|
||||
```yaml
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: argocd-server
|
||||
command:
|
||||
- /argocd-server
|
||||
- --repo-server
|
||||
- argocd-repo-server:8081
|
||||
- --insecure
|
||||
```
|
||||
`--insecure` flag to the argocd-server command, or simply set `server.insecure: "true"` in the `argocd-cmd-params-cm` ConfigMap [as described here](server-commands/additional-configuration-method.md).
|
||||
|
||||
## [kubernetes/ingress-nginx](https://github.com/kubernetes/ingress-nginx)
|
||||
|
||||
@@ -319,20 +306,7 @@ spec:
|
||||
```
|
||||
|
||||
The API server should then be run with TLS disabled. Edit the `argocd-server` deployment to add the
|
||||
`--insecure` flag to the argocd-server command:
|
||||
|
||||
```yaml
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: argocd-server
|
||||
command:
|
||||
- argocd-server
|
||||
- --repo-server
|
||||
- argocd-repo-server:8081
|
||||
- --insecure
|
||||
```
|
||||
`--insecure` flag to the argocd-server command, or simply set `server.insecure: "true"` in the `argocd-cmd-params-cm` ConfigMap [as described here](server-commands/additional-configuration-method.md).
|
||||
|
||||
The obvious disadvantage to this approach is that this technique requires two separate hostnames for
|
||||
the API server -- one for gRPC and the other for HTTP/HTTPS. However it allows TLS termination to
|
||||
@@ -345,7 +319,7 @@ Traefik can be used as an edge router and provide [TLS](https://docs.traefik.io/
|
||||
|
||||
It currently has an advantage over NGINX in that it can terminate both TCP and HTTP connections _on the same port_ meaning you do not require multiple hosts or paths.
|
||||
|
||||
The API server should be run with TLS disabled. Edit the `argocd-server` deployment to add the `--insecure` flag to the argocd-server command.
|
||||
The API server should be run with TLS disabled. Edit the `argocd-server` deployment to add the `--insecure` flag to the argocd-server command or set `server.insecure: "true"` in the `argocd-cmd-params-cm` ConfigMap [as described here](server-commands/additional-configuration-method.md).
|
||||
|
||||
### IngressRoute CRD
|
||||
```yaml
|
||||
@@ -455,26 +429,9 @@ If you need detail for all the options available for these Google integrations,
|
||||
|
||||
### Disable internal TLS
|
||||
|
||||
First, to avoid internal redirection loops from HTTP to HTTPS, the API server should be run with TLS disabled. Edit the argocd-server deployment to add the --insecure flag to the argocd-server command. For this you can edit your resource live with `kubectl -n argocd edit deployments.apps argocd-server` or use a kustomize patch before installing Argo CD.
|
||||
First, to avoid internal redirection loops from HTTP to HTTPS, the API server should be run with TLS disabled.
|
||||
|
||||
The container command should change from:
|
||||
```yaml
|
||||
containers:
|
||||
- command:
|
||||
- argocd-server
|
||||
- --staticassets
|
||||
- /shared/app
|
||||
```
|
||||
|
||||
To:
|
||||
```yaml
|
||||
containers:
|
||||
- command:
|
||||
- argocd-server
|
||||
- --insecure
|
||||
- --staticassets
|
||||
- /shared/app
|
||||
```
|
||||
Edit the `--insecure` flag in the `argocd-server` command of the argocd-server deployment, or simply set `server.insecure: "true"` in the `argocd-cmd-params-cm` ConfigMap [as described here](server-commands/additional-configuration-method.md).
|
||||
|
||||
### Creating a service
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ Not recommended for production use. This type of installation is typically used
|
||||
> Note: Argo CD CRDs are not included into [namespace-install.yaml](https://github.com/argoproj/argo-cd/blob/master/manifests/namespace-install.yaml).
|
||||
> and have to be installed separately. The CRD manifests are located in the [manifests/crds](https://github.com/argoproj/argo-cd/blob/master/manifests/crds) directory.
|
||||
> Use the following command to install them:
|
||||
> ```bash
|
||||
> ```
|
||||
> kubectl apply -k https://github.com/argoproj/argo-cd/manifests/crds\?ref\=stable
|
||||
> ```
|
||||
|
||||
|
||||
@@ -67,8 +67,10 @@ Scraped at the `argocd-server-metrics:8083/metrics` endpoint.
|
||||
| Metric | Type | Description |
|
||||
|--------|:----:|-------------|
|
||||
| `argocd_redis_request_duration` | histogram | Redis requests duration. |
|
||||
| `argocd_redis_request_total` | counter | Number of kubernetes requests executed during application reconciliation. |
|
||||
|
||||
| `argocd_redis_request_total` | counter | Number of kubernetes requests executed during application
|
||||
reconciliation. |
|
||||
| `grpc_server_handled_total` | counter | Total number of RPCs completed on the server, regardless of success or failure. |
|
||||
| `grpc_server_msg_sent_total` | counter | Total number of gRPC stream messages sent by the server. |
|
||||
## Repo Server Metrics
|
||||
Metrics about the Repo Server.
|
||||
Scraped at the `argocd-repo-server:8084/metrics` endpoint.
|
||||
|
||||
@@ -64,3 +64,23 @@ spec:
|
||||
# anywhere by Argo CD. It can be prematurely revoked by removing the entry from this list.
|
||||
jwtTokens:
|
||||
- iat: 1535390316
|
||||
|
||||
# Sync windows restrict when Applications may be synced. https://argo-cd.readthedocs.io/en/stable/user-guide/sync_windows/
|
||||
syncWindows:
|
||||
- kind: allow
|
||||
schedule: '10 1 * * *'
|
||||
duration: 1h
|
||||
applications:
|
||||
- '*-prod'
|
||||
manualSync: true
|
||||
- kind: deny
|
||||
schedule: '0 22 * * *'
|
||||
duration: 1h
|
||||
namespaces:
|
||||
- default
|
||||
- kind: allow
|
||||
schedule: '0 23 * * *'
|
||||
duration: 1h
|
||||
clusters:
|
||||
- in-cluster
|
||||
- cluster1
|
||||
|
||||
@@ -107,7 +107,7 @@ p, role:staging-db-admins, projects, get, staging-db-admins, allow
|
||||
g, db-admins, role:staging-db-admins
|
||||
```
|
||||
|
||||
This example defines a *role* called `staging-db-admins` with *eight permissions* that allow that role to perform the *actions* (`create`/`delete`/`get`/`override`/`sync`/`update` applications, `get` logs, `create` exec and `get` appprojects) against `*` (all) objects in the `staging-db-admins` Argo CD AppProject.
|
||||
This example defines a *role* called `staging-db-admins` with *nine permissions* that allow that role to perform the *actions* (`create`/`delete`/`get`/`override`/`sync`/`update` applications, `get` logs, `create` exec and `get` appprojects) against `*` (all) objects in the `staging-db-admins` Argo CD AppProject.
|
||||
|
||||
## Anonymous Access
|
||||
|
||||
|
||||
@@ -14,3 +14,76 @@ Note that bundled Helm has been upgraded from 3.6.0 to v3.7+. This includes foll
|
||||
- Experimental OCI support has been rewritten.
|
||||
|
||||
More information in the [Helm v3.7.0 release notes](https://github.com/helm/helm/releases/tag/v3.7.0).
|
||||
|
||||
## Support for private repo SSH keys using the SHA-1 signature hash algorithm is removed in 2.2.12
|
||||
|
||||
Argo CD 2.2.12 upgraded its base image from Ubuntu 21.10 to Ubuntu 22.04, which upgraded OpenSSH to 8.9. OpenSSH starting
|
||||
with 8.8 [dropped support for the `ssh-rsa` SHA-1 key signature algorithm](https://www.openssh.com/txt/release-8.8).
|
||||
|
||||
The signature algorithm is _not_ the same as the algorithm used when generating the key. There is no need to update
|
||||
keys.
|
||||
|
||||
The signature algorithm is negotiated with the SSH server when the connection is being set up. The client offers its
|
||||
list of accepted signature algorithms, and if the server has a match, the connection proceeds. For most SSH servers on
|
||||
up-to-date git providers, acceptable algorithms other than `ssh-rsa` should be available.
|
||||
|
||||
Before upgrading to Argo CD 2.2.12, check whether your git provider(s) using SSH authentication support algorithms newer
|
||||
than `rsa-ssh`.
|
||||
|
||||
1. Make sure your version of SSH >= 8.9 (the version used by Argo CD). If not, upgrade it before proceeding.
|
||||
|
||||
```shell
|
||||
ssh -V
|
||||
```
|
||||
|
||||
Example output: `OpenSSH_8.9p1 Ubuntu-3, OpenSSL 3.0.2 15 Mar 2022`
|
||||
|
||||
2. Once you have a recent version of OpenSSH, follow the directions from the [OpenSSH 8.8 release notes](https://www.openssh.com/txt/release-8.7):
|
||||
|
||||
> To check whether a server is using the weak ssh-rsa public key
|
||||
> algorithm, for host authentication, try to connect to it after
|
||||
> removing the ssh-rsa algorithm from ssh(1)'s allowed list:
|
||||
>
|
||||
> ```shell
|
||||
> ssh -oHostKeyAlgorithms=-ssh-rsa user@host
|
||||
> ```
|
||||
>
|
||||
> If the host key verification fails and no other supported host key
|
||||
> types are available, the server software on that host should be
|
||||
> upgraded.
|
||||
|
||||
If the server does not support an acceptable version, you will get an error similar to this;
|
||||
|
||||
```
|
||||
$ ssh -oHostKeyAlgorithms=-ssh-rsa vs-ssh.visualstudio.com
|
||||
Unable to negotiate with 20.42.134.1 port 22: no matching host key type found. Their offer: ssh-rsa
|
||||
```
|
||||
|
||||
This indicates that the server needs to update its supported key signature algorithms, and Argo CD will not connect
|
||||
to it.
|
||||
|
||||
### Workaround
|
||||
|
||||
The [OpenSSH 8.8 release notes](https://www.openssh.com/txt/release-8.8) describe a workaround if you cannot change the
|
||||
server's key signature algorithms configuration.
|
||||
|
||||
> Incompatibility is more likely when connecting to older SSH
|
||||
> implementations that have not been upgraded or have not closely tracked
|
||||
> improvements in the SSH protocol. For these cases, it may be necessary
|
||||
> to selectively re-enable RSA/SHA1 to allow connection and/or user
|
||||
> authentication via the HostkeyAlgorithms and PubkeyAcceptedAlgorithms
|
||||
> options. For example, the following stanza in ~/.ssh/config will enable
|
||||
> RSA/SHA1 for host and user authentication for a single destination host:
|
||||
>
|
||||
> ```
|
||||
> Host old-host
|
||||
> HostkeyAlgorithms +ssh-rsa
|
||||
> PubkeyAcceptedAlgorithms +ssh-rsa
|
||||
> ```
|
||||
>
|
||||
> We recommend enabling RSA/SHA1 only as a stopgap measure until legacy
|
||||
> implementations can be upgraded or reconfigured with another key type
|
||||
> (such as ECDSA or Ed25519).
|
||||
|
||||
To apply this to Argo CD, you could create a ConfigMap with the desired ssh config file and then mount it at
|
||||
`/home/argocd/.ssh/config`.
|
||||
|
||||
@@ -46,3 +46,77 @@ Note that bundled Kustomize version has been upgraded from 4.2.0 to 4.4.1.
|
||||
## Upgraded Helm Version
|
||||
|
||||
Note that bundled Helm version has been upgraded from 3.7.1 to 3.8.0.
|
||||
|
||||
## Support for private repo SSH keys using the SHA-1 signature hash algorithm is removed in 2.3.7
|
||||
|
||||
Argo CD 2.3.7 upgraded its base image from Ubuntu 21.04 to Ubuntu 22.04, which upgraded OpenSSH to 8.9. OpenSSH starting
|
||||
with 8.8 [dropped support for the `ssh-rsa` SHA-1 key signature algorithm](https://www.openssh.com/txt/release-8.8).
|
||||
|
||||
The signature algorithm is _not_ the same as the algorithm used when generating the key. There is no need to update
|
||||
keys.
|
||||
|
||||
The signature algorithm is negotiated with the SSH server when the connection is being set up. The client offers its
|
||||
list of accepted signature algorithms, and if the server has a match, the connection proceeds. For most SSH servers on
|
||||
up-to-date git providers, acceptable algorithms other than `ssh-rsa` should be available.
|
||||
|
||||
Before upgrading to Argo CD 2.3.7, check whether your git provider(s) using SSH authentication support algorithms newer
|
||||
than `rsa-ssh`.
|
||||
|
||||
1. Make sure your version of SSH >= 8.9 (the version used by Argo CD). If not, upgrade it before proceeding.
|
||||
|
||||
```shell
|
||||
ssh -V
|
||||
```
|
||||
|
||||
Example output: `OpenSSH_8.9p1 Ubuntu-3, OpenSSL 3.0.2 15 Mar 2022`
|
||||
|
||||
2. Once you have a recent version of OpenSSH, follow the directions from the [OpenSSH 8.8 release notes](https://www.openssh.com/txt/release-8.7):
|
||||
|
||||
> To check whether a server is using the weak ssh-rsa public key
|
||||
> algorithm, for host authentication, try to connect to it after
|
||||
> removing the ssh-rsa algorithm from ssh(1)'s allowed list:
|
||||
>
|
||||
> ```shell
|
||||
> ssh -oHostKeyAlgorithms=-ssh-rsa user@host
|
||||
> ```
|
||||
>
|
||||
> If the host key verification fails and no other supported host key
|
||||
> types are available, the server software on that host should be
|
||||
> upgraded.
|
||||
|
||||
If the server does not support an acceptable version, you will get an error similar to this;
|
||||
|
||||
```
|
||||
$ ssh -oHostKeyAlgorithms=-ssh-rsa vs-ssh.visualstudio.com
|
||||
Unable to negotiate with 20.42.134.1 port 22: no matching host key type found. Their offer: ssh-rsa
|
||||
```
|
||||
|
||||
This indicates that the server needs to update its supported key signature algorithms, and Argo CD will not connect
|
||||
to it.
|
||||
|
||||
### Workaround
|
||||
|
||||
The [OpenSSH 8.8 release notes](https://www.openssh.com/txt/release-8.8) describe a workaround if you cannot change the
|
||||
server's key signature algorithms configuration.
|
||||
|
||||
> Incompatibility is more likely when connecting to older SSH
|
||||
> implementations that have not been upgraded or have not closely tracked
|
||||
> improvements in the SSH protocol. For these cases, it may be necessary
|
||||
> to selectively re-enable RSA/SHA1 to allow connection and/or user
|
||||
> authentication via the HostkeyAlgorithms and PubkeyAcceptedAlgorithms
|
||||
> options. For example, the following stanza in ~/.ssh/config will enable
|
||||
> RSA/SHA1 for host and user authentication for a single destination host:
|
||||
>
|
||||
> ```
|
||||
> Host old-host
|
||||
> HostkeyAlgorithms +ssh-rsa
|
||||
> PubkeyAcceptedAlgorithms +ssh-rsa
|
||||
> ```
|
||||
>
|
||||
> We recommend enabling RSA/SHA1 only as a stopgap measure until legacy
|
||||
> implementations can be upgraded or reconfigured with another key type
|
||||
> (such as ECDSA or Ed25519).
|
||||
|
||||
To apply this to Argo CD, you could create a ConfigMap with the desired ssh config file and then mount it at
|
||||
`/home/argocd/.ssh/config`.
|
||||
|
||||
|
||||
@@ -12,6 +12,8 @@ Helm 2 support was preserved in the Argo CD. We feel that Helm 3 is stable, and
|
||||
|
||||
## Support for private repo SSH keys using the SHA-1 signature hash algorithm is removed
|
||||
|
||||
Note: this change was back-ported to 2.3.7 and 2.2.12.
|
||||
|
||||
Argo CD 2.4 upgraded its base image from Ubuntu 20.04 to Ubuntu 22.04, which upgraded OpenSSH to 8.9. OpenSSH starting
|
||||
with 8.8 [dropped support for the `ssh-rsa` SHA-1 key signature algorithm](https://www.openssh.com/txt/release-8.8).
|
||||
|
||||
@@ -105,20 +107,26 @@ p, role:org-admin, *, create, my-proj/*, allow
|
||||
New:
|
||||
|
||||
```csv
|
||||
p, role: org-admin, clusters, create, my-proj/*, allow
|
||||
p, role: org-admin, projects, create, my-proj/*, allow
|
||||
p, role: org-admin, applications, create, my-proj/*, allow
|
||||
p, role: org-admin, repositories, create, my-proj/*, allow
|
||||
p, role: org-admin, certificates, create, my-proj/*, allow
|
||||
p, role: org-admin, accounts, create, my-proj/*, allow
|
||||
p, role: org-admin, gpgkeys, create, my-proj/*, allow
|
||||
p, role:org-admin, clusters, create, my-proj/*, allow
|
||||
p, role:org-admin, projects, create, my-proj/*, allow
|
||||
p, role:org-admin, applications, create, my-proj/*, allow
|
||||
p, role:org-admin, repositories, create, my-proj/*, allow
|
||||
p, role:org-admin, certificates, create, my-proj/*, allow
|
||||
p, role:org-admin, accounts, create, my-proj/*, allow
|
||||
p, role:org-admin, gpgkeys, create, my-proj/*, allow
|
||||
```
|
||||
|
||||
## Enable logs RBAC enforcement
|
||||
|
||||
2.4 introduced `logs` as a new RBAC resource. In 2.3, users with `applications, get` access automatically get logs
|
||||
access. In 2.5, you will have to explicitly grant `logs, get` access. Logs RBAC enforcement can be enabled with a flag
|
||||
in 2.4. We recommend enabling the flag now for an easier upgrade experience in 2.5.
|
||||
access. <del>In 2.5, you will have to explicitly grant `logs, get` access. Logs RBAC enforcement can be enabled with a flag
|
||||
in 2.4. We recommend enabling the flag now for an easier upgrade experience in 2.5.</del>
|
||||
|
||||
!!! important
|
||||
Logs RBAC enforcement **will not** be enabled by default in 2.5. This decision
|
||||
[was made](https://github.com/argoproj/argo-cd/issues/10551#issuecomment-1242303457) to avoid breaking logs access
|
||||
under [Project Roles](../../user-guide/projects.md#project-roles), which do not provide a mechanism to grant `logs`
|
||||
resource access.
|
||||
|
||||
To enabled logs RBAC enforcement, add this to your argocd-cm ConfigMap:
|
||||
|
||||
@@ -149,9 +157,13 @@ p, role:test-db-admins, applications, *, staging-db-admins/*, allow
|
||||
p, role:test-db-admins, logs, get, staging-db-admins/*, allow
|
||||
```
|
||||
|
||||
## Known UI issue
|
||||
### Pod Logs UI
|
||||
|
||||
Currently, upon pressing the "LOGS" tab in pod view by users who don't have an explicit allow get logs policy, the red "unable to load data: Internal error" is received in the bottom of the screen, and "Failed to load data, please try again" is displayed.
|
||||
Since 2.4.9, the LOGS tab in pod view is visible in the UI only for users with explicit allow get logs policy.
|
||||
|
||||
### Known pod logs UI issue prior to 2.4.9
|
||||
|
||||
Upon pressing the "LOGS" tab in pod view by users who don't have an explicit allow get logs policy, the red "unable to load data: Internal error" is received in the bottom of the screen, and "Failed to load data, please try again" is displayed.
|
||||
|
||||
## Test repo-server with its new dedicated Service Account
|
||||
|
||||
|
||||
@@ -231,7 +231,7 @@ data:
|
||||
|
||||
### Requesting additional ID token claims
|
||||
|
||||
By default Dex only retrieves the profile and email scopes. In order to retrieve more more claims you
|
||||
By default Dex only retrieves the profile and email scopes. In order to retrieve more claims you
|
||||
can add them under the `scopes` entry in the Dex configuration. To enable group claims through Dex,
|
||||
`insecureEnableGroups` also needs to enabled. Group information is currently only refreshed at authentication
|
||||
time and support to refresh group information more dynamically can be tracked here: [dexidp/dex#1065](https://github.com/dexidp/dex/issues/1065).
|
||||
|
||||
@@ -36,24 +36,24 @@
|
||||
1. Edit `argocd-cm` and add the following `dex.config` to the data section, replacing the `caData`, `my-argo-cd-url` and `my-login-url` your values from the Azure AD App:
|
||||
|
||||
data:
|
||||
url: https://my-argo-cd-url
|
||||
dex.config: |
|
||||
logger:
|
||||
url: https://my-argo-cd-url
|
||||
dex.config: |
|
||||
logger:
|
||||
level: debug
|
||||
format: json
|
||||
connectors:
|
||||
- type: saml
|
||||
connectors:
|
||||
- type: saml
|
||||
id: saml
|
||||
name: saml
|
||||
config:
|
||||
entityIssuer: https://my-argo-cd-url/api/dex/callback
|
||||
ssoURL: https://my-login-url (e.g. https://login.microsoftonline.com/xxxxx/a/saml2)
|
||||
caData: |
|
||||
MY-BASE64-ENCODED-CERTIFICATE-DATA
|
||||
redirectURI: https://my-argo-cd-url/api/dex/callback
|
||||
usernameAttr: email
|
||||
emailAttr: email
|
||||
groupsAttr: Group
|
||||
entityIssuer: https://my-argo-cd-url/api/dex/callback
|
||||
ssoURL: https://my-login-url (e.g. https://login.microsoftonline.com/xxxxx/a/saml2)
|
||||
caData: |
|
||||
MY-BASE64-ENCODED-CERTIFICATE-DATA
|
||||
redirectURI: https://my-argo-cd-url/api/dex/callback
|
||||
usernameAttr: email
|
||||
emailAttr: email
|
||||
groupsAttr: Group
|
||||
|
||||
2. Edit `argocd-rbac-cm` to configure permissions, similar to example below.
|
||||
- Use Azure AD `Group IDs` for assigning roles.
|
||||
@@ -169,7 +169,7 @@
|
||||
p, role:org-admin, repositories, update, *, allow
|
||||
p, role:org-admin, repositories, delete, *, allow
|
||||
g, "84ce98d1-e359-4f3b-85af-985b458de3c6", role:org-admin
|
||||
scopes: '[roles, email]'
|
||||
scopes: '[groups, email]'
|
||||
|
||||
Refer to [operator-manual/argocd-rbac-cm.yaml](https://github.com/argoproj/argo-cd/blob/master/docs/operator-manual/argocd-rbac-cm.yaml) for all of the available variables.
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ argocd login cd.argoproj.io --core
|
||||
-h, --help help for login
|
||||
--name string name to use for the context
|
||||
--password string the password of an account to authenticate
|
||||
--skip-test-tls Skip testing whether the server is configured with TLS (this can help when the command hangs for no apparent reason)
|
||||
--sso perform SSO login
|
||||
--sso-port int port to run local OAuth2 login application (default 8085)
|
||||
--username string the username of an account to authenticate
|
||||
|
||||
@@ -14,7 +14,7 @@ There are two ways to install a Config Management Plugin (CMP):
|
||||
1. Add the plugin config to the Argo CD ConfigMap. The repo-server container will run your plugin's commands.
|
||||
This is a good option for a simple plugin that requires only a few lines of code that fit nicely in the Argo CD ConfigMap.
|
||||
2. Add the plugin as a sidecar to the repo-server Pod.
|
||||
This is a good option for a more complex plugin that would clutter the Argo CD ConfigMap.
|
||||
This is a good option for a more complex plugin that would clutter the Argo CD ConfigMap. A copy of the repository is sent to the sidecar container as a tarball and processed individually per application, which makes it a good option for [concurrent processing of monorepos](../operator-manual/high_availability.md#enable-concurrent-processing).
|
||||
|
||||
### Option 1: Configure plugins via Argo CD configmap
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ data:
|
||||
- '.webhooks[]?.clientConfig.caBundle'
|
||||
```
|
||||
|
||||
Resource customization can also be configured to ignore all differences made by a managedField.manager at the system level. The example bellow shows how to configure ArgoCD to ignore changes made by `kube-controller-manager` in `Deployment` resources.
|
||||
Resource customization can also be configured to ignore all differences made by a managedField.manager at the system level. The example bellow shows how to configure Argo CD to ignore changes made by `kube-controller-manager` in `Deployment` resources.
|
||||
|
||||
```yaml
|
||||
data:
|
||||
@@ -90,7 +90,7 @@ data:
|
||||
- kube-controller-manager
|
||||
```
|
||||
|
||||
It is possible to configure ignoreDifferences to be applied to all resources in every Application managed by an ArgoCD instance. In order to do so, resource customizations can be configured like in the example bellow:
|
||||
It is possible to configure ignoreDifferences to be applied to all resources in every Application managed by an Argo CD instance. In order to do so, resource customizations can be configured like in the example bellow:
|
||||
|
||||
```yaml
|
||||
data:
|
||||
@@ -116,11 +116,26 @@ data:
|
||||
|
||||
By default `status` field is ignored during diffing for `CustomResourceDefinition` resource. The behavior can be extended to all resources using `all` value or disabled using `none`.
|
||||
|
||||
### Ignoring RBAC changes made by AggregateRoles
|
||||
|
||||
If you are using [Aggregated ClusterRoles](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#aggregated-clusterroles) and don't want Argo CD to detect the `rules` changes as drift, you can set `resource.compareoptions.ignoreAggregatedRoles: true`. Then Argo CD will no longer detect these changes as an event that requires syncing.
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: argocd-cm
|
||||
data:
|
||||
resource.compareoptions: |
|
||||
# disables status field diffing in specified resource types
|
||||
ignoreAggregatedRoles: true
|
||||
```
|
||||
|
||||
## Known Kubernetes types in CRDs (Resource limits, Volume mounts etc)
|
||||
|
||||
Some CRDs are re-using data structures defined in the Kubernetes source base and therefore inheriting custom
|
||||
JSON/YAML marshaling. Custom marshalers might serialize CRDs in a slightly different format that causes false
|
||||
positives during drift detection.
|
||||
positives during drift detection.
|
||||
|
||||
A typical example is the `argoproj.io/Rollout` CRD that re-using `core/v1/PodSpec` data structure. Pod resource requests
|
||||
might be reformatted by the custom marshaller of `IntOrString` data type:
|
||||
@@ -140,7 +155,7 @@ resources:
|
||||
```
|
||||
|
||||
The solution is to specify which CRDs fields are using built-in Kubernetes types in the `resource.customizations`
|
||||
section of `argocd-cm` ConfigMap:
|
||||
section of `argocd-cm` ConfigMap:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Sync Options
|
||||
|
||||
ArgoCD allows users to customize some aspects of how it syncs the desired state in the target cluster. Some Sync Options can defined as annotations in a specific resource. Most of the Sync Options are configured in the Application resource `spec.syncPolicy.syncOptions` attribute.
|
||||
Argo CD allows users to customize some aspects of how it syncs the desired state in the target cluster. Some Sync Options can defined as annotations in a specific resource. Most of the Sync Options are configured in the Application resource `spec.syncPolicy.syncOptions` attribute. Multiple Sync Options which are configured with the `argocd.argoproj.io/sync-options` annotation can be concatenated with a `,` in the annotation value; white spaces will be trimmed.
|
||||
|
||||
Below you can find details about each available Sync Option:
|
||||
|
||||
@@ -187,3 +187,17 @@ spec:
|
||||
```
|
||||
|
||||
The example above shows how an ArgoCD Application can be configured so it will ignore the `spec.replicas` field from the desired state (git) during the sync stage. This is achieve by calculating and pre-patching the desired state before applying it in the cluster. Note that the `RespectIgnoreDifferences` sync option is only effective when the resource is already created in the cluster. If the Application is being created and no live state exists, the desired state is applied as-is.
|
||||
|
||||
## Create Namespace
|
||||
|
||||
```yaml
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
namespace: test
|
||||
spec:
|
||||
syncPolicy:
|
||||
syncOptions:
|
||||
- CreateNamespace=true
|
||||
```
|
||||
The example above shows how an Argo CD Application can be configured so it will create namespaces for the Application resources if the namespaces don't exist already. Without this either declared in the Application manifest or passed in the cli via `--sync-option CreateNamespace=true`, the Application will fail to sync if the resources' namespaces do not exist.
|
||||
|
||||
5
go.mod
5
go.mod
@@ -9,7 +9,7 @@ require (
|
||||
github.com/TomOnTime/utfutil v0.0.0-20180511104225-09c41003ee1d
|
||||
github.com/alicebob/miniredis v2.5.0+incompatible
|
||||
github.com/alicebob/miniredis/v2 v2.14.2
|
||||
github.com/argoproj/gitops-engine v0.7.0
|
||||
github.com/argoproj/gitops-engine v0.7.3
|
||||
github.com/argoproj/notifications-engine v0.3.1-0.20220430155844-567361917320
|
||||
github.com/argoproj/pkg v0.11.1-0.20211203175135-36c59d8fafe0
|
||||
github.com/aws/aws-sdk-go v1.38.49
|
||||
@@ -257,6 +257,9 @@ replace (
|
||||
github.com/grpc-ecosystem/grpc-gateway => github.com/grpc-ecosystem/grpc-gateway v1.16.0
|
||||
github.com/improbable-eng/grpc-web => github.com/improbable-eng/grpc-web v0.0.0-20181111100011-16092bd1d58a
|
||||
|
||||
// Avoid CVE-2022-28948
|
||||
gopkg.in/yaml.v3 => gopkg.in/yaml.v3 v3.0.1
|
||||
|
||||
// https://github.com/kubernetes/kubernetes/issues/79384#issuecomment-505627280
|
||||
k8s.io/api => k8s.io/api v0.23.1
|
||||
k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.23.1
|
||||
|
||||
10
go.sum
10
go.sum
@@ -146,8 +146,8 @@ github.com/antonmedv/expr v1.8.9/go.mod h1:5qsM3oLGDND7sDmQGDXHkYfkjYMUX14qsgqmH
|
||||
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||
github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||
github.com/appscode/go v0.0.0-20190808133642-1d4ef1f1c1e0/go.mod h1:iy07dV61Z7QQdCKJCIvUoDL21u6AIceRhZzyleh2ymc=
|
||||
github.com/argoproj/gitops-engine v0.7.0 h1:X6W8VP9bWTe74wWxAV3i8KZ0yBmre5DU8g+GWH09FCo=
|
||||
github.com/argoproj/gitops-engine v0.7.0/go.mod h1:pRgVpLW7pZqf7n3COJ7UcDepk4cI61LAcJd64Q3Jq/c=
|
||||
github.com/argoproj/gitops-engine v0.7.3 h1:0ZlRTReAJG5Y1PviQ8ZIJq/+VowxWe2uFwoXqYcbtXU=
|
||||
github.com/argoproj/gitops-engine v0.7.3/go.mod h1:pRgVpLW7pZqf7n3COJ7UcDepk4cI61LAcJd64Q3Jq/c=
|
||||
github.com/argoproj/notifications-engine v0.3.1-0.20220430155844-567361917320 h1:XDjtTfccs4rSOT1n+i1zV9RpxQdKky1b4YBic16E0qY=
|
||||
github.com/argoproj/notifications-engine v0.3.1-0.20220430155844-567361917320/go.mod h1:R3zlopt+/juYlebQc9Jarn9vBQ2xZruWOWjUNkfGY9M=
|
||||
github.com/argoproj/pkg v0.11.1-0.20211203175135-36c59d8fafe0 h1:Cfp7rO/HpVxnwlRqJe0jHiBbZ77ZgXhB6HWlYD02Xdc=
|
||||
@@ -1814,10 +1814,8 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
|
||||
gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0=
|
||||
gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
|
||||
|
||||
@@ -35,7 +35,7 @@ spec:
|
||||
runAsNonRoot: true
|
||||
containers:
|
||||
- name: dex
|
||||
image: ghcr.io/dexidp/dex:v2.30.2
|
||||
image: ghcr.io/dexidp/dex:v2.35.0-distroless
|
||||
imagePullPolicy: Always
|
||||
command: [/shared/argocd-dex, rundex]
|
||||
securityContext:
|
||||
|
||||
@@ -5,7 +5,7 @@ kind: Kustomization
|
||||
images:
|
||||
- name: quay.io/argoproj/argocd
|
||||
newName: quay.io/argoproj/argocd
|
||||
newTag: v2.4.7
|
||||
newTag: v2.4.13
|
||||
resources:
|
||||
- ./application-controller
|
||||
- ./dex
|
||||
|
||||
@@ -21,7 +21,7 @@ spec:
|
||||
serviceAccountName: argocd-redis
|
||||
containers:
|
||||
- name: redis
|
||||
image: redis:7.0.0-alpine
|
||||
image: redis:7.0.4-alpine
|
||||
imagePullPolicy: Always
|
||||
args:
|
||||
- "--save"
|
||||
|
||||
@@ -9385,7 +9385,7 @@ spec:
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.namespace
|
||||
image: quay.io/argoproj/argocd:v2.4.7
|
||||
image: quay.io/argoproj/argocd:v2.4.13
|
||||
imagePullPolicy: Always
|
||||
name: argocd-applicationset-controller
|
||||
ports:
|
||||
@@ -9465,7 +9465,7 @@ spec:
|
||||
- ""
|
||||
- --appendonly
|
||||
- "no"
|
||||
image: redis:7.0.0-alpine
|
||||
image: redis:7.0.4-alpine
|
||||
imagePullPolicy: Always
|
||||
name: redis
|
||||
ports:
|
||||
@@ -9615,7 +9615,7 @@ spec:
|
||||
value: /helm-working-dir
|
||||
- name: HELM_DATA_HOME
|
||||
value: /helm-working-dir
|
||||
image: quay.io/argoproj/argocd:v2.4.7
|
||||
image: quay.io/argoproj/argocd:v2.4.13
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -9664,7 +9664,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /var/run/argocd/argocd-cmp-server
|
||||
image: quay.io/argoproj/argocd:v2.4.7
|
||||
image: quay.io/argoproj/argocd:v2.4.13
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -9851,7 +9851,7 @@ spec:
|
||||
key: otlp.address
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.4.7
|
||||
image: quay.io/argoproj/argocd:v2.4.13
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
|
||||
@@ -12,4 +12,4 @@ resources:
|
||||
images:
|
||||
- name: quay.io/argoproj/argocd
|
||||
newName: quay.io/argoproj/argocd
|
||||
newTag: v2.4.7
|
||||
newTag: v2.4.13
|
||||
|
||||
@@ -11,7 +11,7 @@ patchesStrategicMerge:
|
||||
images:
|
||||
- name: quay.io/argoproj/argocd
|
||||
newName: quay.io/argoproj/argocd
|
||||
newTag: v2.4.7
|
||||
newTag: v2.4.13
|
||||
resources:
|
||||
- ../../base/application-controller
|
||||
- ../../base/applicationset-controller
|
||||
|
||||
@@ -770,7 +770,7 @@ spec:
|
||||
topologyKey: kubernetes.io/hostname
|
||||
initContainers:
|
||||
- name: config-init
|
||||
image: haproxy:2.0.25-alpine
|
||||
image: haproxy:2.0.29-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
resources:
|
||||
{}
|
||||
@@ -790,7 +790,7 @@ spec:
|
||||
runAsUser: 1000
|
||||
containers:
|
||||
- name: haproxy
|
||||
image: haproxy:2.0.25-alpine
|
||||
image: haproxy:2.0.29-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -878,7 +878,7 @@ spec:
|
||||
automountServiceAccountToken: false
|
||||
initContainers:
|
||||
- name: config-init
|
||||
image: redis:7.0.0-alpine
|
||||
image: redis:7.0.4-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
resources:
|
||||
{}
|
||||
@@ -906,7 +906,7 @@ spec:
|
||||
|
||||
containers:
|
||||
- name: redis
|
||||
image: redis:7.0.0-alpine
|
||||
image: redis:7.0.4-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
command:
|
||||
- redis-server
|
||||
@@ -947,7 +947,7 @@ spec:
|
||||
lifecycle:
|
||||
{}
|
||||
- name: sentinel
|
||||
image: redis:7.0.0-alpine
|
||||
image: redis:7.0.4-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
command:
|
||||
- redis-sentinel
|
||||
|
||||
@@ -9,12 +9,12 @@ redis-ha:
|
||||
haproxy:
|
||||
enabled: true
|
||||
image:
|
||||
tag: 2.0.25-alpine
|
||||
tag: 2.0.29-alpine
|
||||
timeout:
|
||||
server: 6m
|
||||
client: 6m
|
||||
checkInterval: 3s
|
||||
image:
|
||||
tag: 7.0.0-alpine
|
||||
tag: 7.0.4-alpine
|
||||
sentinel:
|
||||
bind: "0.0.0.0"
|
||||
|
||||
@@ -10320,7 +10320,7 @@ spec:
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.namespace
|
||||
image: quay.io/argoproj/argocd:v2.4.7
|
||||
image: quay.io/argoproj/argocd:v2.4.13
|
||||
imagePullPolicy: Always
|
||||
name: argocd-applicationset-controller
|
||||
ports:
|
||||
@@ -10392,7 +10392,7 @@ spec:
|
||||
- command:
|
||||
- /shared/argocd-dex
|
||||
- rundex
|
||||
image: ghcr.io/dexidp/dex:v2.30.2
|
||||
image: ghcr.io/dexidp/dex:v2.35.0-distroless
|
||||
imagePullPolicy: Always
|
||||
name: dex
|
||||
ports:
|
||||
@@ -10417,7 +10417,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /shared/argocd-dex
|
||||
image: quay.io/argoproj/argocd:v2.4.7
|
||||
image: quay.io/argoproj/argocd:v2.4.13
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
securityContext:
|
||||
@@ -10457,7 +10457,7 @@ spec:
|
||||
containers:
|
||||
- command:
|
||||
- argocd-notifications
|
||||
image: quay.io/argoproj/argocd:v2.4.7
|
||||
image: quay.io/argoproj/argocd:v2.4.13
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
@@ -10526,7 +10526,7 @@ spec:
|
||||
app.kubernetes.io/name: argocd-redis-ha-haproxy
|
||||
topologyKey: kubernetes.io/hostname
|
||||
containers:
|
||||
- image: haproxy:2.0.25-alpine
|
||||
- image: haproxy:2.0.29-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
lifecycle: {}
|
||||
livenessProbe:
|
||||
@@ -10555,7 +10555,7 @@ spec:
|
||||
- /readonly/haproxy_init.sh
|
||||
command:
|
||||
- sh
|
||||
image: haproxy:2.0.25-alpine
|
||||
image: haproxy:2.0.29-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: config-init
|
||||
volumeMounts:
|
||||
@@ -10714,7 +10714,7 @@ spec:
|
||||
value: /helm-working-dir
|
||||
- name: HELM_DATA_HOME
|
||||
value: /helm-working-dir
|
||||
image: quay.io/argoproj/argocd:v2.4.7
|
||||
image: quay.io/argoproj/argocd:v2.4.13
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -10763,7 +10763,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /var/run/argocd/argocd-cmp-server
|
||||
image: quay.io/argoproj/argocd:v2.4.7
|
||||
image: quay.io/argoproj/argocd:v2.4.13
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -11010,7 +11010,7 @@ spec:
|
||||
key: otlp.address
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.4.7
|
||||
image: quay.io/argoproj/argocd:v2.4.13
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -11218,7 +11218,7 @@ spec:
|
||||
key: otlp.address
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.4.7
|
||||
image: quay.io/argoproj/argocd:v2.4.13
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -11299,7 +11299,7 @@ spec:
|
||||
- /data/conf/redis.conf
|
||||
command:
|
||||
- redis-server
|
||||
image: redis:7.0.0-alpine
|
||||
image: redis:7.0.4-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
lifecycle: {}
|
||||
livenessProbe:
|
||||
@@ -11337,7 +11337,7 @@ spec:
|
||||
- /data/conf/sentinel.conf
|
||||
command:
|
||||
- redis-sentinel
|
||||
image: redis:7.0.0-alpine
|
||||
image: redis:7.0.4-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
lifecycle: {}
|
||||
livenessProbe:
|
||||
@@ -11383,7 +11383,7 @@ spec:
|
||||
value: 40000915ab58c3fa8fd888fb8b24711944e6cbb4
|
||||
- name: SENTINEL_ID_2
|
||||
value: 2bbec7894d954a8af3bb54d13eaec53cb024e2ca
|
||||
image: redis:7.0.0-alpine
|
||||
image: redis:7.0.4-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: config-init
|
||||
volumeMounts:
|
||||
|
||||
@@ -1244,7 +1244,7 @@ spec:
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.namespace
|
||||
image: quay.io/argoproj/argocd:v2.4.7
|
||||
image: quay.io/argoproj/argocd:v2.4.13
|
||||
imagePullPolicy: Always
|
||||
name: argocd-applicationset-controller
|
||||
ports:
|
||||
@@ -1316,7 +1316,7 @@ spec:
|
||||
- command:
|
||||
- /shared/argocd-dex
|
||||
- rundex
|
||||
image: ghcr.io/dexidp/dex:v2.30.2
|
||||
image: ghcr.io/dexidp/dex:v2.35.0-distroless
|
||||
imagePullPolicy: Always
|
||||
name: dex
|
||||
ports:
|
||||
@@ -1341,7 +1341,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /shared/argocd-dex
|
||||
image: quay.io/argoproj/argocd:v2.4.7
|
||||
image: quay.io/argoproj/argocd:v2.4.13
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
securityContext:
|
||||
@@ -1381,7 +1381,7 @@ spec:
|
||||
containers:
|
||||
- command:
|
||||
- argocd-notifications
|
||||
image: quay.io/argoproj/argocd:v2.4.7
|
||||
image: quay.io/argoproj/argocd:v2.4.13
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
@@ -1450,7 +1450,7 @@ spec:
|
||||
app.kubernetes.io/name: argocd-redis-ha-haproxy
|
||||
topologyKey: kubernetes.io/hostname
|
||||
containers:
|
||||
- image: haproxy:2.0.25-alpine
|
||||
- image: haproxy:2.0.29-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
lifecycle: {}
|
||||
livenessProbe:
|
||||
@@ -1479,7 +1479,7 @@ spec:
|
||||
- /readonly/haproxy_init.sh
|
||||
command:
|
||||
- sh
|
||||
image: haproxy:2.0.25-alpine
|
||||
image: haproxy:2.0.29-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: config-init
|
||||
volumeMounts:
|
||||
@@ -1638,7 +1638,7 @@ spec:
|
||||
value: /helm-working-dir
|
||||
- name: HELM_DATA_HOME
|
||||
value: /helm-working-dir
|
||||
image: quay.io/argoproj/argocd:v2.4.7
|
||||
image: quay.io/argoproj/argocd:v2.4.13
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -1687,7 +1687,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /var/run/argocd/argocd-cmp-server
|
||||
image: quay.io/argoproj/argocd:v2.4.7
|
||||
image: quay.io/argoproj/argocd:v2.4.13
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -1934,7 +1934,7 @@ spec:
|
||||
key: otlp.address
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.4.7
|
||||
image: quay.io/argoproj/argocd:v2.4.13
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -2142,7 +2142,7 @@ spec:
|
||||
key: otlp.address
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.4.7
|
||||
image: quay.io/argoproj/argocd:v2.4.13
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -2223,7 +2223,7 @@ spec:
|
||||
- /data/conf/redis.conf
|
||||
command:
|
||||
- redis-server
|
||||
image: redis:7.0.0-alpine
|
||||
image: redis:7.0.4-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
lifecycle: {}
|
||||
livenessProbe:
|
||||
@@ -2261,7 +2261,7 @@ spec:
|
||||
- /data/conf/sentinel.conf
|
||||
command:
|
||||
- redis-sentinel
|
||||
image: redis:7.0.0-alpine
|
||||
image: redis:7.0.4-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
lifecycle: {}
|
||||
livenessProbe:
|
||||
@@ -2307,7 +2307,7 @@ spec:
|
||||
value: 40000915ab58c3fa8fd888fb8b24711944e6cbb4
|
||||
- name: SENTINEL_ID_2
|
||||
value: 2bbec7894d954a8af3bb54d13eaec53cb024e2ca
|
||||
image: redis:7.0.0-alpine
|
||||
image: redis:7.0.4-alpine
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: config-init
|
||||
volumeMounts:
|
||||
|
||||
@@ -9692,7 +9692,7 @@ spec:
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.namespace
|
||||
image: quay.io/argoproj/argocd:v2.4.7
|
||||
image: quay.io/argoproj/argocd:v2.4.13
|
||||
imagePullPolicy: Always
|
||||
name: argocd-applicationset-controller
|
||||
ports:
|
||||
@@ -9764,7 +9764,7 @@ spec:
|
||||
- command:
|
||||
- /shared/argocd-dex
|
||||
- rundex
|
||||
image: ghcr.io/dexidp/dex:v2.30.2
|
||||
image: ghcr.io/dexidp/dex:v2.35.0-distroless
|
||||
imagePullPolicy: Always
|
||||
name: dex
|
||||
ports:
|
||||
@@ -9789,7 +9789,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /shared/argocd-dex
|
||||
image: quay.io/argoproj/argocd:v2.4.7
|
||||
image: quay.io/argoproj/argocd:v2.4.13
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
securityContext:
|
||||
@@ -9829,7 +9829,7 @@ spec:
|
||||
containers:
|
||||
- command:
|
||||
- argocd-notifications
|
||||
image: quay.io/argoproj/argocd:v2.4.7
|
||||
image: quay.io/argoproj/argocd:v2.4.13
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
@@ -9904,7 +9904,7 @@ spec:
|
||||
- ""
|
||||
- --appendonly
|
||||
- "no"
|
||||
image: redis:7.0.0-alpine
|
||||
image: redis:7.0.4-alpine
|
||||
imagePullPolicy: Always
|
||||
name: redis
|
||||
ports:
|
||||
@@ -10054,7 +10054,7 @@ spec:
|
||||
value: /helm-working-dir
|
||||
- name: HELM_DATA_HOME
|
||||
value: /helm-working-dir
|
||||
image: quay.io/argoproj/argocd:v2.4.7
|
||||
image: quay.io/argoproj/argocd:v2.4.13
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -10103,7 +10103,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /var/run/argocd/argocd-cmp-server
|
||||
image: quay.io/argoproj/argocd:v2.4.7
|
||||
image: quay.io/argoproj/argocd:v2.4.13
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -10346,7 +10346,7 @@ spec:
|
||||
key: otlp.address
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.4.7
|
||||
image: quay.io/argoproj/argocd:v2.4.13
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -10548,7 +10548,7 @@ spec:
|
||||
key: otlp.address
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.4.7
|
||||
image: quay.io/argoproj/argocd:v2.4.13
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
|
||||
@@ -616,7 +616,7 @@ spec:
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.namespace
|
||||
image: quay.io/argoproj/argocd:v2.4.7
|
||||
image: quay.io/argoproj/argocd:v2.4.13
|
||||
imagePullPolicy: Always
|
||||
name: argocd-applicationset-controller
|
||||
ports:
|
||||
@@ -688,7 +688,7 @@ spec:
|
||||
- command:
|
||||
- /shared/argocd-dex
|
||||
- rundex
|
||||
image: ghcr.io/dexidp/dex:v2.30.2
|
||||
image: ghcr.io/dexidp/dex:v2.35.0-distroless
|
||||
imagePullPolicy: Always
|
||||
name: dex
|
||||
ports:
|
||||
@@ -713,7 +713,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /shared/argocd-dex
|
||||
image: quay.io/argoproj/argocd:v2.4.7
|
||||
image: quay.io/argoproj/argocd:v2.4.13
|
||||
imagePullPolicy: Always
|
||||
name: copyutil
|
||||
securityContext:
|
||||
@@ -753,7 +753,7 @@ spec:
|
||||
containers:
|
||||
- command:
|
||||
- argocd-notifications
|
||||
image: quay.io/argoproj/argocd:v2.4.7
|
||||
image: quay.io/argoproj/argocd:v2.4.13
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
@@ -828,7 +828,7 @@ spec:
|
||||
- ""
|
||||
- --appendonly
|
||||
- "no"
|
||||
image: redis:7.0.0-alpine
|
||||
image: redis:7.0.4-alpine
|
||||
imagePullPolicy: Always
|
||||
name: redis
|
||||
ports:
|
||||
@@ -978,7 +978,7 @@ spec:
|
||||
value: /helm-working-dir
|
||||
- name: HELM_DATA_HOME
|
||||
value: /helm-working-dir
|
||||
image: quay.io/argoproj/argocd:v2.4.7
|
||||
image: quay.io/argoproj/argocd:v2.4.13
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
failureThreshold: 3
|
||||
@@ -1027,7 +1027,7 @@ spec:
|
||||
- -n
|
||||
- /usr/local/bin/argocd
|
||||
- /var/run/argocd/argocd-cmp-server
|
||||
image: quay.io/argoproj/argocd:v2.4.7
|
||||
image: quay.io/argoproj/argocd:v2.4.13
|
||||
name: copyutil
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
@@ -1270,7 +1270,7 @@ spec:
|
||||
key: otlp.address
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.4.7
|
||||
image: quay.io/argoproj/argocd:v2.4.13
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
@@ -1472,7 +1472,7 @@ spec:
|
||||
key: otlp.address
|
||||
name: argocd-cmd-params-cm
|
||||
optional: true
|
||||
image: quay.io/argoproj/argocd:v2.4.7
|
||||
image: quay.io/argoproj/argocd:v2.4.13
|
||||
imagePullPolicy: Always
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
|
||||
@@ -161,6 +161,7 @@ nav:
|
||||
- developer-guide/releasing.md
|
||||
- developer-guide/site.md
|
||||
- developer-guide/static-code-analysis.md
|
||||
- developer-guide/ui-extensions.md
|
||||
- developer-guide/faq.md
|
||||
- faq.md
|
||||
- security_considerations.md
|
||||
|
||||
@@ -195,30 +195,40 @@ func (repo *Repository) GetHelmCreds() helm.Creds {
|
||||
}
|
||||
|
||||
func getCAPath(repoURL string) string {
|
||||
hostname := ""
|
||||
// For git ssh protocol url without ssh://, url.Parse() will fail to parse.
|
||||
// However, no warn log is output since ssh scheme url is a possible format.
|
||||
if ok, _ := git.IsSSHURL(repoURL); ok {
|
||||
return ""
|
||||
}
|
||||
|
||||
hostname := ""
|
||||
// url.Parse() will happily parse most things thrown at it. When the URL
|
||||
// is either https or oci, we use the parsed hostname to receive the cert,
|
||||
// otherwise we'll use the parsed path (OCI repos are often specified as
|
||||
// hostname, without protocol).
|
||||
if parsedURL, err := url.Parse(repoURL); err == nil {
|
||||
if parsedURL.Scheme == "https" || parsedURL.Scheme == "oci" {
|
||||
hostname = parsedURL.Host
|
||||
} else if parsedURL.Scheme == "" {
|
||||
hostname = parsedURL.Path
|
||||
}
|
||||
} else {
|
||||
parsedURL, err := url.Parse(repoURL)
|
||||
if err != nil {
|
||||
log.Warnf("Could not parse repo URL '%s': %v", repoURL, err)
|
||||
return ""
|
||||
}
|
||||
if parsedURL.Scheme == "https" || parsedURL.Scheme == "oci" {
|
||||
hostname = parsedURL.Host
|
||||
} else if parsedURL.Scheme == "" {
|
||||
hostname = parsedURL.Path
|
||||
}
|
||||
|
||||
if hostname != "" {
|
||||
if caPath, err := cert.GetCertBundlePathForRepository(hostname); err == nil {
|
||||
return caPath
|
||||
} else {
|
||||
log.Warnf("Could not get cert bundle path for repository '%s': %v", repoURL, err)
|
||||
}
|
||||
if hostname == "" {
|
||||
log.Warnf("Could not get hostname for repository '%s'", repoURL)
|
||||
return ""
|
||||
}
|
||||
return ""
|
||||
|
||||
caPath, err := cert.GetCertBundlePathForRepository(hostname)
|
||||
if err != nil {
|
||||
log.Warnf("Could not get cert bundle path for repository '%s': %v", repoURL, err)
|
||||
return ""
|
||||
}
|
||||
|
||||
return caPath
|
||||
}
|
||||
|
||||
// CopySettingsFrom copies all repository settings from source to receiver
|
||||
|
||||
@@ -2628,6 +2628,7 @@ func TestGetCAPath(t *testing.T) {
|
||||
"oci://bar.example.com",
|
||||
"bar.example.com",
|
||||
"ssh://foo.example.com",
|
||||
"git@example.com:organization/reponame.git",
|
||||
"/some/invalid/thing",
|
||||
"../another/invalid/thing",
|
||||
"./also/invalid",
|
||||
|
||||
@@ -939,6 +939,10 @@ func GenerateManifests(ctx context.Context, appPath, repoRoot, revision string,
|
||||
|
||||
manifests := make([]string, 0)
|
||||
for _, obj := range targetObjs {
|
||||
if obj == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
var targets []*unstructured.Unstructured
|
||||
if obj.IsList() {
|
||||
err = obj.EachListItem(func(object runtime.Object) error {
|
||||
|
||||
@@ -43,4 +43,5 @@ function(tlaString, tlaCode)
|
||||
},
|
||||
},
|
||||
},
|
||||
null,
|
||||
]
|
||||
|
||||
@@ -3,7 +3,7 @@ if obj.status ~= nil then
|
||||
if obj.status.conditions ~= nil and obj.status.replicas ~= nil then
|
||||
numTrue = 0
|
||||
for i, condition in pairs(obj.status.conditions) do
|
||||
if (condition.type == "Available" or condition.type == "Progressing") and condition.status == "True" then
|
||||
if (condition.type == "Available" or (condition.type == "Progressing" and condition.reason == "NewReplicationControllerAvailable")) and condition.status == "True" then
|
||||
numTrue = numTrue + 1
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3,6 +3,10 @@ tests:
|
||||
status: Progressing
|
||||
message: "replication controller is waiting for pods to run"
|
||||
inputPath: testdata/progressing.yaml
|
||||
- healthStatus:
|
||||
status: Progressing
|
||||
message: "replication controller is waiting for pods to run"
|
||||
inputPath: testdata/progressing_rc_updated.yaml
|
||||
- healthStatus:
|
||||
status: Degraded
|
||||
message: "Deployment config is degraded"
|
||||
|
||||
66
resource_customizations/apps.openshift.io/DeploymentConfig/testdata/progressing_rc_updated.yaml
vendored
Normal file
66
resource_customizations/apps.openshift.io/DeploymentConfig/testdata/progressing_rc_updated.yaml
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
kind: DeploymentConfig
|
||||
apiVersion: apps.openshift.io/v1
|
||||
metadata:
|
||||
name: example
|
||||
namespace: default
|
||||
spec:
|
||||
strategy:
|
||||
type: Rolling
|
||||
rollingParams:
|
||||
updatePeriodSeconds: 1
|
||||
intervalSeconds: 1
|
||||
timeoutSeconds: 600
|
||||
maxUnavailable: 25%
|
||||
maxSurge: 25%
|
||||
resources: {}
|
||||
activeDeadlineSeconds: 21600
|
||||
triggers:
|
||||
- type: ConfigChange
|
||||
replicas: 3
|
||||
revisionHistoryLimit: 10
|
||||
test: false
|
||||
selector:
|
||||
app: httpd
|
||||
template:
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
app: httpd
|
||||
spec:
|
||||
containers:
|
||||
- name: httpd
|
||||
image: >-
|
||||
image-registry.openshift-image-registry.svc:5000/openshift/httpd:latest
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
protocol: TCP
|
||||
resources: {}
|
||||
terminationMessagePath: /dev/termination-log
|
||||
terminationMessagePolicy: File
|
||||
imagePullPolicy: Always
|
||||
restartPolicy: Always
|
||||
terminationGracePeriodSeconds: 30
|
||||
dnsPolicy: ClusterFirst
|
||||
securityContext: {}
|
||||
schedulerName: default-scheduler
|
||||
status:
|
||||
observedGeneration: 1
|
||||
details:
|
||||
message: config change
|
||||
causes:
|
||||
- type: ConfigChange
|
||||
availableReplicas: 3
|
||||
conditions:
|
||||
- type: Available
|
||||
status: 'True'
|
||||
lastUpdateTime: '2021-08-25T23:48:29Z'
|
||||
lastTransitionTime: '2021-08-25T23:48:29Z'
|
||||
message: Deployment config has minimum availability.
|
||||
- type: Progressing
|
||||
status: 'True'
|
||||
lastUpdateTime: '2021-08-25T23:48:29Z'
|
||||
lastTransitionTime: '2021-08-25T23:48:15Z'
|
||||
reason: ReplicationControllerUpdated
|
||||
message: replication controller "example-1" is progressing
|
||||
replicas: 3
|
||||
readyReplicas: 3
|
||||
@@ -8,7 +8,9 @@ if obj.status ~= nil then
|
||||
msg = msg .. i .. ": " .. condition.type .. " | " .. condition.status .. "\n"
|
||||
if condition.type == "InstallPlanPending" and condition.status == "True" then
|
||||
numPending = numPending + 1
|
||||
elseif (condition.type == "CatalogSourcesUnhealthy" or condition.type == "InstallPlanMissing" or condition.type == "InstallPlanFailed" or condition.type == "ResolutionFailed") and condition.status == "True" then
|
||||
elseif (condition.type == "InstallPlanMissing" and condition.reason ~= "ReferencedInstallPlanNotFound") then
|
||||
numDegraded = numDegraded + 1
|
||||
elseif (condition.type == "CatalogSourcesUnhealthy" or condition.type == "InstallPlanFailed" or condition.type == "ResolutionFailed") and condition.status == "True" then
|
||||
numDegraded = numDegraded + 1
|
||||
end
|
||||
end
|
||||
|
||||
@@ -8,7 +8,7 @@ tests:
|
||||
message: "1: CatalogSourcesUnhealthy | True\n"
|
||||
inputPath: testdata/catalog_sources_unhealthy.yaml
|
||||
- healthStatus:
|
||||
status: Degraded
|
||||
status: Healthy
|
||||
message: "1: CatalogSourcesUnhealthy | False\n2: InstallPlanMissing | True\n"
|
||||
inputPath: testdata/install_plan_missing.yaml
|
||||
- healthStatus:
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
goio "io"
|
||||
"io/fs"
|
||||
"math"
|
||||
"net"
|
||||
@@ -12,6 +13,7 @@ import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"regexp"
|
||||
go_runtime "runtime"
|
||||
@@ -95,11 +97,12 @@ import (
|
||||
"github.com/argoproj/argo-cd/v2/util/dex"
|
||||
dexutil "github.com/argoproj/argo-cd/v2/util/dex"
|
||||
"github.com/argoproj/argo-cd/v2/util/env"
|
||||
"github.com/argoproj/argo-cd/v2/util/errors"
|
||||
errorsutil "github.com/argoproj/argo-cd/v2/util/errors"
|
||||
grpc_util "github.com/argoproj/argo-cd/v2/util/grpc"
|
||||
"github.com/argoproj/argo-cd/v2/util/healthz"
|
||||
httputil "github.com/argoproj/argo-cd/v2/util/http"
|
||||
"github.com/argoproj/argo-cd/v2/util/io"
|
||||
"github.com/argoproj/argo-cd/v2/util/io/files"
|
||||
jwtutil "github.com/argoproj/argo-cd/v2/util/jwt"
|
||||
kubeutil "github.com/argoproj/argo-cd/v2/util/kube"
|
||||
"github.com/argoproj/argo-cd/v2/util/oidc"
|
||||
@@ -109,6 +112,7 @@ import (
|
||||
"github.com/argoproj/argo-cd/v2/util/swagger"
|
||||
tlsutil "github.com/argoproj/argo-cd/v2/util/tls"
|
||||
"github.com/argoproj/argo-cd/v2/util/webhook"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const maxConcurrentLoginRequestsCountEnv = "ARGOCD_MAX_CONCURRENT_LOGIN_REQUESTS_COUNT"
|
||||
@@ -223,9 +227,9 @@ func initializeDefaultProject(opts ArgoCDServerOpts) error {
|
||||
func NewServer(ctx context.Context, opts ArgoCDServerOpts) *ArgoCDServer {
|
||||
settingsMgr := settings_util.NewSettingsManager(ctx, opts.KubeClientset, opts.Namespace)
|
||||
settings, err := settingsMgr.InitializeSettings(opts.Insecure)
|
||||
errors.CheckError(err)
|
||||
errorsutil.CheckError(err)
|
||||
err = initializeDefaultProject(opts)
|
||||
errors.CheckError(err)
|
||||
errorsutil.CheckError(err)
|
||||
|
||||
factory := appinformer.NewSharedInformerFactoryWithOptions(opts.AppClientset, 0, appinformer.WithNamespace(opts.Namespace), appinformer.WithTweakListOptions(func(options *metav1.ListOptions) {}))
|
||||
projInformer := factory.Argoproj().V1alpha1().AppProjects().Informer()
|
||||
@@ -239,7 +243,7 @@ func NewServer(ctx context.Context, opts ArgoCDServerOpts) *ArgoCDServer {
|
||||
enf := rbac.NewEnforcer(opts.KubeClientset, opts.Namespace, common.ArgoCDRBACConfigMapName, nil)
|
||||
enf.EnableEnforce(!opts.DisableAuth)
|
||||
err = enf.SetBuiltinPolicy(assets.BuiltinPolicyCSV)
|
||||
errors.CheckError(err)
|
||||
errorsutil.CheckError(err)
|
||||
enf.EnableLog(os.Getenv(common.EnvVarRBACDebug) == "1")
|
||||
|
||||
policyEnf := rbacpolicy.NewRBACPolicyEnforcer(enf, projLister)
|
||||
@@ -508,7 +512,7 @@ func (a *ArgoCDServer) watchSettings() {
|
||||
prevURL := a.settings.URL
|
||||
prevOIDCConfig := a.settings.OIDCConfig()
|
||||
prevDexCfgBytes, err := dex.GenerateDexConfigYAML(a.settings)
|
||||
errors.CheckError(err)
|
||||
errorsutil.CheckError(err)
|
||||
prevGitHubSecret := a.settings.WebhookGitHubSecret
|
||||
prevGitLabSecret := a.settings.WebhookGitLabSecret
|
||||
prevBitbucketUUID := a.settings.WebhookBitbucketUUID
|
||||
@@ -523,7 +527,7 @@ func (a *ArgoCDServer) watchSettings() {
|
||||
newSettings := <-updateCh
|
||||
a.settings = newSettings
|
||||
newDexCfgBytes, err := dex.GenerateDexConfigYAML(a.settings)
|
||||
errors.CheckError(err)
|
||||
errorsutil.CheckError(err)
|
||||
if string(newDexCfgBytes) != string(prevDexCfgBytes) {
|
||||
log.Infof("dex config modified. restarting")
|
||||
break
|
||||
@@ -587,7 +591,7 @@ func (a *ArgoCDServer) rbacPolicyLoader(ctx context.Context) {
|
||||
a.policyEnforcer.SetScopes(scopes)
|
||||
return nil
|
||||
})
|
||||
errors.CheckError(err)
|
||||
errorsutil.CheckError(err)
|
||||
}
|
||||
|
||||
func (a *ArgoCDServer) useTLS() bool {
|
||||
@@ -712,7 +716,7 @@ func (a *ArgoCDServer) newGRPCServer() (*grpc.Server, application.AppResourceTre
|
||||
// Register reflection service on gRPC server.
|
||||
reflection.Register(grpcS)
|
||||
grpc_prometheus.Register(grpcS)
|
||||
errors.CheckError(projectService.NormalizeProjs())
|
||||
errorsutil.CheckError(projectService.NormalizeProjs())
|
||||
return grpcS, appResourceTreeFn
|
||||
}
|
||||
|
||||
@@ -871,11 +875,11 @@ func (a *ArgoCDServer) newHTTPServer(ctx context.Context, port int, grpcWebHandl
|
||||
registerDownloadHandlers(mux, "/download")
|
||||
|
||||
// Serve extensions
|
||||
var extensionsApiPath = "/extensions/"
|
||||
var extensionsSharedPath = "/tmp/extensions/"
|
||||
|
||||
extHandler := http.StripPrefix(extensionsApiPath, http.FileServer(http.Dir(extensionsSharedPath)))
|
||||
mux.HandleFunc(extensionsApiPath, extHandler.ServeHTTP)
|
||||
mux.HandleFunc("/extensions.js", func(writer http.ResponseWriter, _ *http.Request) {
|
||||
a.serveExtensions(extensionsSharedPath, writer)
|
||||
})
|
||||
|
||||
// Serve UI static assets
|
||||
var assetsHandler http.Handler = http.HandlerFunc(a.newStaticAssetsHandler())
|
||||
@@ -886,6 +890,48 @@ func (a *ArgoCDServer) newHTTPServer(ctx context.Context, port int, grpcWebHandl
|
||||
return &httpS
|
||||
}
|
||||
|
||||
var extensionsPattern = regexp.MustCompile(`^extension(.*)\.js$`)
|
||||
|
||||
func (a *ArgoCDServer) serveExtensions(extensionsSharedPath string, w http.ResponseWriter) {
|
||||
w.Header().Set("Content-Type", "application/javascript")
|
||||
|
||||
err := filepath.Walk(extensionsSharedPath, func(filePath string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to iterate files in '%s': %w", extensionsSharedPath, err)
|
||||
}
|
||||
if !files.IsSymlink(info) && !info.IsDir() && extensionsPattern.MatchString(info.Name()) {
|
||||
processFile := func() error {
|
||||
if _, err = w.Write([]byte(fmt.Sprintf("// source: %s/%s \n", filePath, info.Name()))); err != nil {
|
||||
return fmt.Errorf("failed to write to response: %w", err)
|
||||
}
|
||||
|
||||
f, err := os.Open(filePath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to open file '%s': %w", filePath, err)
|
||||
}
|
||||
defer io.Close(f)
|
||||
|
||||
if _, err := goio.Copy(w, f); err != nil {
|
||||
return fmt.Errorf("failed to copy file '%s': %w", filePath, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
if processFile() != nil {
|
||||
return fmt.Errorf("failed to serve extension file '%s': %w", filePath, processFile())
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil && !errors.Is(err, fs.ErrNotExist) {
|
||||
log.Errorf("Failed to walk extensions directory: %v", err)
|
||||
http.Error(w, "Internal error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// registerDexHandlers will register dex HTTP handlers, creating the the OAuth client app
|
||||
func (a *ArgoCDServer) registerDexHandlers(mux *http.ServeMux) {
|
||||
if !a.settings.IsSSOConfigured() {
|
||||
@@ -899,7 +945,7 @@ func (a *ArgoCDServer) registerDexHandlers(mux *http.ServeMux) {
|
||||
tlsConfig.InsecureSkipVerify = true
|
||||
}
|
||||
a.ssoClientApp, err = oidc.NewClientApp(a.settings, a.DexServerAddr, a.BaseHRef)
|
||||
errors.CheckError(err)
|
||||
errorsutil.CheckError(err)
|
||||
mux.HandleFunc(common.LoginEndpoint, a.ssoClientApp.HandleLogin)
|
||||
mux.HandleFunc(common.CallbackEndpoint, a.ssoClientApp.HandleCallback)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM redis:7.0.0 as redis
|
||||
FROM redis:7.0.4 as redis
|
||||
|
||||
FROM node:12.18.4-buster as node
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
controller: sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_BINARY_NAME=argocd-application-controller go run ./cmd/main.go --loglevel debug --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081}"
|
||||
api-server: sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_BINARY_NAME=argocd-server go run ./cmd/main.go --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}"
|
||||
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}"
|
||||
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} "
|
||||
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.30.0 serve /dex.yaml"
|
||||
redis: sh -c "/usr/local/bin/redis-server --save "" --appendonly no --port ${ARGOCD_E2E_REDIS_PORT:-6379}"
|
||||
repo-server: sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_GNUPGHOME=${ARGOCD_GNUPGHOME:-/tmp/argocd-local/gpg/keys} ARGOCD_PLUGINSOCKFILEPATH=${ARGOCD_PLUGINSOCKFILEPATH:-/tmp/argo-e2e/app/config/plugin} ARGOCD_GPG_DATA_PATH=${ARGOCD_GPG_DATA_PATH:-/tmp/argocd-local/gpg/source} ARGOCD_BINARY_NAME=argocd-repo-server go run ./cmd/main.go --loglevel debug --port ${ARGOCD_E2E_REPOSERVER_PORT:-8081} --redis localhost:${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"
|
||||
reaper: ./test/container/reaper.sh
|
||||
sshd: sudo sh -c "test $ARGOCD_E2E_TEST = true && /usr/sbin/sshd -p 2222 -D -e"
|
||||
@@ -10,5 +10,5 @@ fcgiwrap: sudo sh -c "test $ARGOCD_E2E_TEST = true && (fcgiwrap -s unix:/var/run
|
||||
nginx: sudo sh -c "test $ARGOCD_E2E_TEST = true && nginx -g 'daemon off;' -c $(pwd)/test/fixture/testrepos/nginx.conf"
|
||||
helm-registry: sudo sh -c "registry serve /etc/docker/registry/config.yml"
|
||||
dev-mounter: test "$ARGOCD_E2E_TEST" != "true" && go run hack/dev-mounter/main.go --configmap argocd-ssh-known-hosts-cm=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} --configmap argocd-tls-certs-cm=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} --configmap argocd-gpg-keys-cm=${ARGOCD_GPG_DATA_PATH:-/tmp/argocd-local/gpg/source}
|
||||
applicationset-controller: sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_ASK_PASS_SOCK=/tmp/applicationset-ask-pass.sock ARGOCD_BINARY_NAME=argocd-applicationset-controller go run ./cmd/main.go --loglevel debug --metrics-addr localhost:12345 --probe-addr localhost:12346 --namespace argocd-e2e --loglevel debug --argocd-repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081}"
|
||||
notification: sh -c "FORCE_LOG_COLORS=4 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_BINARY_NAME=argocd-notifications go run ./cmd/main.go --loglevel debug"
|
||||
applicationset-controller: [ "$BIN_MODE" == 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "FORCE_LOG_COLORS=4 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_ASK_PASS_SOCK=/tmp/applicationset-ask-pass.sock ARGOCD_SSH_DATA_PATH=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} ARGOCD_BINARY_NAME=argocd-applicationset-controller $COMMAND --loglevel debug --metrics-addr localhost:12345 --probe-addr localhost:12346 --argocd-repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081}"
|
||||
notification: sh -c "FORCE_LOG_COLORS=4 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_BINARY_NAME=argocd-notifications go run ./cmd/main.go --loglevel debug"
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
networkingv1 "k8s.io/api/networking/v1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
@@ -1600,9 +1601,11 @@ func TestSyncWithInfos(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
//Given: argocd app create does not provide --dest-namespace
|
||||
// Manifest contains resource console which does not require namespace
|
||||
//Expect: no app.Status.Conditions
|
||||
// Given: argocd app create does not provide --dest-namespace
|
||||
//
|
||||
// Manifest contains resource console which does not require namespace
|
||||
//
|
||||
// Expect: no app.Status.Conditions
|
||||
func TestCreateAppWithNoNameSpaceForGlobalResource(t *testing.T) {
|
||||
Given(t).
|
||||
Path(globalWithNoNameSpace).
|
||||
@@ -1617,10 +1620,12 @@ func TestCreateAppWithNoNameSpaceForGlobalResource(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
//Given: argocd app create does not provide --dest-namespace
|
||||
// Manifest contains resource deployment, and service which requires namespace
|
||||
// Deployment and service do not have namespace in manifest
|
||||
//Expect: app.Status.Conditions for deployment ans service which does not have namespace in manifest
|
||||
// Given: argocd app create does not provide --dest-namespace
|
||||
//
|
||||
// Manifest contains resource deployment, and service which requires namespace
|
||||
// Deployment and service do not have namespace in manifest
|
||||
//
|
||||
// Expect: app.Status.Conditions for deployment ans service which does not have namespace in manifest
|
||||
func TestCreateAppWithNoNameSpaceWhenRequired(t *testing.T) {
|
||||
Given(t).
|
||||
Path(guestbookPath).
|
||||
@@ -1638,11 +1643,13 @@ func TestCreateAppWithNoNameSpaceWhenRequired(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
//Given: argocd app create does not provide --dest-namespace
|
||||
// Manifest contains resource deployment, and service which requires namespace
|
||||
// Some deployment and service has namespace in manifest
|
||||
// Some deployment and service does not have namespace in manifest
|
||||
//Expect: app.Status.Conditions for deployment and service which does not have namespace in manifest
|
||||
// Given: argocd app create does not provide --dest-namespace
|
||||
//
|
||||
// Manifest contains resource deployment, and service which requires namespace
|
||||
// Some deployment and service has namespace in manifest
|
||||
// Some deployment and service does not have namespace in manifest
|
||||
//
|
||||
// Expect: app.Status.Conditions for deployment and service which does not have namespace in manifest
|
||||
func TestCreateAppWithNoNameSpaceWhenRequired2(t *testing.T) {
|
||||
Given(t).
|
||||
Path(guestbookWithNamespace).
|
||||
@@ -1718,10 +1725,13 @@ func TestListResource(t *testing.T) {
|
||||
}
|
||||
|
||||
// Given application is set with --sync-option CreateNamespace=true
|
||||
// application --dest-namespace does not exist
|
||||
//
|
||||
// application --dest-namespace does not exist
|
||||
//
|
||||
// Verity application --dest-namespace is created
|
||||
// application sync successful
|
||||
// when application is deleted, --dest-namespace is not deleted
|
||||
//
|
||||
// application sync successful
|
||||
// when application is deleted, --dest-namespace is not deleted
|
||||
func TestNamespaceAutoCreation(t *testing.T) {
|
||||
SkipOnEnv(t, "OPENSHIFT")
|
||||
updatedNamespace := getNewNamespace(t)
|
||||
@@ -2285,6 +2295,13 @@ func TestAnnotationTrackingExtraResources(t *testing.T) {
|
||||
Expect(SyncStatusIs(SyncStatusCodeSynced)).
|
||||
Expect(HealthIs(health.HealthStatusHealthy)).
|
||||
When().
|
||||
Sync("--prune").
|
||||
And(func() {
|
||||
// The extra configmap must not be pruned, because it's not tracked
|
||||
cm, err := KubeClientset.CoreV1().ConfigMaps(DeploymentNamespace()).Get(context.Background(), "extra-configmap", metav1.GetOptions{})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "extra-configmap", cm.Name)
|
||||
}).
|
||||
And(func() {
|
||||
// Add a resource with an annotation that is self-referencing the
|
||||
// resource.
|
||||
@@ -2301,5 +2318,70 @@ func TestAnnotationTrackingExtraResources(t *testing.T) {
|
||||
Then().
|
||||
Expect(OperationPhaseIs(OperationSucceeded)).
|
||||
Expect(SyncStatusIs(SyncStatusCodeOutOfSync)).
|
||||
Expect(HealthIs(health.HealthStatusHealthy)).
|
||||
When().
|
||||
Sync("--prune").
|
||||
And(func() {
|
||||
// The extra configmap must be pruned now, because it's tracked
|
||||
cm, err := KubeClientset.CoreV1().ConfigMaps(DeploymentNamespace()).Get(context.Background(), "other-configmap", metav1.GetOptions{})
|
||||
require.Error(t, err)
|
||||
require.Equal(t, "", cm.Name)
|
||||
}).
|
||||
Then().
|
||||
Expect(OperationPhaseIs(OperationSucceeded)).
|
||||
Expect(SyncStatusIs(SyncStatusCodeSynced)).
|
||||
Expect(HealthIs(health.HealthStatusHealthy)).
|
||||
When().
|
||||
And(func() {
|
||||
// Add a cluster-scoped resource that is not referencing itself
|
||||
FailOnErr(KubeClientset.RbacV1().ClusterRoles().Create(context.Background(), &rbacv1.ClusterRole{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "e2e-test-clusterrole",
|
||||
Annotations: map[string]string{
|
||||
common.AnnotationKeyAppInstance: fmt.Sprintf("%s:rbac.authorization.k8s.io/ClusterRole:%s/e2e-other-clusterrole", Name(), DeploymentNamespace()),
|
||||
},
|
||||
Labels: map[string]string{
|
||||
fixture.TestingLabel: "true",
|
||||
},
|
||||
},
|
||||
}, metav1.CreateOptions{}))
|
||||
}).
|
||||
Refresh(RefreshTypeNormal).
|
||||
Then().
|
||||
Expect(OperationPhaseIs(OperationSucceeded)).
|
||||
Expect(SyncStatusIs(SyncStatusCodeSynced)).
|
||||
Expect(HealthIs(health.HealthStatusHealthy)).
|
||||
When().
|
||||
And(func() {
|
||||
// Add a cluster-scoped resource that is referencing itself
|
||||
FailOnErr(KubeClientset.RbacV1().ClusterRoles().Create(context.Background(), &rbacv1.ClusterRole{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "e2e-other-clusterrole",
|
||||
Annotations: map[string]string{
|
||||
common.AnnotationKeyAppInstance: fmt.Sprintf("%s:rbac.authorization.k8s.io/ClusterRole:%s/e2e-other-clusterrole", Name(), DeploymentNamespace()),
|
||||
},
|
||||
Labels: map[string]string{
|
||||
fixture.TestingLabel: "true",
|
||||
},
|
||||
},
|
||||
}, metav1.CreateOptions{}))
|
||||
}).
|
||||
Refresh(RefreshTypeNormal).
|
||||
Then().
|
||||
Expect(OperationPhaseIs(OperationSucceeded)).
|
||||
Expect(SyncStatusIs(SyncStatusCodeOutOfSync)).
|
||||
Expect(HealthIs(health.HealthStatusHealthy)).
|
||||
When().
|
||||
Sync("--prune").
|
||||
And(func() {
|
||||
// The extra configmap must be pruned now, because it's tracked and does not exist in git
|
||||
cr, err := KubeClientset.RbacV1().ClusterRoles().Get(context.Background(), "e2e-other-clusterrole", metav1.GetOptions{})
|
||||
require.Error(t, err)
|
||||
require.Equal(t, "", cr.Name)
|
||||
}).
|
||||
Then().
|
||||
Expect(OperationPhaseIs(OperationSucceeded)).
|
||||
Expect(SyncStatusIs(SyncStatusCodeSynced)).
|
||||
Expect(HealthIs(health.HealthStatusHealthy))
|
||||
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ const (
|
||||
defaultAdminPassword = "password"
|
||||
defaultAdminUsername = "admin"
|
||||
DefaultTestUserPassword = "password"
|
||||
testingLabel = "e2e.argoproj.io"
|
||||
TestingLabel = "e2e.argoproj.io"
|
||||
ArgoCDNamespace = "argocd-e2e"
|
||||
|
||||
// ensure all repos are in one directory tree, so we can easily clean them up
|
||||
@@ -299,7 +299,7 @@ func CreateSecret(username, password string) string {
|
||||
"--from-literal=username="+username,
|
||||
"--from-literal=password="+password,
|
||||
"-n", TestNamespace()))
|
||||
FailOnErr(Run("", "kubectl", "label", "secret", secretName, testingLabel+"=true", "-n", TestNamespace()))
|
||||
FailOnErr(Run("", "kubectl", "label", "secret", secretName, TestingLabel+"=true", "-n", TestNamespace()))
|
||||
return secretName
|
||||
}
|
||||
|
||||
@@ -521,10 +521,11 @@ func EnsureCleanState(t *testing.T) {
|
||||
v1.DeleteOptions{PropagationPolicy: &policy}, v1.ListOptions{LabelSelector: common.LabelKeySecretType + "=" + common.LabelValueSecretTypeCluster}))
|
||||
// kubectl delete secrets -l e2e.argoproj.io=true
|
||||
CheckError(KubeClientset.CoreV1().Secrets(TestNamespace()).DeleteCollection(context.Background(),
|
||||
v1.DeleteOptions{PropagationPolicy: &policy}, v1.ListOptions{LabelSelector: testingLabel + "=true"}))
|
||||
v1.DeleteOptions{PropagationPolicy: &policy}, v1.ListOptions{LabelSelector: TestingLabel + "=true"}))
|
||||
|
||||
FailOnErr(Run("", "kubectl", "delete", "ns", "-l", testingLabel+"=true", "--field-selector", "status.phase=Active", "--wait=false"))
|
||||
FailOnErr(Run("", "kubectl", "delete", "crd", "-l", testingLabel+"=true", "--wait=false"))
|
||||
FailOnErr(Run("", "kubectl", "delete", "ns", "-l", TestingLabel+"=true", "--field-selector", "status.phase=Active", "--wait=false"))
|
||||
FailOnErr(Run("", "kubectl", "delete", "crd", "-l", TestingLabel+"=true", "--wait=false"))
|
||||
FailOnErr(Run("", "kubectl", "delete", "clusterroles", "-l", TestingLabel+"=true", "--wait=false"))
|
||||
|
||||
// reset settings
|
||||
updateSettingConfigMap(func(cm *corev1.ConfigMap) error {
|
||||
@@ -615,7 +616,7 @@ func EnsureCleanState(t *testing.T) {
|
||||
|
||||
// create namespace
|
||||
FailOnErr(Run("", "kubectl", "create", "ns", DeploymentNamespace()))
|
||||
FailOnErr(Run("", "kubectl", "label", "ns", DeploymentNamespace(), testingLabel+"=true"))
|
||||
FailOnErr(Run("", "kubectl", "label", "ns", DeploymentNamespace(), TestingLabel+"=true"))
|
||||
|
||||
log.WithFields(log.Fields{"duration": time.Since(start), "name": t.Name(), "id": id, "username": "admin", "password": "password"}).Info("clean state")
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
"json-merge-patch": "^0.2.3",
|
||||
"lodash-es": "^4.17.21",
|
||||
"minimatch": "^3.1.2",
|
||||
"moment": "^2.29.2",
|
||||
"moment": "^2.29.4",
|
||||
"monaco-editor": "^0.33.0",
|
||||
"path": "^0.12.7",
|
||||
"prop-types": "^15.8.1",
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import {DataLoader, Tab, Tabs} from 'argo-ui';
|
||||
import {useData} from 'argo-ui/v2';
|
||||
import * as React from 'react';
|
||||
import {EventsList, YamlEditor} from '../../../shared/components';
|
||||
import * as models from '../../../shared/models';
|
||||
@@ -7,7 +6,7 @@ import {ErrorBoundary} from '../../../shared/components/error-boundary/error-bou
|
||||
import {Context} from '../../../shared/context';
|
||||
import {Application, ApplicationTree, AppSourceType, Event, RepoAppDetails, ResourceNode, State, SyncStatuses} from '../../../shared/models';
|
||||
import {services} from '../../../shared/services';
|
||||
import {ExtensionComponentProps} from '../../../shared/services/extensions-service';
|
||||
import {ResourceTabExtension} from '../../../shared/services/extensions-service';
|
||||
import {NodeInfo, SelectNode} from '../application-details/application-details';
|
||||
import {ApplicationNodeInfo} from '../application-node-info/application-node-info';
|
||||
import {ApplicationParameters} from '../application-parameters/application-parameters';
|
||||
@@ -48,9 +47,11 @@ export const ResourceDetails = (props: ResourceDetailsProps) => {
|
||||
state: State,
|
||||
podState: State,
|
||||
events: Event[],
|
||||
ExtensionComponent: React.ComponentType<ExtensionComponentProps>,
|
||||
extensionTabs: ResourceTabExtension[],
|
||||
tabs: Tab[],
|
||||
execEnabled: boolean
|
||||
execEnabled: boolean,
|
||||
execAllowed: boolean,
|
||||
logsAllowed: boolean
|
||||
) => {
|
||||
if (!node || node === undefined) {
|
||||
return [];
|
||||
@@ -87,31 +88,33 @@ export const ResourceDetails = (props: ResourceDetailsProps) => {
|
||||
|
||||
const onClickContainer = (group: any, i: number) => SelectNode(selectedNodeKey, group.offset + i, 'logs', appContext);
|
||||
|
||||
tabs = tabs.concat([
|
||||
{
|
||||
key: 'logs',
|
||||
icon: 'fa fa-align-left',
|
||||
title: 'LOGS',
|
||||
content: (
|
||||
<div className='application-details__tab-content-full-height'>
|
||||
<PodsLogsViewer
|
||||
podName={(state.kind === 'Pod' && state.metadata.name) || ''}
|
||||
group={node.group}
|
||||
kind={node.kind}
|
||||
name={node.name}
|
||||
namespace={podState.metadata.namespace}
|
||||
applicationName={application.metadata.name}
|
||||
containerName={AppUtils.getContainerName(podState, selectedNodeInfo.container)}
|
||||
page={{number: page, untilTimes}}
|
||||
setPage={pageData => appContext.navigation.goto('.', {page: pageData.number, untilTimes: pageData.untilTimes.join(',')})}
|
||||
containerGroups={containerGroups}
|
||||
onClickContainer={onClickContainer}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
]);
|
||||
if (execEnabled) {
|
||||
if (logsAllowed) {
|
||||
tabs = tabs.concat([
|
||||
{
|
||||
key: 'logs',
|
||||
icon: 'fa fa-align-left',
|
||||
title: 'LOGS',
|
||||
content: (
|
||||
<div className='application-details__tab-content-full-height'>
|
||||
<PodsLogsViewer
|
||||
podName={(state.kind === 'Pod' && state.metadata.name) || ''}
|
||||
group={node.group}
|
||||
kind={node.kind}
|
||||
name={node.name}
|
||||
namespace={podState.metadata.namespace}
|
||||
applicationName={application.metadata.name}
|
||||
containerName={AppUtils.getContainerName(podState, selectedNodeInfo.container)}
|
||||
page={{number: page, untilTimes}}
|
||||
setPage={pageData => appContext.navigation.goto('.', {page: pageData.number, untilTimes: pageData.untilTimes.join(',')})}
|
||||
containerGroups={containerGroups}
|
||||
onClickContainer={onClickContainer}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
]);
|
||||
}
|
||||
if (selectedNode.kind === 'Pod' && execEnabled && execAllowed) {
|
||||
tabs = tabs.concat([
|
||||
{
|
||||
key: 'exec',
|
||||
@@ -124,15 +127,18 @@ export const ResourceDetails = (props: ResourceDetailsProps) => {
|
||||
]);
|
||||
}
|
||||
}
|
||||
if (ExtensionComponent && state) {
|
||||
tabs.push({
|
||||
title: 'More',
|
||||
key: 'extension',
|
||||
content: (
|
||||
<ErrorBoundary message={`Something went wrong with Extension for ${state.kind}`}>
|
||||
<ExtensionComponent tree={tree} resource={state} />
|
||||
</ErrorBoundary>
|
||||
)
|
||||
if (state) {
|
||||
extensionTabs.forEach((tabExtensions, i) => {
|
||||
tabs.push({
|
||||
title: tabExtensions.title,
|
||||
key: `extension-${i}`,
|
||||
content: (
|
||||
<ErrorBoundary message={`Something went wrong with Extension for ${state.kind}`}>
|
||||
<tabExtensions.component tree={tree} resource={state} application={application} />
|
||||
</ErrorBoundary>
|
||||
),
|
||||
icon: tabExtensions.icon
|
||||
});
|
||||
});
|
||||
}
|
||||
return tabs;
|
||||
@@ -209,19 +215,17 @@ export const ResourceDetails = (props: ResourceDetailsProps) => {
|
||||
content: <ApplicationResourceEvents applicationName={application.metadata.name} />
|
||||
});
|
||||
|
||||
return tabs;
|
||||
const extensionTabs = services.extensions.getResourceTabs('argoproj.io', 'Application').map((ext, i) => ({
|
||||
title: ext.title,
|
||||
key: `extension-${i}`,
|
||||
content: <ext.component resource={application} tree={tree} application={application} />,
|
||||
icon: ext.icon
|
||||
}));
|
||||
|
||||
return tabs.concat(extensionTabs);
|
||||
};
|
||||
|
||||
const [extension, , error] = useData(
|
||||
async () => {
|
||||
if (selectedNode?.kind && selectedNode?.group) {
|
||||
return await services.extensions.loadResourceExtension(selectedNode?.group || '', selectedNode?.kind || '');
|
||||
}
|
||||
},
|
||||
null,
|
||||
null,
|
||||
[selectedNode]
|
||||
);
|
||||
const extensions = selectedNode?.kind ? services.extensions.getResourceTabs(selectedNode?.group || '', selectedNode?.kind) : [];
|
||||
|
||||
return (
|
||||
<div style={{width: '100%', height: '100%'}}>
|
||||
@@ -266,8 +270,9 @@ export const ResourceDetails = (props: ResourceDetailsProps) => {
|
||||
|
||||
const settings = await services.authService.settings();
|
||||
const execEnabled = settings.execEnabled;
|
||||
|
||||
return {controlledState, liveState, events, podState, execEnabled};
|
||||
const logsAllowed = await services.accounts.canI('logs', 'get', application.spec.project + '/' + application.metadata.name);
|
||||
const execAllowed = await services.accounts.canI('exec', 'create', application.spec.project + '/' + application.metadata.name);
|
||||
return {controlledState, liveState, events, podState, execEnabled, execAllowed, logsAllowed};
|
||||
}}>
|
||||
{data => (
|
||||
<React.Fragment>
|
||||
@@ -302,7 +307,7 @@ export const ResourceDetails = (props: ResourceDetailsProps) => {
|
||||
data.liveState,
|
||||
data.podState,
|
||||
data.events,
|
||||
error.state ? null : extension?.component,
|
||||
extensions,
|
||||
[
|
||||
{
|
||||
title: 'SUMMARY',
|
||||
@@ -311,7 +316,9 @@ export const ResourceDetails = (props: ResourceDetailsProps) => {
|
||||
content: <ApplicationNodeInfo application={application} live={data.liveState} controlled={data.controlledState} node={selectedNode} />
|
||||
}
|
||||
],
|
||||
data.execEnabled
|
||||
data.execEnabled,
|
||||
data.execAllowed,
|
||||
data.logsAllowed
|
||||
)}
|
||||
selectedTabKey={props.tab}
|
||||
onTabSelected={selected => appContext.navigation.goto('.', {tab: selected}, {replace: true})}
|
||||
|
||||
@@ -5,8 +5,8 @@ import * as React from 'react';
|
||||
import * as ReactForm from 'react-form';
|
||||
import {Text} from 'react-form';
|
||||
import * as moment from 'moment';
|
||||
import {BehaviorSubject, from, fromEvent, merge, Observable, Observer, Subscription} from 'rxjs';
|
||||
import {debounceTime} from 'rxjs/operators';
|
||||
import {BehaviorSubject, combineLatest, concat, from, fromEvent, Observable, Observer, Subscription} from 'rxjs';
|
||||
import {debounceTime, map} from 'rxjs/operators';
|
||||
import {AppContext, Context, ContextApis} from '../../shared/context';
|
||||
import {ResourceTreeNode} from './application-resource-tree/application-resource-tree';
|
||||
|
||||
@@ -321,7 +321,6 @@ function getActionItems(
|
||||
appChanged: BehaviorSubject<appModels.Application>,
|
||||
isQuickStart: boolean
|
||||
): Observable<ActionMenuItem[]> {
|
||||
let menuItems: Observable<ActionMenuItem[]>;
|
||||
const isRoot = resource.root && nodeKey(resource.root) === nodeKey(resource);
|
||||
const items: MenuItem[] = [
|
||||
...((isRoot && [
|
||||
@@ -355,42 +354,61 @@ function getActionItems(
|
||||
action: () => appContext.apis.navigation.goto('.', {node: nodeKey(resource), tab: 'logs'}, {replace: true})
|
||||
});
|
||||
}
|
||||
if (resource.kind === 'Pod') {
|
||||
items.push({
|
||||
title: 'Exec',
|
||||
iconClassName: 'fa fa-terminal',
|
||||
action: () => appContext.apis.navigation.goto('.', {node: nodeKey(resource), tab: 'exec'}, {replace: true})
|
||||
});
|
||||
}
|
||||
|
||||
if (isQuickStart) {
|
||||
return from([items]);
|
||||
}
|
||||
|
||||
const execAction = services.authService
|
||||
.settings()
|
||||
.then(async settings => {
|
||||
const execAllowed = await services.accounts.canI('exec', 'create', application.spec.project + '/' + application.metadata.name);
|
||||
if (resource.kind === 'Pod' && settings.execEnabled && execAllowed) {
|
||||
return [
|
||||
{
|
||||
title: 'Exec',
|
||||
iconClassName: 'fa fa-terminal',
|
||||
action: async () => appContext.apis.navigation.goto('.', {node: nodeKey(resource), tab: 'exec'}, {replace: true})
|
||||
} as MenuItem
|
||||
];
|
||||
}
|
||||
return [] as MenuItem[];
|
||||
})
|
||||
.catch(() => [] as MenuItem[]);
|
||||
|
||||
const resourceActions = services.applications
|
||||
.getResourceActions(application.metadata.name, resource)
|
||||
.then(actions => {
|
||||
return items.concat(
|
||||
actions.map(action => ({
|
||||
title: action.name,
|
||||
disabled: !!action.disabled,
|
||||
action: async () => {
|
||||
try {
|
||||
const confirmed = await appContext.apis.popup.confirm(`Execute '${action.name}' action?`, `Are you sure you want to execute '${action.name}' action?`);
|
||||
if (confirmed) {
|
||||
await services.applications.runResourceAction(application.metadata.name, resource, action.name);
|
||||
return actions.map(
|
||||
action =>
|
||||
({
|
||||
title: action.name,
|
||||
disabled: !!action.disabled,
|
||||
action: async () => {
|
||||
try {
|
||||
const confirmed = await appContext.apis.popup.confirm(
|
||||
`Execute '${action.name}' action?`,
|
||||
`Are you sure you want to execute '${action.name}' action?`
|
||||
);
|
||||
if (confirmed) {
|
||||
await services.applications.runResourceAction(application.metadata.name, resource, action.name);
|
||||
}
|
||||
} catch (e) {
|
||||
appContext.apis.notifications.show({
|
||||
content: <ErrorNotification title='Unable to execute resource action' e={e} />,
|
||||
type: NotificationType.Error
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
appContext.apis.notifications.show({
|
||||
content: <ErrorNotification title='Unable to execute resource action' e={e} />,
|
||||
type: NotificationType.Error
|
||||
});
|
||||
}
|
||||
}
|
||||
}))
|
||||
} as MenuItem)
|
||||
);
|
||||
})
|
||||
.catch(() => items);
|
||||
menuItems = merge(from([items]), from(resourceActions));
|
||||
return menuItems;
|
||||
.catch(() => [] as MenuItem[]);
|
||||
return combineLatest(
|
||||
from([items]), // this resolves immediately
|
||||
concat([[] as MenuItem[]], resourceActions), // this resolves at first to [] and then whatever the API returns
|
||||
concat([[] as MenuItem[]], execAction) // this resolves at first to [] and then whatever the API returns
|
||||
).pipe(map(res => ([] as MenuItem[]).concat(...res)));
|
||||
}
|
||||
|
||||
export function renderResourceMenu(
|
||||
|
||||
@@ -38,7 +38,7 @@ export const Help = () => {
|
||||
<div className='help-box'>
|
||||
<p>Want to download the CLI tool?</p>
|
||||
<a href={`download/argocd-linux-${process.env.HOST_ARCH}`} className='user-info-panel-buttons argo-button argo-button--base'>
|
||||
<i className='fab fa-linux' /> Linux (amd64)
|
||||
<i className='fab fa-linux' /> Linux ({process.env.HOST_ARCH})
|
||||
</a>
|
||||
|
||||
{Object.keys(binaryUrls || {}).map(binaryName => {
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
<link rel='icon' type='image/png' href='assets/favicon/favicon-32x32.png' sizes='32x32'/>
|
||||
<link rel='icon' type='image/png' href='assets/favicon/favicon-16x16.png' sizes='16x16'/>
|
||||
<link href="assets/fonts.css" rel="stylesheet">
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
@@ -20,5 +21,5 @@
|
||||
</noscript>
|
||||
<div id="app"></div>
|
||||
</body>
|
||||
|
||||
<script defer src="extensions.js"></script>
|
||||
</html>
|
||||
|
||||
@@ -27,4 +27,8 @@ export class AccountsService {
|
||||
public deleteToken(name: string, id: string): Promise<any> {
|
||||
return requests.delete(`/account/${name}/token/${id}`);
|
||||
}
|
||||
|
||||
public canI(resource: string, action: string, subresource: string): Promise<boolean> {
|
||||
return requests.get(`/account/can-i/${resource}/${action}/${subresource}`).then(res => res.body.value === 'yes');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,40 +1,62 @@
|
||||
import * as React from 'react';
|
||||
import {ApplicationTree, State} from '../models';
|
||||
import * as minimatch from 'minimatch';
|
||||
|
||||
const extensions: {resources: {[key: string]: Extension}} = {resources: {}};
|
||||
const cache = new Map<string, Promise<Extension>>();
|
||||
import {Application, ApplicationTree, State} from '../models';
|
||||
|
||||
const extensions = {
|
||||
resourceExtentions: new Array<ResourceTabExtension>()
|
||||
};
|
||||
|
||||
function registerResourceExtension(component: ExtensionComponent, group: string, kind: string, tabTitle: string, opts?: {icon: string}) {
|
||||
extensions.resourceExtentions.push({component, group, kind, title: tabTitle, icon: opts?.icon});
|
||||
}
|
||||
|
||||
let legacyInitialized = false;
|
||||
|
||||
function initLegacyExtensions() {
|
||||
if (legacyInitialized) {
|
||||
return;
|
||||
}
|
||||
legacyInitialized = true;
|
||||
const resources = (window as any).extensions.resources;
|
||||
Object.keys(resources).forEach(key => {
|
||||
const [group, kind] = key.split('/');
|
||||
registerResourceExtension(resources[key].component, group, kind, 'More');
|
||||
});
|
||||
}
|
||||
|
||||
export interface ResourceTabExtension {
|
||||
title: string;
|
||||
group: string;
|
||||
kind: string;
|
||||
component: ExtensionComponent;
|
||||
icon?: string;
|
||||
}
|
||||
|
||||
export type ExtensionComponent = React.ComponentType<ExtensionComponentProps>;
|
||||
|
||||
export interface Extension {
|
||||
component: React.ComponentType<ExtensionComponentProps>;
|
||||
component: ExtensionComponent;
|
||||
}
|
||||
|
||||
export interface ExtensionComponentProps {
|
||||
resource: State;
|
||||
tree: ApplicationTree;
|
||||
application: Application;
|
||||
}
|
||||
|
||||
export class ExtensionsService {
|
||||
public async loadResourceExtension(group: string, kind: string): Promise<Extension> {
|
||||
const key = `${group}/${kind}`;
|
||||
const res =
|
||||
cache.get(key) ||
|
||||
new Promise<Extension>((resolve, reject) => {
|
||||
const script = document.createElement('script');
|
||||
script.src = `extensions/resources/${group}/${kind}/ui/extensions.js`;
|
||||
script.onload = () => {
|
||||
const ext = extensions.resources[key];
|
||||
if (!ext) {
|
||||
reject(`Failed to load extension for ${group}/${kind}`);
|
||||
} else {
|
||||
resolve(ext);
|
||||
}
|
||||
};
|
||||
script.onerror = reject;
|
||||
document.body.appendChild(script);
|
||||
});
|
||||
cache.set(key, res);
|
||||
return res;
|
||||
public getResourceTabs(group: string, kind: string): ResourceTabExtension[] {
|
||||
initLegacyExtensions();
|
||||
const items = extensions.resourceExtentions.filter(extension => minimatch(group, extension.group) && minimatch(kind, extension.kind)).slice();
|
||||
return items.sort((a, b) => a.title.localeCompare(b.title));
|
||||
}
|
||||
}
|
||||
|
||||
(window as any).extensions = extensions;
|
||||
((window: any) => {
|
||||
// deprecated: kept for backwards compatibility
|
||||
window.extensions = {resources: {}};
|
||||
window.extensionsAPI = {
|
||||
registerResourceExtension
|
||||
};
|
||||
})(window);
|
||||
|
||||
23
ui/yarn.lock
23
ui/yarn.lock
@@ -6338,15 +6338,10 @@ moment-timezone@^0.5.33:
|
||||
dependencies:
|
||||
moment ">= 2.9.0"
|
||||
|
||||
"moment@>= 2.9.0", moment@^2.24.0, moment@^2.25.3:
|
||||
version "2.29.1"
|
||||
resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3"
|
||||
integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==
|
||||
|
||||
moment@^2.29.2:
|
||||
version "2.29.2"
|
||||
resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.2.tgz#00910c60b20843bcba52d37d58c628b47b1f20e4"
|
||||
integrity sha512-UgzG4rvxYpN15jgCmVJwac49h9ly9NurikMWGPdVxm8GZD6XjkKPxDTjQQ43gtGgnV3X0cAyWDdP2Wexoquifg==
|
||||
"moment@>= 2.9.0", moment@^2.24.0, moment@^2.25.3, moment@^2.29.2, moment@^2.29.4:
|
||||
version "2.29.4"
|
||||
resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108"
|
||||
integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==
|
||||
|
||||
monaco-editor-webpack-plugin@^7.0.0:
|
||||
version "7.0.1"
|
||||
@@ -6792,7 +6787,7 @@ parse-json@^5.2.0:
|
||||
json-parse-even-better-errors "^2.3.0"
|
||||
lines-and-columns "^1.1.6"
|
||||
|
||||
parse-path@^4.0.4:
|
||||
parse-path@^4.0.0:
|
||||
version "4.0.4"
|
||||
resolved "https://registry.yarnpkg.com/parse-path/-/parse-path-4.0.4.tgz#4bf424e6b743fb080831f03b536af9fc43f0ffea"
|
||||
integrity sha512-Z2lWUis7jlmXC1jeOG9giRO2+FsuyNipeQ43HAjqAZjwSe3SEf+q/84FGPHoso3kyntbxa4c4i77t3m6fGf8cw==
|
||||
@@ -6803,13 +6798,13 @@ parse-path@^4.0.4:
|
||||
query-string "^6.13.8"
|
||||
|
||||
parse-url@^6.0.0:
|
||||
version "6.0.2"
|
||||
resolved "https://registry.yarnpkg.com/parse-url/-/parse-url-6.0.2.tgz#4a30b057bfc452af64512dfb1a7755c103db3ea1"
|
||||
integrity sha512-uCSjOvD3T+6B/sPWhR+QowAZcU/o4bjPrVBQBGFxcDF6J6FraCGIaDBsdoQawiaaAVdHvtqBe3w3vKlfBKySOQ==
|
||||
version "6.0.5"
|
||||
resolved "https://registry.yarnpkg.com/parse-url/-/parse-url-6.0.5.tgz#4acab8982cef1846a0f8675fa686cef24b2f6f9b"
|
||||
integrity sha512-e35AeLTSIlkw/5GFq70IN7po8fmDUjpDPY1rIK+VubRfsUvBonjQ+PBZG+vWMACnQSmNlvl524IucoDmcioMxA==
|
||||
dependencies:
|
||||
is-ssh "^1.3.0"
|
||||
normalize-url "^6.1.0"
|
||||
parse-path "^4.0.4"
|
||||
parse-path "^4.0.0"
|
||||
protocols "^1.4.0"
|
||||
|
||||
parse5@6.0.1:
|
||||
|
||||
@@ -190,7 +190,7 @@ func (a *ClientApp) verifyAppState(r *http.Request, w http.ResponseWriter, state
|
||||
redirectURL := a.baseHRef
|
||||
parts := strings.SplitN(cookieVal, ":", 2)
|
||||
if len(parts) == 2 && parts[1] != "" {
|
||||
if !isValidRedirectURL(parts[1], []string{a.settings.URL}) {
|
||||
if !isValidRedirectURL(parts[1], []string{a.settings.URL, a.baseHRef}) {
|
||||
sanitizedUrl := parts[1]
|
||||
if len(sanitizedUrl) > 100 {
|
||||
sanitizedUrl = sanitizedUrl[:100]
|
||||
|
||||
@@ -192,6 +192,52 @@ requestedScopes: ["oidc"]`, oidcTestServer.URL),
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Login_Flow(t *testing.T) {
|
||||
// Show that SSO login works when no redirect URL is provided, and we fall back to the configured base href for the
|
||||
// Argo CD instance.
|
||||
|
||||
oidcTestServer := test.GetOIDCTestServer(t)
|
||||
t.Cleanup(oidcTestServer.Close)
|
||||
|
||||
cdSettings := &settings.ArgoCDSettings{
|
||||
URL: "https://argocd.example.com",
|
||||
OIDCConfigRAW: fmt.Sprintf(`
|
||||
name: Test
|
||||
issuer: %s
|
||||
clientID: xxx
|
||||
clientSecret: yyy
|
||||
requestedScopes: ["oidc"]`, oidcTestServer.URL),
|
||||
OIDCTLSInsecureSkipVerify: true,
|
||||
}
|
||||
|
||||
// The base href (the last argument for NewClientApp) is what HandleLogin will fall back to when no explicit
|
||||
// redirect URL is given.
|
||||
app, err := NewClientApp(cdSettings, "", "/")
|
||||
require.NoError(t, err)
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
req := httptest.NewRequest("GET", "https://argocd.example.com/auth/login", nil)
|
||||
|
||||
app.HandleLogin(w, req)
|
||||
|
||||
redirectUrl, err := w.Result().Location()
|
||||
require.NoError(t, err)
|
||||
|
||||
state := redirectUrl.Query()["state"]
|
||||
|
||||
req = httptest.NewRequest("GET", fmt.Sprintf("https://argocd.example.com/auth/callback?state=%s&code=abc", state), nil)
|
||||
for _, cookie := range w.Result().Cookies() {
|
||||
req.AddCookie(cookie)
|
||||
}
|
||||
|
||||
w = httptest.NewRecorder()
|
||||
|
||||
app.HandleCallback(w, req)
|
||||
|
||||
assert.NotContains(t, w.Body.String(), InvalidRedirectURLError.Error())
|
||||
}
|
||||
|
||||
func TestClientApp_HandleCallback(t *testing.T) {
|
||||
oidcTestServer := test.GetOIDCTestServer(t)
|
||||
t.Cleanup(oidcTestServer.Close)
|
||||
|
||||
Reference in New Issue
Block a user