Compare commits

...

23 Commits

Author SHA1 Message Date
github-actions[bot]
fbb6b20418 Bump version to 2.9.7 (#17372)
Signed-off-by: GitHub <noreply@github.com>
Co-authored-by: crenshaw-dev <crenshaw-dev@users.noreply.github.com>
2024-03-01 17:20:49 -05:00
gcp-cherry-pick-bot[bot]
f05a6b7906 fix: The argocd server api-content-type flag does not allow empty content-type header (#17331) (#17347)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
Co-authored-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2024-02-28 10:15:39 -08:00
gcp-cherry-pick-bot[bot]
7aac4ba0f0 Corrected certificate managment for OCI helm charts (#16656) (#17321)
Signed-off-by: Andrew Block <andy.block@gmail.com>
Co-authored-by: Andrew Block <andy.block@gmail.com>
Co-authored-by: Soumya Ghosh Dastidar <44349253+gdsoumya@users.noreply.github.com>
2024-02-27 17:15:51 -05:00
Prune Sebastien THOMAS
7cac5a8946 backporting kustomize build dir patch from 2.10 (#17132)
Signed-off-by: Prune <prune@lecentre.net>
2024-02-07 18:43:33 -05:00
github-actions[bot]
ba62a0a86d Bump version to 2.9.6 (#17078)
Signed-off-by: GitHub <noreply@github.com>
Co-authored-by: crenshaw-dev <crenshaw-dev@users.noreply.github.com>
2024-02-02 13:12:07 -05:00
AS
3fa66ec42c chore(deps): rm go-jose Cxb6dee8d5-b814 high vuln (#16947) (#16970) (#17056)
* chore(deps): rm go-jose Cxb6dee8d5-b814 high vuln (#16947) (#16970)

Signed-off-by: fengshunli <1171313930@qq.com>
Co-authored-by: fsl <1171313930@qq.com>

* chore(deps): rm go-jose Cxb6dee8d5-b814 high vuln

Signed-off-by: asingh51 <ashutosh_singh@intuit.com>

---------

Signed-off-by: fengshunli <1171313930@qq.com>
Signed-off-by: asingh51 <ashutosh_singh@intuit.com>
Co-authored-by: gcp-cherry-pick-bot[bot] <98988430+gcp-cherry-pick-bot[bot]@users.noreply.github.com>
Co-authored-by: fsl <1171313930@qq.com>
Co-authored-by: asingh51 <ashutosh_singh@intuit.com>
2024-01-31 15:14:28 -05:00
gcp-cherry-pick-bot[bot]
cc672e7609 fix(redis): go-redis v9 regression missing metrics and reconnect hook (#13415) (#15275) (#17024)
* fix(redis): go-redis v9 regression missing metrics and reconnect hook



* fix: golangci lint return values not checked in tests



* chore: move dnsError var locally into func



---------

Signed-off-by: phanama <yudiandreanp@gmail.com>
Co-authored-by: Yudi A Phanama <11147376+phanama@users.noreply.github.com>
2024-01-30 09:44:44 -05:00
gcp-cherry-pick-bot[bot]
cce1e97434 fix(ui): Badge for apps in any namespace (#16739) (#17008)
Signed-off-by: sshenoy6 <sonamkaup_shenoy@intuit.com>
Co-authored-by: Sonam <49382298+sonamkshenoy@users.noreply.github.com>
Co-authored-by: sshenoy6 <sonamkaup_shenoy@intuit.com>
2024-01-26 15:04:03 -05:00
Michael Crenshaw
f43122d3cd fix(server): allow disabling content-type check (#16959) (#16977)
* fix(server): allow disabling content-type check



* fix spacing



---------

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2024-01-24 18:08:09 -05:00
github-actions[bot]
f9436641a6 Bump version to 2.9.5 (#16937)
Signed-off-by: GitHub <noreply@github.com>
Co-authored-by: crenshaw-dev <crenshaw-dev@users.noreply.github.com>
2024-01-19 12:20:10 -05:00
gcp-cherry-pick-bot[bot]
7561cc1cdd fix(ui): set content-type for certain UI requests (#16923) (#16930) (#16933)
Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Co-authored-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2024-01-19 11:49:36 -05:00
github-actions[bot]
bb06722d98 Bump version to 2.9.4 (#16917)
Signed-off-by: GitHub <noreply@github.com>
Co-authored-by: crenshaw-dev <crenshaw-dev@users.noreply.github.com>
2024-01-18 15:43:07 -05:00
Michael Crenshaw
997f89a92c chore(deps): bump github.com/go-git/go-git/v5 from 5.8.1 to 5.11.0 (#16912)
* chore(deps): bump github.com/go-git/go-git/v5 from 5.8.1 to 5.11.0

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>

* tidy

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>

---------

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
2024-01-18 10:56:49 -05:00
Alexander Matyushentsev
f569aa105e fix: enforce content type header for API requests (#16860) (Cherry-pick release-2.9 ) (#16878)
* chore: skip server certificate verification for http requests in e2e tests (#15733)

* chore: skip verifying server certificate for http requests in e2e tests

Signed-off-by: Chris Fry <christopherfry@google.com>

* chore: skip certificate verification only for remote tests

Signed-off-by: Chris Fry <christopherfry@google.com>

---------

Signed-off-by: Chris Fry <christopherfry@google.com>

* fix: enforce content type header for API requests (#16860)

Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>

---------

Signed-off-by: Chris Fry <christopherfry@google.com>
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
Co-authored-by: Christopher Fry <ChristopherFry2008@gmail.com>
2024-01-16 13:03:22 -08:00
gcp-cherry-pick-bot[bot]
dac68ac593 fix: add list permission deployments (#16785) (#16804)
* add list permissions for deployments to application controller



* revert redis-ha chart changes



* revert redis-ha chart changes



---------

Signed-off-by: ishitasequeira <ishiseq29@gmail.com>
Co-authored-by: Ishita Sequeira <46771830+ishitasequeira@users.noreply.github.com>
2024-01-09 21:06:47 -05:00
gcp-cherry-pick-bot[bot]
45d4a071ae fix(ui):Fixed log horizontal scroll for issue #16411 (#16727) (#16761)
* Fixed log horizontal scroll



* Updated log line-height



---------

Signed-off-by: Yi Cai <yicai@redhat.com>
Co-authored-by: Yi Cai <yicai@redhat.com>
2024-01-05 13:44:35 -05:00
gcp-cherry-pick-bot[bot]
a10cb870f8 fix(action): Add missing owner refs and annotation to create-job action (#16607) (#16608)
Signed-off-by: Arron Francis <arron.francis@mettle.co.uk>
Co-authored-by: afrancis101 <64639952+afrancis101@users.noreply.github.com>
2023-12-14 11:50:27 -05:00
gcp-cherry-pick-bot[bot]
8436954759 Added missing 'alias:' prefix for repository name as described here: (#15902) (#16535)
Co-authored-by: ffppmm <ffppmm@users.noreply.github.com>
2023-12-08 19:29:46 +05:30
Maxime Brunet
ab3b2e780e fix(grpcproxy): add missing GRPCKeepAliveEnforcementMinimum (#15708) (#16576)
the absence of the setting potentially causes ENHANCE_YOUR_CALM

Signed-off-by: phanama <yudiandreanp@gmail.com>
Signed-off-by: Maxime Brunet <max@brnt.mx>
Co-authored-by: Yudi A Phanama <11147376+phanama@users.noreply.github.com>
Co-authored-by: Dan Garfield <dan@codefresh.io>
2023-12-08 18:18:44 +05:30
ericblackburn
0e65b848da fix(appset): don't emit k8s events for unchanged apps, log at debug (#16562)
Signed-off-by: Eric Blackburn <eblackburn@indeed.com>
2023-12-06 15:26:18 -05:00
gcp-cherry-pick-bot[bot]
9075601a68 docs: Fix format issue in rbac.md (#16521) (#16538)
Wrongly placed horizontal line (`----`) was formatting code-block as a header. Fixed it with a necessary line break

Signed-off-by: Elouan Keryell-Even <elouan.keryell@gmail.com>
Co-authored-by: Elouan Keryell-Even <elouan.keryell@gmail.com>
2023-12-06 11:47:19 -05:00
Zoltán Reegn
31860d09d4 chore: upgrade k8s client from v0.24.2 to v0.24.17 (#16554)
The new version fixes several well known CVE-s that tools like trivy
alert for.

Fixes #15628

Signed-off-by: Zoltán Reegn <zoltan.reegn@gmail.com>
2023-12-06 11:37:15 -05:00
gcp-cherry-pick-bot[bot]
65dec01de0 fix(appset): Don't use revision cache when reconciling after webhook (#16062) (#16241) (#16536)
* fix(appset): store sha from webhook to get latest change during reconcile (#16062)



* fix(appset): Don't use revision cache when reconciling after webhook(#16062)



---------

Signed-off-by: dhruvang1 <dhruvang1@users.noreply.github.com>
Co-authored-by: Dhruvang Makadia <dhruvang1@users.noreply.github.com>
2023-12-05 13:11:48 -08:00
52 changed files with 1007 additions and 801 deletions

View File

@@ -1 +1 @@
2.9.3
2.9.7

View File

@@ -687,8 +687,16 @@ func (r *ApplicationSetReconciler) createOrUpdateInCluster(ctx context.Context,
continue
}
r.updateCache(ctx, found, appLog)
r.Recorder.Eventf(&applicationSet, corev1.EventTypeNormal, fmt.Sprint(action), "%s Application %q", action, generatedApp.Name)
appLog.Logf(log.InfoLevel, "%s Application", action)
if action != controllerutil.OperationResultNone {
// Don't pollute etcd with "unchanged Application" events
r.Recorder.Eventf(&applicationSet, corev1.EventTypeNormal, fmt.Sprint(action), "%s Application %q", action, generatedApp.Name)
appLog.Logf(log.InfoLevel, "%s Application", action)
} else {
// "unchanged Application" can be inferred by Reconcile Complete with no action being listed
// Or enable debug logging
appLog.Logf(log.DebugLevel, "%s Application", action)
}
}
return firstError
}

View File

@@ -56,12 +56,14 @@ func (g *GitGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.Applic
return nil, EmptyAppSetGeneratorError
}
noRevisionCache := appSet.RefreshRequired()
var err error
var res []map[string]interface{}
if len(appSetGenerator.Git.Directories) != 0 {
res, err = g.generateParamsForGitDirectories(appSetGenerator, appSet.Spec.GoTemplate, appSet.Spec.GoTemplateOptions)
res, err = g.generateParamsForGitDirectories(appSetGenerator, noRevisionCache, appSet.Spec.GoTemplate, appSet.Spec.GoTemplateOptions)
} else if len(appSetGenerator.Git.Files) != 0 {
res, err = g.generateParamsForGitFiles(appSetGenerator, appSet.Spec.GoTemplate, appSet.Spec.GoTemplateOptions)
res, err = g.generateParamsForGitFiles(appSetGenerator, noRevisionCache, appSet.Spec.GoTemplate, appSet.Spec.GoTemplateOptions)
} else {
return nil, EmptyAppSetGeneratorError
}
@@ -72,10 +74,10 @@ func (g *GitGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.Applic
return res, nil
}
func (g *GitGenerator) generateParamsForGitDirectories(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, useGoTemplate bool, goTemplateOptions []string) ([]map[string]interface{}, error) {
func (g *GitGenerator) generateParamsForGitDirectories(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, noRevisionCache bool, useGoTemplate bool, goTemplateOptions []string) ([]map[string]interface{}, error) {
// Directories, not files
allPaths, err := g.repos.GetDirectories(context.TODO(), appSetGenerator.Git.RepoURL, appSetGenerator.Git.Revision)
allPaths, err := g.repos.GetDirectories(context.TODO(), appSetGenerator.Git.RepoURL, appSetGenerator.Git.Revision, noRevisionCache)
if err != nil {
return nil, fmt.Errorf("error getting directories from repo: %w", err)
}
@@ -98,12 +100,12 @@ func (g *GitGenerator) generateParamsForGitDirectories(appSetGenerator *argoproj
return res, nil
}
func (g *GitGenerator) generateParamsForGitFiles(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, useGoTemplate bool, goTemplateOptions []string) ([]map[string]interface{}, error) {
func (g *GitGenerator) generateParamsForGitFiles(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, noRevisionCache bool, useGoTemplate bool, goTemplateOptions []string) ([]map[string]interface{}, error) {
// Get all files that match the requested path string, removing duplicates
allFiles := make(map[string][]byte)
for _, requestedPath := range appSetGenerator.Git.Files {
files, err := g.repos.GetFiles(context.TODO(), appSetGenerator.Git.RepoURL, appSetGenerator.Git.Revision, requestedPath.Path)
files, err := g.repos.GetFiles(context.TODO(), appSetGenerator.Git.RepoURL, appSetGenerator.Git.Revision, requestedPath.Path, noRevisionCache)
if err != nil {
return nil, err
}

View File

@@ -263,7 +263,7 @@ func TestGitGenerateParamsFromDirectories(t *testing.T) {
argoCDServiceMock := mocks.Repos{}
argoCDServiceMock.On("GetDirectories", mock.Anything, mock.Anything, mock.Anything).Return(testCaseCopy.repoApps, testCaseCopy.repoError)
argoCDServiceMock.On("GetDirectories", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(testCaseCopy.repoApps, testCaseCopy.repoError)
var gitGenerator = NewGitGenerator(&argoCDServiceMock)
applicationSetInfo := argoprojiov1alpha1.ApplicationSet{
@@ -559,7 +559,7 @@ func TestGitGenerateParamsFromDirectoriesGoTemplate(t *testing.T) {
argoCDServiceMock := mocks.Repos{}
argoCDServiceMock.On("GetDirectories", mock.Anything, mock.Anything, mock.Anything).Return(testCaseCopy.repoApps, testCaseCopy.repoError)
argoCDServiceMock.On("GetDirectories", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(testCaseCopy.repoApps, testCaseCopy.repoError)
var gitGenerator = NewGitGenerator(&argoCDServiceMock)
applicationSetInfo := argoprojiov1alpha1.ApplicationSet{
@@ -918,7 +918,7 @@ cluster:
t.Parallel()
argoCDServiceMock := mocks.Repos{}
argoCDServiceMock.On("GetFiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything).
argoCDServiceMock.On("GetFiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).
Return(testCaseCopy.repoFileContents, testCaseCopy.repoPathsError)
var gitGenerator = NewGitGenerator(&argoCDServiceMock)
@@ -1268,7 +1268,7 @@ cluster:
t.Parallel()
argoCDServiceMock := mocks.Repos{}
argoCDServiceMock.On("GetFiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything).
argoCDServiceMock.On("GetFiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).
Return(testCaseCopy.repoFileContents, testCaseCopy.repoPathsError)
var gitGenerator = NewGitGenerator(&argoCDServiceMock)

View File

@@ -1108,7 +1108,7 @@ func TestGitGenerator_GenerateParams_list_x_git_matrix_generator(t *testing.T) {
}
repoServiceMock := &mocks.Repos{}
repoServiceMock.On("GetFiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(map[string][]byte{
repoServiceMock.On("GetFiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(map[string][]byte{
"some/path.json": []byte("test: content"),
}, nil)
gitGenerator := NewGitGenerator(repoServiceMock)

View File

@@ -13,25 +13,25 @@ type Repos struct {
mock.Mock
}
// GetDirectories provides a mock function with given fields: ctx, repoURL, revision
func (_m *Repos) GetDirectories(ctx context.Context, repoURL string, revision string) ([]string, error) {
ret := _m.Called(ctx, repoURL, revision)
// GetDirectories provides a mock function with given fields: ctx, repoURL, revision, noRevisionCache
func (_m *Repos) GetDirectories(ctx context.Context, repoURL string, revision string, noRevisionCache bool) ([]string, error) {
ret := _m.Called(ctx, repoURL, revision, noRevisionCache)
var r0 []string
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string, string) ([]string, error)); ok {
return rf(ctx, repoURL, revision)
if rf, ok := ret.Get(0).(func(context.Context, string, string, bool) ([]string, error)); ok {
return rf(ctx, repoURL, revision, noRevisionCache)
}
if rf, ok := ret.Get(0).(func(context.Context, string, string) []string); ok {
r0 = rf(ctx, repoURL, revision)
if rf, ok := ret.Get(0).(func(context.Context, string, string, bool) []string); ok {
r0 = rf(ctx, repoURL, revision, noRevisionCache)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]string)
}
}
if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok {
r1 = rf(ctx, repoURL, revision)
if rf, ok := ret.Get(1).(func(context.Context, string, string, bool) error); ok {
r1 = rf(ctx, repoURL, revision, noRevisionCache)
} else {
r1 = ret.Error(1)
}
@@ -39,25 +39,25 @@ func (_m *Repos) GetDirectories(ctx context.Context, repoURL string, revision st
return r0, r1
}
// GetFiles provides a mock function with given fields: ctx, repoURL, revision, pattern
func (_m *Repos) GetFiles(ctx context.Context, repoURL string, revision string, pattern string) (map[string][]byte, error) {
ret := _m.Called(ctx, repoURL, revision, pattern)
// GetFiles provides a mock function with given fields: ctx, repoURL, revision, pattern, noRevisionCache
func (_m *Repos) GetFiles(ctx context.Context, repoURL string, revision string, pattern string, noRevisionCache bool) (map[string][]byte, error) {
ret := _m.Called(ctx, repoURL, revision, pattern, noRevisionCache)
var r0 map[string][]byte
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string, string, string) (map[string][]byte, error)); ok {
return rf(ctx, repoURL, revision, pattern)
if rf, ok := ret.Get(0).(func(context.Context, string, string, string, bool) (map[string][]byte, error)); ok {
return rf(ctx, repoURL, revision, pattern, noRevisionCache)
}
if rf, ok := ret.Get(0).(func(context.Context, string, string, string) map[string][]byte); ok {
r0 = rf(ctx, repoURL, revision, pattern)
if rf, ok := ret.Get(0).(func(context.Context, string, string, string, bool) map[string][]byte); ok {
r0 = rf(ctx, repoURL, revision, pattern, noRevisionCache)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(map[string][]byte)
}
}
if rf, ok := ret.Get(1).(func(context.Context, string, string, string) error); ok {
r1 = rf(ctx, repoURL, revision, pattern)
if rf, ok := ret.Get(1).(func(context.Context, string, string, string, bool) error); ok {
r1 = rf(ctx, repoURL, revision, pattern, noRevisionCache)
} else {
r1 = ret.Error(1)
}

View File

@@ -11,6 +11,8 @@ import (
"github.com/argoproj/argo-cd/v2/util/io"
)
//go:generate go run github.com/vektra/mockery/v2@v2.25.1 --name=RepositoryDB
// RepositoryDB Is a lean facade for ArgoDB,
// Using a lean interface makes it easier to test the functionality of the git generator
type RepositoryDB interface {
@@ -25,13 +27,15 @@ type argoCDService struct {
newFileGlobbingEnabled bool
}
//go:generate go run github.com/vektra/mockery/v2@v2.25.1 --name=Repos
type Repos interface {
// GetFiles returns content of files (not directories) within the target repo
GetFiles(ctx context.Context, repoURL string, revision string, pattern string) (map[string][]byte, error)
GetFiles(ctx context.Context, repoURL string, revision string, pattern string, noRevisionCache bool) (map[string][]byte, error)
// GetDirectories returns a list of directories (not files) within the target repo
GetDirectories(ctx context.Context, repoURL string, revision string) ([]string, error)
GetDirectories(ctx context.Context, repoURL string, revision string, noRevisionCache bool) ([]string, error)
}
func NewArgoCDService(db db.ArgoDB, submoduleEnabled bool, repoClientset apiclient.Clientset, newFileGlobbingEnabled bool) (Repos, error) {
@@ -43,7 +47,7 @@ func NewArgoCDService(db db.ArgoDB, submoduleEnabled bool, repoClientset apiclie
}, nil
}
func (a *argoCDService) GetFiles(ctx context.Context, repoURL string, revision string, pattern string) (map[string][]byte, error) {
func (a *argoCDService) GetFiles(ctx context.Context, repoURL string, revision string, pattern string, noRevisionCache bool) (map[string][]byte, error) {
repo, err := a.repositoriesDB.GetRepository(ctx, repoURL)
if err != nil {
return nil, fmt.Errorf("error in GetRepository: %w", err)
@@ -55,6 +59,7 @@ func (a *argoCDService) GetFiles(ctx context.Context, repoURL string, revision s
Revision: revision,
Path: pattern,
NewGitFileGlobbingEnabled: a.newFileGlobbingEnabled,
NoRevisionCache: noRevisionCache,
}
closer, client, err := a.repoServerClientSet.NewRepoServerClient()
if err != nil {
@@ -69,7 +74,7 @@ func (a *argoCDService) GetFiles(ctx context.Context, repoURL string, revision s
return fileResponse.GetMap(), nil
}
func (a *argoCDService) GetDirectories(ctx context.Context, repoURL string, revision string) ([]string, error) {
func (a *argoCDService) GetDirectories(ctx context.Context, repoURL string, revision string, noRevisionCache bool) ([]string, error) {
repo, err := a.repositoriesDB.GetRepository(ctx, repoURL)
if err != nil {
return nil, fmt.Errorf("error in GetRepository: %w", err)
@@ -79,6 +84,7 @@ func (a *argoCDService) GetDirectories(ctx context.Context, repoURL string, revi
Repo: repo,
SubmoduleEnabled: a.submoduleEnabled,
Revision: revision,
NoRevisionCache: noRevisionCache,
}
closer, client, err := a.repoServerClientSet.NewRepoServerClient()

View File

@@ -25,9 +25,10 @@ func TestGetDirectories(t *testing.T) {
repoServerClientFuncs []func(*repo_mocks.RepoServerServiceClient)
}
type args struct {
ctx context.Context
repoURL string
revision string
ctx context.Context
repoURL string
revision string
noRevisionCache bool
}
tests := []struct {
name string
@@ -88,11 +89,11 @@ func TestGetDirectories(t *testing.T) {
submoduleEnabled: tt.fields.submoduleEnabled,
repoServerClientSet: &repo_mocks.Clientset{RepoServerServiceClient: mockRepoClient},
}
got, err := a.GetDirectories(tt.args.ctx, tt.args.repoURL, tt.args.revision)
if !tt.wantErr(t, err, fmt.Sprintf("GetDirectories(%v, %v, %v)", tt.args.ctx, tt.args.repoURL, tt.args.revision)) {
got, err := a.GetDirectories(tt.args.ctx, tt.args.repoURL, tt.args.revision, tt.args.noRevisionCache)
if !tt.wantErr(t, err, fmt.Sprintf("GetDirectories(%v, %v, %v, %v)", tt.args.ctx, tt.args.repoURL, tt.args.revision, tt.args.noRevisionCache)) {
return
}
assert.Equalf(t, tt.want, got, "GetDirectories(%v, %v, %v)", tt.args.ctx, tt.args.repoURL, tt.args.revision)
assert.Equalf(t, tt.want, got, "GetDirectories(%v, %v, %v, %v)", tt.args.ctx, tt.args.repoURL, tt.args.revision, tt.args.noRevisionCache)
})
}
}
@@ -105,10 +106,11 @@ func TestGetFiles(t *testing.T) {
repoServerClientFuncs []func(*repo_mocks.RepoServerServiceClient)
}
type args struct {
ctx context.Context
repoURL string
revision string
pattern string
ctx context.Context
repoURL string
revision string
pattern string
noRevisionCache bool
}
tests := []struct {
name string
@@ -175,11 +177,11 @@ func TestGetFiles(t *testing.T) {
submoduleEnabled: tt.fields.submoduleEnabled,
repoServerClientSet: &repo_mocks.Clientset{RepoServerServiceClient: mockRepoClient},
}
got, err := a.GetFiles(tt.args.ctx, tt.args.repoURL, tt.args.revision, tt.args.pattern)
if !tt.wantErr(t, err, fmt.Sprintf("GetFiles(%v, %v, %v, %v)", tt.args.ctx, tt.args.repoURL, tt.args.revision, tt.args.pattern)) {
got, err := a.GetFiles(tt.args.ctx, tt.args.repoURL, tt.args.revision, tt.args.pattern, tt.args.noRevisionCache)
if !tt.wantErr(t, err, fmt.Sprintf("GetFiles(%v, %v, %v, %v, %v)", tt.args.ctx, tt.args.repoURL, tt.args.revision, tt.args.pattern, tt.args.noRevisionCache)) {
return
}
assert.Equalf(t, tt.want, got, "GetFiles(%v, %v, %v, %v)", tt.args.ctx, tt.args.repoURL, tt.args.revision, tt.args.pattern)
assert.Equalf(t, tt.want, got, "GetFiles(%v, %v, %v, %v, %v)", tt.args.ctx, tt.args.repoURL, tt.args.revision, tt.args.pattern, tt.args.noRevisionCache)
})
}
}

View File

@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"math"
"strings"
"time"
"github.com/argoproj/pkg/stats"
@@ -58,6 +59,7 @@ func NewCommand() *cobra.Command {
repoServerAddress string
dexServerAddress string
disableAuth bool
contentTypes string
enableGZip bool
tlsConfigCustomizerSrc func() (tls.ConfigCustomizer, error)
cacheSrc func() (*servercache.Cache, error)
@@ -162,6 +164,11 @@ func NewCommand() *cobra.Command {
baseHRef = rootPath
}
var contentTypesList []string
if contentTypes != "" {
contentTypesList = strings.Split(contentTypes, ";")
}
argoCDOpts := server.ArgoCDServerOpts{
Insecure: insecure,
ListenPort: listenPort,
@@ -177,6 +184,7 @@ func NewCommand() *cobra.Command {
DexServerAddr: dexServerAddress,
DexTLSConfig: dexTlsConfig,
DisableAuth: disableAuth,
ContentTypes: contentTypesList,
EnableGZip: enableGZip,
TLSConfigCustomizer: tlsConfigCustomizer,
Cache: cache,
@@ -224,6 +232,7 @@ func NewCommand() *cobra.Command {
command.Flags().StringVar(&repoServerAddress, "repo-server", env.StringFromEnv("ARGOCD_SERVER_REPO_SERVER", common.DefaultRepoServerAddr), "Repo server address")
command.Flags().StringVar(&dexServerAddress, "dex-server", env.StringFromEnv("ARGOCD_SERVER_DEX_SERVER", common.DefaultDexServerAddr), "Dex server address")
command.Flags().BoolVar(&disableAuth, "disable-auth", env.ParseBoolFromEnv("ARGOCD_SERVER_DISABLE_AUTH", false), "Disable client authentication")
command.Flags().StringVar(&contentTypes, "api-content-types", env.StringFromEnv("ARGOCD_API_CONTENT_TYPES", "application/json", env.StringFromEnvOpts{AllowEmpty: true}), "Semicolon separated list of allowed content types for non GET api requests. Any content type is allowed if empty.")
command.Flags().BoolVar(&enableGZip, "enable-gzip", env.ParseBoolFromEnv("ARGOCD_SERVER_ENABLE_GZIP", true), "Enable GZIP compression")
command.AddCommand(cli.NewVersionCmd(cliName))
command.Flags().StringVar(&listenHost, "address", env.StringFromEnv("ARGOCD_SERVER_LISTEN_ADDRESS", common.DefaultAddressAPIServer), "Listen on given address")

View File

@@ -1031,6 +1031,7 @@ func NewApplicationDiffCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
defer argoio.Close(conn)
cluster, err := clusterIf.Get(ctx, &clusterpkg.ClusterQuery{Name: app.Spec.Destination.Name, Server: app.Spec.Destination.Server})
errors.CheckError(err)
diffOption.local = local
diffOption.localRepoRoot = localRepoRoot
diffOption.cluster = cluster

View File

@@ -72,6 +72,9 @@ data:
server.rootpath: ""
# Directory path that contains additional static assets
server.staticassets: "/shared/app"
# Semicolon-separated list of content types allowed on non-GET requests. Set an empty string to allow all. Be aware
# that allowing content types besides application/json may make your API more vulnerable to CSRF attacks.
server.api.content.types: "application/json"
# Set the logging format. One of: text|json (default "text")
server.log.format: "text"

View File

@@ -159,6 +159,7 @@ data:
g, your-github-org:your-team, role:org-admin
```
----
Another `policy.csv` example might look as follows:

View File

@@ -16,6 +16,7 @@ argocd-server [flags]
```
--address string Listen on given address (default "0.0.0.0")
--api-content-types string Semicolon separated list of allowed content types for non GET api requests. Any content type is allowed if empty. (default "application/json")
--app-state-cache-expiration duration Cache expiration for app state (default 1h0m0s)
--application-namespaces strings List of additional namespaces where application resources can be managed in
--as string Username to impersonate for the operation

100
go.mod
View File

@@ -25,7 +25,8 @@ require (
github.com/evanphx/json-patch v5.6.0+incompatible
github.com/fsnotify/fsnotify v1.6.0
github.com/gfleury/go-bitbucket-v1 v0.0.0-20220301131131-8e7ed04b843e
github.com/go-git/go-git/v5 v5.8.1
github.com/go-git/go-git/v5 v5.11.0
github.com/go-jose/go-jose/v3 v3.0.1
github.com/go-logr/logr v1.2.4
github.com/go-openapi/loads v0.21.2
github.com/go-openapi/runtime v0.26.0
@@ -36,7 +37,7 @@ require (
github.com/gogo/protobuf v1.3.2
github.com/golang-jwt/jwt/v4 v4.5.0
github.com/golang/protobuf v1.5.3
github.com/google/go-cmp v0.5.9
github.com/google/go-cmp v0.6.0
github.com/google/go-github/v35 v35.3.0
github.com/google/go-jsonnet v0.20.0
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
@@ -77,23 +78,22 @@ require (
go.opentelemetry.io/otel v1.16.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.16.0
go.opentelemetry.io/otel/sdk v1.16.0
golang.org/x/crypto v0.14.0
golang.org/x/crypto v0.16.0
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1
golang.org/x/oauth2 v0.11.0
golang.org/x/sync v0.3.0
golang.org/x/term v0.13.0
golang.org/x/term v0.15.0
google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc
google.golang.org/grpc v1.56.2
google.golang.org/protobuf v1.31.0
gopkg.in/square/go-jose.v2 v2.6.0
gopkg.in/yaml.v2 v2.4.0
gopkg.in/yaml.v3 v3.0.1
k8s.io/api v0.24.2
k8s.io/api v0.24.17
k8s.io/apiextensions-apiserver v0.24.2
k8s.io/apimachinery v0.24.2
k8s.io/apiserver v0.24.2
k8s.io/client-go v0.24.2
k8s.io/code-generator v0.24.2
k8s.io/apimachinery v0.24.17
k8s.io/apiserver v0.24.17
k8s.io/client-go v0.24.17
k8s.io/code-generator v0.24.17
k8s.io/klog/v2 v2.70.1
k8s.io/kube-openapi v0.0.0-20220627174259-011e075b9cb8
k8s.io/kubectl v0.24.2
@@ -151,9 +151,8 @@ require (
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/PagerDuty/go-pagerduty v1.7.0 // indirect
github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95 // indirect
github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 // indirect
github.com/RocketChat/Rocket.Chat.Go.SDK v0.0.0-20210112200207-10ab4d695d60 // indirect
github.com/acomagu/bufpipe v1.0.4 // indirect
github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a // indirect
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
github.com/beorn7/perks v1.0.1 // indirect
@@ -175,8 +174,7 @@ require (
github.com/ghodss/yaml v1.0.0 // indirect
github.com/go-errors/errors v1.4.2 // indirect
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
github.com/go-git/go-billy/v5 v5.4.1 // indirect
github.com/go-jose/go-jose/v3 v3.0.0 // indirect
github.com/go-git/go-billy/v5 v5.5.0 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-openapi/analysis v0.21.4 // indirect
github.com/go-openapi/errors v0.20.3 // indirect
@@ -234,7 +232,7 @@ require (
github.com/pjbgf/sha1cd v0.3.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_model v0.3.0 // indirect
github.com/prometheus/client_model v0.3.0
github.com/prometheus/common v0.42.0 // indirect
github.com/prometheus/procfs v0.10.1 // indirect
github.com/rivo/uniseg v0.4.4 // indirect
@@ -243,7 +241,7 @@ require (
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sergi/go-diff v1.1.0 // indirect
github.com/shopspring/decimal v1.2.0 // indirect
github.com/skeema/knownhosts v1.2.0 // indirect
github.com/skeema/knownhosts v1.2.1 // indirect
github.com/slack-go/slack v0.12.2 // indirect
github.com/spf13/cast v1.5.1 // indirect
github.com/stretchr/objx v0.5.0 // indirect
@@ -260,12 +258,12 @@ require (
go.opentelemetry.io/otel/trace v1.16.0 // indirect
go.opentelemetry.io/proto/otlp v0.19.0 // indirect
go.starlark.net v0.0.0-20220328144851-d1966c6b9fcd // indirect
golang.org/x/mod v0.9.0 // indirect
golang.org/x/net v0.17.0
golang.org/x/sys v0.13.0 // indirect
golang.org/x/text v0.13.0 // indirect
golang.org/x/mod v0.12.0 // indirect
golang.org/x/net v0.19.0
golang.org/x/sys v0.15.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/time v0.3.0 // indirect
golang.org/x/tools v0.7.0 // indirect
golang.org/x/tools v0.13.0 // indirect
gomodules.xyz/envconfig v1.3.1-0.20190308184047-426f31af0d45 // indirect
gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
gomodules.xyz/notify v0.1.1 // indirect
@@ -274,12 +272,12 @@ require (
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
k8s.io/cli-runtime v0.24.2 // indirect
k8s.io/component-base v0.24.2 // indirect
k8s.io/component-helpers v0.24.2 // indirect
k8s.io/cli-runtime v0.24.17 // indirect
k8s.io/component-base v0.24.17 // indirect
k8s.io/component-helpers v0.24.17 // indirect
k8s.io/gengo v0.0.0-20211129171323-c02415ce4185 // indirect
k8s.io/kube-aggregator v0.24.2 // indirect
k8s.io/kubernetes v1.24.2 // indirect
k8s.io/kubernetes v1.24.17 // indirect
sigs.k8s.io/json v0.0.0-20220525155127-227cbc7cc124 // indirect
sigs.k8s.io/kustomize/api v0.11.5 // indirect
sigs.k8s.io/kustomize/kyaml v0.13.7 // indirect
@@ -299,29 +297,31 @@ replace (
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.24.2
k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.24.2
k8s.io/apimachinery => k8s.io/apimachinery v0.24.2
k8s.io/apiserver => k8s.io/apiserver v0.24.2
k8s.io/cli-runtime => k8s.io/cli-runtime v0.24.2
k8s.io/client-go => k8s.io/client-go v0.24.2
k8s.io/cloud-provider => k8s.io/cloud-provider v0.24.2
k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.24.2
k8s.io/code-generator => k8s.io/code-generator v0.24.2
k8s.io/component-base => k8s.io/component-base v0.24.2
k8s.io/component-helpers => k8s.io/component-helpers v0.24.2
k8s.io/controller-manager => k8s.io/controller-manager v0.24.2
k8s.io/cri-api => k8s.io/cri-api v0.24.2
k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.24.2
k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.24.2
k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.24.2
k8s.io/kube-proxy => k8s.io/kube-proxy v0.24.2
k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.24.2
k8s.io/kubectl => k8s.io/kubectl v0.24.2
k8s.io/kubelet => k8s.io/kubelet v0.24.2
k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.24.2
k8s.io/metrics => k8s.io/metrics v0.24.2
k8s.io/mount-utils => k8s.io/mount-utils v0.24.2
k8s.io/pod-security-admission => k8s.io/pod-security-admission v0.24.2
k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.24.2
k8s.io/api => k8s.io/api v0.24.17
k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.24.17
k8s.io/apimachinery => k8s.io/apimachinery v0.24.17
k8s.io/apiserver => k8s.io/apiserver v0.24.17
k8s.io/cli-runtime => k8s.io/cli-runtime v0.24.17
k8s.io/client-go => k8s.io/client-go v0.24.17
k8s.io/cloud-provider => k8s.io/cloud-provider v0.24.17
k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.24.17
k8s.io/code-generator => k8s.io/code-generator v0.24.17
k8s.io/component-base => k8s.io/component-base v0.24.17
k8s.io/component-helpers => k8s.io/component-helpers v0.24.17
k8s.io/controller-manager => k8s.io/controller-manager v0.24.17
k8s.io/cri-api => k8s.io/cri-api v0.24.17
k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.24.17
k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.24.17
k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.24.17
k8s.io/kube-proxy => k8s.io/kube-proxy v0.24.17
k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.24.17
k8s.io/kubectl => k8s.io/kubectl v0.24.17
k8s.io/kubelet => k8s.io/kubelet v0.24.17
k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.24.17
k8s.io/metrics => k8s.io/metrics v0.24.17
k8s.io/mount-utils => k8s.io/mount-utils v0.24.17
k8s.io/pod-security-admission => k8s.io/pod-security-admission v0.24.17
k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.24.17
k8s.io/sample-cli-plugin => k8s.io/sample-cli-plugin v0.24.17
k8s.io/sample-controller => k8s.io/sample-controller v0.24.17
)

363
go.sum

File diff suppressed because it is too large Load Diff

View File

@@ -36,3 +36,11 @@ rules:
verbs:
- create
- list
- apiGroups:
- apps
resources:
- deployments
verbs:
- get
- list
- watch

View File

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

View File

@@ -25,136 +25,136 @@ spec:
env:
- name: ARGOCD_SERVER_INSECURE
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.insecure
optional: true
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.insecure
optional: true
- name: ARGOCD_SERVER_BASEHREF
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.basehref
optional: true
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.basehref
optional: true
- name: ARGOCD_SERVER_ROOTPATH
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.rootpath
optional: true
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.rootpath
optional: true
- name: ARGOCD_SERVER_LOGFORMAT
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.log.format
optional: true
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.log.format
optional: true
- name: ARGOCD_SERVER_LOG_LEVEL
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.log.level
optional: true
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.log.level
optional: true
- name: ARGOCD_SERVER_REPO_SERVER
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: repo.server
optional: true
configMapKeyRef:
name: argocd-cmd-params-cm
key: repo.server
optional: true
- name: ARGOCD_SERVER_DEX_SERVER
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.dex.server
optional: true
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.dex.server
optional: true
- name: ARGOCD_SERVER_DISABLE_AUTH
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.disable.auth
optional: true
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.disable.auth
optional: true
- name: ARGOCD_SERVER_ENABLE_GZIP
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.enable.gzip
optional: true
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.enable.gzip
optional: true
- name: ARGOCD_SERVER_REPO_SERVER_TIMEOUT_SECONDS
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.repo.server.timeout.seconds
optional: true
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.repo.server.timeout.seconds
optional: true
- name: ARGOCD_SERVER_X_FRAME_OPTIONS
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.x.frame.options
optional: true
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.x.frame.options
optional: true
- name: ARGOCD_SERVER_CONTENT_SECURITY_POLICY
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.content.security.policy
optional: true
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.content.security.policy
optional: true
- name: ARGOCD_SERVER_REPO_SERVER_PLAINTEXT
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.repo.server.plaintext
optional: true
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.repo.server.plaintext
optional: true
- name: ARGOCD_SERVER_REPO_SERVER_STRICT_TLS
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.repo.server.strict.tls
optional: true
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.repo.server.strict.tls
optional: true
- name: ARGOCD_SERVER_DEX_SERVER_PLAINTEXT
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.dex.server.plaintext
optional: true
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.dex.server.plaintext
optional: true
- name: ARGOCD_SERVER_DEX_SERVER_STRICT_TLS
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.dex.server.strict.tls
optional: true
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.dex.server.strict.tls
optional: true
- name: ARGOCD_TLS_MIN_VERSION
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.tls.minversion
optional: true
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.tls.minversion
optional: true
- name: ARGOCD_TLS_MAX_VERSION
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.tls.maxversion
optional: true
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.tls.maxversion
optional: true
- name: ARGOCD_TLS_CIPHERS
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.tls.ciphers
optional: true
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.tls.ciphers
optional: true
- name: ARGOCD_SERVER_CONNECTION_STATUS_CACHE_EXPIRATION
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.connection.status.cache.expiration
optional: true
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.connection.status.cache.expiration
optional: true
- name: ARGOCD_SERVER_OIDC_CACHE_EXPIRATION
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.oidc.cache.expiration
optional: true
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.oidc.cache.expiration
optional: true
- name: ARGOCD_SERVER_LOGIN_ATTEMPTS_EXPIRATION
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.login.attempts.expiration
optional: true
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.login.attempts.expiration
optional: true
- name: ARGOCD_SERVER_STATIC_ASSETS
valueFrom:
configMapKeyRef:
@@ -163,16 +163,16 @@ spec:
optional: true
- name: ARGOCD_APP_STATE_CACHE_EXPIRATION
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.app.state.cache.expiration
optional: true
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.app.state.cache.expiration
optional: true
- name: REDIS_SERVER
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: redis.server
optional: true
configMapKeyRef:
name: argocd-cmd-params-cm
key: redis.server
optional: true
- name: REDIS_COMPRESSION
valueFrom:
configMapKeyRef:
@@ -181,52 +181,58 @@ spec:
optional: true
- name: REDISDB
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: redis.db
optional: true
configMapKeyRef:
name: argocd-cmd-params-cm
key: redis.db
optional: true
- name: ARGOCD_DEFAULT_CACHE_EXPIRATION
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.default.cache.expiration
optional: true
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.default.cache.expiration
optional: true
- name: ARGOCD_MAX_COOKIE_NUMBER
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.http.cookie.maxnumber
optional: true
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.http.cookie.maxnumber
optional: true
- name: ARGOCD_SERVER_LISTEN_ADDRESS
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.listen.address
optional: true
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.listen.address
optional: true
- name: ARGOCD_SERVER_METRICS_LISTEN_ADDRESS
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.metrics.listen.address
optional: true
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.metrics.listen.address
optional: true
- name: ARGOCD_SERVER_OTLP_ADDRESS
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: otlp.address
optional: true
configMapKeyRef:
name: argocd-cmd-params-cm
key: otlp.address
optional: true
- name: ARGOCD_APPLICATION_NAMESPACES
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: application.namespaces
optional: true
configMapKeyRef:
name: argocd-cmd-params-cm
key: application.namespaces
optional: true
- name: ARGOCD_SERVER_ENABLE_PROXY_EXTENSION
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.enable.proxy.extension
optional: true
- name: ARGOCD_API_CONTENT_TYPES
valueFrom:
configMapKeyRef:
name: argocd-cmd-params-cm
key: server.api.content.types
optional: true
volumeMounts:
- name: ssh-known-hosts
mountPath: /app/config/ssh

View File

@@ -20312,6 +20312,14 @@ rules:
verbs:
- create
- list
- apiGroups:
- apps
resources:
- deployments
verbs:
- get
- list
- watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
@@ -20742,7 +20750,7 @@ spec:
key: applicationsetcontroller.allowed.scm.providers
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.9.3
image: quay.io/argoproj/argocd:v2.9.7
imagePullPolicy: Always
name: argocd-applicationset-controller
ports:
@@ -21042,7 +21050,7 @@ spec:
value: /helm-working-dir
- name: HELM_DATA_HOME
value: /helm-working-dir
image: quay.io/argoproj/argocd:v2.9.3
image: quay.io/argoproj/argocd:v2.9.7
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
@@ -21094,7 +21102,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /var/run/argocd/argocd-cmp-server
image: quay.io/argoproj/argocd:v2.9.3
image: quay.io/argoproj/argocd:v2.9.7
name: copyutil
securityContext:
allowPrivilegeEscalation: false
@@ -21313,7 +21321,7 @@ spec:
key: controller.kubectl.parallelism.limit
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.9.3
image: quay.io/argoproj/argocd:v2.9.7
imagePullPolicy: Always
name: argocd-application-controller
ports:

View File

@@ -12,4 +12,4 @@ resources:
images:
- name: quay.io/argoproj/argocd
newName: quay.io/argoproj/argocd
newTag: v2.9.3
newTag: v2.9.7

View File

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

View File

@@ -20348,6 +20348,14 @@ rules:
verbs:
- create
- list
- apiGroups:
- apps
resources:
- deployments
verbs:
- get
- list
- watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
@@ -21999,7 +22007,7 @@ spec:
key: applicationsetcontroller.allowed.scm.providers
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.9.3
image: quay.io/argoproj/argocd:v2.9.7
imagePullPolicy: Always
name: argocd-applicationset-controller
ports:
@@ -22122,7 +22130,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /shared/argocd-dex
image: quay.io/argoproj/argocd:v2.9.3
image: quay.io/argoproj/argocd:v2.9.7
imagePullPolicy: Always
name: copyutil
securityContext:
@@ -22198,7 +22206,7 @@ spec:
key: application.namespaces
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.9.3
image: quay.io/argoproj/argocd:v2.9.7
imagePullPolicy: Always
livenessProbe:
tcpSocket:
@@ -22529,7 +22537,7 @@ spec:
value: /helm-working-dir
- name: HELM_DATA_HOME
value: /helm-working-dir
image: quay.io/argoproj/argocd:v2.9.3
image: quay.io/argoproj/argocd:v2.9.7
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
@@ -22581,7 +22589,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /var/run/argocd/argocd-cmp-server
image: quay.io/argoproj/argocd:v2.9.3
image: quay.io/argoproj/argocd:v2.9.7
name: copyutil
securityContext:
allowPrivilegeEscalation: false
@@ -22870,7 +22878,13 @@ spec:
key: server.enable.proxy.extension
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.9.3
- name: ARGOCD_API_CONTENT_TYPES
valueFrom:
configMapKeyRef:
key: server.api.content.types
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.9.7
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -23116,7 +23130,7 @@ spec:
key: controller.kubectl.parallelism.limit
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.9.3
image: quay.io/argoproj/argocd:v2.9.7
imagePullPolicy: Always
name: argocd-application-controller
ports:

View File

@@ -109,6 +109,14 @@ rules:
verbs:
- create
- list
- apiGroups:
- apps
resources:
- deployments
verbs:
- get
- list
- watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
@@ -1654,7 +1662,7 @@ spec:
key: applicationsetcontroller.allowed.scm.providers
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.9.3
image: quay.io/argoproj/argocd:v2.9.7
imagePullPolicy: Always
name: argocd-applicationset-controller
ports:
@@ -1777,7 +1785,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /shared/argocd-dex
image: quay.io/argoproj/argocd:v2.9.3
image: quay.io/argoproj/argocd:v2.9.7
imagePullPolicy: Always
name: copyutil
securityContext:
@@ -1853,7 +1861,7 @@ spec:
key: application.namespaces
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.9.3
image: quay.io/argoproj/argocd:v2.9.7
imagePullPolicy: Always
livenessProbe:
tcpSocket:
@@ -2184,7 +2192,7 @@ spec:
value: /helm-working-dir
- name: HELM_DATA_HOME
value: /helm-working-dir
image: quay.io/argoproj/argocd:v2.9.3
image: quay.io/argoproj/argocd:v2.9.7
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
@@ -2236,7 +2244,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /var/run/argocd/argocd-cmp-server
image: quay.io/argoproj/argocd:v2.9.3
image: quay.io/argoproj/argocd:v2.9.7
name: copyutil
securityContext:
allowPrivilegeEscalation: false
@@ -2525,7 +2533,13 @@ spec:
key: server.enable.proxy.extension
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.9.3
- name: ARGOCD_API_CONTENT_TYPES
valueFrom:
configMapKeyRef:
key: server.api.content.types
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.9.7
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -2771,7 +2785,7 @@ spec:
key: controller.kubectl.parallelism.limit
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.9.3
image: quay.io/argoproj/argocd:v2.9.7
imagePullPolicy: Always
name: argocd-application-controller
ports:

View File

@@ -20339,6 +20339,14 @@ rules:
verbs:
- create
- list
- apiGroups:
- apps
resources:
- deployments
verbs:
- get
- list
- watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
@@ -21094,7 +21102,7 @@ spec:
key: applicationsetcontroller.allowed.scm.providers
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.9.3
image: quay.io/argoproj/argocd:v2.9.7
imagePullPolicy: Always
name: argocd-applicationset-controller
ports:
@@ -21217,7 +21225,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /shared/argocd-dex
image: quay.io/argoproj/argocd:v2.9.3
image: quay.io/argoproj/argocd:v2.9.7
imagePullPolicy: Always
name: copyutil
securityContext:
@@ -21293,7 +21301,7 @@ spec:
key: application.namespaces
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.9.3
image: quay.io/argoproj/argocd:v2.9.7
imagePullPolicy: Always
livenessProbe:
tcpSocket:
@@ -21575,7 +21583,7 @@ spec:
value: /helm-working-dir
- name: HELM_DATA_HOME
value: /helm-working-dir
image: quay.io/argoproj/argocd:v2.9.3
image: quay.io/argoproj/argocd:v2.9.7
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
@@ -21627,7 +21635,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /var/run/argocd/argocd-cmp-server
image: quay.io/argoproj/argocd:v2.9.3
image: quay.io/argoproj/argocd:v2.9.7
name: copyutil
securityContext:
allowPrivilegeEscalation: false
@@ -21914,7 +21922,13 @@ spec:
key: server.enable.proxy.extension
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.9.3
- name: ARGOCD_API_CONTENT_TYPES
valueFrom:
configMapKeyRef:
key: server.api.content.types
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.9.7
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -22160,7 +22174,7 @@ spec:
key: controller.kubectl.parallelism.limit
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.9.3
image: quay.io/argoproj/argocd:v2.9.7
imagePullPolicy: Always
name: argocd-application-controller
ports:

View File

@@ -100,6 +100,14 @@ rules:
verbs:
- create
- list
- apiGroups:
- apps
resources:
- deployments
verbs:
- get
- list
- watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
@@ -749,7 +757,7 @@ spec:
key: applicationsetcontroller.allowed.scm.providers
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.9.3
image: quay.io/argoproj/argocd:v2.9.7
imagePullPolicy: Always
name: argocd-applicationset-controller
ports:
@@ -872,7 +880,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /shared/argocd-dex
image: quay.io/argoproj/argocd:v2.9.3
image: quay.io/argoproj/argocd:v2.9.7
imagePullPolicy: Always
name: copyutil
securityContext:
@@ -948,7 +956,7 @@ spec:
key: application.namespaces
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.9.3
image: quay.io/argoproj/argocd:v2.9.7
imagePullPolicy: Always
livenessProbe:
tcpSocket:
@@ -1230,7 +1238,7 @@ spec:
value: /helm-working-dir
- name: HELM_DATA_HOME
value: /helm-working-dir
image: quay.io/argoproj/argocd:v2.9.3
image: quay.io/argoproj/argocd:v2.9.7
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
@@ -1282,7 +1290,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /var/run/argocd/argocd-cmp-server
image: quay.io/argoproj/argocd:v2.9.3
image: quay.io/argoproj/argocd:v2.9.7
name: copyutil
securityContext:
allowPrivilegeEscalation: false
@@ -1569,7 +1577,13 @@ spec:
key: server.enable.proxy.extension
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.9.3
- name: ARGOCD_API_CONTENT_TYPES
valueFrom:
configMapKeyRef:
key: server.api.content.types
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.9.7
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -1815,7 +1829,7 @@ spec:
key: controller.kubectl.parallelism.limit
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.9.3
image: quay.io/argoproj/argocd:v2.9.7
imagePullPolicy: Always
name: argocd-application-controller
ports:

View File

@@ -13,9 +13,11 @@ import (
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/keepalive"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
"github.com/argoproj/argo-cd/v2/common"
argocderrors "github.com/argoproj/argo-cd/v2/util/errors"
argoio "github.com/argoproj/argo-cd/v2/util/io"
"github.com/argoproj/argo-cd/v2/util/rand"
@@ -112,6 +114,11 @@ func (c *client) startGRPCProxy() (*grpc.Server, net.Listener, error) {
}
proxySrv := grpc.NewServer(
grpc.ForceServerCodec(&noopCodec{}),
grpc.KeepaliveEnforcementPolicy(
keepalive.EnforcementPolicy{
MinTime: common.GRPCKeepAliveEnforcementMinimum,
},
),
grpc.UnknownServiceHandler(func(srv interface{}, stream grpc.ServerStream) error {
fullMethodName, ok := grpc.MethodFromServerStream(stream)
if !ok {

View File

@@ -1910,6 +1910,7 @@ type GitFilesRequest struct {
Revision string `protobuf:"bytes,3,opt,name=revision,proto3" json:"revision,omitempty"`
Path string `protobuf:"bytes,4,opt,name=path,proto3" json:"path,omitempty"`
NewGitFileGlobbingEnabled bool `protobuf:"varint,5,opt,name=NewGitFileGlobbingEnabled,proto3" json:"NewGitFileGlobbingEnabled,omitempty"`
NoRevisionCache bool `protobuf:"varint,6,opt,name=noRevisionCache,proto3" json:"noRevisionCache,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@@ -1983,6 +1984,13 @@ func (m *GitFilesRequest) GetNewGitFileGlobbingEnabled() bool {
return false
}
func (m *GitFilesRequest) GetNoRevisionCache() bool {
if m != nil {
return m.NoRevisionCache
}
return false
}
type GitFilesResponse struct {
// Map consisting of path of the path to its contents in bytes
Map map[string][]byte `protobuf:"bytes,1,rep,name=map,proto3" json:"map,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
@@ -2035,6 +2043,7 @@ type GitDirectoriesRequest struct {
Repo *v1alpha1.Repository `protobuf:"bytes,1,opt,name=repo,proto3" json:"repo,omitempty"`
SubmoduleEnabled bool `protobuf:"varint,2,opt,name=submoduleEnabled,proto3" json:"submoduleEnabled,omitempty"`
Revision string `protobuf:"bytes,3,opt,name=revision,proto3" json:"revision,omitempty"`
NoRevisionCache bool `protobuf:"varint,4,opt,name=noRevisionCache,proto3" json:"noRevisionCache,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@@ -2094,6 +2103,13 @@ func (m *GitDirectoriesRequest) GetRevision() string {
return ""
}
func (m *GitDirectoriesRequest) GetNoRevisionCache() bool {
if m != nil {
return m.NoRevisionCache
}
return false
}
type GitDirectoriesResponse struct {
// A set of directory paths
Paths []string `protobuf:"bytes,1,rep,name=paths,proto3" json:"paths,omitempty"`
@@ -2189,140 +2205,140 @@ func init() {
}
var fileDescriptor_dd8723cfcc820480 = []byte{
// 2114 bytes of a gzipped FileDescriptorProto
// 2127 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x5a, 0x5b, 0x6f, 0x1b, 0xc7,
0x15, 0xe6, 0x92, 0xba, 0x90, 0x47, 0xb2, 0x44, 0x8d, 0x75, 0x59, 0x31, 0x8e, 0xa0, 0x6c, 0x6b,
0x43, 0xb5, 0x13, 0x12, 0x92, 0x91, 0xb8, 0x70, 0xd2, 0x14, 0x8a, 0x62, 0x4b, 0x8e, 0x2d, 0x5b,
0x5d, 0xbb, 0x2d, 0xd2, 0xba, 0x2d, 0x86, 0xcb, 0x21, 0xb9, 0xe1, 0x5e, 0xc6, 0xbb, 0xb3, 0x0a,
0x64, 0xa0, 0x0f, 0x45, 0x8b, 0x02, 0xfd, 0x03, 0x7d, 0xe8, 0xff, 0x28, 0xfa, 0x54, 0xf4, 0xa9,
0x97, 0xc7, 0xa0, 0x7f, 0xa0, 0x85, 0x1f, 0xfb, 0x2b, 0x8a, 0xb9, 0xec, 0x95, 0x2b, 0xd9, 0x29,
0x65, 0x19, 0xcd, 0x8b, 0xbd, 0x73, 0xe6, 0xcc, 0x39, 0x67, 0xce, 0x9c, 0xcb, 0x37, 0x43, 0xc1,
0xb5, 0x80, 0x50, 0x3f, 0x24, 0xc1, 0x31, 0x09, 0x3a, 0xe2, 0xd3, 0x66, 0x7e, 0x70, 0x92, 0xf9,
0x6c, 0xd3, 0xc0, 0x67, 0x3e, 0x82, 0x94, 0xd2, 0x7a, 0x30, 0xb0, 0xd9, 0x30, 0xea, 0xb6, 0x2d,
0xdf, 0xed, 0xe0, 0x60, 0xe0, 0xd3, 0xc0, 0xff, 0x42, 0x7c, 0xbc, 0x67, 0xf5, 0x3a, 0xc7, 0x3b,
0x1d, 0x3a, 0x1a, 0x74, 0x30, 0xb5, 0xc3, 0x0e, 0xa6, 0xd4, 0xb1, 0x2d, 0xcc, 0x6c, 0xdf, 0xeb,
0x1c, 0x6f, 0x63, 0x87, 0x0e, 0xf1, 0x76, 0x67, 0x40, 0x3c, 0x12, 0x60, 0x46, 0x7a, 0x52, 0x72,
0xeb, 0xad, 0x81, 0xef, 0x0f, 0x1c, 0xd2, 0x11, 0xa3, 0x6e, 0xd4, 0xef, 0x10, 0x97, 0x32, 0xa5,
0xd6, 0xf8, 0xcf, 0x3c, 0x2c, 0x1e, 0x62, 0xcf, 0xee, 0x93, 0x90, 0x99, 0xe4, 0x59, 0x44, 0x42,
0x86, 0x9e, 0xc2, 0x14, 0x37, 0x46, 0xd7, 0x36, 0xb5, 0xad, 0xb9, 0x9d, 0x83, 0x76, 0x6a, 0x4d,
0x3b, 0xb6, 0x46, 0x7c, 0xfc, 0xc2, 0xea, 0xb5, 0x8f, 0x77, 0xda, 0x74, 0x34, 0x68, 0x73, 0x6b,
0xda, 0x19, 0x6b, 0xda, 0xb1, 0x35, 0x6d, 0x33, 0xd9, 0x96, 0x29, 0xa4, 0xa2, 0x16, 0xd4, 0x03,
0x72, 0x6c, 0x87, 0xb6, 0xef, 0xe9, 0xd5, 0x4d, 0x6d, 0xab, 0x61, 0x26, 0x63, 0xa4, 0xc3, 0xac,
0xe7, 0xef, 0x61, 0x6b, 0x48, 0xf4, 0xda, 0xa6, 0xb6, 0x55, 0x37, 0xe3, 0x21, 0xda, 0x84, 0x39,
0x4c, 0xe9, 0x03, 0xdc, 0x25, 0xce, 0x7d, 0x72, 0xa2, 0x4f, 0x89, 0x85, 0x59, 0x12, 0x5f, 0x8b,
0x29, 0x7d, 0x88, 0x5d, 0xa2, 0x4f, 0x8b, 0xd9, 0x78, 0x88, 0xae, 0x40, 0xc3, 0xc3, 0x2e, 0x09,
0x29, 0xb6, 0x88, 0x5e, 0x17, 0x73, 0x29, 0x01, 0xfd, 0x12, 0x96, 0x32, 0x86, 0x3f, 0xf6, 0xa3,
0xc0, 0x22, 0x3a, 0x88, 0xad, 0x3f, 0x9a, 0x6c, 0xeb, 0xbb, 0x45, 0xb1, 0xe6, 0xb8, 0x26, 0xf4,
0x73, 0x98, 0x16, 0x27, 0xaf, 0xcf, 0x6d, 0xd6, 0xce, 0xd5, 0xdb, 0x52, 0x2c, 0xf2, 0x60, 0x96,
0x3a, 0xd1, 0xc0, 0xf6, 0x42, 0x7d, 0x5e, 0x68, 0x78, 0x32, 0x99, 0x86, 0x3d, 0xdf, 0xeb, 0xdb,
0x83, 0x43, 0xec, 0xe1, 0x01, 0x71, 0x89, 0xc7, 0x8e, 0x84, 0x70, 0x33, 0x56, 0x82, 0x9e, 0x43,
0x73, 0x14, 0x85, 0xcc, 0x77, 0xed, 0xe7, 0xe4, 0x11, 0xe5, 0x6b, 0x43, 0xfd, 0x92, 0xf0, 0xe6,
0xc3, 0xc9, 0x14, 0xdf, 0x2f, 0x48, 0x35, 0xc7, 0xf4, 0xf0, 0x20, 0x19, 0x45, 0x5d, 0xf2, 0x23,
0x12, 0x88, 0xe8, 0x5a, 0x90, 0x41, 0x92, 0x21, 0xc9, 0x30, 0xb2, 0xd5, 0x28, 0xd4, 0x17, 0x37,
0x6b, 0x32, 0x8c, 0x12, 0x12, 0xda, 0x82, 0xc5, 0x63, 0x12, 0xd8, 0xfd, 0x93, 0xc7, 0xf6, 0xc0,
0xc3, 0x2c, 0x0a, 0x88, 0xde, 0x14, 0xa1, 0x58, 0x24, 0x23, 0x17, 0x2e, 0x0d, 0x89, 0xe3, 0x72,
0x97, 0xef, 0x05, 0xa4, 0x17, 0xea, 0x4b, 0xc2, 0xbf, 0xfb, 0x93, 0x9f, 0xa0, 0x10, 0x67, 0xe6,
0xa5, 0x73, 0xc3, 0x3c, 0xdf, 0x54, 0x99, 0x22, 0x73, 0x04, 0x49, 0xc3, 0x0a, 0x64, 0x74, 0x0d,
0x16, 0x58, 0x80, 0xad, 0x91, 0xed, 0x0d, 0x0e, 0x09, 0x1b, 0xfa, 0x3d, 0xfd, 0xb2, 0xf0, 0x44,
0x81, 0x8a, 0x2c, 0x40, 0xc4, 0xc3, 0x5d, 0x87, 0xf4, 0x64, 0x2c, 0x3e, 0x39, 0xa1, 0x24, 0xd4,
0x97, 0xc5, 0x2e, 0x6e, 0xb6, 0x33, 0x15, 0xaa, 0x50, 0x20, 0xda, 0x77, 0xc6, 0x56, 0xdd, 0xf1,
0x58, 0x70, 0x62, 0x96, 0x88, 0x43, 0x23, 0x98, 0xe3, 0xfb, 0x88, 0x43, 0x61, 0x45, 0x84, 0xc2,
0xbd, 0xc9, 0x7c, 0x74, 0x90, 0x0a, 0x34, 0xb3, 0xd2, 0x51, 0x1b, 0xd0, 0x10, 0x87, 0x87, 0x91,
0xc3, 0x6c, 0xea, 0x10, 0x69, 0x46, 0xa8, 0xaf, 0x0a, 0x37, 0x95, 0xcc, 0xa0, 0xfb, 0x00, 0x01,
0xe9, 0xc7, 0x7c, 0x6b, 0x62, 0xe7, 0x37, 0xce, 0xda, 0xb9, 0x99, 0x70, 0xcb, 0x1d, 0x67, 0x96,
0x73, 0xe5, 0x7c, 0x1b, 0xc4, 0x62, 0x2a, 0xdb, 0x45, 0x5a, 0xeb, 0x22, 0xc4, 0x4a, 0x66, 0x78,
0x2c, 0x2a, 0xaa, 0x28, 0x5a, 0xeb, 0x32, 0x5a, 0x33, 0xa4, 0xd6, 0x1d, 0x58, 0x3b, 0xc5, 0xd5,
0xa8, 0x09, 0xb5, 0x11, 0x39, 0x11, 0x25, 0xba, 0x61, 0xf2, 0x4f, 0xb4, 0x0c, 0xd3, 0xc7, 0xd8,
0x89, 0x88, 0x28, 0xaa, 0x75, 0x53, 0x0e, 0x6e, 0x57, 0xbf, 0xab, 0xb5, 0x7e, 0xab, 0xc1, 0x62,
0xc1, 0xf0, 0x92, 0xf5, 0x3f, 0xcb, 0xae, 0x3f, 0x87, 0x30, 0xee, 0x3f, 0xc1, 0xc1, 0x80, 0xb0,
0x8c, 0x21, 0xc6, 0x3f, 0x35, 0xd0, 0x0b, 0x1e, 0xfd, 0xb1, 0xcd, 0x86, 0x77, 0x6d, 0x87, 0x84,
0xe8, 0x16, 0xcc, 0x06, 0x92, 0xa6, 0x1a, 0xcf, 0x5b, 0x67, 0x1c, 0xc4, 0x41, 0xc5, 0x8c, 0xb9,
0xd1, 0xc7, 0x50, 0x77, 0x09, 0xc3, 0x3d, 0xcc, 0xb0, 0xb2, 0x7d, 0xb3, 0x6c, 0x25, 0xd7, 0x72,
0xa8, 0xf8, 0x0e, 0x2a, 0x66, 0xb2, 0x06, 0xbd, 0x0f, 0xd3, 0xd6, 0x30, 0xf2, 0x46, 0xa2, 0xe5,
0xcc, 0xed, 0xbc, 0x7d, 0xda, 0xe2, 0x3d, 0xce, 0x74, 0x50, 0x31, 0x25, 0xf7, 0x27, 0x33, 0x30,
0x45, 0x71, 0xc0, 0x8c, 0xbb, 0xb0, 0x5c, 0xa6, 0x82, 0xf7, 0x39, 0x6b, 0x48, 0xac, 0x51, 0x18,
0xb9, 0xca, 0xcd, 0xc9, 0x18, 0x21, 0x98, 0x0a, 0xed, 0xe7, 0xd2, 0xd5, 0x35, 0x53, 0x7c, 0x1b,
0xdf, 0x81, 0xa5, 0x31, 0x6d, 0xfc, 0x50, 0xa5, 0x6d, 0x5c, 0xc2, 0xbc, 0x52, 0x6d, 0x44, 0xb0,
0xf2, 0x44, 0xf8, 0x22, 0x29, 0xf6, 0x17, 0xd1, 0xb9, 0x8d, 0x03, 0x58, 0x2d, 0xaa, 0x0d, 0xa9,
0xef, 0x85, 0x84, 0x87, 0xbe, 0xa8, 0x8e, 0x36, 0xe9, 0xa5, 0xb3, 0xc2, 0x8a, 0xba, 0x59, 0x32,
0x63, 0xfc, 0xaa, 0x0a, 0xab, 0x26, 0x09, 0x7d, 0xe7, 0x98, 0xc4, 0xa5, 0xeb, 0x62, 0xc0, 0xc7,
0x4f, 0xa1, 0x86, 0x29, 0x55, 0x61, 0x72, 0xef, 0xdc, 0xda, 0xbb, 0xc9, 0xa5, 0xa2, 0x77, 0x61,
0x09, 0xbb, 0x5d, 0x7b, 0x10, 0xf9, 0x51, 0x18, 0x6f, 0x4b, 0x04, 0x55, 0xc3, 0x1c, 0x9f, 0x30,
0x2c, 0x58, 0x1b, 0x73, 0x81, 0x72, 0x67, 0x16, 0x22, 0x69, 0x05, 0x88, 0x54, 0xaa, 0xa4, 0x7a,
0x9a, 0x92, 0xbf, 0x69, 0xd0, 0x4c, 0x53, 0x47, 0x89, 0xbf, 0x02, 0x0d, 0x57, 0xd1, 0x42, 0x5d,
0x13, 0xf5, 0x29, 0x25, 0xe4, 0xd1, 0x52, 0xb5, 0x88, 0x96, 0x56, 0x61, 0x46, 0x82, 0x59, 0xb5,
0x31, 0x35, 0xca, 0x99, 0x3c, 0x55, 0x30, 0x79, 0x03, 0x20, 0x4c, 0xea, 0x97, 0x3e, 0x23, 0x66,
0x33, 0x14, 0x64, 0xc0, 0xbc, 0xec, 0xad, 0x26, 0x09, 0x23, 0x87, 0xe9, 0xb3, 0x82, 0x23, 0x47,
0x33, 0x7c, 0x58, 0x7c, 0x60, 0xf3, 0x3d, 0xf4, 0xc3, 0x8b, 0x09, 0xf6, 0x0f, 0x60, 0x8a, 0x2b,
0xe3, 0x1b, 0xeb, 0x06, 0xd8, 0xb3, 0x86, 0x24, 0xf6, 0x55, 0x32, 0xe6, 0x69, 0xcc, 0xf0, 0x20,
0xd4, 0xab, 0x82, 0x2e, 0xbe, 0x8d, 0x3f, 0x55, 0xa5, 0xa5, 0xbb, 0x94, 0x86, 0x6f, 0x1e, 0x50,
0x97, 0xb7, 0xf8, 0xda, 0x78, 0x8b, 0x2f, 0x98, 0xfc, 0x75, 0x5a, 0xfc, 0x39, 0xb5, 0x29, 0x23,
0x82, 0xd9, 0x5d, 0x4a, 0xb9, 0x21, 0x68, 0x1b, 0xa6, 0x30, 0xa5, 0xd2, 0xe1, 0x85, 0x8a, 0xac,
0x58, 0xf8, 0xff, 0xca, 0x24, 0xc1, 0xda, 0xba, 0x05, 0x8d, 0x84, 0xf4, 0x32, 0xb5, 0x8d, 0xac,
0xda, 0x4d, 0x00, 0x89, 0x61, 0xef, 0x79, 0x7d, 0x9f, 0x1f, 0x29, 0x0f, 0x76, 0xb5, 0x54, 0x7c,
0x1b, 0xb7, 0x63, 0x0e, 0x61, 0xdb, 0xbb, 0x30, 0x6d, 0x33, 0xe2, 0xc6, 0xc6, 0xad, 0x66, 0x8d,
0x4b, 0x05, 0x99, 0x92, 0xc9, 0xf8, 0x7b, 0x1d, 0xd6, 0xf9, 0x89, 0x3d, 0x16, 0x69, 0xb2, 0x4b,
0xe9, 0xa7, 0x84, 0x61, 0xdb, 0x09, 0x7f, 0x10, 0x91, 0xe0, 0xe4, 0x35, 0x07, 0xc6, 0x00, 0x66,
0x64, 0x96, 0xa9, 0x7a, 0x77, 0xee, 0xd7, 0x19, 0x25, 0x3e, 0xbd, 0xc3, 0xd4, 0x5e, 0xcf, 0x1d,
0xa6, 0xec, 0x4e, 0x31, 0x75, 0x41, 0x77, 0x8a, 0xd3, 0xaf, 0x95, 0x99, 0xcb, 0xea, 0x4c, 0xfe,
0xb2, 0x5a, 0x02, 0xd5, 0x67, 0x5f, 0x15, 0xaa, 0xd7, 0x4b, 0xa1, 0xba, 0x5b, 0x9a, 0xc7, 0x0d,
0xe1, 0xee, 0xef, 0x65, 0x23, 0xf0, 0xd4, 0x58, 0x9b, 0x04, 0xb4, 0xc3, 0x6b, 0x05, 0xed, 0x3f,
0xcc, 0x81, 0x70, 0x79, 0x0d, 0x7e, 0xff, 0xd5, 0xf6, 0x74, 0x06, 0x1c, 0xff, 0xc6, 0x81, 0xe7,
0xdf, 0x08, 0xcc, 0x44, 0xfd, 0xd4, 0x07, 0x49, 0x43, 0xe7, 0x7d, 0x88, 0xb7, 0x56, 0x55, 0xb4,
0xf8, 0x37, 0xba, 0x01, 0x53, 0xdc, 0xc9, 0x0a, 0xd4, 0xae, 0x65, 0xfd, 0xc9, 0x4f, 0x62, 0x97,
0xd2, 0xc7, 0x94, 0x58, 0xa6, 0x60, 0x42, 0xb7, 0xa1, 0x91, 0x04, 0xbe, 0xca, 0xac, 0x2b, 0xd9,
0x15, 0x49, 0x9e, 0xc4, 0xcb, 0x52, 0x76, 0xbe, 0xb6, 0x67, 0x07, 0xc4, 0x12, 0x90, 0x6f, 0x7a,
0x7c, 0xed, 0xa7, 0xf1, 0x64, 0xb2, 0x36, 0x61, 0x47, 0xdb, 0x30, 0x23, 0xdf, 0x0d, 0x44, 0x06,
0xcd, 0xed, 0xac, 0x8f, 0x17, 0xd3, 0x78, 0x95, 0x62, 0x34, 0xfe, 0xaa, 0xc1, 0x3b, 0x69, 0x40,
0xc4, 0xd9, 0x14, 0xa3, 0xee, 0x37, 0xdf, 0x71, 0xaf, 0xc1, 0x82, 0x80, 0xf9, 0xe9, 0xf3, 0x81,
0x7c, 0xc9, 0x2a, 0x50, 0x8d, 0x3f, 0x6a, 0x70, 0x75, 0x7c, 0x1f, 0x7b, 0x43, 0x1c, 0xb0, 0xe4,
0x78, 0x2f, 0x62, 0x2f, 0x71, 0xc3, 0xab, 0xa6, 0x0d, 0x2f, 0xb7, 0xbf, 0x5a, 0x7e, 0x7f, 0xc6,
0x5f, 0xaa, 0x30, 0x97, 0x09, 0xa0, 0xb2, 0x86, 0xc9, 0x01, 0x9f, 0x88, 0x5b, 0x71, 0xb1, 0x13,
0x4d, 0xa1, 0x61, 0x66, 0x28, 0x68, 0x04, 0x40, 0x71, 0x80, 0x5d, 0xc2, 0x48, 0xc0, 0x2b, 0x39,
0xcf, 0xf8, 0xfb, 0x93, 0x57, 0x97, 0xa3, 0x58, 0xa6, 0x99, 0x11, 0xcf, 0x11, 0xab, 0x50, 0x1d,
0xaa, 0xfa, 0xad, 0x46, 0xe8, 0x4b, 0x58, 0xe8, 0xdb, 0x0e, 0x39, 0x4a, 0x0d, 0x99, 0x11, 0x86,
0x3c, 0x9a, 0xdc, 0x90, 0xbb, 0x59, 0xb9, 0x66, 0x41, 0x8d, 0x71, 0x1d, 0x9a, 0xc5, 0x7c, 0xe2,
0x46, 0xda, 0x2e, 0x1e, 0x24, 0xde, 0x52, 0x23, 0x03, 0x41, 0xb3, 0x98, 0x3f, 0xc6, 0xbf, 0xaa,
0xb0, 0x92, 0x88, 0xdb, 0xf5, 0x3c, 0x3f, 0xf2, 0x2c, 0xf1, 0x14, 0x57, 0x7a, 0x16, 0xcb, 0x30,
0xcd, 0x6c, 0xe6, 0x24, 0xc0, 0x47, 0x0c, 0x78, 0xef, 0x62, 0xbe, 0xef, 0x30, 0x9b, 0xaa, 0x03,
0x8e, 0x87, 0xf2, 0xec, 0x9f, 0x45, 0x76, 0x40, 0x7a, 0xa2, 0x12, 0xd4, 0xcd, 0x64, 0xcc, 0xe7,
0x38, 0xaa, 0x11, 0x30, 0x5e, 0x3a, 0x33, 0x19, 0x8b, 0xb8, 0xf7, 0x1d, 0x87, 0x58, 0xdc, 0x1d,
0x19, 0xa0, 0x5f, 0xa0, 0x8a, 0x0b, 0x04, 0x0b, 0x6c, 0x6f, 0xa0, 0x60, 0xbe, 0x1a, 0x71, 0x3b,
0x71, 0x10, 0xe0, 0x13, 0xbd, 0x2e, 0x1c, 0x20, 0x07, 0xe8, 0x23, 0xa8, 0xb9, 0x98, 0xaa, 0x46,
0x77, 0x3d, 0x57, 0x1d, 0xca, 0x3c, 0xd0, 0x3e, 0xc4, 0x54, 0x76, 0x02, 0xbe, 0xac, 0xf5, 0x01,
0xd4, 0x63, 0xc2, 0xd7, 0x82, 0x84, 0x5f, 0xc0, 0xa5, 0x5c, 0xf1, 0x41, 0x9f, 0xc3, 0x6a, 0x1a,
0x51, 0x59, 0x85, 0x0a, 0x04, 0xbe, 0xf3, 0x52, 0xcb, 0xcc, 0x53, 0x04, 0x18, 0xcf, 0x60, 0x89,
0x87, 0x8c, 0x48, 0xfc, 0x0b, 0xba, 0xda, 0x7c, 0x08, 0x8d, 0x44, 0x65, 0x69, 0xcc, 0xb4, 0xa0,
0x7e, 0x1c, 0x3f, 0x91, 0xca, 0xbb, 0x4d, 0x32, 0x36, 0x76, 0x01, 0x65, 0xed, 0x55, 0x1d, 0xe8,
0x46, 0x1e, 0x14, 0xaf, 0x14, 0xdb, 0x8d, 0x60, 0x8f, 0x31, 0xf1, 0xef, 0xaa, 0xb0, 0xb8, 0x6f,
0x8b, 0x57, 0x8e, 0x0b, 0x2a, 0x72, 0xd7, 0xa1, 0x19, 0x46, 0x5d, 0xd7, 0xef, 0x45, 0x0e, 0x51,
0xa0, 0x40, 0x75, 0xfa, 0x31, 0xfa, 0x59, 0xc5, 0x8f, 0x3b, 0x8b, 0x62, 0x36, 0x54, 0x37, 0x5c,
0xf1, 0x8d, 0x3e, 0x82, 0xf5, 0x87, 0xe4, 0x4b, 0xb5, 0x9f, 0x7d, 0xc7, 0xef, 0x76, 0x6d, 0x6f,
0x10, 0x2b, 0x99, 0x16, 0x4a, 0x4e, 0x67, 0x30, 0x7e, 0xad, 0x41, 0x33, 0xf5, 0x85, 0xf2, 0xe6,
0x2d, 0x19, 0xf5, 0xd2, 0x97, 0x57, 0xb3, 0xbe, 0x2c, 0xb2, 0xfe, 0xef, 0x01, 0x3f, 0x9f, 0x0d,
0xf8, 0x3f, 0x6b, 0xb0, 0xb2, 0x6f, 0xb3, 0xb8, 0xd4, 0xd8, 0xff, 0x67, 0xe7, 0x62, 0xb4, 0x61,
0xb5, 0x68, 0xbe, 0x72, 0xe5, 0x32, 0x4c, 0xf3, 0x53, 0x8a, 0xef, 0xee, 0x72, 0xb0, 0xf3, 0x55,
0x03, 0x96, 0xd2, 0xe6, 0xcb, 0xff, 0xb5, 0x2d, 0x82, 0x1e, 0x41, 0x73, 0x5f, 0xfd, 0x76, 0x16,
0xbf, 0x99, 0xa0, 0xb3, 0x1e, 0x21, 0x5b, 0x57, 0xca, 0x27, 0xa5, 0x6a, 0xa3, 0x82, 0x2c, 0x58,
0x2f, 0x0a, 0x4c, 0xdf, 0x3b, 0xbf, 0x7d, 0x86, 0xe4, 0x84, 0xeb, 0x65, 0x2a, 0xb6, 0x34, 0xf4,
0x39, 0x2c, 0xe4, 0x5f, 0xe5, 0x50, 0xae, 0x1a, 0x95, 0x3e, 0x14, 0xb6, 0x8c, 0xb3, 0x58, 0x12,
0xfb, 0x9f, 0x72, 0xe8, 0x9b, 0x7b, 0xa2, 0x42, 0x46, 0x1e, 0x98, 0x97, 0x3d, 0xe1, 0xb5, 0xbe,
0x75, 0x26, 0x4f, 0x22, 0xfd, 0x43, 0xa8, 0xc7, 0x4f, 0x3a, 0x79, 0x37, 0x17, 0x1e, 0x7a, 0x5a,
0xcd, 0xbc, 0xbc, 0x7e, 0x68, 0x54, 0xd0, 0xc7, 0x72, 0x31, 0xbf, 0xf2, 0x8f, 0x2f, 0xce, 0x3c,
0x64, 0xb4, 0x2e, 0x97, 0x3c, 0x1e, 0x18, 0x15, 0xf4, 0x7d, 0x98, 0xe3, 0x5f, 0x47, 0xea, 0x57,
0xab, 0xd5, 0xb6, 0xfc, 0x91, 0xb4, 0x1d, 0xff, 0x48, 0xda, 0xbe, 0xe3, 0x52, 0x76, 0xd2, 0x2a,
0xb9, 0xdd, 0x2b, 0x01, 0x4f, 0xe1, 0xd2, 0x3e, 0x61, 0x29, 0x18, 0x47, 0x57, 0x5f, 0xe9, 0xca,
0xd2, 0x32, 0x8a, 0x6c, 0xe3, 0x78, 0xde, 0xa8, 0xa0, 0xdf, 0x6b, 0x70, 0x79, 0x9f, 0xb0, 0x22,
0xbc, 0x45, 0xef, 0x95, 0x2b, 0x39, 0x05, 0x06, 0xb7, 0x1e, 0x4e, 0x9a, 0xaf, 0x79, 0xb1, 0x46,
0x05, 0xfd, 0x41, 0x83, 0xb5, 0x8c, 0x61, 0x59, 0xbc, 0x8a, 0xb6, 0xcf, 0x36, 0xae, 0x04, 0xdb,
0xb6, 0x3e, 0x9b, 0xf0, 0xc7, 0xc8, 0x8c, 0x48, 0xa3, 0x82, 0x8e, 0xc4, 0x99, 0xa4, 0xed, 0x09,
0xbd, 0x5d, 0xda, 0x87, 0x12, 0xed, 0x1b, 0xa7, 0x4d, 0x27, 0xe7, 0xf0, 0x19, 0xcc, 0xed, 0x13,
0x16, 0x57, 0xdd, 0x7c, 0xa4, 0x15, 0x5a, 0x58, 0x3e, 0x55, 0x8b, 0x85, 0x5a, 0x44, 0xcc, 0x92,
0x94, 0x95, 0xa9, 0x53, 0xf9, 0x5c, 0x2d, 0x2d, 0xc1, 0xf9, 0x88, 0x29, 0x2f, 0x73, 0x46, 0xe5,
0x93, 0xdd, 0x7f, 0xbc, 0xd8, 0xd0, 0xbe, 0x7a, 0xb1, 0xa1, 0xfd, 0xfb, 0xc5, 0x86, 0xf6, 0x93,
0x9b, 0x2f, 0xf9, 0x0b, 0x82, 0xcc, 0x1f, 0x25, 0x60, 0x6a, 0x5b, 0x8e, 0x4d, 0x3c, 0xd6, 0x9d,
0x11, 0xc1, 0x7f, 0xf3, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0xf8, 0x86, 0xe4, 0x0d, 0xb3, 0x20,
0x00, 0x00,
0xf5, 0xe7, 0x92, 0x94, 0x44, 0x1e, 0xd9, 0x12, 0x35, 0xd6, 0x65, 0xc5, 0x38, 0x82, 0xb2, 0xff,
0xbf, 0x0d, 0xd5, 0x4e, 0x48, 0x48, 0x46, 0xe2, 0xc2, 0x49, 0x53, 0x28, 0x8a, 0x2d, 0x39, 0xb6,
0x6c, 0x75, 0xed, 0xb6, 0x48, 0xeb, 0xb6, 0x18, 0x2e, 0x87, 0xe4, 0x86, 0x7b, 0x19, 0xef, 0xce,
0x2a, 0x90, 0x81, 0x3e, 0x14, 0x2d, 0xfa, 0x11, 0xfa, 0xd0, 0xaf, 0x51, 0x14, 0x7d, 0xec, 0x53,
0x2f, 0x8f, 0x41, 0xbf, 0x40, 0x0b, 0xbf, 0x14, 0xe8, 0xa7, 0x28, 0xe6, 0xb2, 0x57, 0xae, 0x64,
0xa7, 0x94, 0x15, 0xb4, 0x2f, 0xf6, 0xce, 0x99, 0x33, 0xe7, 0x9c, 0x39, 0x73, 0x2e, 0xbf, 0x19,
0x0a, 0xae, 0x07, 0x84, 0xfa, 0x21, 0x09, 0x8e, 0x49, 0xd0, 0x15, 0x9f, 0x36, 0xf3, 0x83, 0x93,
0xcc, 0x67, 0x87, 0x06, 0x3e, 0xf3, 0x11, 0xa4, 0x94, 0xf6, 0xc3, 0xa1, 0xcd, 0x46, 0x51, 0xaf,
0x63, 0xf9, 0x6e, 0x17, 0x07, 0x43, 0x9f, 0x06, 0xfe, 0x17, 0xe2, 0xe3, 0x3d, 0xab, 0xdf, 0x3d,
0xde, 0xe9, 0xd2, 0xf1, 0xb0, 0x8b, 0xa9, 0x1d, 0x76, 0x31, 0xa5, 0x8e, 0x6d, 0x61, 0x66, 0xfb,
0x5e, 0xf7, 0x78, 0x1b, 0x3b, 0x74, 0x84, 0xb7, 0xbb, 0x43, 0xe2, 0x91, 0x00, 0x33, 0xd2, 0x97,
0x92, 0xdb, 0x6f, 0x0d, 0x7d, 0x7f, 0xe8, 0x90, 0xae, 0x18, 0xf5, 0xa2, 0x41, 0x97, 0xb8, 0x94,
0x29, 0xb5, 0xc6, 0xbf, 0x2e, 0xc1, 0xe2, 0x21, 0xf6, 0xec, 0x01, 0x09, 0x99, 0x49, 0x9e, 0x47,
0x24, 0x64, 0xe8, 0x19, 0xd4, 0xb9, 0x31, 0xba, 0xb6, 0xa9, 0x6d, 0xcd, 0xef, 0x1c, 0x74, 0x52,
0x6b, 0x3a, 0xb1, 0x35, 0xe2, 0xe3, 0x67, 0x56, 0xbf, 0x73, 0xbc, 0xd3, 0xa1, 0xe3, 0x61, 0x87,
0x5b, 0xd3, 0xc9, 0x58, 0xd3, 0x89, 0xad, 0xe9, 0x98, 0xc9, 0xb6, 0x4c, 0x21, 0x15, 0xb5, 0xa1,
0x11, 0x90, 0x63, 0x3b, 0xb4, 0x7d, 0x4f, 0xaf, 0x6e, 0x6a, 0x5b, 0x4d, 0x33, 0x19, 0x23, 0x1d,
0xe6, 0x3c, 0x7f, 0x0f, 0x5b, 0x23, 0xa2, 0xd7, 0x36, 0xb5, 0xad, 0x86, 0x19, 0x0f, 0xd1, 0x26,
0xcc, 0x63, 0x4a, 0x1f, 0xe2, 0x1e, 0x71, 0x1e, 0x90, 0x13, 0xbd, 0x2e, 0x16, 0x66, 0x49, 0x7c,
0x2d, 0xa6, 0xf4, 0x11, 0x76, 0x89, 0x3e, 0x23, 0x66, 0xe3, 0x21, 0xba, 0x0a, 0x4d, 0x0f, 0xbb,
0x24, 0xa4, 0xd8, 0x22, 0x7a, 0x43, 0xcc, 0xa5, 0x04, 0xf4, 0x73, 0x58, 0xca, 0x18, 0xfe, 0xc4,
0x8f, 0x02, 0x8b, 0xe8, 0x20, 0xb6, 0xfe, 0x78, 0xba, 0xad, 0xef, 0x16, 0xc5, 0x9a, 0x93, 0x9a,
0xd0, 0x4f, 0x61, 0x46, 0x9c, 0xbc, 0x3e, 0xbf, 0x59, 0x3b, 0x57, 0x6f, 0x4b, 0xb1, 0xc8, 0x83,
0x39, 0xea, 0x44, 0x43, 0xdb, 0x0b, 0xf5, 0x4b, 0x42, 0xc3, 0xd3, 0xe9, 0x34, 0xec, 0xf9, 0xde,
0xc0, 0x1e, 0x1e, 0x62, 0x0f, 0x0f, 0x89, 0x4b, 0x3c, 0x76, 0x24, 0x84, 0x9b, 0xb1, 0x12, 0xf4,
0x02, 0x5a, 0xe3, 0x28, 0x64, 0xbe, 0x6b, 0xbf, 0x20, 0x8f, 0x29, 0x5f, 0x1b, 0xea, 0x97, 0x85,
0x37, 0x1f, 0x4d, 0xa7, 0xf8, 0x41, 0x41, 0xaa, 0x39, 0xa1, 0x87, 0x07, 0xc9, 0x38, 0xea, 0x91,
0x1f, 0x90, 0x40, 0x44, 0xd7, 0x82, 0x0c, 0x92, 0x0c, 0x49, 0x86, 0x91, 0xad, 0x46, 0xa1, 0xbe,
0xb8, 0x59, 0x93, 0x61, 0x94, 0x90, 0xd0, 0x16, 0x2c, 0x1e, 0x93, 0xc0, 0x1e, 0x9c, 0x3c, 0xb1,
0x87, 0x1e, 0x66, 0x51, 0x40, 0xf4, 0x96, 0x08, 0xc5, 0x22, 0x19, 0xb9, 0x70, 0x79, 0x44, 0x1c,
0x97, 0xbb, 0x7c, 0x2f, 0x20, 0xfd, 0x50, 0x5f, 0x12, 0xfe, 0xdd, 0x9f, 0xfe, 0x04, 0x85, 0x38,
0x33, 0x2f, 0x9d, 0x1b, 0xe6, 0xf9, 0xa6, 0xca, 0x14, 0x99, 0x23, 0x48, 0x1a, 0x56, 0x20, 0xa3,
0xeb, 0xb0, 0xc0, 0x02, 0x6c, 0x8d, 0x6d, 0x6f, 0x78, 0x48, 0xd8, 0xc8, 0xef, 0xeb, 0x57, 0x84,
0x27, 0x0a, 0x54, 0x64, 0x01, 0x22, 0x1e, 0xee, 0x39, 0xa4, 0x2f, 0x63, 0xf1, 0xe9, 0x09, 0x25,
0xa1, 0xbe, 0x2c, 0x76, 0x71, 0xab, 0x93, 0xa9, 0x50, 0x85, 0x02, 0xd1, 0xb9, 0x3b, 0xb1, 0xea,
0xae, 0xc7, 0x82, 0x13, 0xb3, 0x44, 0x1c, 0x1a, 0xc3, 0x3c, 0xdf, 0x47, 0x1c, 0x0a, 0x2b, 0x22,
0x14, 0xee, 0x4f, 0xe7, 0xa3, 0x83, 0x54, 0xa0, 0x99, 0x95, 0x8e, 0x3a, 0x80, 0x46, 0x38, 0x3c,
0x8c, 0x1c, 0x66, 0x53, 0x87, 0x48, 0x33, 0x42, 0x7d, 0x55, 0xb8, 0xa9, 0x64, 0x06, 0x3d, 0x00,
0x08, 0xc8, 0x20, 0xe6, 0x5b, 0x13, 0x3b, 0xbf, 0x79, 0xd6, 0xce, 0xcd, 0x84, 0x5b, 0xee, 0x38,
0xb3, 0x9c, 0x2b, 0xe7, 0xdb, 0x20, 0x16, 0x53, 0xd9, 0x2e, 0xd2, 0x5a, 0x17, 0x21, 0x56, 0x32,
0xc3, 0x63, 0x51, 0x51, 0x45, 0xd1, 0x5a, 0x97, 0xd1, 0x9a, 0x21, 0xb5, 0xef, 0xc2, 0xda, 0x29,
0xae, 0x46, 0x2d, 0xa8, 0x8d, 0xc9, 0x89, 0x28, 0xd1, 0x4d, 0x93, 0x7f, 0xa2, 0x65, 0x98, 0x39,
0xc6, 0x4e, 0x44, 0x44, 0x51, 0x6d, 0x98, 0x72, 0x70, 0xa7, 0xfa, 0x6d, 0xad, 0xfd, 0x6b, 0x0d,
0x16, 0x0b, 0x86, 0x97, 0xac, 0xff, 0x49, 0x76, 0xfd, 0x39, 0x84, 0xf1, 0xe0, 0x29, 0x0e, 0x86,
0x84, 0x65, 0x0c, 0x31, 0xfe, 0xa6, 0x81, 0x5e, 0xf0, 0xe8, 0x0f, 0x6d, 0x36, 0xba, 0x67, 0x3b,
0x24, 0x44, 0xb7, 0x61, 0x2e, 0x90, 0x34, 0xd5, 0x78, 0xde, 0x3a, 0xe3, 0x20, 0x0e, 0x2a, 0x66,
0xcc, 0x8d, 0x3e, 0x86, 0x86, 0x4b, 0x18, 0xee, 0x63, 0x86, 0x95, 0xed, 0x9b, 0x65, 0x2b, 0xb9,
0x96, 0x43, 0xc5, 0x77, 0x50, 0x31, 0x93, 0x35, 0xe8, 0x7d, 0x98, 0xb1, 0x46, 0x91, 0x37, 0x16,
0x2d, 0x67, 0x7e, 0xe7, 0xed, 0xd3, 0x16, 0xef, 0x71, 0xa6, 0x83, 0x8a, 0x29, 0xb9, 0x3f, 0x99,
0x85, 0x3a, 0xc5, 0x01, 0x33, 0xee, 0xc1, 0x72, 0x99, 0x0a, 0xde, 0xe7, 0xac, 0x11, 0xb1, 0xc6,
0x61, 0xe4, 0x2a, 0x37, 0x27, 0x63, 0x84, 0xa0, 0x1e, 0xda, 0x2f, 0xa4, 0xab, 0x6b, 0xa6, 0xf8,
0x36, 0xbe, 0x05, 0x4b, 0x13, 0xda, 0xf8, 0xa1, 0x4a, 0xdb, 0xb8, 0x84, 0x4b, 0x4a, 0xb5, 0x11,
0xc1, 0xca, 0x53, 0xe1, 0x8b, 0xa4, 0xd8, 0x5f, 0x44, 0xe7, 0x36, 0x0e, 0x60, 0xb5, 0xa8, 0x36,
0xa4, 0xbe, 0x17, 0x12, 0x1e, 0xfa, 0xa2, 0x3a, 0xda, 0xa4, 0x9f, 0xce, 0x0a, 0x2b, 0x1a, 0x66,
0xc9, 0x8c, 0xf1, 0x8b, 0x2a, 0xac, 0x9a, 0x24, 0xf4, 0x9d, 0x63, 0x12, 0x97, 0xae, 0x8b, 0x01,
0x1f, 0x3f, 0x86, 0x1a, 0xa6, 0x54, 0x85, 0xc9, 0xfd, 0x73, 0x6b, 0xef, 0x26, 0x97, 0x8a, 0xde,
0x85, 0x25, 0xec, 0xf6, 0xec, 0x61, 0xe4, 0x47, 0x61, 0xbc, 0x2d, 0x11, 0x54, 0x4d, 0x73, 0x72,
0xc2, 0xb0, 0x60, 0x6d, 0xc2, 0x05, 0xca, 0x9d, 0x59, 0x88, 0xa4, 0x15, 0x20, 0x52, 0xa9, 0x92,
0xea, 0x69, 0x4a, 0xfe, 0xac, 0x41, 0x2b, 0x4d, 0x1d, 0x25, 0xfe, 0x2a, 0x34, 0x5d, 0x45, 0x0b,
0x75, 0x4d, 0xd4, 0xa7, 0x94, 0x90, 0x47, 0x4b, 0xd5, 0x22, 0x5a, 0x5a, 0x85, 0x59, 0x09, 0x66,
0xd5, 0xc6, 0xd4, 0x28, 0x67, 0x72, 0xbd, 0x60, 0xf2, 0x06, 0x40, 0x98, 0xd4, 0x2f, 0x7d, 0x56,
0xcc, 0x66, 0x28, 0xc8, 0x80, 0x4b, 0xb2, 0xb7, 0x9a, 0x24, 0x8c, 0x1c, 0xa6, 0xcf, 0x09, 0x8e,
0x1c, 0xcd, 0xf0, 0x61, 0xf1, 0xa1, 0xcd, 0xf7, 0x30, 0x08, 0x2f, 0x26, 0xd8, 0x3f, 0x80, 0x3a,
0x57, 0xc6, 0x37, 0xd6, 0x0b, 0xb0, 0x67, 0x8d, 0x48, 0xec, 0xab, 0x64, 0xcc, 0xd3, 0x98, 0xe1,
0x61, 0xa8, 0x57, 0x05, 0x5d, 0x7c, 0x1b, 0x7f, 0xa8, 0x4a, 0x4b, 0x77, 0x29, 0x0d, 0xbf, 0x79,
0x40, 0x5d, 0xde, 0xe2, 0x6b, 0x93, 0x2d, 0xbe, 0x60, 0xf2, 0xd7, 0x69, 0xf1, 0xe7, 0xd4, 0xa6,
0x8c, 0x08, 0xe6, 0x76, 0x29, 0xe5, 0x86, 0xa0, 0x6d, 0xa8, 0x63, 0x4a, 0xa5, 0xc3, 0x0b, 0x15,
0x59, 0xb1, 0xf0, 0xff, 0x95, 0x49, 0x82, 0xb5, 0x7d, 0x1b, 0x9a, 0x09, 0xe9, 0x55, 0x6a, 0x9b,
0x59, 0xb5, 0x9b, 0x00, 0x12, 0xc3, 0xde, 0xf7, 0x06, 0x3e, 0x3f, 0x52, 0x1e, 0xec, 0x6a, 0xa9,
0xf8, 0x36, 0xee, 0xc4, 0x1c, 0xc2, 0xb6, 0x77, 0x61, 0xc6, 0x66, 0xc4, 0x8d, 0x8d, 0x5b, 0xcd,
0x1a, 0x97, 0x0a, 0x32, 0x25, 0x93, 0xf1, 0x97, 0x06, 0xac, 0xf3, 0x13, 0x7b, 0x22, 0xd2, 0x64,
0x97, 0xd2, 0x4f, 0x09, 0xc3, 0xb6, 0x13, 0x7e, 0x2f, 0x22, 0xc1, 0xc9, 0x1b, 0x0e, 0x8c, 0x21,
0xcc, 0xca, 0x2c, 0x53, 0xf5, 0xee, 0xdc, 0xaf, 0x33, 0x4a, 0x7c, 0x7a, 0x87, 0xa9, 0xbd, 0x99,
0x3b, 0x4c, 0xd9, 0x9d, 0xa2, 0x7e, 0x41, 0x77, 0x8a, 0xd3, 0xaf, 0x95, 0x99, 0xcb, 0xea, 0x6c,
0xfe, 0xb2, 0x5a, 0x02, 0xd5, 0xe7, 0x5e, 0x17, 0xaa, 0x37, 0x4a, 0xa1, 0xba, 0x5b, 0x9a, 0xc7,
0x4d, 0xe1, 0xee, 0xef, 0x64, 0x23, 0xf0, 0xd4, 0x58, 0x9b, 0x06, 0xb4, 0xc3, 0x1b, 0x05, 0xed,
0xdf, 0xcf, 0x81, 0x70, 0x79, 0x0d, 0x7e, 0xff, 0xf5, 0xf6, 0x74, 0x06, 0x1c, 0xff, 0x9f, 0x03,
0xcf, 0xbf, 0x12, 0x98, 0x89, 0xfa, 0xa9, 0x0f, 0x92, 0x86, 0xce, 0xfb, 0x10, 0x6f, 0xad, 0xaa,
0x68, 0xf1, 0x6f, 0x74, 0x13, 0xea, 0xdc, 0xc9, 0x0a, 0xd4, 0xae, 0x65, 0xfd, 0xc9, 0x4f, 0x62,
0x97, 0xd2, 0x27, 0x94, 0x58, 0xa6, 0x60, 0x42, 0x77, 0xa0, 0x99, 0x04, 0xbe, 0xca, 0xac, 0xab,
0xd9, 0x15, 0x49, 0x9e, 0xc4, 0xcb, 0x52, 0x76, 0xbe, 0xb6, 0x6f, 0x07, 0xc4, 0x12, 0x90, 0x6f,
0x66, 0x72, 0xed, 0xa7, 0xf1, 0x64, 0xb2, 0x36, 0x61, 0x47, 0xdb, 0x30, 0x2b, 0xdf, 0x0d, 0x44,
0x06, 0xcd, 0xef, 0xac, 0x4f, 0x16, 0xd3, 0x78, 0x95, 0x62, 0x34, 0xfe, 0xa4, 0xc1, 0x3b, 0x69,
0x40, 0xc4, 0xd9, 0x14, 0xa3, 0xee, 0x6f, 0xbe, 0xe3, 0x5e, 0x87, 0x05, 0x01, 0xf3, 0xd3, 0xe7,
0x03, 0xf9, 0x92, 0x55, 0xa0, 0x1a, 0xbf, 0xd7, 0xe0, 0xda, 0xe4, 0x3e, 0xf6, 0x46, 0x38, 0x60,
0xc9, 0xf1, 0x5e, 0xc4, 0x5e, 0xe2, 0x86, 0x57, 0x4d, 0x1b, 0x5e, 0x6e, 0x7f, 0xb5, 0xfc, 0xfe,
0x8c, 0x3f, 0x56, 0x61, 0x3e, 0x13, 0x40, 0x65, 0x0d, 0x93, 0x03, 0x3e, 0x11, 0xb7, 0xe2, 0x62,
0x27, 0x9a, 0x42, 0xd3, 0xcc, 0x50, 0xd0, 0x18, 0x80, 0xe2, 0x00, 0xbb, 0x84, 0x91, 0x80, 0x57,
0x72, 0x9e, 0xf1, 0x0f, 0xa6, 0xaf, 0x2e, 0x47, 0xb1, 0x4c, 0x33, 0x23, 0x9e, 0x23, 0x56, 0xa1,
0x3a, 0x54, 0xf5, 0x5b, 0x8d, 0xd0, 0x97, 0xb0, 0x30, 0xb0, 0x1d, 0x72, 0x94, 0x1a, 0x32, 0x2b,
0x0c, 0x79, 0x3c, 0xbd, 0x21, 0xf7, 0xb2, 0x72, 0xcd, 0x82, 0x1a, 0xe3, 0x06, 0xb4, 0x8a, 0xf9,
0xc4, 0x8d, 0xb4, 0x5d, 0x3c, 0x4c, 0xbc, 0xa5, 0x46, 0x06, 0x82, 0x56, 0x31, 0x7f, 0x8c, 0xbf,
0x57, 0x61, 0x25, 0x11, 0xb7, 0xeb, 0x79, 0x7e, 0xe4, 0x59, 0xe2, 0x29, 0xae, 0xf4, 0x2c, 0x96,
0x61, 0x86, 0xd9, 0xcc, 0x49, 0x80, 0x8f, 0x18, 0xf0, 0xde, 0xc5, 0x7c, 0xdf, 0x61, 0x36, 0x55,
0x07, 0x1c, 0x0f, 0xe5, 0xd9, 0x3f, 0x8f, 0xec, 0x80, 0xf4, 0x45, 0x25, 0x68, 0x98, 0xc9, 0x98,
0xcf, 0x71, 0x54, 0x23, 0x60, 0xbc, 0x74, 0x66, 0x32, 0x16, 0x71, 0xef, 0x3b, 0x0e, 0xb1, 0xb8,
0x3b, 0x32, 0x40, 0xbf, 0x40, 0x15, 0x17, 0x08, 0x16, 0xd8, 0xde, 0x50, 0xc1, 0x7c, 0x35, 0xe2,
0x76, 0xe2, 0x20, 0xc0, 0x27, 0x7a, 0x43, 0x38, 0x40, 0x0e, 0xd0, 0x47, 0x50, 0x73, 0x31, 0x55,
0x8d, 0xee, 0x46, 0xae, 0x3a, 0x94, 0x79, 0xa0, 0x73, 0x88, 0xa9, 0xec, 0x04, 0x7c, 0x59, 0xfb,
0x03, 0x68, 0xc4, 0x84, 0xaf, 0x05, 0x09, 0xbf, 0x80, 0xcb, 0xb9, 0xe2, 0x83, 0x3e, 0x87, 0xd5,
0x34, 0xa2, 0xb2, 0x0a, 0x15, 0x08, 0x7c, 0xe7, 0x95, 0x96, 0x99, 0xa7, 0x08, 0x30, 0x9e, 0xc3,
0x12, 0x0f, 0x19, 0x91, 0xf8, 0x17, 0x74, 0xb5, 0xf9, 0x10, 0x9a, 0x89, 0xca, 0xd2, 0x98, 0x69,
0x43, 0xe3, 0x38, 0x7e, 0x22, 0x95, 0x77, 0x9b, 0x64, 0x6c, 0xec, 0x02, 0xca, 0xda, 0xab, 0x3a,
0xd0, 0xcd, 0x3c, 0x28, 0x5e, 0x29, 0xb6, 0x1b, 0xc1, 0x1e, 0x63, 0xe2, 0xdf, 0x55, 0x61, 0x71,
0xdf, 0x16, 0xaf, 0x1c, 0x17, 0x54, 0xe4, 0x6e, 0x40, 0x2b, 0x8c, 0x7a, 0xae, 0xdf, 0x8f, 0x1c,
0xa2, 0x40, 0x81, 0xea, 0xf4, 0x13, 0xf4, 0xb3, 0x8a, 0x1f, 0x77, 0x16, 0xc5, 0x6c, 0xa4, 0x6e,
0xb8, 0xe2, 0x1b, 0x7d, 0x04, 0xeb, 0x8f, 0xc8, 0x97, 0x6a, 0x3f, 0xfb, 0x8e, 0xdf, 0xeb, 0xd9,
0xde, 0x30, 0x56, 0x32, 0x23, 0x94, 0x9c, 0xce, 0x50, 0x06, 0x15, 0x67, 0x4b, 0xa1, 0xa2, 0xf1,
0x4b, 0x0d, 0x5a, 0xa9, 0xd7, 0x94, 0xdf, 0x6f, 0xcb, 0xfc, 0x90, 0x5e, 0xbf, 0x96, 0xf5, 0x7a,
0x91, 0xf5, 0x3f, 0x4f, 0x8d, 0x4b, 0xd9, 0xd4, 0xf8, 0xa7, 0x06, 0x2b, 0xfb, 0x36, 0x8b, 0x8b,
0x92, 0xfd, 0xdf, 0x76, 0x82, 0x25, 0xfe, 0xae, 0x97, 0xfb, 0xbb, 0x03, 0xab, 0xc5, 0x8d, 0x2a,
0xa7, 0x2f, 0xc3, 0x0c, 0x3f, 0xf9, 0xf8, 0x3d, 0x40, 0x0e, 0x76, 0xbe, 0x6a, 0xc2, 0x52, 0xda,
0xd0, 0xf9, 0xbf, 0xb6, 0x45, 0xd0, 0x63, 0x68, 0xed, 0xab, 0xdf, 0xe3, 0xe2, 0x77, 0x18, 0x74,
0xd6, 0xc3, 0x66, 0xfb, 0x6a, 0xf9, 0xa4, 0x54, 0x6d, 0x54, 0x90, 0x05, 0xeb, 0x45, 0x81, 0xe9,
0x1b, 0xea, 0xff, 0x9f, 0x21, 0x39, 0xe1, 0x7a, 0x95, 0x8a, 0x2d, 0x0d, 0x7d, 0x0e, 0x0b, 0xf9,
0x97, 0x3e, 0x94, 0xab, 0x70, 0xa5, 0x8f, 0x8f, 0x6d, 0xe3, 0x2c, 0x96, 0xc4, 0xfe, 0x67, 0x1c,
0x4e, 0xe7, 0x9e, 0xbd, 0x90, 0x91, 0x07, 0xfb, 0x65, 0xcf, 0x82, 0xed, 0xff, 0x3b, 0x93, 0x27,
0x91, 0xfe, 0x21, 0x34, 0xe2, 0x67, 0xa2, 0xbc, 0x9b, 0x0b, 0x8f, 0x47, 0xed, 0x56, 0x5e, 0xde,
0x20, 0x34, 0x2a, 0xe8, 0x63, 0xb9, 0x78, 0x97, 0xd2, 0x92, 0xc5, 0x99, 0xc7, 0x91, 0xf6, 0x95,
0x92, 0x07, 0x09, 0xa3, 0x82, 0xbe, 0x0b, 0xf3, 0xfc, 0xeb, 0x48, 0xfd, 0x12, 0xb6, 0xda, 0x91,
0x3f, 0xbc, 0x76, 0xe2, 0x1f, 0x5e, 0x3b, 0x77, 0x5d, 0xca, 0x4e, 0xda, 0x25, 0x2f, 0x06, 0x4a,
0xc0, 0x33, 0xb8, 0xbc, 0x4f, 0x58, 0x0a, 0xf0, 0xd1, 0xb5, 0xd7, 0xba, 0x06, 0xb5, 0x8d, 0x22,
0xdb, 0xe4, 0x1d, 0xc1, 0xa8, 0xa0, 0xdf, 0x68, 0x70, 0x65, 0x9f, 0xb0, 0x22, 0x64, 0x46, 0xef,
0x95, 0x2b, 0x39, 0x05, 0x5a, 0xb7, 0x1f, 0x4d, 0x9b, 0xd9, 0x79, 0xb1, 0x46, 0x05, 0xfd, 0x56,
0x83, 0xb5, 0x8c, 0x61, 0x59, 0x0c, 0x8c, 0xb6, 0xcf, 0x36, 0xae, 0x04, 0x2f, 0xb7, 0x3f, 0x9b,
0xf2, 0x07, 0xce, 0x8c, 0x48, 0xa3, 0x82, 0x8e, 0xc4, 0x99, 0xa4, 0x2d, 0x0f, 0xbd, 0x5d, 0xda,
0xdb, 0x12, 0xed, 0x1b, 0xa7, 0x4d, 0x27, 0xe7, 0xf0, 0x19, 0xcc, 0xef, 0x13, 0x16, 0xd7, 0xe7,
0x7c, 0xa4, 0x15, 0xda, 0x62, 0x3e, 0x55, 0x8b, 0x25, 0x5d, 0x44, 0xcc, 0x92, 0x94, 0x95, 0xa9,
0x53, 0xf9, 0x5c, 0x2d, 0x2d, 0xd6, 0xf9, 0x88, 0x29, 0x2f, 0x73, 0x46, 0xe5, 0x93, 0xdd, 0xbf,
0xbe, 0xdc, 0xd0, 0xbe, 0x7a, 0xb9, 0xa1, 0xfd, 0xe3, 0xe5, 0x86, 0xf6, 0xa3, 0x5b, 0xaf, 0xf8,
0xab, 0x84, 0xcc, 0x1f, 0x3a, 0x60, 0x6a, 0x5b, 0x8e, 0x4d, 0x3c, 0xd6, 0x9b, 0x15, 0xc1, 0x7f,
0xeb, 0xdf, 0x01, 0x00, 0x00, 0xff, 0xff, 0xf2, 0x91, 0xe2, 0xd9, 0x07, 0x21, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.
@@ -4679,6 +4695,16 @@ func (m *GitFilesRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i -= len(m.XXX_unrecognized)
copy(dAtA[i:], m.XXX_unrecognized)
}
if m.NoRevisionCache {
i--
if m.NoRevisionCache {
dAtA[i] = 1
} else {
dAtA[i] = 0
}
i--
dAtA[i] = 0x30
}
if m.NewGitFileGlobbingEnabled {
i--
if m.NewGitFileGlobbingEnabled {
@@ -4800,6 +4826,16 @@ func (m *GitDirectoriesRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i -= len(m.XXX_unrecognized)
copy(dAtA[i:], m.XXX_unrecognized)
}
if m.NoRevisionCache {
i--
if m.NoRevisionCache {
dAtA[i] = 1
} else {
dAtA[i] = 0
}
i--
dAtA[i] = 0x20
}
if len(m.Revision) > 0 {
i -= len(m.Revision)
copy(dAtA[i:], m.Revision)
@@ -5686,6 +5722,9 @@ func (m *GitFilesRequest) Size() (n int) {
if m.NewGitFileGlobbingEnabled {
n += 2
}
if m.NoRevisionCache {
n += 2
}
if m.XXX_unrecognized != nil {
n += len(m.XXX_unrecognized)
}
@@ -5733,6 +5772,9 @@ func (m *GitDirectoriesRequest) Size() (n int) {
if l > 0 {
n += 1 + l + sovRepository(uint64(l))
}
if m.NoRevisionCache {
n += 2
}
if m.XXX_unrecognized != nil {
n += len(m.XXX_unrecognized)
}
@@ -10874,6 +10916,26 @@ func (m *GitFilesRequest) Unmarshal(dAtA []byte) error {
}
}
m.NewGitFileGlobbingEnabled = bool(v != 0)
case 6:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field NoRevisionCache", wireType)
}
var v int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowRepository
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
v |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
m.NoRevisionCache = bool(v != 0)
default:
iNdEx = preIndex
skippy, err := skipRepository(dAtA[iNdEx:])
@@ -11192,6 +11254,26 @@ func (m *GitDirectoriesRequest) Unmarshal(dAtA []byte) error {
}
m.Revision = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 4:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field NoRevisionCache", wireType)
}
var v int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowRepository
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
v |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
m.NoRevisionCache = bool(v != 0)
default:
iNdEx = preIndex
skippy, err := skipRepository(dAtA[iNdEx:])

View File

@@ -1022,6 +1022,10 @@ func getHelmDependencyRepos(appPath string) ([]*v1alpha1.Repository, error) {
repos = append(repos, &v1alpha1.Repository{
Name: r.Repository[1:],
})
} else if strings.HasPrefix(r.Repository, "alias:") {
repos = append(repos, &v1alpha1.Repository{
Name: strings.TrimPrefix(r.Repository, "alias:"),
})
} else if u, err := url.Parse(r.Repository); err == nil && (u.Scheme == "https" || u.Scheme == "oci") {
repo := &v1alpha1.Repository{
// trimming oci:// prefix since it is currently not supported by Argo CD (OCI repos just have no scheme)
@@ -1374,7 +1378,7 @@ func GenerateManifests(ctx context.Context, appPath, repoRoot, revision string,
if q.KustomizeOptions != nil {
kustomizeBinary = q.KustomizeOptions.BinaryPath
}
k := kustomize.NewKustomizeApp(appPath, q.Repo.GetGitCreds(gitCredsStore), repoURL, kustomizeBinary)
k := kustomize.NewKustomizeApp(repoRoot, appPath, q.Repo.GetGitCreds(gitCredsStore), repoURL, kustomizeBinary)
targetObjs, _, err = k.Build(q.ApplicationSource.Kustomize, q.KustomizeOptions, env)
case v1alpha1.ApplicationSourceTypePlugin:
pluginName := ""
@@ -1961,7 +1965,7 @@ func (s *Service) GetAppDetails(ctx context.Context, q *apiclient.RepoServerAppD
return err
}
case v1alpha1.ApplicationSourceTypeKustomize:
if err := populateKustomizeAppDetails(res, q, opContext.appPath, commitSHA, s.gitCredsStore); err != nil {
if err := populateKustomizeAppDetails(res, q, repoRoot, opContext.appPath, commitSHA, s.gitCredsStore); err != nil {
return err
}
case v1alpha1.ApplicationSourceTypePlugin:
@@ -2102,13 +2106,13 @@ func findHelmValueFilesInPath(path string) ([]string, error) {
return result, nil
}
func populateKustomizeAppDetails(res *apiclient.RepoAppDetailsResponse, q *apiclient.RepoServerAppDetailsQuery, appPath string, reversion string, credsStore git.CredsStore) error {
func populateKustomizeAppDetails(res *apiclient.RepoAppDetailsResponse, q *apiclient.RepoServerAppDetailsQuery, repoRoot string, appPath string, reversion string, credsStore git.CredsStore) error {
res.Kustomize = &apiclient.KustomizeAppSpec{}
kustomizeBinary := ""
if q.KustomizeOptions != nil {
kustomizeBinary = q.KustomizeOptions.BinaryPath
}
k := kustomize.NewKustomizeApp(appPath, q.Repo.GetGitCreds(credsStore), q.Repo.Repo, kustomizeBinary)
k := kustomize.NewKustomizeApp(repoRoot, appPath, q.Repo.GetGitCreds(credsStore), q.Repo.Repo, kustomizeBinary)
fakeManifestRequest := apiclient.ManifestRequest{
AppName: q.AppName,
Namespace: "", // FIXME: omit it for now
@@ -2506,6 +2510,7 @@ func (s *Service) GetGitFiles(_ context.Context, request *apiclient.GitFilesRequ
repo := request.GetRepo()
revision := request.GetRevision()
gitPath := request.GetPath()
noRevisionCache := request.GetNoRevisionCache()
enableNewGitFileGlobbing := request.GetNewGitFileGlobbingEnabled()
if gitPath == "" {
gitPath = "."
@@ -2515,7 +2520,7 @@ func (s *Service) GetGitFiles(_ context.Context, request *apiclient.GitFilesRequ
return nil, status.Error(codes.InvalidArgument, "must pass a valid repo")
}
gitClient, revision, err := s.newClientResolveRevision(repo, revision, git.WithCache(s.cache, true))
gitClient, revision, err := s.newClientResolveRevision(repo, revision, git.WithCache(s.cache, !noRevisionCache))
if err != nil {
return nil, status.Errorf(codes.Internal, "unable to resolve git revision %s: %v", revision, err)
}
@@ -2568,12 +2573,12 @@ func (s *Service) GetGitFiles(_ context.Context, request *apiclient.GitFilesRequ
func (s *Service) GetGitDirectories(_ context.Context, request *apiclient.GitDirectoriesRequest) (*apiclient.GitDirectoriesResponse, error) {
repo := request.GetRepo()
revision := request.GetRevision()
noRevisionCache := request.GetNoRevisionCache()
if repo == nil {
return nil, status.Error(codes.InvalidArgument, "must pass a valid repo")
}
gitClient, revision, err := s.newClientResolveRevision(repo, revision, git.WithCache(s.cache, true))
gitClient, revision, err := s.newClientResolveRevision(repo, revision, git.WithCache(s.cache, !noRevisionCache))
if err != nil {
return nil, status.Errorf(codes.Internal, "unable to resolve git revision %s: %v", revision, err)
}

View File

@@ -236,6 +236,7 @@ message GitFilesRequest {
string revision = 3;
string path = 4;
bool NewGitFileGlobbingEnabled = 5;
bool noRevisionCache = 6;
}
message GitFilesResponse {
@@ -247,6 +248,7 @@ message GitDirectoriesRequest {
github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.Repository repo = 1;
bool submoduleEnabled = 2;
string revision = 3;
bool noRevisionCache = 4;
}
message GitDirectoriesResponse {

View File

@@ -1440,6 +1440,7 @@ func TestListApps(t *testing.T) {
"out-of-bounds-values-file-link": "Helm",
"values-files": "Helm",
"helm-with-dependencies": "Helm",
"helm-with-dependencies-alias": "Helm",
}
assert.Equal(t, expectedApps, res.Apps)
}
@@ -2938,6 +2939,22 @@ func TestGetHelmRepo_NamedRepos(t *testing.T) {
assert.Equal(t, helmRepos[0].Repo, "https://example.com")
}
func TestGetHelmRepo_NamedReposAlias(t *testing.T) {
src := argoappv1.ApplicationSource{Path: "."}
q := apiclient.ManifestRequest{Repo: &argoappv1.Repository{}, ApplicationSource: &src, Repos: []*argoappv1.Repository{{
Name: "custom-repo-alias",
Repo: "https://example.com",
Username: "test-alias",
}}}
helmRepos, err := getHelmRepos("./testdata/helm-with-dependencies-alias", q.Repos, q.HelmRepoCreds)
assert.Nil(t, err)
assert.Equal(t, len(helmRepos), 1)
assert.Equal(t, helmRepos[0].Username, "test-alias")
assert.Equal(t, helmRepos[0].Repo, "https://example.com")
}
func Test_getResolvedValueFiles(t *testing.T) {
tempDir := t.TempDir()
paths := io.NewRandomizedTempPaths(tempDir)

View File

@@ -0,0 +1,7 @@
apiVersion: v2
name: helm-with-dependencies-alias
version: v1.0.0
dependencies:
- name: helm
repository: "alias:custom-repo-alias"
version: v1.0.0

View File

@@ -38,12 +38,18 @@ if job.metadata == nil then
end
job.metadata.name = obj.metadata.name .. "-" ..os.date("!%Y%m%d%H%M")
job.metadata.namespace = obj.metadata.namespace
if job.metadata.annotations == nil then
job.metadata.annotations = {}
end
job.metadata.annotations['cronjob.kubernetes.io/instantiate'] = "manual"
local ownerRef = {}
ownerRef.apiVersion = obj.apiVersion
ownerRef.kind = obj.kind
ownerRef.name = obj.metadata.name
ownerRef.uid = obj.metadata.uid
ownerRef.blockOwnerDeletion = true
ownerRef.controller = true
job.metadata.ownerReferences = {}
job.metadata.ownerReferences[1] = ownerRef

View File

@@ -8,6 +8,7 @@
labels:
my: label
annotations:
cronjob.kubernetes.io/instantiate: manual
my: annotation
spec:
ttlSecondsAfterFinished: 100
@@ -26,4 +27,4 @@
- /bin/sh
- -c
- date; echo Hello from the Kubernetes cluster
restartPolicy: OnFailure
restartPolicy: OnFailure

View File

@@ -197,6 +197,7 @@ type ArgoCDServer struct {
type ArgoCDServerOpts struct {
DisableAuth bool
ContentTypes []string
EnableGZip bool
Insecure bool
StaticAssetsDir string
@@ -989,6 +990,11 @@ func (a *ArgoCDServer) newHTTPServer(ctx context.Context, port int, grpcWebHandl
if a.EnableGZip {
handler = compressHandler(handler)
}
if len(a.ContentTypes) > 0 {
handler = enforceContentTypes(handler, a.ContentTypes)
} else {
log.WithField(common.SecurityField, common.SecurityHigh).Warnf("Content-Type enforcement is disabled, which may make your API vulnerable to CSRF attacks")
}
mux.Handle("/api/", handler)
terminal := application.NewHandler(a.appLister, a.Namespace, a.ApplicationNamespaces, a.db, a.enf, a.Cache, appResourceTreeFn, a.settings.ExecShells, *a.sessionMgr).
@@ -1055,6 +1061,20 @@ func (a *ArgoCDServer) newHTTPServer(ctx context.Context, port int, grpcWebHandl
return &httpS
}
func enforceContentTypes(handler http.Handler, types []string) http.Handler {
allowedTypes := map[string]bool{}
for _, t := range types {
allowedTypes[strings.ToLower(t)] = true
}
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodGet || allowedTypes[strings.ToLower(r.Header.Get("Content-Type"))] {
handler.ServeHTTP(w, r)
} else {
http.Error(w, "Invalid content type", http.StatusUnsupportedMediaType)
}
})
}
// registerExtensions will try to register all configured extensions
// in the given mux. If any error is returned while registering
// extensions handlers, no route will be added in the given mux.

View File

@@ -1425,3 +1425,46 @@ func TestReplaceBaseHRef(t *testing.T) {
})
}
}
func Test_enforceContentTypes(t *testing.T) {
getBaseHandler := func(t *testing.T, allow bool) http.Handler {
return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
assert.True(t, allow, "http handler was hit when it should have been blocked by content type enforcement")
writer.WriteHeader(200)
})
}
t.Parallel()
t.Run("GET - not providing a content type, should still succeed", func(t *testing.T) {
handler := enforceContentTypes(getBaseHandler(t, true), []string{"application/json"}).(http.HandlerFunc)
req := httptest.NewRequest("GET", "/", nil)
w := httptest.NewRecorder()
handler(w, req)
resp := w.Result()
assert.Equal(t, 200, resp.StatusCode)
})
t.Run("POST", func(t *testing.T) {
handler := enforceContentTypes(getBaseHandler(t, true), []string{"application/json"}).(http.HandlerFunc)
req := httptest.NewRequest("POST", "/", nil)
w := httptest.NewRecorder()
handler(w, req)
resp := w.Result()
assert.Equal(t, 415, resp.StatusCode, "didn't provide a content type, should have gotten an error")
req = httptest.NewRequest("POST", "/", nil)
req.Header = map[string][]string{"Content-Type": {"application/json"}}
w = httptest.NewRecorder()
handler(w, req)
resp = w.Result()
assert.Equal(t, 200, resp.StatusCode, "should have passed, since an allowed content type was provided")
req = httptest.NewRequest("POST", "/", nil)
req.Header = map[string][]string{"Content-Type": {"not-allowed"}}
w = httptest.NewRecorder()
handler(w, req)
resp = w.Result()
assert.Equal(t, 415, resp.StatusCode, "should not have passed, since a disallowed content type was provided")
})
}

View File

@@ -748,7 +748,7 @@ func TestNamespacedResourceDiffing(t *testing.T) {
Then().
Expect(SyncStatusIs(SyncStatusCodeOutOfSync)).
And(func(app *Application) {
diffOutput, err := RunCli("app", "diff", ctx.AppQualifiedName(), "--local", "testdata/guestbook")
diffOutput, err := RunCli("app", "diff", ctx.AppQualifiedName(), "--local-repo-root", ".", "--local", "testdata/guestbook")
assert.Error(t, err)
assert.Contains(t, diffOutput, fmt.Sprintf("===== apps/Deployment %s/guestbook-ui ======", DeploymentNamespace()))
}).
@@ -761,7 +761,7 @@ func TestNamespacedResourceDiffing(t *testing.T) {
Then().
Expect(SyncStatusIs(SyncStatusCodeSynced)).
And(func(app *Application) {
diffOutput, err := RunCli("app", "diff", ctx.AppQualifiedName(), "--local", "testdata/guestbook")
diffOutput, err := RunCli("app", "diff", ctx.AppQualifiedName(), "--local-repo-root", ".", "--local", "testdata/guestbook")
assert.NoError(t, err)
assert.Empty(t, diffOutput)
}).
@@ -897,7 +897,7 @@ func testNSEdgeCasesApplicationResources(t *testing.T, appPath string, statusCod
expect.
Expect(HealthIs(statusCode)).
And(func(app *Application) {
diffOutput, err := RunCli("app", "diff", ctx.AppQualifiedName(), "--local", path.Join("testdata", appPath))
diffOutput, err := RunCli("app", "diff", ctx.AppQualifiedName(), "--local-repo-root", ".", "--local", path.Join("testdata", appPath))
assert.Empty(t, diffOutput)
assert.NoError(t, err)
})
@@ -998,7 +998,7 @@ func TestNamespacedLocalManifestSync(t *testing.T) {
Given().
LocalPath(guestbookPathLocal).
When().
Sync().
Sync("--local-repo-root", ".").
Then().
Expect(SyncStatusIs(SyncStatusCodeSynced)).
And(func(app *Application) {
@@ -1066,7 +1066,7 @@ func TestNamespacedLocalSyncDryRunWithASEnabled(t *testing.T) {
assert.NoError(t, err)
appBefore := app.DeepCopy()
_, err = RunCli("app", "sync", app.QualifiedName(), "--dry-run", "--local", guestbookPathLocal)
_, err = RunCli("app", "sync", app.QualifiedName(), "--dry-run", "--local-repo-root", ".", "--local", guestbookPathLocal)
assert.NoError(t, err)
appAfter := app.DeepCopy()

View File

@@ -1324,7 +1324,7 @@ func TestLocalManifestSync(t *testing.T) {
Given().
LocalPath(guestbookPathLocal).
When().
Sync().
Sync("--local-repo-root", ".").
Then().
Expect(SyncStatusIs(SyncStatusCodeSynced)).
And(func(app *Application) {
@@ -1385,7 +1385,7 @@ func TestLocalSyncDryRunWithAutosyncEnabled(t *testing.T) {
assert.NoError(t, err)
appBefore := app.DeepCopy()
_, err = RunCli("app", "sync", app.Name, "--dry-run", "--local", guestbookPathLocal)
_, err = RunCli("app", "sync", app.Name, "--dry-run", "--local-repo-root", ".", "--local", guestbookPathLocal)
assert.NoError(t, err)
appAfter := app.DeepCopy()

View File

@@ -2,6 +2,7 @@ package fixture
import (
"bytes"
"crypto/tls"
"encoding/json"
"io"
"net/http"
@@ -27,7 +28,15 @@ func DoHttpRequest(method string, path string, data ...byte) (*http.Response, er
return nil, err
}
req.AddCookie(&http.Cookie{Name: common.AuthCookieName, Value: token})
return http.DefaultClient.Do(req)
req.Header.Set("Content-Type", "application/json")
httpClient := &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: IsRemote()},
},
}
return httpClient.Do(req)
}
// DoHttpJsonRequest executes a http request against the Argo CD API server and unmarshals the response body as JSON

View File

@@ -15,7 +15,7 @@ import {
RevisionHelpIcon
} from '../../../shared/components';
import {BadgePanel, Spinner} from '../../../shared/components';
import {Consumer, ContextApis} from '../../../shared/context';
import {AuthSettingsCtx, Consumer, ContextApis} from '../../../shared/context';
import * as models from '../../../shared/models';
import {services} from '../../../shared/services';
@@ -47,6 +47,7 @@ export const ApplicationSummary = (props: ApplicationSummaryProps) => {
const source = getAppDefaultSource(app);
const isHelm = source.hasOwnProperty('chart');
const initialState = app.spec.destination.server === undefined ? 'NAME' : 'URL';
const useAuthSettingsCtx = React.useContext(AuthSettingsCtx);
const [destFormat, setDestFormat] = React.useState(initialState);
const [changeSync, setChangeSync] = React.useState(false);
@@ -589,7 +590,7 @@ export const ApplicationSummary = (props: ApplicationSummaryProps) => {
</div>
)}
</Consumer>
<BadgePanel app={props.app.metadata.name} />
<BadgePanel app={props.app.metadata.name} appNamespace={props.app.metadata.namespace} nsEnabled={useAuthSettingsCtx?.appsInAnyNamespaceEnabled} />
<EditablePanel
save={updateApp}
values={app}

View File

@@ -149,9 +149,9 @@ export const PodsLogsViewer = (props: PodLogsProps) => {
const logsContent = (width: number, height: number, isWrapped: boolean) => (
<div ref={logsContainerRef} onScroll={handleScroll} style={{width, height, overflow: 'scroll'}}>
{logs.map((log, lineNum) => (
<pre key={lineNum} style={{whiteSpace: isWrapped ? 'normal' : 'pre'}} className='noscroll'>
<div key={lineNum} style={{whiteSpace: isWrapped ? 'normal' : 'pre', lineHeight: '16px'}} className='noscroll'>
<Ansi>{renderLog(log, lineNum)}</Ansi>
</pre>
</div>
))}
</div>
);

View File

@@ -6,7 +6,7 @@ import {Context} from '../../context';
require('./badge-panel.scss');
export const BadgePanel = ({app, project}: {app?: string; project?: string}) => {
export const BadgePanel = ({app, project, appNamespace, nsEnabled}: {app?: string; project?: string; appNamespace?: string; nsEnabled?: boolean}) => {
const [badgeType, setBadgeType] = React.useState('URL');
const context = React.useContext(Context);
if (!app && !project) {
@@ -20,6 +20,9 @@ export const BadgePanel = ({app, project}: {app?: string; project?: string}) =>
let alt = '';
if (app) {
badgeURL = `${root}api/badge?name=${app}&revision=true`;
if (nsEnabled) {
badgeURL += `&namespace=${appNamespace}`;
}
entityURL = `${root}applications/${app}`;
alt = 'App Status';
} else if (project) {

View File

@@ -51,19 +51,19 @@ export default {
},
post(url: string) {
return initHandlers(agent.post(`${apiRoot()}${url}`));
return initHandlers(agent.post(`${apiRoot()}${url}`)).set('Content-Type', 'application/json');
},
put(url: string) {
return initHandlers(agent.put(`${apiRoot()}${url}`));
return initHandlers(agent.put(`${apiRoot()}${url}`)).set('Content-Type', 'application/json');
},
patch(url: string) {
return initHandlers(agent.patch(`${apiRoot()}${url}`));
return initHandlers(agent.patch(`${apiRoot()}${url}`)).set('Content-Type', 'application/json');
},
delete(url: string) {
return initHandlers(agent.del(`${apiRoot()}${url}`));
return initHandlers(agent.del(`${apiRoot()}${url}`)).set('Content-Type', 'application/json');
},
loadEventSource(url: string): Observable<string> {

41
util/cache/redis.go vendored
View File

@@ -7,6 +7,7 @@ import (
"encoding/json"
"fmt"
"io"
"net"
"time"
ioutil "github.com/argoproj/argo-cd/v2/util/io"
@@ -155,41 +156,27 @@ type MetricsRegistry interface {
ObserveRedisRequestDuration(duration time.Duration)
}
var metricStartTimeKey = struct{}{}
type redisHook struct {
registry MetricsRegistry
}
func (rh *redisHook) BeforeProcess(ctx context.Context, cmd redis.Cmder) (context.Context, error) {
return context.WithValue(ctx, metricStartTimeKey, time.Now()), nil
func (rh *redisHook) DialHook(next redis.DialHook) redis.DialHook {
return func(ctx context.Context, network, addr string) (net.Conn, error) {
conn, err := next(ctx, network, addr)
return conn, err
}
}
func (rh *redisHook) AfterProcess(ctx context.Context, cmd redis.Cmder) error {
cmdErr := cmd.Err()
rh.registry.IncRedisRequest(cmdErr != nil && cmdErr != redis.Nil)
func (rh *redisHook) ProcessHook(next redis.ProcessHook) redis.ProcessHook {
return func(ctx context.Context, cmd redis.Cmder) error {
startTime := time.Now()
startTime := ctx.Value(metricStartTimeKey).(time.Time)
duration := time.Since(startTime)
rh.registry.ObserveRedisRequestDuration(duration)
err := next(ctx, cmd)
rh.registry.IncRedisRequest(err != nil && err != redis.Nil)
rh.registry.ObserveRedisRequestDuration(time.Since(startTime))
return nil
}
func (redisHook) BeforeProcessPipeline(ctx context.Context, _ []redis.Cmder) (context.Context, error) {
return ctx, nil
}
func (redisHook) AfterProcessPipeline(_ context.Context, _ []redis.Cmder) error {
return nil
}
func (redisHook) DialHook(next redis.DialHook) redis.DialHook {
return nil
}
func (redisHook) ProcessHook(next redis.ProcessHook) redis.ProcessHook {
return nil
return err
}
}
func (redisHook) ProcessPipelineHook(next redis.ProcessPipelineHook) redis.ProcessPipelineHook {

View File

@@ -2,14 +2,13 @@ package cache
import (
"context"
"strings"
"errors"
"net"
"github.com/redis/go-redis/v9"
log "github.com/sirupsen/logrus"
)
const NoSuchHostErr = "no such host"
type argoRedisHooks struct {
reconnectCallback func()
}
@@ -18,32 +17,23 @@ func NewArgoRedisHook(reconnectCallback func()) *argoRedisHooks {
return &argoRedisHooks{reconnectCallback: reconnectCallback}
}
func (hook *argoRedisHooks) BeforeProcess(ctx context.Context, cmd redis.Cmder) (context.Context, error) {
return ctx, nil
}
func (hook *argoRedisHooks) AfterProcess(ctx context.Context, cmd redis.Cmder) error {
if cmd.Err() != nil && strings.Contains(cmd.Err().Error(), NoSuchHostErr) {
log.Warnf("Reconnect to redis because error: \"%v\"", cmd.Err())
hook.reconnectCallback()
}
return nil
}
func (hook *argoRedisHooks) BeforeProcessPipeline(ctx context.Context, cmds []redis.Cmder) (context.Context, error) {
return ctx, nil
}
func (hook *argoRedisHooks) AfterProcessPipeline(ctx context.Context, cmds []redis.Cmder) error {
return nil
}
func (hook *argoRedisHooks) DialHook(next redis.DialHook) redis.DialHook {
return nil
return func(ctx context.Context, network, addr string) (net.Conn, error) {
conn, err := next(ctx, network, addr)
return conn, err
}
}
func (hook *argoRedisHooks) ProcessHook(next redis.ProcessHook) redis.ProcessHook {
return nil
return func(ctx context.Context, cmd redis.Cmder) error {
var dnsError *net.DNSError
err := next(ctx, cmd)
if err != nil && errors.As(err, &dnsError) {
log.Warnf("Reconnect to redis because error: \"%v\"", err)
hook.reconnectCallback()
}
return err
}
}
func (hook *argoRedisHooks) ProcessPipelineHook(next redis.ProcessPipelineHook) redis.ProcessPipelineHook {

View File

@@ -1,38 +1,53 @@
package cache
import (
"context"
"errors"
"testing"
"time"
"github.com/alicebob/miniredis/v2"
"github.com/stretchr/testify/assert"
"github.com/redis/go-redis/v9"
)
func Test_ReconnectCallbackHookCalled(t *testing.T) {
mr, err := miniredis.Run()
if err != nil {
panic(err)
}
defer mr.Close()
called := false
hook := NewArgoRedisHook(func() {
called = true
})
cmd := &redis.StringCmd{}
cmd.SetErr(errors.New("Failed to resync revoked tokens. retrying again in 1 minute: dial tcp: lookup argocd-redis on 10.179.0.10:53: no such host"))
_ = hook.AfterProcess(context.Background(), cmd)
faultyDNSRedisClient := redis.NewClient(&redis.Options{Addr: "invalidredishost.invalid:12345"})
faultyDNSRedisClient.AddHook(hook)
faultyDNSClient := NewRedisCache(faultyDNSRedisClient, 60*time.Second, RedisCompressionNone)
err = faultyDNSClient.Set(&Item{Key: "baz", Object: "foo"})
assert.Equal(t, called, true)
assert.Error(t, err)
}
func Test_ReconnectCallbackHookNotCalled(t *testing.T) {
mr, err := miniredis.Run()
if err != nil {
panic(err)
}
defer mr.Close()
called := false
hook := NewArgoRedisHook(func() {
called = true
})
cmd := &redis.StringCmd{}
cmd.SetErr(errors.New("Something wrong"))
_ = hook.AfterProcess(context.Background(), cmd)
redisClient := redis.NewClient(&redis.Options{Addr: mr.Addr()})
redisClient.AddHook(hook)
client := NewRedisCache(redisClient, 60*time.Second, RedisCompressionNone)
err = client.Set(&Item{Key: "foo", Object: "bar"})
assert.Equal(t, called, false)
assert.NoError(t, err)
}

View File

@@ -2,14 +2,59 @@ package cache
import (
"context"
"strconv"
"testing"
"time"
promcm "github.com/prometheus/client_model/go"
"github.com/alicebob/miniredis/v2"
"github.com/prometheus/client_golang/prometheus"
"github.com/redis/go-redis/v9"
"github.com/stretchr/testify/assert"
)
var (
redisRequestCounter = prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "argocd_redis_request_total",
},
[]string{"initiator", "failed"},
)
redisRequestHistogram = prometheus.NewHistogramVec(
prometheus.HistogramOpts{
Name: "argocd_redis_request_duration",
Buckets: []float64{0.1, 0.25, .5, 1, 2},
},
[]string{"initiator"},
)
)
type MockMetricsServer struct {
registry *prometheus.Registry
redisRequestCounter *prometheus.CounterVec
redisRequestHistogram *prometheus.HistogramVec
}
func NewMockMetricsServer() *MockMetricsServer {
registry := prometheus.NewRegistry()
registry.MustRegister(redisRequestCounter)
registry.MustRegister(redisRequestHistogram)
return &MockMetricsServer{
registry: registry,
redisRequestCounter: redisRequestCounter,
redisRequestHistogram: redisRequestHistogram,
}
}
func (m *MockMetricsServer) IncRedisRequest(failed bool) {
m.redisRequestCounter.WithLabelValues("mock", strconv.FormatBool(failed)).Inc()
}
func (m *MockMetricsServer) ObserveRedisRequestDuration(duration time.Duration) {
m.redisRequestHistogram.WithLabelValues("mock").Observe(duration.Seconds())
}
func TestRedisSetCache(t *testing.T) {
mr, err := miniredis.Run()
if err != nil {
@@ -70,3 +115,50 @@ func TestRedisSetCacheCompressed(t *testing.T) {
assert.Equal(t, testValue, result)
}
func TestRedisMetrics(t *testing.T) {
mr, err := miniredis.Run()
if err != nil {
panic(err)
}
defer mr.Close()
metric := &promcm.Metric{}
ms := NewMockMetricsServer()
redisClient := redis.NewClient(&redis.Options{Addr: mr.Addr()})
faultyRedisClient := redis.NewClient(&redis.Options{Addr: "invalidredishost.invalid:12345"})
CollectMetrics(redisClient, ms)
CollectMetrics(faultyRedisClient, ms)
client := NewRedisCache(redisClient, 60*time.Second, RedisCompressionNone)
faultyClient := NewRedisCache(faultyRedisClient, 60*time.Second, RedisCompressionNone)
var res string
//client successful request
err = client.Set(&Item{Key: "foo", Object: "bar"})
assert.NoError(t, err)
err = client.Get("foo", &res)
assert.NoError(t, err)
c, err := ms.redisRequestCounter.GetMetricWithLabelValues("mock", "false")
assert.NoError(t, err)
err = c.Write(metric)
assert.NoError(t, err)
assert.Equal(t, metric.Counter.GetValue(), float64(2))
//faulty client failed request
err = faultyClient.Get("foo", &res)
assert.Error(t, err)
c, err = ms.redisRequestCounter.GetMetricWithLabelValues("mock", "true")
assert.NoError(t, err)
err = c.Write(metric)
assert.NoError(t, err)
assert.Equal(t, metric.Counter.GetValue(), float64(1))
//both clients histogram count
o, err := ms.redisRequestHistogram.GetMetricWithLabelValues("mock")
assert.NoError(t, err)
err = o.(prometheus.Metric).Write(metric)
assert.NoError(t, err)
assert.Equal(t, int(metric.Histogram.GetSampleCount()), 3)
}

13
util/env/env.go vendored
View File

@@ -124,8 +124,17 @@ func ParseDurationFromEnv(env string, defaultValue, min, max time.Duration) time
return dur
}
func StringFromEnv(env string, defaultValue string) string {
if str := os.Getenv(env); str != "" {
type StringFromEnvOpts struct {
// AllowEmpty allows the value to be empty as long as the environment variable is set.
AllowEmpty bool
}
func StringFromEnv(env string, defaultValue string, opts ...StringFromEnvOpts) string {
opt := StringFromEnvOpts{}
for _, o := range opts {
opt.AllowEmpty = opt.AllowEmpty || o.AllowEmpty
}
if str, ok := os.LookupEnv(env); opt.AllowEmpty && ok || str != "" {
return str
}
return defaultValue

19
util/env/env_test.go vendored
View File

@@ -7,6 +7,7 @@ import (
"time"
"github.com/stretchr/testify/assert"
"k8s.io/utils/pointer"
)
func TestParseNumFromEnv(t *testing.T) {
@@ -167,19 +168,25 @@ func TestStringFromEnv(t *testing.T) {
testCases := []struct {
name string
env string
env *string
expected string
def string
opts []StringFromEnvOpts
}{
{"Some string", "true", "true", def},
{"Empty string with default", "", def, def},
{"Empty string without default", "", "", ""},
{"Some string", pointer.String("true"), "true", def, nil},
{"Empty string with default", pointer.String(""), def, def, nil},
{"Empty string without default", pointer.String(""), "", "", nil},
{"No env variable with default allow empty", nil, "default", "default", []StringFromEnvOpts{{AllowEmpty: true}}},
{"Some variable with default allow empty", pointer.String("true"), "true", "default", []StringFromEnvOpts{{AllowEmpty: true}}},
{"Empty variable with default allow empty", pointer.String(""), "", "default", []StringFromEnvOpts{{AllowEmpty: true}}},
}
for _, tt := range testCases {
t.Run(tt.name, func(t *testing.T) {
t.Setenv(envKey, tt.env)
b := StringFromEnv(envKey, tt.def)
if tt.env != nil {
t.Setenv(envKey, *tt.env)
}
b := StringFromEnv(envKey, tt.def, tt.opts...)
assert.Equal(t, tt.expected, b)
})
}

View File

@@ -91,6 +91,28 @@ func (c *Cmd) RegistryLogin(repo string, creds Creds) (string, error) {
args = append(args, "--password", creds.Password)
}
if creds.CAPath != "" {
args = append(args, "--ca-file", creds.CAPath)
}
if len(creds.CertData) > 0 {
filePath, closer, err := writeToTmp(creds.CertData)
if err != nil {
return "", err
}
defer argoio.Close(closer)
args = append(args, "--cert-file", filePath)
}
if len(creds.KeyData) > 0 {
filePath, closer, err := writeToTmp(creds.KeyData)
if err != nil {
return "", err
}
defer argoio.Close(closer)
args = append(args, "--key-file", filePath)
}
if creds.InsecureSkipVerify {
args = append(args, "--insecure")
}
@@ -238,6 +260,25 @@ func (c *Cmd) PullOCI(repo string, chart string, version string, destination str
if creds.CAPath != "" {
args = append(args, "--ca-file", creds.CAPath)
}
if len(creds.CertData) > 0 {
filePath, closer, err := writeToTmp(creds.CertData)
if err != nil {
return "", err
}
defer argoio.Close(closer)
args = append(args, "--cert-file", filePath)
}
if len(creds.KeyData) > 0 {
filePath, closer, err := writeToTmp(creds.KeyData)
if err != nil {
return "", err
}
defer argoio.Close(closer)
args = append(args, "--key-file", filePath)
}
if creds.InsecureSkipVerify && c.insecureSkipVerifySupported {
args = append(args, "--insecure-skip-tls-verify")
}

View File

@@ -35,8 +35,9 @@ type Kustomize interface {
}
// NewKustomizeApp create a new wrapper to run commands on the `kustomize` command-line tool.
func NewKustomizeApp(path string, creds git.Creds, fromRepo string, binaryPath string) Kustomize {
func NewKustomizeApp(repoRoot string, path string, creds git.Creds, fromRepo string, binaryPath string) Kustomize {
return &kustomize{
repoRoot: repoRoot,
path: path,
creds: creds,
repo: fromRepo,
@@ -45,6 +46,8 @@ func NewKustomizeApp(path string, creds git.Creds, fromRepo string, binaryPath s
}
type kustomize struct {
// path to the Git repository root
repoRoot string
// path inside the checked out tree
path string
// creds structure
@@ -281,6 +284,7 @@ func (k *kustomize) Build(opts *v1alpha1.ApplicationSourceKustomize, kustomizeOp
}
cmd.Env = append(cmd.Env, environ...)
cmd.Dir = k.repoRoot
out, err := executil.Run(cmd)
if err != nil {
return nil, nil, err

View File

@@ -39,7 +39,7 @@ func TestKustomizeBuild(t *testing.T) {
namePrefix := "namePrefix-"
nameSuffix := "-nameSuffix"
namespace := "custom-namespace"
kustomize := NewKustomizeApp(appPath, git.NopCreds{}, "", "")
kustomize := NewKustomizeApp(appPath, appPath, git.NopCreds{}, "", "")
env := &v1alpha1.Env{
&v1alpha1.EnvEntry{Name: "ARGOCD_APP_NAME", Value: "argo-cd-tests"},
}
@@ -122,7 +122,7 @@ func TestKustomizeBuild(t *testing.T) {
func TestFailKustomizeBuild(t *testing.T) {
appPath, err := testDataDir(t, kustomization1)
assert.Nil(t, err)
kustomize := NewKustomizeApp(appPath, git.NopCreds{}, "", "")
kustomize := NewKustomizeApp(appPath, appPath, git.NopCreds{}, "", "")
kustomizeSource := v1alpha1.ApplicationSourceKustomize{
Replicas: []v1alpha1.KustomizeReplica{
{
@@ -221,7 +221,7 @@ func TestKustomizeBuildForceCommonLabels(t *testing.T) {
for _, tc := range testCases {
appPath, err := testDataDir(t, tc.TestData)
assert.Nil(t, err)
kustomize := NewKustomizeApp(appPath, git.NopCreds{}, "", "")
kustomize := NewKustomizeApp(appPath, appPath, git.NopCreds{}, "", "")
objs, _, err := kustomize.Build(&tc.KustomizeSource, nil, tc.Env)
switch tc.ExpectErr {
case true:
@@ -313,7 +313,7 @@ func TestKustomizeBuildForceCommonAnnotations(t *testing.T) {
for _, tc := range testCases {
appPath, err := testDataDir(t, tc.TestData)
assert.Nil(t, err)
kustomize := NewKustomizeApp(appPath, git.NopCreds{}, "", "")
kustomize := NewKustomizeApp(appPath, appPath, git.NopCreds{}, "", "")
objs, _, err := kustomize.Build(&tc.KustomizeSource, nil, tc.Env)
switch tc.ExpectErr {
case true:
@@ -333,7 +333,7 @@ func TestKustomizeCustomVersion(t *testing.T) {
kustomizePath, err := testDataDir(t, kustomization4)
assert.Nil(t, err)
envOutputFile := kustomizePath + "/env_output"
kustomize := NewKustomizeApp(appPath, git.NopCreds{}, "", kustomizePath+"/kustomize.special")
kustomize := NewKustomizeApp(appPath, appPath, git.NopCreds{}, "", kustomizePath+"/kustomize.special")
kustomizeSource := v1alpha1.ApplicationSourceKustomize{
Version: "special",
}
@@ -355,7 +355,7 @@ func TestKustomizeCustomVersion(t *testing.T) {
func TestKustomizeBuildPatches(t *testing.T) {
appPath, err := testDataDir(t, kustomization5)
assert.Nil(t, err)
kustomize := NewKustomizeApp(appPath, git.NopCreds{}, "", "")
kustomize := NewKustomizeApp(appPath, appPath, git.NopCreds{}, "", "")
kustomizeSource := v1alpha1.ApplicationSourceKustomize{
Patches: []v1alpha1.KustomizePatch{

View File

@@ -8,9 +8,9 @@ import (
"net/http/httptest"
"testing"
"github.com/go-jose/go-jose/v3"
"github.com/golang-jwt/jwt/v4"
"github.com/stretchr/testify/require"
"gopkg.in/square/go-jose.v2"
)
// Cert is a certificate for tests. It was generated like this: