mirror of
https://github.com/argoproj/argo-cd
synced 2026-04-21 17:07:16 +00:00
feat: Applications in any namespace (#9755)
* feat: Applications in any namespace Signed-off-by: jannfis <jann@mistrust.net> * Fix typo in CI Signed-off-by: jannfis <jann@mistrust.net> * Create argocd-e2e-external namespace Signed-off-by: jannfis <jann@mistrust.net> * Update from codegen Signed-off-by: jannfis <jann@mistrust.net> * Remove debug code Signed-off-by: jannfis <jann@mistrust.net> * Update help text for -N option to app create Signed-off-by: jannfis <jann@mistrust.net> * Wrap error when retrieving AppProject from cache Signed-off-by: jannfis <jann@mistrust.net> * Check for controller namespace first before matching on additional ns Signed-off-by: jannfis <jann@mistrust.net> * Improve TestAppProjectIsSourceNamespacePermitted unit test Signed-off-by: jannfis <jann@mistrust.net> * Get rid of some debug leftovers Signed-off-by: jannfis <jann@mistrust.net> * Better error wrapping; return IsNotFound as-is Signed-off-by: jannfis <jann@mistrust.net> * Updates from codegen Signed-off-by: jannfis <jann@mistrust.net> * We don't need AppShortName() anymore Signed-off-by: jannfis <jann@mistrust.net> * Update end-to-end tests to use annotation methods Signed-off-by: jannfis <jann@mistrust.net> * Add e2e tests to test for app creation in not permitted ns Signed-off-by: jannfis <jann@mistrust.net> * Remove deprecated code Signed-off-by: jannfis <jann@mistrust.net> * Remove dead code Signed-off-by: jannfis <jann@mistrust.net> * Add RBACName() method to application type Signed-off-by: jannfis <jann@mistrust.net> * Update from codegen Signed-off-by: jannfis <jann@mistrust.net> * Fix e2e test Signed-off-by: jannfis <jann@mistrust.net> * Update codegen Signed-off-by: jannfis <jann@mistrust.net> * Move RBAC name generation to an application receiver Signed-off-by: jannfis <jann@mistrust.net> * Fix sync window status in UI Signed-off-by: jannfis <jann@mistrust.net> * Fix pod logs viewer Signed-off-by: jannfis <jann@mistrust.net> * Fix application events in UI Signed-off-by: jannfis <jann@mistrust.net> * Fix application search in UI Signed-off-by: jannfis <jann@mistrust.net> * Fix yarn lint Signed-off-by: jannfis <jann@mistrust.net> * Only set up cluster-wide application informer when additional namespaces are specified Signed-off-by: jannfis <jann@mistrust.net> * Adapt e2e test to a changed error message Signed-off-by: jannfis <jann@mistrust.net> * Application namespace should be taken into account for create Signed-off-by: jannfis <jann@mistrust.net> * Use non-qualified application name as Helm release name Signed-off-by: jannfis <jann@mistrust.net> * Support --app-namespace in e2e tests Signed-off-by: jannfis <jann@mistrust.net> * Enable more e2e tests Signed-off-by: jannfis <jann@mistrust.net> * Increase e2e timeout for newly added tests Signed-off-by: jannfis <jann@mistrust.net>
This commit is contained in:
parent
3d06d8202e
commit
068048cb80
100 changed files with 5895 additions and 1129 deletions
1
.github/workflows/ci-build.yaml
vendored
1
.github/workflows/ci-build.yaml
vendored
|
|
@ -354,6 +354,7 @@ jobs:
|
|||
ARGOCD_E2E_K3S: "true"
|
||||
ARGOCD_IN_CI: "true"
|
||||
ARGOCD_E2E_APISERVER_PORT: "8088"
|
||||
ARGOCD_APPLICATION_NAMESPACES: "argocd-e2e-external"
|
||||
ARGOCD_SERVER: "127.0.0.1:8088"
|
||||
GITHUB_TOKEN: ${{ secrets.E2E_TEST_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
|
||||
GITLAB_TOKEN: ${{ secrets.E2E_TEST_GITLAB_TOKEN }}
|
||||
|
|
|
|||
10
Makefile
10
Makefile
|
|
@ -47,7 +47,7 @@ ARGOCD_E2E_DEX_PORT?=5556
|
|||
ARGOCD_E2E_YARN_HOST?=localhost
|
||||
ARGOCD_E2E_DISABLE_AUTH?=
|
||||
|
||||
ARGOCD_E2E_TEST_TIMEOUT?=30m
|
||||
ARGOCD_E2E_TEST_TIMEOUT?=45m
|
||||
|
||||
ARGOCD_IN_CI?=false
|
||||
ARGOCD_TEST_E2E?=true
|
||||
|
|
@ -81,6 +81,7 @@ define run-in-test-server
|
|||
-e ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} \
|
||||
-e ARGOCD_SSH_DATA_PATH=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} \
|
||||
-e ARGOCD_GPG_DATA_PATH=${ARGOCD_GPG_DATA_PATH:-/tmp/argocd-local/gpg/source} \
|
||||
-e ARGOCD_APPLICATION_NAMESPACES \
|
||||
-e GITHUB_TOKEN \
|
||||
-v ${DOCKER_SRC_MOUNT} \
|
||||
-v ${GOPATH}/pkg/mod:/go/pkg/mod${VOLUME_MOUNT} \
|
||||
|
|
@ -118,7 +119,7 @@ endef
|
|||
|
||||
#
|
||||
define exec-in-test-server
|
||||
docker exec -it -u $(shell id -u):$(shell id -g) -e ARGOCD_E2E_K3S=$(ARGOCD_E2E_K3S) argocd-test-server $(1)
|
||||
docker exec -it -u $(shell id -u):$(shell id -g) -e ARGOCD_E2E_RECORD=$(ARGOCD_E2E_RECORD) -e ARGOCD_E2E_K3S=$(ARGOCD_E2E_K3S) argocd-test-server $(1)
|
||||
endef
|
||||
|
||||
PATH:=$(PATH):$(PWD)/hack
|
||||
|
|
@ -405,7 +406,7 @@ test-e2e:
|
|||
test-e2e-local: cli-local
|
||||
# NO_PROXY ensures all tests don't go out through a proxy if one is configured on the test system
|
||||
export GO111MODULE=off
|
||||
ARGOCD_GPG_ENABLED=true NO_PROXY=* ./hack/test.sh -timeout $(ARGOCD_E2E_TEST_TIMEOUT) -v ./test/e2e
|
||||
ARGOCD_E2E_RECORD=${ARGOCD_E2E_RECORD} ARGOCD_GPG_ENABLED=true NO_PROXY=* ./hack/test.sh -timeout $(ARGOCD_E2E_TEST_TIMEOUT) -v ./test/e2e
|
||||
|
||||
# Spawns a shell in the test server container for debugging purposes
|
||||
debug-test-server: test-tools-image
|
||||
|
|
@ -426,6 +427,7 @@ start-e2e: test-tools-image
|
|||
.PHONY: start-e2e-local
|
||||
start-e2e-local: mod-vendor-local dep-ui-local cli-local
|
||||
kubectl create ns argocd-e2e || true
|
||||
kubectl create ns argocd-e2e-external || true
|
||||
kubectl config set-context --current --namespace=argocd-e2e
|
||||
kustomize build test/manifests/base | kubectl apply -f -
|
||||
kubectl apply -f https://raw.githubusercontent.com/open-cluster-management/api/a6845f2ebcb186ec26b832f60c988537a58f3859/cluster/v1alpha1/0000_04_clusters.open-cluster-management.io_placementdecisions.crd.yaml
|
||||
|
|
@ -446,6 +448,7 @@ start-e2e-local: mod-vendor-local dep-ui-local cli-local
|
|||
ARGOCD_ZJWT_FEATURE_FLAG=always \
|
||||
ARGOCD_IN_CI=$(ARGOCD_IN_CI) \
|
||||
BIN_MODE=$(ARGOCD_BIN_MODE) \
|
||||
ARGOCD_APPLICATION_NAMESPACES=argocd-e2e-external \
|
||||
ARGOCD_E2E_TEST=true \
|
||||
goreman -f $(ARGOCD_PROCFILE) start ${ARGOCD_START}
|
||||
|
||||
|
|
@ -477,6 +480,7 @@ start-local: mod-vendor-local dep-ui-local cli-local
|
|||
ARGOCD_IN_CI=false \
|
||||
ARGOCD_GPG_ENABLED=$(ARGOCD_GPG_ENABLED) \
|
||||
ARGOCD_E2E_TEST=false \
|
||||
ARGOCD_APPLICATION_NAMESPACES=$(ARGOCD_APPLICATION_NAMESPACES) \
|
||||
goreman -f $(ARGOCD_PROCFILE) start ${ARGOCD_START}
|
||||
|
||||
# Run goreman start with exclude option , provide exclude env variable with list of services
|
||||
|
|
|
|||
4
Procfile
4
Procfile
|
|
@ -1,5 +1,5 @@
|
|||
controller: [ "$BIN_MODE" == 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_SSH_DATA_PATH=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} ARGOCD_BINARY_NAME=argocd-application-controller $COMMAND --loglevel debug --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081} --otlp-address=${ARGOCD_OTLP_ADDRESS}"
|
||||
api-server: [ "$BIN_MODE" == 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_SSH_DATA_PATH=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} ARGOCD_BINARY_NAME=argocd-server $COMMAND --loglevel debug --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --disable-auth=${ARGOCD_E2E_DISABLE_AUTH:-'true'} --insecure --dex-server http://localhost:${ARGOCD_E2E_DEX_PORT:-5556} --repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081} --port ${ARGOCD_E2E_APISERVER_PORT:-8080} --otlp-address=${ARGOCD_OTLP_ADDRESS}"
|
||||
controller: [ "$BIN_MODE" == 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_SSH_DATA_PATH=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} ARGOCD_BINARY_NAME=argocd-application-controller $COMMAND --loglevel debug --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081} --otlp-address=${ARGOCD_OTLP_ADDRESS} --application-namespaces=${ARGOCD_APPLICATION_NAMESPACES:-''}"
|
||||
api-server: [ "$BIN_MODE" == 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_SSH_DATA_PATH=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} ARGOCD_BINARY_NAME=argocd-server $COMMAND --loglevel debug --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --disable-auth=${ARGOCD_E2E_DISABLE_AUTH:-'true'} --insecure --dex-server http://localhost:${ARGOCD_E2E_DEX_PORT:-5556} --repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081} --port ${ARGOCD_E2E_APISERVER_PORT:-8080} --otlp-address=${ARGOCD_OTLP_ADDRESS} --application-namespaces=${ARGOCD_APPLICATION_NAMESPACES:-''}"
|
||||
dex: sh -c "ARGOCD_BINARY_NAME=argocd-dex go run github.com/argoproj/argo-cd/v2/cmd gendexcfg -o `pwd`/dist/dex.yaml && docker run --rm -p ${ARGOCD_E2E_DEX_PORT:-5556}:${ARGOCD_E2E_DEX_PORT:-5556} -v `pwd`/dist/dex.yaml:/dex.yaml ghcr.io/dexidp/dex:$(grep "image: ghcr.io/dexidp/dex" manifests/base/dex/argocd-dex-server-deployment.yaml | cut -d':' -f3) dex serve /dex.yaml"
|
||||
redis: bash -c "if [ \"$ARGOCD_REDIS_LOCAL\" == 'true' ]; then redis-server --save '' --appendonly no --port ${ARGOCD_E2E_REDIS_PORT:-6379}; else docker run --rm --name argocd-redis -i -p ${ARGOCD_E2E_REDIS_PORT:-6379}:${ARGOCD_E2E_REDIS_PORT:-6379} redis:$(grep "image: redis" manifests/base/redis/argocd-redis-deployment.yaml | cut -d':' -f3) --save '' --appendonly no --port ${ARGOCD_E2E_REDIS_PORT:-6379}; fi"
|
||||
repo-server: [ "$BIN_MODE" == 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_GNUPGHOME=${ARGOCD_GNUPGHOME:-/tmp/argocd-local/gpg/keys} ARGOCD_PLUGINSOCKFILEPATH=${ARGOCD_PLUGINSOCKFILEPATH:-./test/cmp} ARGOCD_GPG_DATA_PATH=${ARGOCD_GPG_DATA_PATH:-/tmp/argocd-local/gpg/source} ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_SSH_DATA_PATH=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} ARGOCD_BINARY_NAME=argocd-repo-server ARGOCD_GPG_ENABLED=${ARGOCD_GPG_ENABLED:-false} $COMMAND --loglevel debug --port ${ARGOCD_E2E_REPOSERVER_PORT:-8081} --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --otlp-address=${ARGOCD_OTLP_ADDRESS}"
|
||||
|
|
|
|||
|
|
@ -265,6 +265,12 @@
|
|||
"description": "the repoURL to restrict returned list applications.",
|
||||
"name": "repo",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "the application's namespace.",
|
||||
"name": "appNamespace",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
|
|
@ -407,6 +413,11 @@
|
|||
"type": "string",
|
||||
"name": "kind",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "appNamespace",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
|
|
@ -463,6 +474,11 @@
|
|||
"type": "string",
|
||||
"name": "kind",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "appNamespace",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
|
|
@ -529,6 +545,12 @@
|
|||
"description": "the repoURL to restrict returned list applications.",
|
||||
"name": "repo",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "the application's namespace.",
|
||||
"name": "appNamespace",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
|
|
@ -568,6 +590,11 @@
|
|||
"type": "string",
|
||||
"name": "propagationPolicy",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "appNamespace",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
|
|
@ -651,6 +678,11 @@
|
|||
"type": "string",
|
||||
"name": "resourceUID",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "appNamespace",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
|
|
@ -758,6 +790,11 @@
|
|||
"type": "boolean",
|
||||
"name": "previous",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "appNamespace",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
|
|
@ -803,6 +840,11 @@
|
|||
"type": "string",
|
||||
"name": "revision",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "appNamespace",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
|
|
@ -834,6 +876,11 @@
|
|||
"name": "name",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "appNamespace",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
|
|
@ -942,6 +989,11 @@
|
|||
"type": "boolean",
|
||||
"name": "previous",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "appNamespace",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
|
|
@ -1007,6 +1059,11 @@
|
|||
"type": "string",
|
||||
"name": "kind",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "appNamespace",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
|
|
@ -1074,6 +1131,11 @@
|
|||
"type": "string",
|
||||
"name": "patchType",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "appNamespace",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
|
|
@ -1138,6 +1200,11 @@
|
|||
"type": "boolean",
|
||||
"name": "orphan",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "appNamespace",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
|
|
@ -1194,6 +1261,11 @@
|
|||
"type": "string",
|
||||
"name": "kind",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "appNamespace",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
|
|
@ -1256,6 +1328,11 @@
|
|||
"type": "string",
|
||||
"name": "kind",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "appNamespace",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
|
|
@ -1295,6 +1372,12 @@
|
|||
"name": "revision",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "the application's namespace.",
|
||||
"name": "appNamespace",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
|
|
@ -1378,6 +1461,11 @@
|
|||
"type": "boolean",
|
||||
"name": "validate",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "appNamespace",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
|
|
@ -1448,6 +1536,11 @@
|
|||
"name": "name",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "appNamespace",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
|
|
@ -3167,6 +3260,12 @@
|
|||
"description": "the repoURL to restrict returned list applications.",
|
||||
"name": "repo",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "the application's namespace.",
|
||||
"name": "appNamespace",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
|
|
@ -3232,6 +3331,11 @@
|
|||
"type": "string",
|
||||
"name": "kind",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "appNamespace",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
|
|
@ -3390,6 +3494,9 @@
|
|||
"type": "object",
|
||||
"title": "ApplicationPatchRequest is a request to patch an application",
|
||||
"properties": {
|
||||
"appNamespace": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
|
|
@ -3415,6 +3522,9 @@
|
|||
"applicationApplicationRollbackRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"appNamespace": {
|
||||
"type": "string"
|
||||
},
|
||||
"dryRun": {
|
||||
"type": "boolean"
|
||||
},
|
||||
|
|
@ -3434,6 +3544,9 @@
|
|||
"type": "object",
|
||||
"title": "ApplicationSyncRequest is a request to apply the config state to live state",
|
||||
"properties": {
|
||||
"appNamespace": {
|
||||
"type": "string"
|
||||
},
|
||||
"dryRun": {
|
||||
"type": "boolean"
|
||||
},
|
||||
|
|
@ -3704,6 +3817,9 @@
|
|||
"$ref": "#/definitions/v1alpha1ConfigManagementPlugin"
|
||||
}
|
||||
},
|
||||
"controllerNamespace": {
|
||||
"type": "string"
|
||||
},
|
||||
"dexConfig": {
|
||||
"$ref": "#/definitions/clusterDexConfig"
|
||||
},
|
||||
|
|
@ -4755,6 +4871,13 @@
|
|||
"$ref": "#/definitions/v1alpha1SignatureKey"
|
||||
}
|
||||
},
|
||||
"sourceNamespaces": {
|
||||
"type": "array",
|
||||
"title": "SourceNamespaces defines the namespaces application resources are allowed to be created in",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"sourceRepos": {
|
||||
"type": "array",
|
||||
"title": "SourceRepos contains list of repository URLs which can be used for deployment",
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ func NewCommand() *cobra.Command {
|
|||
repoServerPlaintext bool
|
||||
repoServerStrictTLS bool
|
||||
otlpAddress string
|
||||
applicationNamespaces []string
|
||||
)
|
||||
var command = cobra.Command{
|
||||
Use: cliName,
|
||||
|
|
@ -148,7 +149,8 @@ func NewCommand() *cobra.Command {
|
|||
metricsCacheExpiration,
|
||||
metricsAplicationLabels,
|
||||
kubectlParallelismLimit,
|
||||
clusterFilter)
|
||||
clusterFilter,
|
||||
applicationNamespaces)
|
||||
errors.CheckError(err)
|
||||
cacheutil.CollectMetrics(redisClient, appController.GetMetricsServer())
|
||||
|
||||
|
|
@ -189,6 +191,7 @@ func NewCommand() *cobra.Command {
|
|||
command.Flags().BoolVar(&repoServerStrictTLS, "repo-server-strict-tls", env.ParseBoolFromEnv("ARGOCD_APPLICATION_CONTROLLER_REPO_SERVER_STRICT_TLS", false), "Whether to use strict validation of the TLS cert presented by the repo server")
|
||||
command.Flags().StringSliceVar(&metricsAplicationLabels, "metrics-application-labels", []string{}, "List of Application labels that will be added to the argocd_application_labels metric")
|
||||
command.Flags().StringVar(&otlpAddress, "otlp-address", env.StringFromEnv("ARGOCD_APPLICATION_CONTROLLER_OTLP_ADDRESS", ""), "OpenTelemetry collector address to send traces to")
|
||||
command.Flags().StringSliceVar(&applicationNamespaces, "application-namespaces", []string{}, "List of additional namespaces that applications are allowed to be created in")
|
||||
cacheSrc = appstatecache.AddCacheFlagsToCmd(&command, func(client *redis.Client) {
|
||||
redisClient = client
|
||||
})
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ func NewCommand() *cobra.Command {
|
|||
dexServerPlaintext bool
|
||||
dexServerStrictTLS bool
|
||||
staticAssetsDir string
|
||||
applicationNamespaces []string
|
||||
)
|
||||
var command = &cobra.Command{
|
||||
Use: cliName,
|
||||
|
|
@ -182,6 +183,7 @@ func NewCommand() *cobra.Command {
|
|||
ContentSecurityPolicy: contentSecurityPolicy,
|
||||
RedisClient: redisClient,
|
||||
StaticAssetsDir: staticAssetsDir,
|
||||
ApplicationNamespaces: applicationNamespaces,
|
||||
}
|
||||
|
||||
stats.RegisterStackDumper()
|
||||
|
|
@ -232,6 +234,7 @@ func NewCommand() *cobra.Command {
|
|||
command.Flags().BoolVar(&repoServerStrictTLS, "repo-server-strict-tls", env.ParseBoolFromEnv("ARGOCD_SERVER_REPO_SERVER_STRICT_TLS", false), "Perform strict validation of TLS certificates when connecting to repo server")
|
||||
command.Flags().BoolVar(&dexServerPlaintext, "dex-server-plaintext", env.ParseBoolFromEnv("ARGOCD_SERVER_DEX_SERVER_PLAINTEXT", false), "Use a plaintext client (non-TLS) to connect to dex server")
|
||||
command.Flags().BoolVar(&dexServerStrictTLS, "dex-server-strict-tls", env.ParseBoolFromEnv("ARGOCD_SERVER_DEX_SERVER_STRICT_TLS", false), "Perform strict validation of TLS certificates when connecting to dex server")
|
||||
command.Flags().StringSliceVar(&applicationNamespaces, "application-namespaces", []string{}, "List of namespaces where application resources can exist")
|
||||
tlsConfigCustomizerSrc = tls.AddTLSFlagsToCmd(command)
|
||||
cacheSrc = servercache.AddCacheFlagsToCmd(command, func(client *redis.Client) {
|
||||
redisClient = client
|
||||
|
|
|
|||
|
|
@ -112,6 +112,7 @@ func NewApplicationCreateCommand(clientOpts *argocdclient.ClientOptions) *cobra.
|
|||
labels []string
|
||||
annotations []string
|
||||
setFinalizer bool
|
||||
appNamespace string
|
||||
)
|
||||
var command = &cobra.Command{
|
||||
Use: "create APPNAME",
|
||||
|
|
@ -146,6 +147,9 @@ func NewApplicationCreateCommand(clientOpts *argocdclient.ClientOptions) *cobra.
|
|||
c.HelpFunc()(c, args)
|
||||
os.Exit(1)
|
||||
}
|
||||
if appNamespace != "" {
|
||||
app.Namespace = appNamespace
|
||||
}
|
||||
if setFinalizer {
|
||||
app.Finalizers = append(app.Finalizers, "resources-finalizer.argocd.argoproj.io")
|
||||
}
|
||||
|
|
@ -190,6 +194,7 @@ func NewApplicationCreateCommand(clientOpts *argocdclient.ClientOptions) *cobra.
|
|||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
command.Flags().StringVarP(&appNamespace, "app-namespace", "N", "", "Namespace where the application will be created in")
|
||||
cmdutil.AddAppFlags(command, &appOpts)
|
||||
return command
|
||||
}
|
||||
|
|
@ -274,8 +279,13 @@ func NewApplicationGetCommand(clientOpts *argocdclient.ClientOptions) *cobra.Com
|
|||
acdClient := headless.NewClientOrDie(clientOpts, c)
|
||||
conn, appIf := acdClient.NewApplicationClientOrDie()
|
||||
defer argoio.Close(conn)
|
||||
appName := args[0]
|
||||
app, err := appIf.Get(ctx, &applicationpkg.ApplicationQuery{Name: &appName, Refresh: getRefreshType(refresh, hardRefresh)})
|
||||
|
||||
appName, appNs := argo.ParseAppQualifiedName(args[0], "")
|
||||
app, err := appIf.Get(ctx, &applicationpkg.ApplicationQuery{
|
||||
Name: &appName,
|
||||
Refresh: getRefreshType(refresh, hardRefresh),
|
||||
AppNamespace: &appNs,
|
||||
})
|
||||
errors.CheckError(err)
|
||||
|
||||
pConn, projIf := headless.NewClientOrDie(clientOpts, c).NewProjectClientOrDie()
|
||||
|
|
@ -354,7 +364,7 @@ func NewApplicationLogsCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
|
|||
acdClient := headless.NewClientOrDie(clientOpts, c)
|
||||
conn, appIf := acdClient.NewApplicationClientOrDie()
|
||||
defer argoio.Close(conn)
|
||||
appName := args[0]
|
||||
appName, appNs := argo.ParseAppQualifiedName(args[0], "")
|
||||
|
||||
retry := true
|
||||
for retry {
|
||||
|
|
@ -372,6 +382,7 @@ func NewApplicationLogsCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
|
|||
Filter: &filter,
|
||||
Container: pointer.String(container),
|
||||
Previous: pointer.Bool(previous),
|
||||
AppNamespace: &appNs,
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatalf("failed to get pod logs: %v", err)
|
||||
|
|
@ -419,7 +430,7 @@ func NewApplicationLogsCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
|
|||
}
|
||||
|
||||
func printAppSummaryTable(app *argoappv1.Application, appURL string, windows *argoappv1.SyncWindows) {
|
||||
fmt.Printf(printOpFmtStr, "Name:", app.Name)
|
||||
fmt.Printf(printOpFmtStr, "Name:", app.QualifiedName())
|
||||
fmt.Printf(printOpFmtStr, "Project:", app.Spec.GetProject())
|
||||
fmt.Printf(printOpFmtStr, "Server:", getServer(app))
|
||||
fmt.Printf(printOpFmtStr, "Namespace:", app.Spec.Destination.Namespace)
|
||||
|
|
@ -590,11 +601,11 @@ func NewApplicationSetCommand(clientOpts *argocdclient.ClientOptions) *cobra.Com
|
|||
c.HelpFunc()(c, args)
|
||||
os.Exit(1)
|
||||
}
|
||||
appName := args[0]
|
||||
appName, appNs := argo.ParseAppQualifiedName(args[0], "")
|
||||
argocdClient := headless.NewClientOrDie(clientOpts, c)
|
||||
conn, appIf := argocdClient.NewApplicationClientOrDie()
|
||||
defer argoio.Close(conn)
|
||||
app, err := appIf.Get(ctx, &applicationpkg.ApplicationQuery{Name: &appName})
|
||||
app, err := appIf.Get(ctx, &applicationpkg.ApplicationQuery{Name: &appName, AppNamespace: &appNs})
|
||||
errors.CheckError(err)
|
||||
visited := cmdutil.SetAppSpecOptions(c.Flags(), &app.Spec, &appOpts)
|
||||
if visited == 0 {
|
||||
|
|
@ -604,9 +615,10 @@ func NewApplicationSetCommand(clientOpts *argocdclient.ClientOptions) *cobra.Com
|
|||
}
|
||||
setParameterOverrides(app, appOpts.Parameters)
|
||||
_, err = appIf.UpdateSpec(ctx, &applicationpkg.ApplicationUpdateSpecRequest{
|
||||
Name: &app.Name,
|
||||
Spec: &app.Spec,
|
||||
Validate: &appOpts.Validate,
|
||||
Name: &app.Name,
|
||||
Spec: &app.Spec,
|
||||
Validate: &appOpts.Validate,
|
||||
AppNamespace: &appNs,
|
||||
})
|
||||
errors.CheckError(err)
|
||||
},
|
||||
|
|
@ -652,10 +664,10 @@ func NewApplicationUnsetCommand(clientOpts *argocdclient.ClientOptions) *cobra.C
|
|||
c.HelpFunc()(c, args)
|
||||
os.Exit(1)
|
||||
}
|
||||
appName := args[0]
|
||||
appName, appNs := argo.ParseAppQualifiedName(args[0], "")
|
||||
conn, appIf := headless.NewClientOrDie(clientOpts, c).NewApplicationClientOrDie()
|
||||
defer argoio.Close(conn)
|
||||
app, err := appIf.Get(ctx, &applicationpkg.ApplicationQuery{Name: &appName})
|
||||
app, err := appIf.Get(ctx, &applicationpkg.ApplicationQuery{Name: &appName, AppNamespace: &appNs})
|
||||
errors.CheckError(err)
|
||||
|
||||
updated, nothingToUnset := unset(&app.Spec.Source, opts)
|
||||
|
|
@ -669,9 +681,10 @@ func NewApplicationUnsetCommand(clientOpts *argocdclient.ClientOptions) *cobra.C
|
|||
|
||||
cmdutil.SetAppSpecOptions(c.Flags(), &app.Spec, &appOpts)
|
||||
_, err = appIf.UpdateSpec(ctx, &applicationpkg.ApplicationUpdateSpecRequest{
|
||||
Name: &app.Name,
|
||||
Spec: &app.Spec,
|
||||
Validate: &appOpts.Validate,
|
||||
Name: &app.Name,
|
||||
Spec: &app.Spec,
|
||||
Validate: &appOpts.Validate,
|
||||
AppNamespace: &appNs,
|
||||
})
|
||||
errors.CheckError(err)
|
||||
},
|
||||
|
|
@ -803,7 +816,6 @@ func getLocalObjects(ctx context.Context, app *argoappv1.Application, local, loc
|
|||
|
||||
func getLocalObjectsString(ctx context.Context, app *argoappv1.Application, local, localRepoRoot, appLabelKey, kubeVersion string, apiVersions []string, kustomizeOptions *argoappv1.KustomizeOptions,
|
||||
configManagementPlugins []*argoappv1.ConfigManagementPlugin, trackingMethod string) []string {
|
||||
|
||||
res, err := repository.GenerateManifests(ctx, local, localRepoRoot, app.Spec.Source.TargetRevision, &repoapiclient.ManifestRequest{
|
||||
Repo: &argoappv1.Repository{Repo: app.Spec.Source.RepoURL},
|
||||
AppLabelKey: appLabelKey,
|
||||
|
|
@ -882,10 +894,14 @@ func NewApplicationDiffCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
|
|||
clientset := headless.NewClientOrDie(clientOpts, c)
|
||||
conn, appIf := clientset.NewApplicationClientOrDie()
|
||||
defer argoio.Close(conn)
|
||||
appName := args[0]
|
||||
app, err := appIf.Get(ctx, &applicationpkg.ApplicationQuery{Name: &appName, Refresh: getRefreshType(refresh, hardRefresh)})
|
||||
appName, appNs := argo.ParseAppQualifiedName(args[0], "")
|
||||
app, err := appIf.Get(ctx, &applicationpkg.ApplicationQuery{
|
||||
Name: &appName,
|
||||
Refresh: getRefreshType(refresh, hardRefresh),
|
||||
AppNamespace: &appNs,
|
||||
})
|
||||
errors.CheckError(err)
|
||||
resources, err := appIf.ManagedResources(ctx, &applicationpkg.ResourcesQuery{ApplicationName: &appName})
|
||||
resources, err := appIf.ManagedResources(ctx, &applicationpkg.ResourcesQuery{ApplicationName: &appName, AppNamespace: &appNs})
|
||||
errors.CheckError(err)
|
||||
conn, settingsIf := clientset.NewSettingsClientOrDie()
|
||||
defer argoio.Close(conn)
|
||||
|
|
@ -894,8 +910,9 @@ func NewApplicationDiffCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
|
|||
diffOption := &DifferenceOption{}
|
||||
if revision != "" {
|
||||
q := applicationpkg.ApplicationManifestQuery{
|
||||
Name: &appName,
|
||||
Revision: &revision,
|
||||
Name: &appName,
|
||||
Revision: &revision,
|
||||
AppNamespace: &appNs,
|
||||
}
|
||||
res, err := appIf.GetManifests(ctx, &q)
|
||||
errors.CheckError(err)
|
||||
|
|
@ -943,7 +960,7 @@ func findandPrintDiff(ctx context.Context, app *argoappv1.Application, resources
|
|||
items := make([]objKeyLiveTarget, 0)
|
||||
if diffOptions.local != "" {
|
||||
localObjs := groupObjsByKey(getLocalObjects(ctx, app, diffOptions.local, diffOptions.localRepoRoot, argoSettings.AppLabelKey, diffOptions.cluster.Info.ServerVersion, diffOptions.cluster.Info.APIVersions, argoSettings.KustomizeOptions, argoSettings.ConfigManagementPlugins, argoSettings.TrackingMethod), liveObjs, app.Spec.Destination.Namespace)
|
||||
items = groupObjsForDiff(resources, localObjs, items, argoSettings, appName)
|
||||
items = groupObjsForDiff(resources, localObjs, items, argoSettings, app.InstanceName(argoSettings.ControllerNamespace))
|
||||
} else if diffOptions.revision != "" {
|
||||
var unstructureds []*unstructured.Unstructured
|
||||
for _, mfst := range diffOptions.res.Manifests {
|
||||
|
|
@ -952,7 +969,7 @@ func findandPrintDiff(ctx context.Context, app *argoappv1.Application, resources
|
|||
unstructureds = append(unstructureds, obj)
|
||||
}
|
||||
groupedObjs := groupObjsByKey(unstructureds, liveObjs, app.Spec.Destination.Namespace)
|
||||
items = groupObjsForDiff(resources, groupedObjs, items, argoSettings, appName)
|
||||
items = groupObjsForDiff(resources, groupedObjs, items, argoSettings, app.Name)
|
||||
} else {
|
||||
for i := range resources.Items {
|
||||
res := resources.Items[i]
|
||||
|
|
@ -1072,9 +1089,11 @@ func NewApplicationDeleteCommand(clientOpts *argocdclient.ClientOptions) *cobra.
|
|||
if promptFlag.Changed && promptFlag.Value.String() == "true" {
|
||||
noPrompt = true
|
||||
}
|
||||
for _, appName := range args {
|
||||
for _, appFullName := range args {
|
||||
appName, appNs := argo.ParseAppQualifiedName(appFullName, "")
|
||||
appDeleteReq := applicationpkg.ApplicationDeleteRequest{
|
||||
Name: &appName,
|
||||
Name: &appName,
|
||||
AppNamespace: &appNs,
|
||||
}
|
||||
if c.Flag("cascade").Changed {
|
||||
appDeleteReq.Cascade = &cascade
|
||||
|
|
@ -1085,10 +1104,10 @@ func NewApplicationDeleteCommand(clientOpts *argocdclient.ClientOptions) *cobra.
|
|||
if cascade && isTerminal && !noPrompt {
|
||||
var lowercaseAnswer string
|
||||
if numOfApps == 1 {
|
||||
lowercaseAnswer = cli.AskToProceedS("Are you sure you want to delete '" + appName + "' and all its resources? [y/n]")
|
||||
lowercaseAnswer = cli.AskToProceedS("Are you sure you want to delete '" + appFullName + "' and all its resources? [y/n]")
|
||||
} else {
|
||||
if !isConfirmAll {
|
||||
lowercaseAnswer = cli.AskToProceedS("Are you sure you want to delete '" + appName + "' and all its resources? [y/n/A] where 'A' is to delete all specified apps and their resources without prompting")
|
||||
lowercaseAnswer = cli.AskToProceedS("Are you sure you want to delete '" + appFullName + "' and all its resources? [y/n/A] where 'A' is to delete all specified apps and their resources without prompting")
|
||||
if lowercaseAnswer == "a" {
|
||||
lowercaseAnswer = "y"
|
||||
isConfirmAll = true
|
||||
|
|
@ -1100,9 +1119,9 @@ func NewApplicationDeleteCommand(clientOpts *argocdclient.ClientOptions) *cobra.
|
|||
if lowercaseAnswer == "y" {
|
||||
_, err := appIf.Delete(ctx, &appDeleteReq)
|
||||
errors.CheckError(err)
|
||||
fmt.Printf("application '%s' deleted\n", appName)
|
||||
fmt.Printf("application '%s' deleted\n", appFullName)
|
||||
} else {
|
||||
fmt.Println("The command to delete '" + appName + "' was cancelled.")
|
||||
fmt.Println("The command to delete '" + appFullName + "' was cancelled.")
|
||||
}
|
||||
} else {
|
||||
_, err := appIf.Delete(ctx, &appDeleteReq)
|
||||
|
|
@ -1120,7 +1139,7 @@ func NewApplicationDeleteCommand(clientOpts *argocdclient.ClientOptions) *cobra.
|
|||
// Print simple list of application names
|
||||
func printApplicationNames(apps []argoappv1.Application) {
|
||||
for _, app := range apps {
|
||||
fmt.Println(app.Name)
|
||||
fmt.Println(app.QualifiedName())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1138,7 +1157,7 @@ func printApplicationTable(apps []argoappv1.Application, output *string) {
|
|||
_, _ = fmt.Fprintf(w, fmtStr, headers...)
|
||||
for _, app := range apps {
|
||||
vals := []interface{}{
|
||||
app.Name,
|
||||
app.QualifiedName(),
|
||||
getServer(&app),
|
||||
app.Spec.Destination.Namespace,
|
||||
app.Spec.GetProject(),
|
||||
|
|
@ -1158,10 +1177,11 @@ func printApplicationTable(apps []argoappv1.Application, output *string) {
|
|||
// NewApplicationListCommand returns a new instance of an `argocd app list` command
|
||||
func NewApplicationListCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
|
||||
var (
|
||||
output string
|
||||
selector string
|
||||
projects []string
|
||||
repo string
|
||||
output string
|
||||
selector string
|
||||
projects []string
|
||||
repo string
|
||||
appNamespace string
|
||||
)
|
||||
var command = &cobra.Command{
|
||||
Use: "list",
|
||||
|
|
@ -1176,7 +1196,10 @@ func NewApplicationListCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
|
|||
|
||||
conn, appIf := headless.NewClientOrDie(clientOpts, c).NewApplicationClientOrDie()
|
||||
defer argoio.Close(conn)
|
||||
apps, err := appIf.List(ctx, &applicationpkg.ApplicationQuery{Selector: pointer.String(selector)})
|
||||
apps, err := appIf.List(ctx, &applicationpkg.ApplicationQuery{
|
||||
Selector: pointer.String(selector),
|
||||
AppNamespace: &appNamespace,
|
||||
})
|
||||
errors.CheckError(err)
|
||||
appList := apps.Items
|
||||
if len(projects) != 0 {
|
||||
|
|
@ -1202,6 +1225,7 @@ func NewApplicationListCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
|
|||
command.Flags().StringVarP(&selector, "selector", "l", "", "List apps by label")
|
||||
command.Flags().StringArrayVarP(&projects, "project", "p", []string{}, "Filter by project name")
|
||||
command.Flags().StringVarP(&repo, "repo", "r", "", "List apps by source repo URL")
|
||||
command.Flags().StringVarP(&appNamespace, "app-namespace", "N", "", "Only list applications in namespace")
|
||||
return command
|
||||
}
|
||||
|
||||
|
|
@ -1442,16 +1466,18 @@ func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
|
|||
}
|
||||
|
||||
for _, i := range list.Items {
|
||||
appNames = append(appNames, i.Name)
|
||||
appNames = append(appNames, i.QualifiedName())
|
||||
}
|
||||
}
|
||||
|
||||
for _, appName := range appNames {
|
||||
for _, appQualifiedName := range appNames {
|
||||
appName, appNs := argo.ParseAppQualifiedName(appQualifiedName, "")
|
||||
|
||||
if len(selectedLabels) > 0 {
|
||||
q := applicationpkg.ApplicationManifestQuery{
|
||||
Name: &appName,
|
||||
Revision: &revision,
|
||||
Name: &appName,
|
||||
AppNamespace: &appNs,
|
||||
Revision: &revision,
|
||||
}
|
||||
|
||||
res, err := appIf.GetManifests(ctx, &q)
|
||||
|
|
@ -1484,7 +1510,10 @@ func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
|
|||
var localObjsStrings []string
|
||||
diffOption := &DifferenceOption{}
|
||||
if local != "" {
|
||||
app, err := appIf.Get(ctx, &applicationpkg.ApplicationQuery{Name: &appName})
|
||||
app, err := appIf.Get(ctx, &applicationpkg.ApplicationQuery{
|
||||
Name: &appName,
|
||||
AppNamespace: &appNs,
|
||||
})
|
||||
errors.CheckError(err)
|
||||
if app.Spec.SyncPolicy != nil && app.Spec.SyncPolicy.Automated != nil && !dryRun {
|
||||
log.Fatal("Cannot use local sync when Automatic Sync Policy is enabled except with --dry-run")
|
||||
|
|
@ -1527,14 +1556,15 @@ func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
|
|||
}
|
||||
|
||||
syncReq := applicationpkg.ApplicationSyncRequest{
|
||||
Name: &appName,
|
||||
DryRun: &dryRun,
|
||||
Revision: &revision,
|
||||
Resources: selectedResources,
|
||||
Prune: &prune,
|
||||
Manifests: localObjsStrings,
|
||||
Infos: getInfos(infos),
|
||||
SyncOptions: syncOptionsFactory(),
|
||||
Name: &appName,
|
||||
AppNamespace: &appNs,
|
||||
DryRun: &dryRun,
|
||||
Revision: &revision,
|
||||
Resources: selectedResources,
|
||||
Prune: &prune,
|
||||
Manifests: localObjsStrings,
|
||||
Infos: getInfos(infos),
|
||||
SyncOptions: syncOptionsFactory(),
|
||||
}
|
||||
|
||||
switch strategy {
|
||||
|
|
@ -1558,20 +1588,26 @@ func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
|
|||
}
|
||||
}
|
||||
if diffChanges {
|
||||
app, err := appIf.Get(ctx, &applicationpkg.ApplicationQuery{Name: &appName})
|
||||
app, err := appIf.Get(ctx, &applicationpkg.ApplicationQuery{
|
||||
Name: &appName,
|
||||
AppNamespace: &appNs,
|
||||
})
|
||||
errors.CheckError(err)
|
||||
resources, err := appIf.ManagedResources(ctx, &applicationpkg.ResourcesQuery{ApplicationName: &appName})
|
||||
resources, err := appIf.ManagedResources(ctx, &applicationpkg.ResourcesQuery{
|
||||
ApplicationName: &appName,
|
||||
AppNamespace: &appNs,
|
||||
})
|
||||
errors.CheckError(err)
|
||||
conn, settingsIf := acdClient.NewSettingsClientOrDie()
|
||||
defer argoio.Close(conn)
|
||||
argoSettings, err := settingsIf.Get(ctx, &settingspkg.SettingsQuery{})
|
||||
errors.CheckError(err)
|
||||
foundDiffs := false
|
||||
fmt.Printf("====== Previewing differences between live and desired state of application %s ======\n", appName)
|
||||
foundDiffs = findandPrintDiff(ctx, app, resources, argoSettings, appName, diffOption)
|
||||
fmt.Printf("====== Previewing differences between live and desired state of application %s ======\n", appQualifiedName)
|
||||
foundDiffs = findandPrintDiff(ctx, app, resources, argoSettings, appQualifiedName, diffOption)
|
||||
if foundDiffs {
|
||||
if !diffChangesConfirm {
|
||||
yesno := cli.AskToProceed(fmt.Sprintf("Please review changes to application %s shown above. Do you want to continue the sync process? (y/n): ", appName))
|
||||
yesno := cli.AskToProceed(fmt.Sprintf("Please review changes to application %s shown above. Do you want to continue the sync process? (y/n): ", appQualifiedName))
|
||||
if !yesno {
|
||||
os.Exit(0)
|
||||
}
|
||||
|
|
@ -1584,7 +1620,7 @@ func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
|
|||
errors.CheckError(err)
|
||||
|
||||
if !async {
|
||||
app, err := waitOnApplicationStatus(ctx, acdClient, appName, timeout, watchOpts{operation: true}, selectedResources)
|
||||
app, err := waitOnApplicationStatus(ctx, acdClient, appQualifiedName, timeout, watchOpts{operation: true}, selectedResources)
|
||||
errors.CheckError(err)
|
||||
|
||||
if !dryRun {
|
||||
|
|
@ -1783,12 +1819,18 @@ func waitOnApplicationStatus(ctx context.Context, acdClient argocdclient.Client,
|
|||
// time when the sync status lags behind when an operation completes
|
||||
refresh := false
|
||||
|
||||
appRealName, appNs := argo.ParseAppQualifiedName(appName, "")
|
||||
|
||||
printFinalStatus := func(app *argoappv1.Application) *argoappv1.Application {
|
||||
var err error
|
||||
if refresh {
|
||||
conn, appClient := acdClient.NewApplicationClientOrDie()
|
||||
refreshType := string(argoappv1.RefreshTypeNormal)
|
||||
app, err = appClient.Get(ctx, &applicationpkg.ApplicationQuery{Name: &appName, Refresh: &refreshType})
|
||||
app, err = appClient.Get(ctx, &applicationpkg.ApplicationQuery{
|
||||
Name: &appRealName,
|
||||
Refresh: &refreshType,
|
||||
AppNamespace: &appNs,
|
||||
})
|
||||
errors.CheckError(err)
|
||||
_ = conn.Close()
|
||||
}
|
||||
|
|
@ -1821,7 +1863,10 @@ func waitOnApplicationStatus(ctx context.Context, acdClient argocdclient.Client,
|
|||
prevStates := make(map[string]*resourceState)
|
||||
conn, appClient := acdClient.NewApplicationClientOrDie()
|
||||
defer argoio.Close(conn)
|
||||
app, err := appClient.Get(ctx, &applicationpkg.ApplicationQuery{Name: &appName})
|
||||
app, err := appClient.Get(ctx, &applicationpkg.ApplicationQuery{
|
||||
Name: &appRealName,
|
||||
AppNamespace: &appNs,
|
||||
})
|
||||
errors.CheckError(err)
|
||||
appEventCh := acdClient.WatchApplicationWithRetry(ctx, appName, app.ResourceVersion)
|
||||
for appEvent := range appEventCh {
|
||||
|
|
@ -1965,8 +2010,11 @@ func NewApplicationHistoryCommand(clientOpts *argocdclient.ClientOptions) *cobra
|
|||
}
|
||||
conn, appIf := headless.NewClientOrDie(clientOpts, c).NewApplicationClientOrDie()
|
||||
defer argoio.Close(conn)
|
||||
appName := args[0]
|
||||
app, err := appIf.Get(ctx, &applicationpkg.ApplicationQuery{Name: &appName})
|
||||
appName, appNs := argo.ParseAppQualifiedName(args[0], "")
|
||||
app, err := appIf.Get(ctx, &applicationpkg.ApplicationQuery{
|
||||
Name: &appName,
|
||||
AppNamespace: &appNs,
|
||||
})
|
||||
errors.CheckError(err)
|
||||
if output == "id" {
|
||||
printApplicationHistoryIds(app.Status.History)
|
||||
|
|
@ -2012,7 +2060,7 @@ func NewApplicationRollbackCommand(clientOpts *argocdclient.ClientOptions) *cobr
|
|||
c.HelpFunc()(c, args)
|
||||
os.Exit(1)
|
||||
}
|
||||
appName := args[0]
|
||||
appName, appNs := argo.ParseAppQualifiedName(args[0], "")
|
||||
var err error
|
||||
depID := -1
|
||||
if len(args) > 1 {
|
||||
|
|
@ -2022,20 +2070,24 @@ func NewApplicationRollbackCommand(clientOpts *argocdclient.ClientOptions) *cobr
|
|||
acdClient := headless.NewClientOrDie(clientOpts, c)
|
||||
conn, appIf := acdClient.NewApplicationClientOrDie()
|
||||
defer argoio.Close(conn)
|
||||
app, err := appIf.Get(ctx, &applicationpkg.ApplicationQuery{Name: &appName})
|
||||
app, err := appIf.Get(ctx, &applicationpkg.ApplicationQuery{
|
||||
Name: &appName,
|
||||
AppNamespace: &appNs,
|
||||
})
|
||||
errors.CheckError(err)
|
||||
|
||||
depInfo, err := findRevisionHistory(app, int64(depID))
|
||||
errors.CheckError(err)
|
||||
|
||||
_, err = appIf.Rollback(ctx, &applicationpkg.ApplicationRollbackRequest{
|
||||
Name: &appName,
|
||||
Id: pointer.Int64(depInfo.ID),
|
||||
Prune: pointer.Bool(prune),
|
||||
Name: &appName,
|
||||
AppNamespace: &appNs,
|
||||
Id: pointer.Int64(depInfo.ID),
|
||||
Prune: pointer.Bool(prune),
|
||||
})
|
||||
errors.CheckError(err)
|
||||
|
||||
_, err = waitOnApplicationStatus(ctx, acdClient, appName, timeout, watchOpts{
|
||||
_, err = waitOnApplicationStatus(ctx, acdClient, app.QualifiedName(), timeout, watchOpts{
|
||||
operation: true,
|
||||
}, nil)
|
||||
errors.CheckError(err)
|
||||
|
|
@ -2090,11 +2142,14 @@ func NewApplicationManifestsCommand(clientOpts *argocdclient.ClientOptions) *cob
|
|||
c.HelpFunc()(c, args)
|
||||
os.Exit(1)
|
||||
}
|
||||
appName := args[0]
|
||||
appName, appNs := argo.ParseAppQualifiedName(args[0], "")
|
||||
clientset := headless.NewClientOrDie(clientOpts, c)
|
||||
conn, appIf := clientset.NewApplicationClientOrDie()
|
||||
defer argoio.Close(conn)
|
||||
resources, err := appIf.ManagedResources(ctx, &applicationpkg.ResourcesQuery{ApplicationName: &appName})
|
||||
resources, err := appIf.ManagedResources(ctx, &applicationpkg.ResourcesQuery{
|
||||
ApplicationName: &appName,
|
||||
AppNamespace: &appNs,
|
||||
})
|
||||
errors.CheckError(err)
|
||||
|
||||
var unstructureds []*unstructured.Unstructured
|
||||
|
|
@ -2117,8 +2172,9 @@ func NewApplicationManifestsCommand(clientOpts *argocdclient.ClientOptions) *cob
|
|||
unstructureds = getLocalObjects(context.Background(), app, local, localRepoRoot, argoSettings.AppLabelKey, cluster.ServerVersion, cluster.Info.APIVersions, argoSettings.KustomizeOptions, argoSettings.ConfigManagementPlugins, argoSettings.TrackingMethod)
|
||||
} else if revision != "" {
|
||||
q := applicationpkg.ApplicationManifestQuery{
|
||||
Name: &appName,
|
||||
Revision: pointer.String(revision),
|
||||
Name: &appName,
|
||||
AppNamespace: &appNs,
|
||||
Revision: pointer.String(revision),
|
||||
}
|
||||
res, err := appIf.GetManifests(ctx, &q)
|
||||
errors.CheckError(err)
|
||||
|
|
@ -2167,10 +2223,13 @@ func NewApplicationTerminateOpCommand(clientOpts *argocdclient.ClientOptions) *c
|
|||
c.HelpFunc()(c, args)
|
||||
os.Exit(1)
|
||||
}
|
||||
appName := args[0]
|
||||
appName, appNs := argo.ParseAppQualifiedName(args[0], "")
|
||||
conn, appIf := headless.NewClientOrDie(clientOpts, c).NewApplicationClientOrDie()
|
||||
defer argoio.Close(conn)
|
||||
_, err := appIf.TerminateOperation(ctx, &applicationpkg.OperationTerminateRequest{Name: &appName})
|
||||
_, err := appIf.TerminateOperation(ctx, &applicationpkg.OperationTerminateRequest{
|
||||
Name: &appName,
|
||||
AppNamespace: &appNs,
|
||||
})
|
||||
errors.CheckError(err)
|
||||
fmt.Printf("Application '%s' operation terminating\n", appName)
|
||||
},
|
||||
|
|
@ -2189,10 +2248,13 @@ func NewApplicationEditCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
|
|||
c.HelpFunc()(c, args)
|
||||
os.Exit(1)
|
||||
}
|
||||
appName := args[0]
|
||||
appName, appNs := argo.ParseAppQualifiedName(args[0], "")
|
||||
conn, appIf := headless.NewClientOrDie(clientOpts, c).NewApplicationClientOrDie()
|
||||
defer argoio.Close(conn)
|
||||
app, err := appIf.Get(ctx, &applicationpkg.ApplicationQuery{Name: &appName})
|
||||
app, err := appIf.Get(ctx, &applicationpkg.ApplicationQuery{
|
||||
Name: &appName,
|
||||
AppNamespace: &appNs,
|
||||
})
|
||||
errors.CheckError(err)
|
||||
appData, err := json.Marshal(app.Spec)
|
||||
errors.CheckError(err)
|
||||
|
|
@ -2212,7 +2274,12 @@ func NewApplicationEditCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
|
|||
|
||||
var appOpts cmdutil.AppOptions
|
||||
cmdutil.SetAppSpecOptions(c.Flags(), &app.Spec, &appOpts)
|
||||
_, err = appIf.UpdateSpec(ctx, &applicationpkg.ApplicationUpdateSpecRequest{Name: &app.Name, Spec: &updatedSpec, Validate: &appOpts.Validate})
|
||||
_, err = appIf.UpdateSpec(ctx, &applicationpkg.ApplicationUpdateSpecRequest{
|
||||
Name: &appName,
|
||||
Spec: &updatedSpec,
|
||||
Validate: &appOpts.Validate,
|
||||
AppNamespace: &appNs,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to update application spec:\n%v", err)
|
||||
}
|
||||
|
|
@ -2243,14 +2310,15 @@ func NewApplicationPatchCommand(clientOpts *argocdclient.ClientOptions) *cobra.C
|
|||
c.HelpFunc()(c, args)
|
||||
os.Exit(1)
|
||||
}
|
||||
appName := args[0]
|
||||
appName, appNs := argo.ParseAppQualifiedName(args[0], "")
|
||||
conn, appIf := headless.NewClientOrDie(clientOpts, c).NewApplicationClientOrDie()
|
||||
defer argoio.Close(conn)
|
||||
|
||||
patchedApp, err := appIf.Patch(ctx, &applicationpkg.ApplicationPatchRequest{
|
||||
Name: &appName,
|
||||
Patch: &patch,
|
||||
PatchType: &patchType,
|
||||
Name: &appName,
|
||||
Patch: &patch,
|
||||
PatchType: &patchType,
|
||||
AppNamespace: &appNs,
|
||||
})
|
||||
errors.CheckError(err)
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import (
|
|||
"github.com/argoproj/argo-cd/v2/cmd/argocd/commands/headless"
|
||||
argocdclient "github.com/argoproj/argo-cd/v2/pkg/apiclient"
|
||||
applicationpkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/application"
|
||||
"github.com/argoproj/argo-cd/v2/util/argo"
|
||||
"github.com/argoproj/argo-cd/v2/util/errors"
|
||||
"github.com/argoproj/argo-cd/v2/util/io"
|
||||
)
|
||||
|
|
@ -62,10 +63,13 @@ func NewApplicationResourceActionsListCommand(clientOpts *argocdclient.ClientOpt
|
|||
c.HelpFunc()(c, args)
|
||||
os.Exit(1)
|
||||
}
|
||||
appName := args[0]
|
||||
appName, appNs := argo.ParseAppQualifiedName(args[0], "")
|
||||
conn, appIf := headless.NewClientOrDie(clientOpts, c).NewApplicationClientOrDie()
|
||||
defer io.Close(conn)
|
||||
resources, err := appIf.ManagedResources(ctx, &applicationpkg.ResourcesQuery{ApplicationName: &appName})
|
||||
resources, err := appIf.ManagedResources(ctx, &applicationpkg.ResourcesQuery{
|
||||
ApplicationName: &appName,
|
||||
AppNamespace: &appNs,
|
||||
})
|
||||
errors.CheckError(err)
|
||||
filteredObjects, err := util.FilterResources(command.Flags().Changed("group"), resources.Items, group, kind, namespace, resourceName, true)
|
||||
errors.CheckError(err)
|
||||
|
|
@ -75,6 +79,7 @@ func NewApplicationResourceActionsListCommand(clientOpts *argocdclient.ClientOpt
|
|||
gvk := obj.GroupVersionKind()
|
||||
availActionsForResource, err := appIf.ListResourceActions(ctx, &applicationpkg.ApplicationResourceRequest{
|
||||
Name: &appName,
|
||||
AppNamespace: &appNs,
|
||||
Namespace: pointer.String(obj.GetNamespace()),
|
||||
ResourceName: pointer.String(obj.GetName()),
|
||||
Group: pointer.String(gvk.Group),
|
||||
|
|
@ -147,12 +152,15 @@ func NewApplicationResourceActionsRunCommand(clientOpts *argocdclient.ClientOpti
|
|||
c.HelpFunc()(c, args)
|
||||
os.Exit(1)
|
||||
}
|
||||
appName := args[0]
|
||||
appName, appNs := argo.ParseAppQualifiedName(args[0], "")
|
||||
actionName := args[1]
|
||||
|
||||
conn, appIf := headless.NewClientOrDie(clientOpts, c).NewApplicationClientOrDie()
|
||||
defer io.Close(conn)
|
||||
resources, err := appIf.ManagedResources(ctx, &applicationpkg.ResourcesQuery{ApplicationName: &appName})
|
||||
resources, err := appIf.ManagedResources(ctx, &applicationpkg.ResourcesQuery{
|
||||
ApplicationName: &appName,
|
||||
AppNamespace: &appNs,
|
||||
})
|
||||
errors.CheckError(err)
|
||||
filteredObjects, err := util.FilterResources(command.Flags().Changed("group"), resources.Items, group, kind, namespace, resourceName, all)
|
||||
errors.CheckError(err)
|
||||
|
|
@ -169,6 +177,7 @@ func NewApplicationResourceActionsRunCommand(clientOpts *argocdclient.ClientOpti
|
|||
objResourceName := obj.GetName()
|
||||
_, err := appIf.RunResourceAction(ctx, &applicationpkg.ResourceActionRunRequest{
|
||||
Name: &appName,
|
||||
AppNamespace: &appNs,
|
||||
Namespace: pointer.String(obj.GetNamespace()),
|
||||
ResourceName: pointer.String(objResourceName),
|
||||
Group: pointer.String(gvk.Group),
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import (
|
|||
"github.com/argoproj/argo-cd/v2/cmd/argocd/commands/headless"
|
||||
argocdclient "github.com/argoproj/argo-cd/v2/pkg/apiclient"
|
||||
applicationpkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/application"
|
||||
"github.com/argoproj/argo-cd/v2/util/argo"
|
||||
"github.com/argoproj/argo-cd/v2/util/errors"
|
||||
argoio "github.com/argoproj/argo-cd/v2/util/io"
|
||||
|
||||
|
|
@ -53,11 +54,14 @@ func NewApplicationPatchResourceCommand(clientOpts *argocdclient.ClientOptions)
|
|||
c.HelpFunc()(c, args)
|
||||
os.Exit(1)
|
||||
}
|
||||
appName := args[0]
|
||||
appName, appNs := argo.ParseAppQualifiedName(args[0], "")
|
||||
|
||||
conn, appIf := headless.NewClientOrDie(clientOpts, c).NewApplicationClientOrDie()
|
||||
defer argoio.Close(conn)
|
||||
resources, err := appIf.ManagedResources(ctx, &applicationpkg.ResourcesQuery{ApplicationName: &appName})
|
||||
resources, err := appIf.ManagedResources(ctx, &applicationpkg.ResourcesQuery{
|
||||
ApplicationName: &appName,
|
||||
AppNamespace: &appNs,
|
||||
})
|
||||
errors.CheckError(err)
|
||||
objectsToPatch, err := util.FilterResources(command.Flags().Changed("group"), resources.Items, group, kind, namespace, resourceName, all)
|
||||
errors.CheckError(err)
|
||||
|
|
@ -66,6 +70,7 @@ func NewApplicationPatchResourceCommand(clientOpts *argocdclient.ClientOptions)
|
|||
gvk := obj.GroupVersionKind()
|
||||
_, err = appIf.PatchResource(ctx, &applicationpkg.ApplicationResourcePatchRequest{
|
||||
Name: &appName,
|
||||
AppNamespace: &appNs,
|
||||
Namespace: pointer.String(obj.GetNamespace()),
|
||||
ResourceName: pointer.String(obj.GetName()),
|
||||
Version: pointer.String(gvk.Version),
|
||||
|
|
@ -111,11 +116,14 @@ func NewApplicationDeleteResourceCommand(clientOpts *argocdclient.ClientOptions)
|
|||
c.HelpFunc()(c, args)
|
||||
os.Exit(1)
|
||||
}
|
||||
appName := args[0]
|
||||
appName, appNs := argo.ParseAppQualifiedName(args[0], "")
|
||||
|
||||
conn, appIf := headless.NewClientOrDie(clientOpts, c).NewApplicationClientOrDie()
|
||||
defer argoio.Close(conn)
|
||||
resources, err := appIf.ManagedResources(ctx, &applicationpkg.ResourcesQuery{ApplicationName: &appName})
|
||||
resources, err := appIf.ManagedResources(ctx, &applicationpkg.ResourcesQuery{
|
||||
ApplicationName: &appName,
|
||||
AppNamespace: &appNs,
|
||||
})
|
||||
errors.CheckError(err)
|
||||
objectsToDelete, err := util.FilterResources(command.Flags().Changed("group"), resources.Items, group, kind, namespace, resourceName, all)
|
||||
errors.CheckError(err)
|
||||
|
|
@ -124,6 +132,7 @@ func NewApplicationDeleteResourceCommand(clientOpts *argocdclient.ClientOptions)
|
|||
gvk := obj.GroupVersionKind()
|
||||
_, err = appIf.DeleteResource(ctx, &applicationpkg.ApplicationResourceDeleteRequest{
|
||||
Name: &appName,
|
||||
AppNamespace: &appNs,
|
||||
Namespace: pointer.String(obj.GetNamespace()),
|
||||
ResourceName: pointer.String(obj.GetName()),
|
||||
Version: pointer.String(gvk.Version),
|
||||
|
|
@ -173,10 +182,13 @@ func NewApplicationListResourcesCommand(clientOpts *argocdclient.ClientOptions)
|
|||
os.Exit(1)
|
||||
}
|
||||
listAll := !c.Flag("orphaned").Changed
|
||||
appName := args[0]
|
||||
appName, appNs := argo.ParseAppQualifiedName(args[0], "")
|
||||
conn, appIf := headless.NewClientOrDie(clientOpts, c).NewApplicationClientOrDie()
|
||||
defer argoio.Close(conn)
|
||||
appResourceTree, err := appIf.ResourceTree(ctx, &applicationpkg.ResourcesQuery{ApplicationName: &appName})
|
||||
appResourceTree, err := appIf.ResourceTree(ctx, &applicationpkg.ResourcesQuery{
|
||||
ApplicationName: &appName,
|
||||
AppNamespace: &appNs,
|
||||
})
|
||||
errors.CheckError(err)
|
||||
printResources(listAll, orphaned, appResourceTree)
|
||||
},
|
||||
|
|
|
|||
|
|
@ -552,7 +552,7 @@ func TestPrintAppSummaryTable(t *testing.T) {
|
|||
return nil
|
||||
})
|
||||
|
||||
expectation := `Name: test
|
||||
expectation := `Name: argocd/test
|
||||
Project: default
|
||||
Server: local
|
||||
Namespace: argocd
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import (
|
|||
|
||||
"github.com/argoproj/argo-cd/v2/pkg/apis/application"
|
||||
argoappv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/v2/util/argo"
|
||||
"github.com/argoproj/argo-cd/v2/util/config"
|
||||
"github.com/argoproj/argo-cd/v2/util/errors"
|
||||
"github.com/argoproj/argo-cd/v2/util/text/label"
|
||||
|
|
@ -561,6 +562,7 @@ func constructAppsFromStdin() ([]*argoappv1.Application, error) {
|
|||
|
||||
func constructAppsBaseOnName(appName string, labels, annotations, args []string, appOpts AppOptions, flags *pflag.FlagSet) ([]*argoappv1.Application, error) {
|
||||
var app *argoappv1.Application
|
||||
|
||||
// read arguments
|
||||
if len(args) == 1 {
|
||||
if appName != "" && appName != args[0] {
|
||||
|
|
@ -568,13 +570,15 @@ func constructAppsBaseOnName(appName string, labels, annotations, args []string,
|
|||
}
|
||||
appName = args[0]
|
||||
}
|
||||
appName, appNs := argo.ParseAppQualifiedName(appName, "")
|
||||
app = &argoappv1.Application{
|
||||
TypeMeta: v1.TypeMeta{
|
||||
Kind: application.ApplicationKind,
|
||||
APIVersion: application.Group + "/v1alpha1",
|
||||
},
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: appName,
|
||||
Name: appName,
|
||||
Namespace: appNs,
|
||||
},
|
||||
}
|
||||
SetAppSpecOptions(flags, &app.Spec, &appOpts)
|
||||
|
|
|
|||
|
|
@ -20,10 +20,11 @@ import (
|
|||
)
|
||||
|
||||
type ProjectOpts struct {
|
||||
Description string
|
||||
destinations []string
|
||||
Sources []string
|
||||
SignatureKeys []string
|
||||
Description string
|
||||
destinations []string
|
||||
Sources []string
|
||||
SignatureKeys []string
|
||||
SourceNamespaces []string
|
||||
|
||||
orphanedResourcesEnabled bool
|
||||
orphanedResourcesWarn bool
|
||||
|
|
@ -45,6 +46,7 @@ func AddProjFlags(command *cobra.Command, opts *ProjectOpts) {
|
|||
command.Flags().StringArrayVar(&opts.deniedClusterResources, "deny-cluster-resource", []string{}, "List of denied cluster level resources")
|
||||
command.Flags().StringArrayVar(&opts.allowedNamespacedResources, "allow-namespaced-resource", []string{}, "List of allowed namespaced resources")
|
||||
command.Flags().StringArrayVar(&opts.deniedNamespacedResources, "deny-namespaced-resource", []string{}, "List of denied namespaced resources")
|
||||
command.Flags().StringSliceVar(&opts.SourceNamespaces, "source-namespaces", []string{}, "List of source namespaces for applications")
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -104,6 +106,10 @@ func (opts *ProjectOpts) GetSignatureKeys() []v1alpha1.SignatureKey {
|
|||
return signatureKeys
|
||||
}
|
||||
|
||||
func (opts *ProjectOpts) GetSourceNamespaces() []string {
|
||||
return opts.SourceNamespaces
|
||||
}
|
||||
|
||||
func GetOrphanedResourcesSettings(flagSet *pflag.FlagSet, opts ProjectOpts) *v1alpha1.OrphanedResourcesMonitorSettings {
|
||||
warnChanged := flagSet.Changed("orphaned-resources-warn")
|
||||
if opts.orphanedResourcesEnabled || warnChanged {
|
||||
|
|
@ -156,6 +162,8 @@ func SetProjSpecOptions(flags *pflag.FlagSet, spec *v1alpha1.AppProjectSpec, pro
|
|||
spec.NamespaceResourceWhitelist = projOpts.GetAllowedNamespacedResources()
|
||||
case "deny-namespaced-resource":
|
||||
spec.NamespaceResourceBlacklist = projOpts.GetDeniedNamespacedResources()
|
||||
case "source-namespaces":
|
||||
spec.SourceNamespaces = projOpts.GetSourceNamespaces()
|
||||
}
|
||||
})
|
||||
if flags.Changed("orphaned-resources") || flags.Changed("orphaned-resources-warn") {
|
||||
|
|
@ -197,6 +205,5 @@ func ConstructAppProj(fileURL string, args []string, opts ProjectOpts, c *cobra.
|
|||
proj.Name = args[0]
|
||||
}
|
||||
SetProjSpecOptions(c.Flags(), &proj.Spec, &opts)
|
||||
|
||||
return &proj, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -113,6 +113,7 @@ type ApplicationController struct {
|
|||
kubectlSemaphore *semaphore.Weighted
|
||||
clusterFilter func(cluster *appv1.Cluster) bool
|
||||
projByNameCache sync.Map
|
||||
applicationNamespaces []string
|
||||
}
|
||||
|
||||
// NewApplicationController creates new instance of ApplicationController.
|
||||
|
|
@ -132,6 +133,7 @@ func NewApplicationController(
|
|||
metricsApplicationLabels []string,
|
||||
kubectlParallelismLimit int64,
|
||||
clusterFilter func(cluster *appv1.Cluster) bool,
|
||||
applicationNamespaces []string,
|
||||
) (*ApplicationController, error) {
|
||||
log.Infof("appResyncPeriod=%v, appHardResyncPeriod=%v", appResyncPeriod, appHardResyncPeriod)
|
||||
db := db.NewDB(namespace, settingsMgr, kubeClientset)
|
||||
|
|
@ -156,6 +158,7 @@ func NewApplicationController(
|
|||
selfHealTimeout: selfHealTimeout,
|
||||
clusterFilter: clusterFilter,
|
||||
projByNameCache: sync.Map{},
|
||||
applicationNamespaces: applicationNamespaces,
|
||||
}
|
||||
if kubectlParallelismLimit > 0 {
|
||||
ctrl.kubectlSemaphore = semaphore.NewWeighted(kubectlParallelismLimit)
|
||||
|
|
@ -270,6 +273,9 @@ type appProjCache struct {
|
|||
appProj *appv1.AppProject
|
||||
}
|
||||
|
||||
// GetAppProject gets an AppProject from the cache. If the AppProject is not
|
||||
// yet cached, retrieves the AppProject from the K8s control plane and stores
|
||||
// in the cache.
|
||||
func (projCache *appProjCache) GetAppProject(ctx context.Context) (*appv1.AppProject, error) {
|
||||
projCache.lock.Lock()
|
||||
defer projCache.lock.Unlock()
|
||||
|
|
@ -284,9 +290,21 @@ func (projCache *appProjCache) GetAppProject(ctx context.Context) (*appv1.AppPro
|
|||
return projCache.appProj, nil
|
||||
}
|
||||
|
||||
// getAppProj gets the AppProject for the given Application app.
|
||||
func (ctrl *ApplicationController) getAppProj(app *appv1.Application) (*appv1.AppProject, error) {
|
||||
projCache, _ := ctrl.projByNameCache.LoadOrStore(app.Spec.GetProject(), ctrl.newAppProjCache(app.Spec.GetProject()))
|
||||
return projCache.(*appProjCache).GetAppProject(context.TODO())
|
||||
proj, err := projCache.(*appProjCache).GetAppProject(context.TODO())
|
||||
if err != nil {
|
||||
if apierr.IsNotFound(err) {
|
||||
return nil, err
|
||||
} else {
|
||||
return nil, fmt.Errorf("could not retrieve AppProject '%s' from cache: %v", app.Spec.Project, err)
|
||||
}
|
||||
}
|
||||
if !proj.IsAppNamespacePermitted(app, ctrl.namespace) {
|
||||
return nil, argo.ErrProjectNotPermitted(app.GetName(), app.GetNamespace(), proj.GetName())
|
||||
}
|
||||
return proj, nil
|
||||
}
|
||||
|
||||
func (ctrl *ApplicationController) handleObjectUpdated(managedByApp map[string]bool, ref v1.ObjectReference) {
|
||||
|
|
@ -300,13 +318,17 @@ func (ctrl *ApplicationController) handleObjectUpdated(managedByApp map[string]b
|
|||
continue
|
||||
}
|
||||
|
||||
managedByApp[app.Name] = true
|
||||
managedByApp[app.InstanceName(ctrl.namespace)] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
for appName, isManagedResource := range managedByApp {
|
||||
obj, exists, err := ctrl.appInformer.GetIndexer().GetByKey(ctrl.namespace + "/" + appName)
|
||||
if app, ok := obj.(*appv1.Application); exists && err == nil && ok && isSelfReferencedApp(app, ref) {
|
||||
// The appName is given as <namespace>_<name>, but the indexer needs it
|
||||
// format <namespace>/<name>
|
||||
appKey := ctrl.toAppKey(appName)
|
||||
obj, exists, err := ctrl.appInformer.GetIndexer().GetByKey(appKey)
|
||||
app, ok := obj.(*appv1.Application)
|
||||
if exists && err == nil && ok && isSelfReferencedApp(app, ref) {
|
||||
// Don't force refresh app if related resource is application itself. This prevents infinite reconciliation loop.
|
||||
continue
|
||||
}
|
||||
|
|
@ -316,6 +338,13 @@ func (ctrl *ApplicationController) handleObjectUpdated(managedByApp map[string]b
|
|||
continue
|
||||
}
|
||||
|
||||
// Enforce application's permission for the source namespace
|
||||
_, err = ctrl.getAppProj(app)
|
||||
if err != nil {
|
||||
log.Errorf("Unable to determine project for app '%s': %v", app.QualifiedName(), err)
|
||||
continue
|
||||
}
|
||||
|
||||
level := ComparisonWithNothing
|
||||
if isManagedResource {
|
||||
level = CompareWithRecent
|
||||
|
|
@ -330,10 +359,10 @@ func (ctrl *ApplicationController) handleObjectUpdated(managedByApp map[string]b
|
|||
} else {
|
||||
resKey = "(cluster-scoped)/" + ref.Name
|
||||
}
|
||||
log.Debugf("Refreshing app %s for change in cluster of object %s of type %s/%s", appName, resKey, ref.APIVersion, ref.Kind)
|
||||
log.Debugf("Refreshing app %s for change in cluster of object %s of type %s/%s", appKey, resKey, ref.APIVersion, ref.Kind)
|
||||
}
|
||||
|
||||
ctrl.requestAppRefresh(appName, &level, nil)
|
||||
ctrl.requestAppRefresh(app.QualifiedName(), &level, nil)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -348,11 +377,11 @@ func (ctrl *ApplicationController) setAppManagedResources(a *appv1.Application,
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting resource tree: %s", err)
|
||||
}
|
||||
err = ctrl.cache.SetAppResourcesTree(a.Name, tree)
|
||||
err = ctrl.cache.SetAppResourcesTree(a.InstanceName(ctrl.namespace), tree)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error setting app resource tree: %s", err)
|
||||
}
|
||||
err = ctrl.cache.SetAppManagedResources(a.Name, managedResources)
|
||||
err = ctrl.cache.SetAppManagedResources(a.InstanceName(ctrl.namespace), managedResources)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error setting app managed resources: %s", err)
|
||||
}
|
||||
|
|
@ -443,7 +472,8 @@ func (ctrl *ApplicationController) getResourceTree(a *appv1.Application, managed
|
|||
err := ctrl.stateCache.IterateHierarchy(a.Spec.Destination.Server, k, func(child appv1.ResourceNode, appName string) bool {
|
||||
belongToAnotherApp := false
|
||||
if appName != "" {
|
||||
if _, exists, err := ctrl.appInformer.GetIndexer().GetByKey(ctrl.namespace + "/" + appName); exists && err == nil {
|
||||
appKey := ctrl.toAppKey(appName)
|
||||
if _, exists, err := ctrl.appInformer.GetIndexer().GetByKey(appKey); exists && err == nil {
|
||||
belongToAnotherApp = true
|
||||
}
|
||||
}
|
||||
|
|
@ -474,7 +504,6 @@ func (ctrl *ApplicationController) getResourceTree(a *appv1.Application, managed
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &appv1.ApplicationTree{Nodes: nodes, OrphanedNodes: orphanedNodes, Hosts: hosts}, nil
|
||||
}
|
||||
|
||||
|
|
@ -705,15 +734,16 @@ func (ctrl *ApplicationController) Run(ctx context.Context, statusProcessors int
|
|||
<-ctx.Done()
|
||||
}
|
||||
|
||||
// requestAppRefresh adds a request for given app to the refresh queue. appName
|
||||
// needs to be the qualified name of the application, i.e. <namespace>/<name>.
|
||||
func (ctrl *ApplicationController) requestAppRefresh(appName string, compareWith *CompareWith, after *time.Duration) {
|
||||
key := fmt.Sprintf("%s/%s", ctrl.namespace, appName)
|
||||
|
||||
key := ctrl.toAppKey(appName)
|
||||
if compareWith != nil && after != nil {
|
||||
ctrl.appComparisonTypeRefreshQueue.AddAfter(fmt.Sprintf("%s/%d", key, compareWith), *after)
|
||||
} else {
|
||||
if compareWith != nil {
|
||||
ctrl.refreshRequestedAppsMutex.Lock()
|
||||
ctrl.refreshRequestedApps[appName] = compareWith.Max(ctrl.refreshRequestedApps[appName])
|
||||
ctrl.refreshRequestedApps[key] = compareWith.Max(ctrl.refreshRequestedApps[key])
|
||||
ctrl.refreshRequestedAppsMutex.Unlock()
|
||||
}
|
||||
if after != nil {
|
||||
|
|
@ -770,7 +800,7 @@ func (ctrl *ApplicationController) processAppOperationQueueItem() (processNext b
|
|||
// If we get here, we are about process an operation but we cannot rely on informer since it might has stale data.
|
||||
// So always retrieve the latest version to ensure it is not stale to avoid unnecessary syncing.
|
||||
// We cannot rely on informer since applications might be updated by both application controller and api server.
|
||||
freshApp, err := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(ctrl.namespace).Get(context.Background(), app.ObjectMeta.Name, metav1.GetOptions{})
|
||||
freshApp, err := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(app.ObjectMeta.Namespace).Get(context.Background(), app.ObjectMeta.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
log.Errorf("Failed to retrieve latest application state: %v", err)
|
||||
return
|
||||
|
|
@ -816,7 +846,7 @@ func (ctrl *ApplicationController) processAppComparisonTypeQueueItem() (processN
|
|||
log.Warnf("Unable to parse comparison type: %v", err)
|
||||
return
|
||||
} else {
|
||||
ctrl.requestAppRefresh(parts[1], CompareWith(compareWith).Pointer(), nil)
|
||||
ctrl.requestAppRefresh(ctrl.toAppQualifiedName(parts[1], parts[0]), CompareWith(compareWith).Pointer(), nil)
|
||||
}
|
||||
}
|
||||
return
|
||||
|
|
@ -910,7 +940,7 @@ func (ctrl *ApplicationController) getPermittedAppLiveObjects(app *appv1.Applica
|
|||
}
|
||||
|
||||
func (ctrl *ApplicationController) finalizeApplicationDeletion(app *appv1.Application) ([]*unstructured.Unstructured, error) {
|
||||
logCtx := log.WithField("application", app.Name)
|
||||
logCtx := log.WithField("application", app.QualifiedName())
|
||||
logCtx.Infof("Deleting resources")
|
||||
// Get refreshed application info, since informer app copy might be stale
|
||||
app, err := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(app.Namespace).Get(context.Background(), app.Name, metav1.GetOptions{})
|
||||
|
|
@ -1019,11 +1049,15 @@ func (ctrl *ApplicationController) finalizeApplicationDeletion(app *appv1.Applic
|
|||
logCtx.Infof("Resource entries removed from undefined cluster")
|
||||
}
|
||||
|
||||
ctrl.projectRefreshQueue.Add(fmt.Sprintf("%s/%s", app.Namespace, app.Spec.GetProject()))
|
||||
ctrl.projectRefreshQueue.Add(fmt.Sprintf("%s/%s", ctrl.namespace, app.Spec.GetProject()))
|
||||
return objs, nil
|
||||
}
|
||||
|
||||
func (ctrl *ApplicationController) removeCascadeFinalizer(app *appv1.Application) error {
|
||||
_, err := ctrl.getAppProj(app)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
app.UnSetCascadedDeletion()
|
||||
var patch []byte
|
||||
patch, _ = json.Marshal(map[string]interface{}{
|
||||
|
|
@ -1032,7 +1066,7 @@ func (ctrl *ApplicationController) removeCascadeFinalizer(app *appv1.Application
|
|||
},
|
||||
})
|
||||
|
||||
_, err := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(app.Namespace).Patch(context.Background(), app.Name, types.MergePatchType, patch, metav1.PatchOptions{})
|
||||
_, err = ctrl.applicationClientset.ArgoprojV1alpha1().Applications(app.Namespace).Patch(context.Background(), app.Name, types.MergePatchType, patch, metav1.PatchOptions{})
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
@ -1061,7 +1095,7 @@ func (ctrl *ApplicationController) setAppCondition(app *appv1.Application, condi
|
|||
}
|
||||
|
||||
func (ctrl *ApplicationController) processRequestedAppOperation(app *appv1.Application) {
|
||||
logCtx := log.WithField("application", app.Name)
|
||||
logCtx := log.WithField("application", app.QualifiedName())
|
||||
var state *appv1.OperationState
|
||||
// Recover from any unexpected panics and automatically set the status to be failed
|
||||
defer func() {
|
||||
|
|
@ -1092,7 +1126,7 @@ func (ctrl *ApplicationController) processRequestedAppOperation(app *appv1.Appli
|
|||
retryAfter := time.Until(retryAt)
|
||||
if retryAfter > 0 {
|
||||
logCtx.Infof("Skipping retrying in-progress operation. Attempting again at: %s", retryAt.Format(time.RFC3339))
|
||||
ctrl.requestAppRefresh(app.Name, CompareWithLatest.Pointer(), &retryAfter)
|
||||
ctrl.requestAppRefresh(app.QualifiedName(), CompareWithLatest.Pointer(), &retryAfter)
|
||||
return
|
||||
} else {
|
||||
// retrying operation. remove previous failure time in app since it is used as a trigger
|
||||
|
|
@ -1118,11 +1152,24 @@ func (ctrl *ApplicationController) processRequestedAppOperation(app *appv1.Appli
|
|||
ctrl.appStateManager.SyncAppState(app, state)
|
||||
}
|
||||
|
||||
// Check whether application is allowed to use project
|
||||
_, err := ctrl.getAppProj(app)
|
||||
if err != nil {
|
||||
state.Phase = synccommon.OperationError
|
||||
state.Message = err.Error()
|
||||
}
|
||||
|
||||
if state.Phase == synccommon.OperationRunning {
|
||||
// It's possible for an app to be terminated while we were operating on it. We do not want
|
||||
// to clobber the Terminated state with Running. Get the latest app state to check for this.
|
||||
freshApp, err := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(ctrl.namespace).Get(context.Background(), app.ObjectMeta.Name, metav1.GetOptions{})
|
||||
freshApp, err := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(app.Namespace).Get(context.Background(), app.ObjectMeta.Name, metav1.GetOptions{})
|
||||
if err == nil {
|
||||
// App may have lost permissions to use the project meanwhile.
|
||||
_, err = ctrl.getAppProj(freshApp)
|
||||
if err != nil {
|
||||
state.Phase = synccommon.OperationFailed
|
||||
state.Message = fmt.Sprintf("operation not allowed: %v", err)
|
||||
}
|
||||
if freshApp.Status.OperationState != nil && freshApp.Status.OperationState.Phase == synccommon.OperationTerminating {
|
||||
state.Phase = synccommon.OperationTerminating
|
||||
state.Message = "operation is terminating"
|
||||
|
|
@ -1155,7 +1202,7 @@ func (ctrl *ApplicationController) processRequestedAppOperation(app *appv1.Appli
|
|||
// sync/health information
|
||||
if _, err := cache.MetaNamespaceKeyFunc(app); err == nil {
|
||||
// force app refresh with using CompareWithLatest comparison type and trigger app reconciliation loop
|
||||
ctrl.requestAppRefresh(app.Name, CompareWithLatest.Pointer(), nil)
|
||||
ctrl.requestAppRefresh(app.QualifiedName(), CompareWithLatest.Pointer(), nil)
|
||||
} else {
|
||||
logCtx.Warnf("Fails to requeue application: %v", err)
|
||||
}
|
||||
|
|
@ -1183,7 +1230,7 @@ func (ctrl *ApplicationController) setOperationState(app *appv1.Application, sta
|
|||
patch["operation"] = nil
|
||||
}
|
||||
if reflect.DeepEqual(app.Status.OperationState, state) {
|
||||
log.Infof("No operation updates necessary to '%s'. Skipping patch", app.Name)
|
||||
log.Infof("No operation updates necessary to '%s'. Skipping patch", app.QualifiedName())
|
||||
return nil
|
||||
}
|
||||
patchJSON, err := json.Marshal(patch)
|
||||
|
|
@ -1197,7 +1244,7 @@ func (ctrl *ApplicationController) setOperationState(app *appv1.Application, sta
|
|||
}
|
||||
}
|
||||
|
||||
appClient := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(ctrl.namespace)
|
||||
appClient := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(app.Namespace)
|
||||
_, err = appClient.Patch(context.Background(), app.Name, types.MergePatchType, patchJSON, metav1.PatchOptions{})
|
||||
if err != nil {
|
||||
// Stop retrying updating deleted application
|
||||
|
|
@ -1206,7 +1253,7 @@ func (ctrl *ApplicationController) setOperationState(app *appv1.Application, sta
|
|||
}
|
||||
return err
|
||||
}
|
||||
log.Infof("updated '%s' operation (phase: %s)", app.Name, state.Phase)
|
||||
log.Infof("updated '%s' operation (phase: %s)", app.QualifiedName(), state.Phase)
|
||||
if state.Phase.Completed() {
|
||||
eventInfo := argo.EventInfo{Reason: argo.EventReasonOperationCompleted}
|
||||
var messages []string
|
||||
|
|
@ -1268,7 +1315,7 @@ func (ctrl *ApplicationController) processAppRefreshQueueItem() (processNext boo
|
|||
}
|
||||
|
||||
app := origApp.DeepCopy()
|
||||
logCtx := log.WithFields(log.Fields{"application": app.Name})
|
||||
logCtx := log.WithFields(log.Fields{"application": app.QualifiedName()})
|
||||
startTime := time.Now()
|
||||
defer func() {
|
||||
reconcileDuration := time.Since(startTime)
|
||||
|
|
@ -1284,13 +1331,13 @@ func (ctrl *ApplicationController) processAppRefreshQueueItem() (processNext boo
|
|||
|
||||
if comparisonLevel == ComparisonWithNothing {
|
||||
managedResources := make([]*appv1.ResourceDiff, 0)
|
||||
if err := ctrl.cache.GetAppManagedResources(app.Name, &managedResources); err != nil {
|
||||
if err := ctrl.cache.GetAppManagedResources(app.InstanceName(ctrl.namespace), &managedResources); err != nil {
|
||||
logCtx.Warnf("Failed to get cached managed resources for tree reconciliation, fall back to full reconciliation")
|
||||
} else {
|
||||
var tree *appv1.ApplicationTree
|
||||
if tree, err = ctrl.getResourceTree(app, managedResources); err == nil {
|
||||
app.Status.Summary = tree.GetSummary()
|
||||
if err := ctrl.cache.SetAppResourcesTree(app.Name, tree); err != nil {
|
||||
if err := ctrl.cache.SetAppResourcesTree(app.InstanceName(ctrl.namespace), tree); err != nil {
|
||||
logCtx.Errorf("Failed to cache resources tree: %v", err)
|
||||
return
|
||||
}
|
||||
|
|
@ -1307,10 +1354,10 @@ func (ctrl *ApplicationController) processAppRefreshQueueItem() (processNext boo
|
|||
app.Status.Health.Status = health.HealthStatusUnknown
|
||||
ctrl.persistAppStatus(origApp, &app.Status)
|
||||
|
||||
if err := ctrl.cache.SetAppResourcesTree(app.Name, &appv1.ApplicationTree{}); err != nil {
|
||||
if err := ctrl.cache.SetAppResourcesTree(app.InstanceName(ctrl.namespace), &appv1.ApplicationTree{}); err != nil {
|
||||
log.Warnf("failed to set app resource tree: %v", err)
|
||||
}
|
||||
if err := ctrl.cache.SetAppManagedResources(app.Name, nil); err != nil {
|
||||
if err := ctrl.cache.SetAppManagedResources(app.InstanceName(ctrl.namespace), nil); err != nil {
|
||||
log.Warnf("failed to set app managed resources tree: %v", err)
|
||||
}
|
||||
return
|
||||
|
|
@ -1383,7 +1430,7 @@ func resourceStatusKey(res appv1.ResourceStatus) string {
|
|||
// Additionally returns whether full refresh was requested or not.
|
||||
// If full refresh is requested then target and live state should be reconciled, else only live state tree should be updated.
|
||||
func (ctrl *ApplicationController) needRefreshAppStatus(app *appv1.Application, statusRefreshTimeout, statusHardRefreshTimeout time.Duration) (bool, appv1.RefreshType, CompareWith) {
|
||||
logCtx := log.WithFields(log.Fields{"application": app.Name})
|
||||
logCtx := log.WithFields(log.Fields{"application": app.QualifiedName()})
|
||||
var reason string
|
||||
compareWith := CompareWithLatest
|
||||
refreshType := appv1.RefreshTypeNormal
|
||||
|
|
@ -1413,7 +1460,7 @@ func (ctrl *ApplicationController) needRefreshAppStatus(app *appv1.Application,
|
|||
}
|
||||
} else if !app.Spec.Destination.Equals(app.Status.Sync.ComparedTo.Destination) {
|
||||
reason = "spec.destination differs"
|
||||
} else if requested, level := ctrl.isRefreshRequested(app.Name); requested {
|
||||
} else if requested, level := ctrl.isRefreshRequested(app.QualifiedName()); requested {
|
||||
compareWith = level
|
||||
reason = "controller refresh requested"
|
||||
}
|
||||
|
|
@ -1460,7 +1507,7 @@ func (ctrl *ApplicationController) refreshAppConditions(app *appv1.Application)
|
|||
|
||||
// normalizeApplication normalizes an application.spec and additionally persists updates if it changed
|
||||
func (ctrl *ApplicationController) normalizeApplication(orig, app *appv1.Application) {
|
||||
logCtx := log.WithFields(log.Fields{"application": app.Name})
|
||||
logCtx := log.WithFields(log.Fields{"application": app.QualifiedName()})
|
||||
app.Spec = *argo.NormalizeApplicationSpec(&app.Spec)
|
||||
patch, modified, err := diff.CreateTwoWayMergePatch(orig, app, appv1.Application{})
|
||||
if err != nil {
|
||||
|
|
@ -1478,7 +1525,7 @@ func (ctrl *ApplicationController) normalizeApplication(orig, app *appv1.Applica
|
|||
|
||||
// persistAppStatus persists updates to application status. If no changes were made, it is a no-op
|
||||
func (ctrl *ApplicationController) persistAppStatus(orig *appv1.Application, newStatus *appv1.ApplicationStatus) {
|
||||
logCtx := log.WithFields(log.Fields{"application": orig.Name})
|
||||
logCtx := log.WithFields(log.Fields{"application": orig.QualifiedName()})
|
||||
if orig.Status.Sync.Status != newStatus.Sync.Status {
|
||||
message := fmt.Sprintf("Updated sync status: %s -> %s", orig.Status.Sync.Status, newStatus.Sync.Status)
|
||||
ctrl.auditLogger.LogAppEvent(orig, argo.EventInfo{Reason: argo.EventReasonResourceUpdated, Type: v1.EventTypeNormal}, message)
|
||||
|
|
@ -1521,7 +1568,7 @@ func (ctrl *ApplicationController) autoSync(app *appv1.Application, syncStatus *
|
|||
if app.Spec.SyncPolicy == nil || app.Spec.SyncPolicy.Automated == nil {
|
||||
return nil
|
||||
}
|
||||
logCtx := log.WithFields(log.Fields{"application": app.Name})
|
||||
logCtx := log.WithFields(log.Fields{"application": app.QualifiedName()})
|
||||
if app.Operation != nil {
|
||||
logCtx.Infof("Skipping auto-sync: another operation is in progress")
|
||||
return nil
|
||||
|
|
@ -1592,7 +1639,7 @@ func (ctrl *ApplicationController) autoSync(app *appv1.Application, syncStatus *
|
|||
}
|
||||
} else {
|
||||
logCtx.Infof("Skipping auto-sync: already attempted sync to %s with timeout %v (retrying in %v)", desiredCommitSHA, ctrl.selfHealTimeout, retryAfter)
|
||||
ctrl.requestAppRefresh(app.Name, CompareWithLatest.Pointer(), &retryAfter)
|
||||
ctrl.requestAppRefresh(app.QualifiedName(), CompareWithLatest.Pointer(), &retryAfter)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -1669,10 +1716,22 @@ func (ctrl *ApplicationController) canProcessApp(obj interface{}) bool {
|
|||
return ctrl.clusterFilter(cluster)
|
||||
}
|
||||
|
||||
// Only process given app if it exists in a watched namespace, or in the
|
||||
// control plane's namespace.
|
||||
if app.Namespace != ctrl.namespace && !glob.MatchStringInList(ctrl.applicationNamespaces, app.Namespace, false) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (ctrl *ApplicationController) newApplicationInformerAndLister() (cache.SharedIndexInformer, applisters.ApplicationLister) {
|
||||
watchNamespace := ctrl.namespace
|
||||
// If we have at least one additional namespace configured, we need to
|
||||
// watch on them all.
|
||||
if len(ctrl.applicationNamespaces) > 0 {
|
||||
watchNamespace = ""
|
||||
}
|
||||
refreshTimeout := ctrl.statusRefreshTimeout
|
||||
if ctrl.statusHardRefreshTimeout.Seconds() != 0 && (ctrl.statusHardRefreshTimeout < ctrl.statusRefreshTimeout) {
|
||||
refreshTimeout = ctrl.statusHardRefreshTimeout
|
||||
|
|
@ -1680,10 +1739,23 @@ func (ctrl *ApplicationController) newApplicationInformerAndLister() (cache.Shar
|
|||
informer := cache.NewSharedIndexInformer(
|
||||
&cache.ListWatch{
|
||||
ListFunc: func(options metav1.ListOptions) (apiruntime.Object, error) {
|
||||
return ctrl.applicationClientset.ArgoprojV1alpha1().Applications(ctrl.namespace).List(context.TODO(), options)
|
||||
// We are only interested in apps that exist in namespaces the
|
||||
// user wants to be enabled.
|
||||
appList, err := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(watchNamespace).List(context.TODO(), options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
newItems := []appv1.Application{}
|
||||
for _, app := range appList.Items {
|
||||
if ctrl.namespace == app.Namespace || glob.MatchStringInList(ctrl.applicationNamespaces, app.Namespace, false) {
|
||||
newItems = append(newItems, app)
|
||||
}
|
||||
}
|
||||
appList.Items = newItems
|
||||
return appList, nil
|
||||
},
|
||||
WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
|
||||
return ctrl.applicationClientset.ArgoprojV1alpha1().Applications(ctrl.namespace).Watch(context.TODO(), options)
|
||||
return ctrl.applicationClientset.ArgoprojV1alpha1().Applications(watchNamespace).Watch(context.TODO(), options)
|
||||
},
|
||||
},
|
||||
&appv1.Application{},
|
||||
|
|
@ -1701,6 +1773,12 @@ func (ctrl *ApplicationController) newApplicationInformerAndLister() (cache.Shar
|
|||
if err := argo.ValidateDestination(context.Background(), &app.Spec.Destination, ctrl.db); err != nil {
|
||||
ctrl.setAppCondition(app, appv1.ApplicationCondition{Type: appv1.ApplicationConditionInvalidSpecError, Message: err.Error()})
|
||||
}
|
||||
|
||||
// If the application is not allowed to use the project,
|
||||
// log an error.
|
||||
if _, err := ctrl.getAppProj(app); err != nil {
|
||||
ctrl.setAppCondition(app, appv1.ApplicationCondition{Type: appv1.ApplicationConditionUnknownError, Message: err.Error()})
|
||||
}
|
||||
}
|
||||
|
||||
return cache.MetaNamespaceIndexFunc(obj)
|
||||
|
|
@ -1748,10 +1826,10 @@ func (ctrl *ApplicationController) newApplicationInformerAndLister() (cache.Shar
|
|||
oldApp, oldOK := old.(*appv1.Application)
|
||||
newApp, newOK := new.(*appv1.Application)
|
||||
if oldOK && newOK && automatedSyncEnabled(oldApp, newApp) {
|
||||
log.WithField("application", newApp.Name).Info("Enabled automated sync")
|
||||
log.WithField("application", newApp.QualifiedName()).Info("Enabled automated sync")
|
||||
compareWith = CompareWithLatest.Pointer()
|
||||
}
|
||||
ctrl.requestAppRefresh(newApp.Name, compareWith, nil)
|
||||
ctrl.requestAppRefresh(newApp.QualifiedName(), compareWith, nil)
|
||||
ctrl.appOperationQueue.Add(key)
|
||||
},
|
||||
DeleteFunc: func(obj interface{}) {
|
||||
|
|
@ -1771,7 +1849,7 @@ func (ctrl *ApplicationController) newApplicationInformerAndLister() (cache.Shar
|
|||
}
|
||||
|
||||
func (ctrl *ApplicationController) RegisterClusterSecretUpdater(ctx context.Context) {
|
||||
updater := NewClusterInfoUpdater(ctrl.stateCache, ctrl.db, ctrl.appLister.Applications(ctrl.namespace), ctrl.cache, ctrl.clusterFilter)
|
||||
updater := NewClusterInfoUpdater(ctrl.stateCache, ctrl.db, ctrl.appLister.Applications(""), ctrl.cache, ctrl.clusterFilter, ctrl.getAppProj, ctrl.namespace)
|
||||
go updater.Run(ctx)
|
||||
}
|
||||
|
||||
|
|
@ -1804,3 +1882,21 @@ func automatedSyncEnabled(oldApp *appv1.Application, newApp *appv1.Application)
|
|||
// nothing changed
|
||||
return false
|
||||
}
|
||||
|
||||
// toAppKey returns the application key from a given appName, that is, it will
|
||||
// replace underscores with forward-slashes to become a <namespace>/<name>
|
||||
// format. If the appName is an unqualified name (such as, "app"), it will use
|
||||
// the controller's namespace in the key.
|
||||
func (ctrl *ApplicationController) toAppKey(appName string) string {
|
||||
if !strings.Contains(appName, "_") && !strings.Contains(appName, "/") {
|
||||
return ctrl.namespace + "/" + appName
|
||||
} else if strings.Contains(appName, "/") {
|
||||
return appName
|
||||
} else {
|
||||
return strings.ReplaceAll(appName, "_", "/")
|
||||
}
|
||||
}
|
||||
|
||||
func (ctrl *ApplicationController) toAppQualifiedName(appName, appNamespace string) string {
|
||||
return fmt.Sprintf("%s/%s", appNamespace, appName)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -110,6 +110,7 @@ func newFakeController(data *fakeData) *ApplicationController {
|
|||
[]string{},
|
||||
0,
|
||||
nil,
|
||||
[]string{},
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
|
@ -754,15 +755,17 @@ func TestHandleAppUpdated(t *testing.T) {
|
|||
app := newFakeApp()
|
||||
app.Spec.Destination.Namespace = test.FakeArgoCDNamespace
|
||||
app.Spec.Destination.Server = argoappv1.KubernetesInternalAPIServerAddr
|
||||
ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}})
|
||||
proj := defaultProj.DeepCopy()
|
||||
proj.Spec.SourceNamespaces = []string{test.FakeArgoCDNamespace}
|
||||
ctrl := newFakeController(&fakeData{apps: []runtime.Object{app, proj}})
|
||||
|
||||
ctrl.handleObjectUpdated(map[string]bool{app.Name: true}, kube.GetObjectRef(kube.MustToUnstructured(app)))
|
||||
isRequested, level := ctrl.isRefreshRequested(app.Name)
|
||||
ctrl.handleObjectUpdated(map[string]bool{app.InstanceName(ctrl.namespace): true}, kube.GetObjectRef(kube.MustToUnstructured(app)))
|
||||
isRequested, level := ctrl.isRefreshRequested(app.QualifiedName())
|
||||
assert.False(t, isRequested)
|
||||
assert.Equal(t, ComparisonWithNothing, level)
|
||||
|
||||
ctrl.handleObjectUpdated(map[string]bool{app.Name: true}, corev1.ObjectReference{UID: "test", Kind: kube.DeploymentKind, Name: "test", Namespace: "default"})
|
||||
isRequested, level = ctrl.isRefreshRequested(app.Name)
|
||||
ctrl.handleObjectUpdated(map[string]bool{app.InstanceName(ctrl.namespace): true}, corev1.ObjectReference{UID: "test", Kind: kube.DeploymentKind, Name: "test", Namespace: "default"})
|
||||
isRequested, level = ctrl.isRefreshRequested(app.QualifiedName())
|
||||
assert.True(t, isRequested)
|
||||
assert.Equal(t, CompareWithRecent, level)
|
||||
}
|
||||
|
|
@ -785,11 +788,11 @@ func TestHandleOrphanedResourceUpdated(t *testing.T) {
|
|||
|
||||
ctrl.handleObjectUpdated(map[string]bool{}, corev1.ObjectReference{UID: "test", Kind: kube.DeploymentKind, Name: "test", Namespace: test.FakeArgoCDNamespace})
|
||||
|
||||
isRequested, level := ctrl.isRefreshRequested(app1.Name)
|
||||
isRequested, level := ctrl.isRefreshRequested(app1.QualifiedName())
|
||||
assert.True(t, isRequested)
|
||||
assert.Equal(t, CompareWithRecent, level)
|
||||
|
||||
isRequested, level = ctrl.isRefreshRequested(app2.Name)
|
||||
isRequested, level = ctrl.isRefreshRequested(app2.QualifiedName())
|
||||
assert.True(t, isRequested)
|
||||
assert.Equal(t, CompareWithRecent, level)
|
||||
}
|
||||
|
|
@ -1097,7 +1100,7 @@ func TestFinalizeProjectDeletion_DoesNotHaveApplications(t *testing.T) {
|
|||
|
||||
func TestProcessRequestedAppOperation_FailedNoRetries(t *testing.T) {
|
||||
app := newFakeApp()
|
||||
app.Spec.Project = "invalid-project"
|
||||
app.Spec.Project = "default"
|
||||
app.Operation = &argoappv1.Operation{
|
||||
Sync: &argoappv1.SyncOperation{},
|
||||
}
|
||||
|
|
@ -1123,7 +1126,10 @@ func TestProcessRequestedAppOperation_InvalidDestination(t *testing.T) {
|
|||
app.Operation = &argoappv1.Operation{
|
||||
Sync: &argoappv1.SyncOperation{},
|
||||
}
|
||||
ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}})
|
||||
proj := defaultProj
|
||||
proj.Name = "test-project"
|
||||
proj.Spec.SourceNamespaces = []string{test.FakeArgoCDNamespace}
|
||||
ctrl := newFakeController(&fakeData{apps: []runtime.Object{app, &proj}})
|
||||
fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset)
|
||||
receivedPatch := map[string]interface{}{}
|
||||
func() {
|
||||
|
|
@ -1311,3 +1317,22 @@ func TestMetricsExpiration(t *testing.T) {
|
|||
ctrl = newFakeController(&fakeData{apps: []runtime.Object{app}, metricsCacheExpiration: 10 * time.Second})
|
||||
assert.True(t, ctrl.metricsServer.HasExpiration())
|
||||
}
|
||||
|
||||
func TestToAppKey(t *testing.T) {
|
||||
ctrl := newFakeController(&fakeData{})
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
expected string
|
||||
}{
|
||||
{"From instance name", "foo_bar", "foo/bar"},
|
||||
{"From qualified name", "foo/bar", "foo/bar"},
|
||||
{"From unqualified name", "bar", ctrl.namespace + "/bar"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assert.Equal(t, tt.expected, ctrl.toAppKey(tt.input))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
2
controller/cache/cache.go
vendored
2
controller/cache/cache.go
vendored
|
|
@ -529,7 +529,7 @@ func (c *liveStateCache) GetManagedLiveObjs(a *appv1.Application, targetObjs []*
|
|||
return nil, err
|
||||
}
|
||||
return clusterInfo.GetManagedLiveObjs(targetObjs, func(r *clustercache.Resource) bool {
|
||||
return resInfo(r).AppName == a.Name
|
||||
return resInfo(r).AppName == a.InstanceName(c.settingsMgr.GetNamespace())
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,8 @@ type clusterInfoUpdater struct {
|
|||
appLister v1alpha1.ApplicationNamespaceLister
|
||||
cache *appstatecache.Cache
|
||||
clusterFilter func(cluster *appv1.Cluster) bool
|
||||
projGetter func(app *appv1.Application) (*appv1.AppProject, error)
|
||||
namespace string
|
||||
}
|
||||
|
||||
func NewClusterInfoUpdater(
|
||||
|
|
@ -35,9 +37,11 @@ func NewClusterInfoUpdater(
|
|||
db db.ArgoDB,
|
||||
appLister v1alpha1.ApplicationNamespaceLister,
|
||||
cache *appstatecache.Cache,
|
||||
clusterFilter func(cluster *appv1.Cluster) bool) *clusterInfoUpdater {
|
||||
clusterFilter func(cluster *appv1.Cluster) bool,
|
||||
projGetter func(app *appv1.Application) (*appv1.AppProject, error),
|
||||
namespace string) *clusterInfoUpdater {
|
||||
|
||||
return &clusterInfoUpdater{infoSource, db, appLister, cache, clusterFilter}
|
||||
return &clusterInfoUpdater{infoSource, db, appLister, cache, clusterFilter, projGetter, namespace}
|
||||
}
|
||||
|
||||
func (c *clusterInfoUpdater) Run(ctx context.Context) {
|
||||
|
|
@ -93,6 +97,12 @@ func (c *clusterInfoUpdater) updateClusterInfo(cluster appv1.Cluster, info *cach
|
|||
}
|
||||
var appCount int64
|
||||
for _, a := range apps {
|
||||
if c.projGetter != nil {
|
||||
proj, err := c.projGetter(a)
|
||||
if err != nil || !proj.IsAppNamespacePermitted(a, c.namespace) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if err := argo.ValidateDestination(context.Background(), &a.Spec.Destination, c.db); err != nil {
|
||||
continue
|
||||
}
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ func TestClusterSecretUpdater(t *testing.T) {
|
|||
}
|
||||
|
||||
lister := applisters.NewApplicationLister(appInformer.GetIndexer()).Applications(fakeNamespace)
|
||||
updater := NewClusterInfoUpdater(nil, argoDB, lister, appCache, nil)
|
||||
updater := NewClusterInfoUpdater(nil, argoDB, lister, appCache, nil, nil, fakeNamespace)
|
||||
|
||||
err = updater.updateClusterInfo(*cluster, info)
|
||||
assert.NoError(t, err, "Invoking updateClusterInfo failed.")
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/argoproj/gitops-engine/pkg/diff"
|
||||
|
|
@ -177,7 +178,7 @@ func (m *appStateManager) getRepoObjs(app *v1alpha1.Application, source v1alpha1
|
|||
NoCache: noCache,
|
||||
NoRevisionCache: noRevisionCache,
|
||||
AppLabelKey: appLabelKey,
|
||||
AppName: app.Name,
|
||||
AppName: app.InstanceName(m.namespace),
|
||||
Namespace: app.Spec.Destination.Namespace,
|
||||
ApplicationSource: &source,
|
||||
Plugins: tools,
|
||||
|
|
@ -200,7 +201,7 @@ func (m *appStateManager) getRepoObjs(app *v1alpha1.Application, source v1alpha1
|
|||
}
|
||||
|
||||
ts.AddCheckpoint("unmarshal_ms")
|
||||
logCtx := log.WithField("application", app.Name)
|
||||
logCtx := log.WithField("application", app.QualifiedName())
|
||||
for k, v := range ts.Timings() {
|
||||
logCtx = logCtx.WithField(k, v.Milliseconds())
|
||||
}
|
||||
|
|
@ -349,7 +350,7 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap
|
|||
failedToLoadObjs := false
|
||||
conditions := make([]v1alpha1.ApplicationCondition, 0)
|
||||
|
||||
logCtx := log.WithField("application", app.Name)
|
||||
logCtx := log.WithField("application", app.QualifiedName())
|
||||
logCtx.Infof("Comparing app state (cluster: %s, namespace: %s)", app.Spec.Destination.Server, app.Spec.Destination.Namespace)
|
||||
|
||||
var targetObjs []*unstructured.Unstructured
|
||||
|
|
@ -427,10 +428,11 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap
|
|||
for _, liveObj := range liveObjByKey {
|
||||
if liveObj != nil {
|
||||
appInstanceName := m.resourceTracking.GetAppName(liveObj, appLabelKey, trackingMethod)
|
||||
if appInstanceName != "" && appInstanceName != app.Name {
|
||||
if appInstanceName != "" && appInstanceName != app.InstanceName(m.namespace) {
|
||||
fqInstanceName := strings.ReplaceAll(appInstanceName, "_", "/")
|
||||
conditions = append(conditions, v1alpha1.ApplicationCondition{
|
||||
Type: v1alpha1.ApplicationConditionSharedResourceWarning,
|
||||
Message: fmt.Sprintf("%s/%s is part of applications %s and %s", liveObj.GetKind(), liveObj.GetName(), app.Name, appInstanceName),
|
||||
Message: fmt.Sprintf("%s/%s is part of applications %s and %s", liveObj.GetKind(), liveObj.GetName(), app.QualifiedName(), fqInstanceName),
|
||||
LastTransitionTime: &now,
|
||||
})
|
||||
}
|
||||
|
|
@ -644,7 +646,7 @@ func (m *appStateManager) persistRevisionHistory(app *v1alpha1.Application, revi
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = m.appclientset.ArgoprojV1alpha1().Applications(m.namespace).Patch(context.Background(), app.Name, types.MergePatchType, patch, metav1.PatchOptions{})
|
||||
_, err = m.appclientset.ArgoprojV1alpha1().Applications(app.Namespace).Patch(context.Background(), app.Name, types.MergePatchType, patch, metav1.PatchOptions{})
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -374,7 +374,7 @@ func TestSetManagedResourcesWithResourcesOfAnotherApp(t *testing.T) {
|
|||
tree, err := ctrl.setAppManagedResources(app1, &comparisonResult{managedResources: make([]managedResource, 0)})
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, len(tree.OrphanedNodes), 0)
|
||||
assert.Equal(t, 0, len(tree.OrphanedNodes))
|
||||
}
|
||||
|
||||
func TestReturnUnknownComparisonStateOnSettingLoadError(t *testing.T) {
|
||||
|
|
@ -399,6 +399,7 @@ func TestReturnUnknownComparisonStateOnSettingLoadError(t *testing.T) {
|
|||
func TestSetManagedResourcesKnownOrphanedResourceExceptions(t *testing.T) {
|
||||
proj := defaultProj.DeepCopy()
|
||||
proj.Spec.OrphanedResources = &argoappv1.OrphanedResourcesMonitorSettings{}
|
||||
proj.Spec.SourceNamespaces = []string{"default"}
|
||||
|
||||
app := newFakeApp()
|
||||
app.Namespace = "default"
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ func (m *appStateManager) SyncAppState(app *v1alpha1.Application, state *v1alpha
|
|||
revision = syncOp.Revision
|
||||
}
|
||||
|
||||
proj, err := argo.GetAppProject(&app.Spec, listersv1alpha1.NewAppProjectLister(m.projInformer.GetIndexer()), m.namespace, m.settingsMgr, m.db, context.TODO())
|
||||
proj, err := argo.GetAppProject(app, listersv1alpha1.NewAppProjectLister(m.projInformer.GetIndexer()), m.namespace, m.settingsMgr, m.db, context.TODO())
|
||||
if err != nil {
|
||||
state.Phase = common.OperationError
|
||||
state.Message = fmt.Sprintf("Failed to load application project: %v", err)
|
||||
|
|
@ -157,7 +157,7 @@ func (m *appStateManager) SyncAppState(app *v1alpha1.Application, state *v1alpha
|
|||
}
|
||||
syncId := fmt.Sprintf("%05d-%s", syncIdPrefix, randSuffix)
|
||||
|
||||
logEntry := log.WithFields(log.Fields{"application": app.Name, "syncId": syncId})
|
||||
logEntry := log.WithFields(log.Fields{"application": app.QualifiedName(), "syncId": syncId})
|
||||
initialResourcesRes := make([]common.ResourceSyncResult, 0)
|
||||
for i, res := range syncRes.Resources {
|
||||
key := kube.ResourceKey{Group: res.Group, Kind: res.Kind, Namespace: res.Namespace, Name: res.Name}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ argocd-application-controller [flags]
|
|||
--app-hard-resync int Time period in seconds for application hard resync.
|
||||
--app-resync int Time period in seconds for application resync. (default 180)
|
||||
--app-state-cache-expiration duration Cache expiration for app state (default 1h0m0s)
|
||||
--application-namespaces strings List of additional namespaces that applications are allowed to be created in
|
||||
--as string Username to impersonate for the operation
|
||||
--as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups.
|
||||
--as-uid string UID to impersonate for the operation
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ argocd-server [flags]
|
|||
|
||||
```
|
||||
--app-state-cache-expiration duration Cache expiration for app state (default 1h0m0s)
|
||||
--application-namespaces strings List of namespaces where application resources can exist
|
||||
--as string Username to impersonate for the operation
|
||||
--as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups.
|
||||
--as-uid string UID to impersonate for the operation
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ argocd admin proj generate-spec PROJECT [flags]
|
|||
--orphaned-resources-warn Specifies if applications should have a warning condition when orphaned resources detected
|
||||
-o, --output string Output format. One of: json|yaml (default "yaml")
|
||||
--signature-keys strings GnuPG public key IDs for commit signature verification
|
||||
--source-namespaces strings List of source namespaces for applications
|
||||
-s, --src stringArray Permitted source repository URL
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ argocd app create APPNAME [flags]
|
|||
```
|
||||
--allow-empty Set allow zero live resources when sync is automated
|
||||
--annotations stringArray Set metadata annotations (e.g. example=value)
|
||||
-N, --app-namespace string Namespace where the application will be created in
|
||||
--auto-prune Set automatic pruning when sync is automated
|
||||
--config-management-plugin string Config management plugin name
|
||||
--dest-name string K8s cluster Name (e.g. minikube)
|
||||
|
|
|
|||
|
|
@ -19,11 +19,12 @@ argocd app list [flags]
|
|||
### Options
|
||||
|
||||
```
|
||||
-h, --help help for list
|
||||
-o, --output string Output format. One of: wide|name|json|yaml (default "wide")
|
||||
-p, --project stringArray Filter by project name
|
||||
-r, --repo string List apps by source repo URL
|
||||
-l, --selector string List apps by label
|
||||
-N, --app-namespace string Only list applications in namespace
|
||||
-h, --help help for list
|
||||
-o, --output string Output format. One of: wide|name|json|yaml (default "wide")
|
||||
-p, --project stringArray Filter by project name
|
||||
-r, --repo string List apps by source repo URL
|
||||
-l, --selector string List apps by label
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ argocd proj create PROJECT [flags]
|
|||
--orphaned-resources Enables orphaned resources monitoring
|
||||
--orphaned-resources-warn Specifies if applications should have a warning condition when orphaned resources detected
|
||||
--signature-keys strings GnuPG public key IDs for commit signature verification
|
||||
--source-namespaces strings List of source namespaces for applications
|
||||
-s, --src stringArray Permitted source repository URL
|
||||
--upsert Allows to override a project with the same name even if supplied project spec is different from existing spec
|
||||
```
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ argocd proj set PROJECT [flags]
|
|||
--orphaned-resources Enables orphaned resources monitoring
|
||||
--orphaned-resources-warn Specifies if applications should have a warning condition when orphaned resources detected
|
||||
--signature-keys strings GnuPG public key IDs for commit signature verification
|
||||
--source-namespaces strings List of source namespaces for applications
|
||||
-s, --src stringArray Permitted source repository URL
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -28,3 +28,11 @@ rules:
|
|||
- pods/log
|
||||
verbs:
|
||||
- get # supports viewing pod logs from UI
|
||||
- apiGroups:
|
||||
- "argoproj.io"
|
||||
resources:
|
||||
- "applications"
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
|
|
|
|||
|
|
@ -9121,6 +9121,12 @@ spec:
|
|||
- keyID
|
||||
type: object
|
||||
type: array
|
||||
sourceNamespaces:
|
||||
description: SourceNamespaces defines the namespaces application resources
|
||||
are allowed to be created in
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
sourceRepos:
|
||||
description: SourceRepos contains list of repository URLs which can
|
||||
be used for deployment
|
||||
|
|
|
|||
|
|
@ -221,6 +221,12 @@ spec:
|
|||
- keyID
|
||||
type: object
|
||||
type: array
|
||||
sourceNamespaces:
|
||||
description: SourceNamespaces defines the namespaces application resources
|
||||
are allowed to be created in
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
sourceRepos:
|
||||
description: SourceRepos contains list of repository URLs which can
|
||||
be used for deployment
|
||||
|
|
|
|||
|
|
@ -9121,6 +9121,12 @@ spec:
|
|||
- keyID
|
||||
type: object
|
||||
type: array
|
||||
sourceNamespaces:
|
||||
description: SourceNamespaces defines the namespaces application resources
|
||||
are allowed to be created in
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
sourceRepos:
|
||||
description: SourceRepos contains list of repository URLs which can
|
||||
be used for deployment
|
||||
|
|
@ -9573,6 +9579,14 @@ rules:
|
|||
- pods/log
|
||||
verbs:
|
||||
- get
|
||||
- apiGroups:
|
||||
- argoproj.io
|
||||
resources:
|
||||
- applications
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
|
|
|
|||
|
|
@ -9121,6 +9121,12 @@ spec:
|
|||
- keyID
|
||||
type: object
|
||||
type: array
|
||||
sourceNamespaces:
|
||||
description: SourceNamespaces defines the namespaces application resources
|
||||
are allowed to be created in
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
sourceRepos:
|
||||
description: SourceRepos contains list of repository URLs which can
|
||||
be used for deployment
|
||||
|
|
@ -9532,6 +9538,14 @@ rules:
|
|||
- pods/log
|
||||
verbs:
|
||||
- get
|
||||
- apiGroups:
|
||||
- argoproj.io
|
||||
resources:
|
||||
- applications
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ import (
|
|||
versionpkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/version"
|
||||
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
argoappv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/v2/util/argo"
|
||||
"github.com/argoproj/argo-cd/v2/util/env"
|
||||
grpc_util "github.com/argoproj/argo-cd/v2/util/grpc"
|
||||
http_util "github.com/argoproj/argo-cd/v2/util/http"
|
||||
|
|
@ -765,13 +766,18 @@ func (c *client) NewAccountClientOrDie() (io.Closer, accountpkg.AccountServiceCl
|
|||
func (c *client) WatchApplicationWithRetry(ctx context.Context, appName string, revision string) chan *argoappv1.ApplicationWatchEvent {
|
||||
appEventsCh := make(chan *argoappv1.ApplicationWatchEvent)
|
||||
cancelled := false
|
||||
appName, appNs := argo.ParseAppQualifiedName(appName, "")
|
||||
go func() {
|
||||
defer close(appEventsCh)
|
||||
for !cancelled {
|
||||
conn, appIf, err := c.NewApplicationClient()
|
||||
if err == nil {
|
||||
var wc applicationpkg.ApplicationService_WatchClient
|
||||
wc, err = appIf.Watch(ctx, &applicationpkg.ApplicationQuery{Name: &appName, ResourceVersion: &revision})
|
||||
wc, err = appIf.Watch(ctx, &applicationpkg.ApplicationQuery{
|
||||
Name: &appName,
|
||||
AppNamespace: &appNs,
|
||||
ResourceVersion: &revision,
|
||||
})
|
||||
if err == nil {
|
||||
for {
|
||||
var appEvent *v1alpha1.ApplicationWatchEvent
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -293,6 +293,10 @@ func local_request_ApplicationService_Get_0(ctx context.Context, marshaler runti
|
|||
|
||||
}
|
||||
|
||||
var (
|
||||
filter_ApplicationService_GetApplicationSyncWindows_0 = &utilities.DoubleArray{Encoding: map[string]int{"name": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}}
|
||||
)
|
||||
|
||||
func request_ApplicationService_GetApplicationSyncWindows_0(ctx context.Context, marshaler runtime.Marshaler, client ApplicationServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq ApplicationSyncWindowsQuery
|
||||
var metadata runtime.ServerMetadata
|
||||
|
|
@ -315,6 +319,13 @@ func request_ApplicationService_GetApplicationSyncWindows_0(ctx context.Context,
|
|||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err)
|
||||
}
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ApplicationService_GetApplicationSyncWindows_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := client.GetApplicationSyncWindows(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
|
|
@ -342,11 +353,22 @@ func local_request_ApplicationService_GetApplicationSyncWindows_0(ctx context.Co
|
|||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err)
|
||||
}
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ApplicationService_GetApplicationSyncWindows_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := server.GetApplicationSyncWindows(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
var (
|
||||
filter_ApplicationService_RevisionMetadata_0 = &utilities.DoubleArray{Encoding: map[string]int{"name": 0, "revision": 1}, Base: []int{1, 1, 2, 0, 0}, Check: []int{0, 1, 1, 2, 3}}
|
||||
)
|
||||
|
||||
func request_ApplicationService_RevisionMetadata_0(ctx context.Context, marshaler runtime.Marshaler, client ApplicationServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq RevisionMetadataQuery
|
||||
var metadata runtime.ServerMetadata
|
||||
|
|
@ -380,6 +402,13 @@ func request_ApplicationService_RevisionMetadata_0(ctx context.Context, marshale
|
|||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "revision", err)
|
||||
}
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ApplicationService_RevisionMetadata_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := client.RevisionMetadata(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
|
|
@ -418,6 +447,13 @@ func local_request_ApplicationService_RevisionMetadata_0(ctx context.Context, ma
|
|||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "revision", err)
|
||||
}
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ApplicationService_RevisionMetadata_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := server.RevisionMetadata(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
|
|
@ -1143,6 +1179,10 @@ func local_request_ApplicationService_Rollback_0(ctx context.Context, marshaler
|
|||
|
||||
}
|
||||
|
||||
var (
|
||||
filter_ApplicationService_TerminateOperation_0 = &utilities.DoubleArray{Encoding: map[string]int{"name": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}}
|
||||
)
|
||||
|
||||
func request_ApplicationService_TerminateOperation_0(ctx context.Context, marshaler runtime.Marshaler, client ApplicationServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq OperationTerminateRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
|
@ -1165,6 +1205,13 @@ func request_ApplicationService_TerminateOperation_0(ctx context.Context, marsha
|
|||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err)
|
||||
}
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ApplicationService_TerminateOperation_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := client.TerminateOperation(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
|
|
@ -1192,6 +1239,13 @@ func local_request_ApplicationService_TerminateOperation_0(ctx context.Context,
|
|||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err)
|
||||
}
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ApplicationService_TerminateOperation_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := server.TerminateOperation(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
|
|
|
|||
|
|
@ -98,6 +98,7 @@ type Settings struct {
|
|||
UiBannerPosition string `protobuf:"bytes,20,opt,name=uiBannerPosition,proto3" json:"uiBannerPosition,omitempty"`
|
||||
StatusBadgeRootUrl string `protobuf:"bytes,21,opt,name=statusBadgeRootUrl,proto3" json:"statusBadgeRootUrl,omitempty"`
|
||||
ExecEnabled bool `protobuf:"varint,22,opt,name=execEnabled,proto3" json:"execEnabled,omitempty"`
|
||||
ControllerNamespace string `protobuf:"bytes,23,opt,name=controllerNamespace,proto3" json:"controllerNamespace,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
|
|
@ -290,6 +291,13 @@ func (m *Settings) GetExecEnabled() bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (m *Settings) GetControllerNamespace() string {
|
||||
if m != nil {
|
||||
return m.ControllerNamespace
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type GoogleAnalyticsConfig struct {
|
||||
TrackingID string `protobuf:"bytes,1,opt,name=trackingID,proto3" json:"trackingID,omitempty"`
|
||||
AnonymizeUsers bool `protobuf:"varint,2,opt,name=anonymizeUsers,proto3" json:"anonymizeUsers,omitempty"`
|
||||
|
|
@ -667,77 +675,78 @@ func init() {
|
|||
func init() { proto.RegisterFile("server/settings/settings.proto", fileDescriptor_a480d494da040caa) }
|
||||
|
||||
var fileDescriptor_a480d494da040caa = []byte{
|
||||
// 1106 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x56, 0x5d, 0x6f, 0x23, 0x35,
|
||||
0x17, 0xd6, 0x34, 0xdd, 0x36, 0x39, 0xd9, 0x36, 0xad, 0xb7, 0xdb, 0x77, 0xde, 0x68, 0x49, 0x43,
|
||||
0x2e, 0x56, 0x01, 0xc1, 0x84, 0x66, 0x85, 0x40, 0x48, 0x2b, 0x20, 0xc9, 0x6a, 0x37, 0x6c, 0x4a,
|
||||
0xcb, 0x6c, 0xbb, 0x17, 0x48, 0xa8, 0x72, 0x67, 0xcc, 0xd4, 0x64, 0x62, 0x8f, 0x6c, 0x4f, 0x68,
|
||||
0xf6, 0x92, 0x3b, 0x6e, 0xb8, 0x81, 0x5f, 0xc3, 0x0f, 0x40, 0x5c, 0x22, 0x71, 0x5f, 0xa1, 0x88,
|
||||
0x1f, 0x82, 0xec, 0xf9, 0xe8, 0x34, 0x09, 0x1f, 0xd2, 0xde, 0xd9, 0xcf, 0x73, 0xbe, 0x7c, 0x7c,
|
||||
0x8e, 0x8f, 0xa1, 0x21, 0x89, 0x98, 0x12, 0xd1, 0x91, 0x44, 0x29, 0xca, 0x02, 0x99, 0x2f, 0x9c,
|
||||
0x48, 0x70, 0xc5, 0xd1, 0xa6, 0x17, 0xc6, 0x52, 0x11, 0x51, 0xdf, 0x0b, 0x78, 0xc0, 0x0d, 0xd6,
|
||||
0xd1, 0xab, 0x84, 0xae, 0x3f, 0x08, 0x38, 0x0f, 0x42, 0xd2, 0xc1, 0x11, 0xed, 0x60, 0xc6, 0xb8,
|
||||
0xc2, 0x8a, 0x72, 0x96, 0x2a, 0xd7, 0x47, 0x01, 0x55, 0x97, 0xf1, 0x85, 0xe3, 0xf1, 0x49, 0x07,
|
||||
0x0b, 0xa3, 0xfe, 0x8d, 0x59, 0xbc, 0xeb, 0xf9, 0x9d, 0x69, 0xb7, 0x13, 0x8d, 0x03, 0xad, 0x29,
|
||||
0x3b, 0x38, 0x8a, 0x42, 0xea, 0x19, 0xdd, 0xce, 0xf4, 0x10, 0x87, 0xd1, 0x25, 0x3e, 0xec, 0x04,
|
||||
0x84, 0x11, 0x81, 0x15, 0xf1, 0x53, 0x6b, 0x9f, 0xfc, 0x8b, 0xb5, 0xc5, 0x93, 0x70, 0xea, 0x7b,
|
||||
0x1d, 0x2f, 0xc4, 0x74, 0x92, 0xc6, 0xd3, 0xaa, 0xc1, 0xd6, 0x8b, 0x94, 0xfd, 0x22, 0x26, 0x62,
|
||||
0xd6, 0xfa, 0x05, 0xa0, 0x9c, 0x21, 0xe8, 0xff, 0x50, 0x8a, 0x45, 0x68, 0x5b, 0x4d, 0xab, 0x5d,
|
||||
0xe9, 0x6d, 0xce, 0xaf, 0x0f, 0x4a, 0x67, 0xee, 0xc8, 0xd5, 0x18, 0x7a, 0x0f, 0x2a, 0x3e, 0xb9,
|
||||
0xea, 0x73, 0xf6, 0x35, 0x0d, 0xec, 0xb5, 0xa6, 0xd5, 0xae, 0x76, 0x91, 0x93, 0x66, 0xc6, 0x19,
|
||||
0x64, 0x8c, 0x7b, 0x23, 0x84, 0xfa, 0x00, 0xda, 0x7f, 0xaa, 0x52, 0x32, 0x2a, 0xf7, 0x72, 0x95,
|
||||
0xe3, 0xe1, 0xa0, 0x9f, 0x50, 0xbd, 0xed, 0xf9, 0xf5, 0x01, 0xdc, 0xec, 0xdd, 0x82, 0x1a, 0x6a,
|
||||
0x42, 0x15, 0x47, 0xd1, 0x08, 0x5f, 0x90, 0xf0, 0x39, 0x99, 0xd9, 0xeb, 0x3a, 0x32, 0xb7, 0x08,
|
||||
0xa1, 0x97, 0xb0, 0x2b, 0x88, 0xe4, 0xb1, 0xf0, 0xc8, 0xf1, 0x94, 0x08, 0x41, 0x7d, 0x22, 0xed,
|
||||
0x3b, 0xcd, 0x52, 0xbb, 0xda, 0x6d, 0xe7, 0xde, 0xb2, 0x13, 0x3a, 0xee, 0xa2, 0xe8, 0x13, 0xa6,
|
||||
0xc4, 0xcc, 0x5d, 0x36, 0x81, 0x1c, 0x40, 0x52, 0x61, 0x15, 0xcb, 0x1e, 0xf6, 0x03, 0xf2, 0x84,
|
||||
0xe1, 0x8b, 0x90, 0xf8, 0xf6, 0x46, 0xd3, 0x6a, 0x97, 0xdd, 0x15, 0x0c, 0x7a, 0x06, 0xb5, 0xa4,
|
||||
0x12, 0x3e, 0x65, 0x38, 0x9c, 0x29, 0xea, 0x49, 0x7b, 0xd3, 0x9c, 0xb9, 0x91, 0x47, 0xf1, 0xf4,
|
||||
0x36, 0x9f, 0x1e, 0x77, 0x51, 0x0d, 0xbd, 0x82, 0x9d, 0x71, 0x2c, 0x15, 0x9f, 0xd0, 0x57, 0xe4,
|
||||
0x38, 0x32, 0xd5, 0x64, 0x97, 0x8d, 0xa9, 0xcf, 0x9d, 0x9b, 0x02, 0x70, 0xb2, 0x02, 0x30, 0x8b,
|
||||
0x73, 0xcf, 0x77, 0xa6, 0x5d, 0x27, 0x1a, 0x07, 0x8e, 0x2e, 0x27, 0xa7, 0x50, 0x4e, 0x4e, 0x56,
|
||||
0x4e, 0xce, 0xf3, 0x05, 0xab, 0xee, 0x92, 0x1f, 0xf4, 0x26, 0xac, 0x5f, 0x92, 0x30, 0xb2, 0x2b,
|
||||
0xc6, 0xdf, 0x56, 0x1e, 0xfa, 0x33, 0x12, 0x46, 0xae, 0xa1, 0xd0, 0x5b, 0xb0, 0x19, 0x85, 0x71,
|
||||
0x40, 0x99, 0xb4, 0xc1, 0xa4, 0xb9, 0x96, 0x4b, 0x9d, 0x18, 0xdc, 0xcd, 0x78, 0x9d, 0xc3, 0x58,
|
||||
0x12, 0x31, 0xe2, 0x7a, 0x37, 0xa0, 0x32, 0xc9, 0x61, 0x35, 0xc9, 0xe1, 0x32, 0x83, 0x7e, 0xb0,
|
||||
0xe0, 0x7f, 0x9e, 0xc9, 0xca, 0x11, 0x66, 0x38, 0x20, 0x13, 0xc2, 0xd4, 0x49, 0xea, 0xeb, 0xae,
|
||||
0xf1, 0x75, 0xfa, 0x7a, 0x19, 0xe8, 0xaf, 0x34, 0xee, 0xfe, 0x9d, 0x53, 0xf4, 0x0e, 0xec, 0xe6,
|
||||
0x29, 0x7a, 0x49, 0x84, 0x34, 0x77, 0xb1, 0xd5, 0x2c, 0xb5, 0x2b, 0xee, 0x32, 0x81, 0xea, 0x50,
|
||||
0x8e, 0x69, 0x5f, 0xca, 0x33, 0x77, 0x64, 0x6f, 0x9b, 0x4a, 0xcd, 0xf7, 0xa8, 0x0d, 0xb5, 0x98,
|
||||
0xf6, 0x30, 0x63, 0x44, 0xf4, 0x39, 0x53, 0x84, 0x29, 0xbb, 0x66, 0x44, 0x16, 0x61, 0x5d, 0xf2,
|
||||
0x19, 0xa4, 0x0d, 0xed, 0x24, 0x25, 0x5f, 0x80, 0xb4, 0xad, 0x08, 0x4b, 0xf9, 0x2d, 0x17, 0xfe,
|
||||
0x09, 0x56, 0x8a, 0x08, 0x66, 0xef, 0x26, 0xb6, 0x16, 0x60, 0xf4, 0x10, 0xb6, 0x95, 0xc0, 0xde,
|
||||
0x98, 0xb2, 0xe0, 0x88, 0xa8, 0x4b, 0xee, 0xdb, 0xc8, 0x08, 0x2e, 0xa0, 0xfa, 0x9c, 0x99, 0x83,
|
||||
0x13, 0x22, 0x26, 0x98, 0xe9, 0xf8, 0xee, 0x99, 0x7b, 0x5a, 0x26, 0xd0, 0xdb, 0xb0, 0x93, 0x83,
|
||||
0x5c, 0x52, 0x9d, 0x62, 0x7b, 0xcf, 0xd8, 0x5d, 0xc2, 0x17, 0xda, 0xc8, 0xe5, 0x5c, 0x9d, 0x89,
|
||||
0xd0, 0xbe, 0x6f, 0xa4, 0x57, 0x30, 0xfa, 0xf4, 0xe4, 0x8a, 0x78, 0x59, 0xbf, 0xed, 0x9b, 0x18,
|
||||
0x8a, 0x50, 0xfd, 0x27, 0x0b, 0xf6, 0x57, 0xb7, 0x31, 0xda, 0x81, 0xd2, 0x98, 0xcc, 0x92, 0xf7,
|
||||
0xcb, 0xd5, 0x4b, 0xe4, 0xc3, 0x9d, 0x29, 0x0e, 0x63, 0x92, 0x3e, 0x59, 0xaf, 0xd9, 0x40, 0x8b,
|
||||
0x6e, 0xdd, 0xc4, 0xf8, 0x47, 0x6b, 0x1f, 0x5a, 0xad, 0x73, 0xb8, 0xbf, 0xb2, 0xbf, 0x51, 0x03,
|
||||
0x20, 0xcb, 0xf6, 0x70, 0x90, 0xc6, 0x56, 0x40, 0xf4, 0x1d, 0x61, 0xc6, 0xd9, 0x4c, 0x97, 0xd2,
|
||||
0x99, 0x24, 0x42, 0x9a, 0x58, 0xcb, 0xee, 0x02, 0xda, 0xfa, 0xd9, 0x82, 0x75, 0xdd, 0x86, 0xc8,
|
||||
0x86, 0x4d, 0xef, 0x12, 0x9b, 0x3c, 0x26, 0xd6, 0xb2, 0xad, 0x2e, 0x40, 0xbd, 0x3c, 0x25, 0x57,
|
||||
0xca, 0x18, 0xa9, 0xb8, 0xf9, 0x1e, 0x3d, 0x06, 0xb8, 0xa0, 0x0c, 0x8b, 0xd9, 0x99, 0x08, 0xa5,
|
||||
0x5d, 0x32, 0xdd, 0xf4, 0xc6, 0xad, 0xfe, 0x76, 0x7a, 0x39, 0x9f, 0xbc, 0x8a, 0x05, 0x85, 0xfa,
|
||||
0x63, 0xa8, 0x2d, 0xd0, 0x2b, 0xb2, 0xbd, 0x57, 0xcc, 0x76, 0xa5, 0x98, 0x9d, 0x07, 0xb0, 0x91,
|
||||
0xf4, 0x14, 0x42, 0xb0, 0xce, 0xf0, 0x84, 0xa4, 0x6a, 0x66, 0xdd, 0xfa, 0x18, 0x2a, 0xf9, 0x08,
|
||||
0x41, 0x5d, 0x00, 0x8f, 0x33, 0x46, 0x3c, 0xc5, 0x85, 0xb4, 0x2d, 0x13, 0xe8, 0xcd, 0xa8, 0xe9,
|
||||
0x67, 0x94, 0x5b, 0x90, 0x6a, 0x3d, 0x82, 0x4a, 0x4e, 0xac, 0xf2, 0xa0, 0x31, 0x35, 0x8b, 0xb2,
|
||||
0xc0, 0xcc, 0xba, 0xf5, 0x7d, 0x09, 0x0a, 0x63, 0x67, 0xa5, 0xda, 0x3e, 0x6c, 0x50, 0x29, 0x63,
|
||||
0x22, 0x52, 0xc5, 0x74, 0x87, 0xda, 0x50, 0xf6, 0x42, 0x4a, 0x98, 0x1a, 0x0e, 0xcc, 0x64, 0xab,
|
||||
0xf4, 0xee, 0xce, 0xaf, 0x0f, 0xca, 0xfd, 0x14, 0x73, 0x73, 0x16, 0x1d, 0x42, 0xd5, 0x0b, 0x69,
|
||||
0x46, 0x24, 0x03, 0xac, 0x57, 0x9b, 0x5f, 0x1f, 0x54, 0xfb, 0xa3, 0x61, 0x2e, 0x5f, 0x94, 0xd1,
|
||||
0x4e, 0xa5, 0xc7, 0xa3, 0x74, 0x8c, 0x55, 0xdc, 0x74, 0x87, 0xce, 0x61, 0x8b, 0xfa, 0xa7, 0x7c,
|
||||
0x4c, 0x58, 0xdf, 0x8c, 0x74, 0x7b, 0xc3, 0xe4, 0xe6, 0xe1, 0x8a, 0x99, 0xea, 0x0c, 0x8b, 0x82,
|
||||
0xe6, 0xba, 0x7a, 0xbb, 0xf3, 0xeb, 0x83, 0xad, 0xe1, 0xa0, 0x80, 0xbb, 0xb7, 0xed, 0xd5, 0x67,
|
||||
0x80, 0x96, 0xf5, 0x56, 0x5c, 0xf3, 0xd1, 0xed, 0xa6, 0xfa, 0xe0, 0x1f, 0x9b, 0x2a, 0xf9, 0x93,
|
||||
0x38, 0xf9, 0xa7, 0x4a, 0x0f, 0x77, 0xc7, 0xd8, 0x2f, 0xd4, 0x47, 0xf7, 0x2b, 0xa8, 0x65, 0x33,
|
||||
0xfa, 0x05, 0x11, 0x53, 0xea, 0x11, 0xf4, 0x19, 0x94, 0x9e, 0x12, 0x85, 0xf6, 0x97, 0x86, 0xb8,
|
||||
0xf9, 0xb8, 0xd4, 0x77, 0x97, 0xf0, 0x96, 0xfd, 0xdd, 0xef, 0x7f, 0xfe, 0xb8, 0x86, 0xd0, 0x8e,
|
||||
0xf9, 0x8c, 0x4d, 0x0f, 0xf3, 0x8f, 0x50, 0xaf, 0xff, 0xeb, 0xbc, 0x61, 0xfd, 0x36, 0x6f, 0x58,
|
||||
0x7f, 0xcc, 0x1b, 0xd6, 0x97, 0xef, 0xff, 0xb7, 0x4f, 0x59, 0x72, 0x87, 0xb9, 0x91, 0x8b, 0x0d,
|
||||
0xf3, 0x85, 0x7a, 0xf4, 0x57, 0x00, 0x00, 0x00, 0xff, 0xff, 0xe2, 0xea, 0x37, 0xfe, 0x31, 0x0a,
|
||||
0x00, 0x00,
|
||||
// 1129 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x56, 0x4f, 0x6f, 0x1b, 0x45,
|
||||
0x14, 0xd7, 0xd6, 0x69, 0x62, 0xbf, 0x34, 0x75, 0x32, 0x6d, 0xd3, 0xc5, 0x2a, 0x8e, 0xf1, 0xa1,
|
||||
0x32, 0x08, 0xd6, 0x8d, 0x2b, 0x04, 0x42, 0xaa, 0x00, 0xdb, 0x55, 0x6b, 0xea, 0xb6, 0x61, 0xdb,
|
||||
0xf4, 0x80, 0x84, 0xaa, 0xc9, 0xee, 0x63, 0xb3, 0x78, 0x3d, 0xb3, 0x9a, 0x99, 0x35, 0x75, 0x8f,
|
||||
0xdc, 0xb8, 0x70, 0x81, 0x4f, 0xc3, 0x27, 0xe0, 0x88, 0xc4, 0x3d, 0x42, 0x16, 0x1f, 0x82, 0x23,
|
||||
0x9a, 0xd9, 0x3f, 0xd9, 0xd8, 0xe6, 0x8f, 0xd4, 0xdb, 0xcc, 0xef, 0xf7, 0xfe, 0xcd, 0x9b, 0x37,
|
||||
0xf3, 0x1e, 0x34, 0x25, 0x8a, 0x19, 0x8a, 0xae, 0x44, 0xa5, 0x42, 0x16, 0xc8, 0x62, 0xe1, 0xc4,
|
||||
0x82, 0x2b, 0x4e, 0xb6, 0xbc, 0x28, 0x91, 0x0a, 0x45, 0xe3, 0x7a, 0xc0, 0x03, 0x6e, 0xb0, 0xae,
|
||||
0x5e, 0xa5, 0x74, 0xe3, 0x56, 0xc0, 0x79, 0x10, 0x61, 0x97, 0xc6, 0x61, 0x97, 0x32, 0xc6, 0x15,
|
||||
0x55, 0x21, 0x67, 0x99, 0x72, 0x63, 0x1c, 0x84, 0xea, 0x34, 0x39, 0x71, 0x3c, 0x3e, 0xed, 0x52,
|
||||
0x61, 0xd4, 0xbf, 0x35, 0x8b, 0x0f, 0x3c, 0xbf, 0x3b, 0xeb, 0x75, 0xe3, 0x49, 0xa0, 0x35, 0x65,
|
||||
0x97, 0xc6, 0x71, 0x14, 0x7a, 0x46, 0xb7, 0x3b, 0x3b, 0xa4, 0x51, 0x7c, 0x4a, 0x0f, 0xbb, 0x01,
|
||||
0x32, 0x14, 0x54, 0xa1, 0x9f, 0x59, 0xfb, 0xec, 0x3f, 0xac, 0x2d, 0x9f, 0x84, 0x87, 0xbe, 0xd7,
|
||||
0xf5, 0x22, 0x1a, 0x4e, 0xb3, 0x78, 0xda, 0x75, 0xd8, 0x79, 0x96, 0xb1, 0x5f, 0x26, 0x28, 0xe6,
|
||||
0xed, 0xbf, 0x00, 0xaa, 0x39, 0x42, 0xde, 0x82, 0x4a, 0x22, 0x22, 0xdb, 0x6a, 0x59, 0x9d, 0x5a,
|
||||
0x7f, 0x6b, 0x71, 0x76, 0x50, 0x39, 0x76, 0xc7, 0xae, 0xc6, 0xc8, 0x1d, 0xa8, 0xf9, 0xf8, 0x6a,
|
||||
0xc0, 0xd9, 0x37, 0x61, 0x60, 0x5f, 0x6a, 0x59, 0x9d, 0xed, 0x1e, 0x71, 0xb2, 0xcc, 0x38, 0xc3,
|
||||
0x9c, 0x71, 0xcf, 0x85, 0xc8, 0x00, 0x40, 0xfb, 0xcf, 0x54, 0x2a, 0x46, 0xe5, 0x5a, 0xa1, 0xf2,
|
||||
0x74, 0x34, 0x1c, 0xa4, 0x54, 0xff, 0xea, 0xe2, 0xec, 0x00, 0xce, 0xf7, 0x6e, 0x49, 0x8d, 0xb4,
|
||||
0x60, 0x9b, 0xc6, 0xf1, 0x98, 0x9e, 0x60, 0xf4, 0x08, 0xe7, 0xf6, 0x86, 0x8e, 0xcc, 0x2d, 0x43,
|
||||
0xe4, 0x05, 0xec, 0x09, 0x94, 0x3c, 0x11, 0x1e, 0x3e, 0x9d, 0xa1, 0x10, 0xa1, 0x8f, 0xd2, 0xbe,
|
||||
0xdc, 0xaa, 0x74, 0xb6, 0x7b, 0x9d, 0xc2, 0x5b, 0x7e, 0x42, 0xc7, 0x5d, 0x16, 0xbd, 0xcf, 0x94,
|
||||
0x98, 0xbb, 0xab, 0x26, 0x88, 0x03, 0x44, 0x2a, 0xaa, 0x12, 0xd9, 0xa7, 0x7e, 0x80, 0xf7, 0x19,
|
||||
0x3d, 0x89, 0xd0, 0xb7, 0x37, 0x5b, 0x56, 0xa7, 0xea, 0xae, 0x61, 0xc8, 0x43, 0xa8, 0xa7, 0x95,
|
||||
0xf0, 0x39, 0xa3, 0xd1, 0x5c, 0x85, 0x9e, 0xb4, 0xb7, 0xcc, 0x99, 0x9b, 0x45, 0x14, 0x0f, 0x2e,
|
||||
0xf2, 0xd9, 0x71, 0x97, 0xd5, 0xc8, 0x6b, 0xd8, 0x9d, 0x24, 0x52, 0xf1, 0x69, 0xf8, 0x1a, 0x9f,
|
||||
0xc6, 0xa6, 0x9a, 0xec, 0xaa, 0x31, 0xf5, 0xc4, 0x39, 0x2f, 0x00, 0x27, 0x2f, 0x00, 0xb3, 0x78,
|
||||
0xe9, 0xf9, 0xce, 0xac, 0xe7, 0xc4, 0x93, 0xc0, 0xd1, 0xe5, 0xe4, 0x94, 0xca, 0xc9, 0xc9, 0xcb,
|
||||
0xc9, 0x79, 0xb4, 0x64, 0xd5, 0x5d, 0xf1, 0x43, 0xde, 0x81, 0x8d, 0x53, 0x8c, 0x62, 0xbb, 0x66,
|
||||
0xfc, 0xed, 0x14, 0xa1, 0x3f, 0xc4, 0x28, 0x76, 0x0d, 0x45, 0xde, 0x85, 0xad, 0x38, 0x4a, 0x82,
|
||||
0x90, 0x49, 0x1b, 0x4c, 0x9a, 0xeb, 0x85, 0xd4, 0x91, 0xc1, 0xdd, 0x9c, 0xd7, 0x39, 0x4c, 0x24,
|
||||
0x8a, 0x31, 0xd7, 0xbb, 0x61, 0x28, 0xd3, 0x1c, 0x6e, 0xa7, 0x39, 0x5c, 0x65, 0xc8, 0x8f, 0x16,
|
||||
0xdc, 0xf4, 0x4c, 0x56, 0x1e, 0x53, 0x46, 0x03, 0x9c, 0x22, 0x53, 0x47, 0x99, 0xaf, 0x2b, 0xc6,
|
||||
0xd7, 0xf3, 0x37, 0xcb, 0xc0, 0x60, 0xad, 0x71, 0xf7, 0x9f, 0x9c, 0x92, 0xf7, 0x61, 0xaf, 0x48,
|
||||
0xd1, 0x0b, 0x14, 0xd2, 0xdc, 0xc5, 0x4e, 0xab, 0xd2, 0xa9, 0xb9, 0xab, 0x04, 0x69, 0x40, 0x35,
|
||||
0x09, 0x07, 0x52, 0x1e, 0xbb, 0x63, 0xfb, 0xaa, 0xa9, 0xd4, 0x62, 0x4f, 0x3a, 0x50, 0x4f, 0xc2,
|
||||
0x3e, 0x65, 0x0c, 0xc5, 0x80, 0x33, 0x85, 0x4c, 0xd9, 0x75, 0x23, 0xb2, 0x0c, 0xeb, 0x92, 0xcf,
|
||||
0x21, 0x6d, 0x68, 0x37, 0x2d, 0xf9, 0x12, 0xa4, 0x6d, 0xc5, 0x54, 0xca, 0xef, 0xb8, 0xf0, 0x8f,
|
||||
0xa8, 0x52, 0x28, 0x98, 0xbd, 0x97, 0xda, 0x5a, 0x82, 0xc9, 0x6d, 0xb8, 0xaa, 0x04, 0xf5, 0x26,
|
||||
0x21, 0x0b, 0x1e, 0xa3, 0x3a, 0xe5, 0xbe, 0x4d, 0x8c, 0xe0, 0x12, 0xaa, 0xcf, 0x99, 0x3b, 0x38,
|
||||
0x42, 0x31, 0xa5, 0x4c, 0xc7, 0x77, 0xcd, 0xdc, 0xd3, 0x2a, 0x41, 0xde, 0x83, 0xdd, 0x02, 0xe4,
|
||||
0x32, 0xd4, 0x29, 0xb6, 0xaf, 0x1b, 0xbb, 0x2b, 0xf8, 0xd2, 0x33, 0x72, 0x39, 0x57, 0xc7, 0x22,
|
||||
0xb2, 0x6f, 0x18, 0xe9, 0x35, 0x8c, 0x3e, 0x3d, 0xbe, 0x42, 0x2f, 0x7f, 0x6f, 0xfb, 0x26, 0x86,
|
||||
0x32, 0x44, 0xee, 0xc0, 0x35, 0x8f, 0x33, 0x25, 0x78, 0x14, 0xa1, 0x78, 0x42, 0xa7, 0x28, 0x63,
|
||||
0xea, 0xa1, 0x7d, 0xd3, 0x98, 0x5c, 0x47, 0x35, 0x7e, 0xb6, 0x60, 0x7f, 0xfd, 0xc3, 0x27, 0xbb,
|
||||
0x50, 0x99, 0xe0, 0x3c, 0xfd, 0xf1, 0x5c, 0xbd, 0x24, 0x3e, 0x5c, 0x9e, 0xd1, 0x28, 0xc1, 0xec,
|
||||
0x93, 0x7b, 0xc3, 0x27, 0xb7, 0xec, 0xd6, 0x4d, 0x8d, 0x7f, 0x72, 0xe9, 0x63, 0xab, 0xfd, 0x12,
|
||||
0x6e, 0xac, 0xfd, 0x11, 0x48, 0x13, 0x20, 0xbf, 0x9f, 0xd1, 0x30, 0x8b, 0xad, 0x84, 0xe8, 0x5b,
|
||||
0xa5, 0x8c, 0xb3, 0xb9, 0x2e, 0xbe, 0x63, 0x89, 0x42, 0x9a, 0x58, 0xab, 0xee, 0x12, 0xda, 0xfe,
|
||||
0xc5, 0x82, 0x0d, 0xfd, 0x70, 0x89, 0x0d, 0x5b, 0xde, 0x29, 0x35, 0x99, 0x4f, 0xad, 0xe5, 0x5b,
|
||||
0x5d, 0xb2, 0x7a, 0xf9, 0x1c, 0x5f, 0x29, 0x63, 0xa4, 0xe6, 0x16, 0x7b, 0x72, 0x0f, 0xe0, 0x24,
|
||||
0x64, 0x54, 0xcc, 0x8f, 0x45, 0x24, 0xed, 0x8a, 0x79, 0x7f, 0x6f, 0x5f, 0xf8, 0x11, 0x9c, 0x7e,
|
||||
0xc1, 0xa7, 0xff, 0x68, 0x49, 0xa1, 0x71, 0x0f, 0xea, 0x4b, 0xf4, 0x9a, 0x6c, 0x5f, 0x2f, 0x67,
|
||||
0xbb, 0x56, 0xce, 0xce, 0x2d, 0xd8, 0x4c, 0x5f, 0x21, 0x21, 0xb0, 0xc1, 0xe8, 0x14, 0x33, 0x35,
|
||||
0xb3, 0x6e, 0x7f, 0x0a, 0xb5, 0xa2, 0xe9, 0x90, 0x1e, 0x80, 0xc7, 0x19, 0x43, 0x4f, 0x71, 0x21,
|
||||
0x6d, 0xcb, 0x04, 0x7a, 0xde, 0x9c, 0x06, 0x39, 0xe5, 0x96, 0xa4, 0xda, 0x77, 0xa1, 0x56, 0x10,
|
||||
0xeb, 0x3c, 0x68, 0x4c, 0xcd, 0xe3, 0x3c, 0x30, 0xb3, 0x6e, 0xff, 0x50, 0x81, 0x52, 0xa3, 0x5a,
|
||||
0xab, 0xb6, 0x0f, 0x9b, 0xa1, 0x94, 0x09, 0x8a, 0x4c, 0x31, 0xdb, 0x91, 0x0e, 0x54, 0xbd, 0x28,
|
||||
0x44, 0xa6, 0x46, 0x43, 0xd3, 0x0b, 0x6b, 0xfd, 0x2b, 0x8b, 0xb3, 0x83, 0xea, 0x20, 0xc3, 0xdc,
|
||||
0x82, 0x25, 0x87, 0xb0, 0xed, 0x45, 0x61, 0x4e, 0xa4, 0x2d, 0xaf, 0x5f, 0x5f, 0x9c, 0x1d, 0x6c,
|
||||
0x0f, 0xc6, 0xa3, 0x42, 0xbe, 0x2c, 0xa3, 0x9d, 0x4a, 0x8f, 0xc7, 0x59, 0xe3, 0xab, 0xb9, 0xd9,
|
||||
0x8e, 0xbc, 0x84, 0x9d, 0xd0, 0x7f, 0xce, 0x27, 0xc8, 0x06, 0x66, 0x08, 0xb0, 0x37, 0x4d, 0x6e,
|
||||
0x6e, 0xaf, 0xe9, 0xc2, 0xce, 0xa8, 0x2c, 0x68, 0xae, 0xab, 0xbf, 0xb7, 0x38, 0x3b, 0xd8, 0x19,
|
||||
0x0d, 0x4b, 0xb8, 0x7b, 0xd1, 0x5e, 0x63, 0x0e, 0x64, 0x55, 0x6f, 0xcd, 0x35, 0x3f, 0xbe, 0xf8,
|
||||
0xa8, 0x3e, 0xfa, 0xd7, 0x47, 0x95, 0x4e, 0x31, 0x4e, 0x31, 0x86, 0xe9, 0x71, 0xc0, 0x31, 0xf6,
|
||||
0x4b, 0xf5, 0xd1, 0xfb, 0x1a, 0xea, 0x79, 0x57, 0x7f, 0x86, 0x62, 0x16, 0x7a, 0x48, 0xbe, 0x80,
|
||||
0xca, 0x03, 0x54, 0x64, 0x7f, 0xa5, 0xed, 0x9b, 0x51, 0xa7, 0xb1, 0xb7, 0x82, 0xb7, 0xed, 0xef,
|
||||
0x7f, 0xff, 0xf3, 0xa7, 0x4b, 0x84, 0xec, 0x9a, 0xf1, 0x6d, 0x76, 0x58, 0x8c, 0x4e, 0xfd, 0xc1,
|
||||
0xaf, 0x8b, 0xa6, 0xf5, 0xdb, 0xa2, 0x69, 0xfd, 0xb1, 0x68, 0x5a, 0x5f, 0x7d, 0xf8, 0xff, 0xc6,
|
||||
0xb8, 0xf4, 0x0e, 0x0b, 0x23, 0x27, 0x9b, 0x66, 0xe8, 0xba, 0xfb, 0x77, 0x00, 0x00, 0x00, 0xff,
|
||||
0xff, 0x2a, 0xfc, 0x97, 0xee, 0x63, 0x0a, 0x00, 0x00,
|
||||
}
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
|
|
@ -873,6 +882,15 @@ func (m *Settings) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
|||
i -= len(m.XXX_unrecognized)
|
||||
copy(dAtA[i:], m.XXX_unrecognized)
|
||||
}
|
||||
if len(m.ControllerNamespace) > 0 {
|
||||
i -= len(m.ControllerNamespace)
|
||||
copy(dAtA[i:], m.ControllerNamespace)
|
||||
i = encodeVarintSettings(dAtA, i, uint64(len(m.ControllerNamespace)))
|
||||
i--
|
||||
dAtA[i] = 0x1
|
||||
i--
|
||||
dAtA[i] = 0xba
|
||||
}
|
||||
if m.ExecEnabled {
|
||||
i--
|
||||
if m.ExecEnabled {
|
||||
|
|
@ -1554,6 +1572,10 @@ func (m *Settings) Size() (n int) {
|
|||
if m.ExecEnabled {
|
||||
n += 3
|
||||
}
|
||||
l = len(m.ControllerNamespace)
|
||||
if l > 0 {
|
||||
n += 2 + l + sovSettings(uint64(l))
|
||||
}
|
||||
if m.XXX_unrecognized != nil {
|
||||
n += len(m.XXX_unrecognized)
|
||||
}
|
||||
|
|
@ -2571,6 +2593,38 @@ func (m *Settings) Unmarshal(dAtA []byte) error {
|
|||
}
|
||||
}
|
||||
m.ExecEnabled = bool(v != 0)
|
||||
case 23:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field ControllerNamespace", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowSettings
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthSettings
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthSettings
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.ControllerNamespace = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipSettings(dAtA[iNdEx:])
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/ap
|
|||
API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,AppProjectSpec,NamespaceResourceWhitelist
|
||||
API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,AppProjectSpec,Roles
|
||||
API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,AppProjectSpec,SignatureKeys
|
||||
API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,AppProjectSpec,SourceNamespaces
|
||||
API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,AppProjectSpec,SourceRepos
|
||||
API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,ApplicationSourceHelm,FileParameters
|
||||
API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,ApplicationSourceHelm,Parameters
|
||||
|
|
|
|||
|
|
@ -172,6 +172,15 @@ func (p *AppProject) ValidateProject() error {
|
|||
}
|
||||
destKeys[key] = true
|
||||
}
|
||||
|
||||
srcNamespaces := make(map[string]bool)
|
||||
for _, ns := range p.Spec.SourceNamespaces {
|
||||
if _, ok := srcNamespaces[ns]; ok {
|
||||
return status.Errorf(codes.InvalidArgument, "source namespaces '%s' already added", ns)
|
||||
}
|
||||
destKeys[ns] = true
|
||||
}
|
||||
|
||||
srcRepos := make(map[string]bool)
|
||||
for _, src := range p.Spec.SourceRepos {
|
||||
if _, ok := srcRepos[src]; ok {
|
||||
|
|
@ -482,3 +491,18 @@ func jwtTokensCombine(tokens1 []JWTToken, tokens2 []JWTToken) []JWTToken {
|
|||
})
|
||||
return tokens
|
||||
}
|
||||
|
||||
// IsAppNamespacePermitted checks whether an application that associates with
|
||||
// this AppProject is allowed by comparing the Application's namespace with
|
||||
// the list of allowed namespaces in the AppProject.
|
||||
//
|
||||
// Applications in the installation namespace are always permitted. Also, at
|
||||
// application creation time, its namespace may yet be empty to indicate that
|
||||
// the application will be created in the controller's namespace.
|
||||
func (p AppProject) IsAppNamespacePermitted(app *Application, controllerNs string) bool {
|
||||
if app.Namespace == "" || app.Namespace == controllerNs {
|
||||
return true
|
||||
}
|
||||
|
||||
return glob.MatchStringInList(p.Spec.SourceNamespaces, app.Namespace, false)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2604,433 +2604,434 @@ func init() {
|
|||
}
|
||||
|
||||
var fileDescriptor_030104ce3b95bcac = []byte{
|
||||
// 6809 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x7d, 0x5d, 0x8c, 0x24, 0xc9,
|
||||
0x51, 0xf0, 0x55, 0xf7, 0xfc, 0x74, 0xc7, 0xfc, 0xec, 0x4e, 0xee, 0xcf, 0x8d, 0xe7, 0x3b, 0xef,
|
||||
0xac, 0xea, 0x64, 0xfb, 0xbe, 0xcf, 0xf6, 0xcc, 0x77, 0xcb, 0xd9, 0x1c, 0x3e, 0x73, 0x66, 0x7a,
|
||||
0x66, 0x7f, 0x66, 0x77, 0xfe, 0x36, 0x66, 0x76, 0x17, 0x9f, 0x8d, 0xb9, 0x9a, 0xea, 0xec, 0xee,
|
||||
0xda, 0xe9, 0xae, 0xea, 0xab, 0xaa, 0x9e, 0x9d, 0xb6, 0xf1, 0x9f, 0x64, 0xf0, 0x49, 0xfe, 0x95,
|
||||
0xcd, 0x83, 0x2d, 0x21, 0x30, 0x3f, 0x42, 0xe2, 0xc1, 0x02, 0x9e, 0x00, 0x21, 0x1e, 0x30, 0x2f,
|
||||
0x46, 0x3c, 0x60, 0x09, 0x84, 0x0d, 0x16, 0x83, 0xbd, 0x80, 0x0c, 0x48, 0x80, 0x00, 0xbf, 0xb0,
|
||||
0xe2, 0x01, 0xe5, 0x4f, 0x65, 0x66, 0x55, 0x77, 0xef, 0xcc, 0x6c, 0xd7, 0x2e, 0x96, 0xc5, 0xdb,
|
||||
0x74, 0x44, 0x64, 0x44, 0x64, 0x56, 0x66, 0x64, 0x44, 0x64, 0x64, 0x0e, 0xac, 0xd5, 0xbd, 0xb8,
|
||||
0xd1, 0xd9, 0x5d, 0x70, 0x83, 0xd6, 0xa2, 0x13, 0xd6, 0x83, 0x76, 0x18, 0xdc, 0xe5, 0x7f, 0xbc,
|
||||
0xdd, 0xad, 0x2e, 0xee, 0x5f, 0x5a, 0x6c, 0xef, 0xd5, 0x17, 0x9d, 0xb6, 0x17, 0x2d, 0x3a, 0xed,
|
||||
0x76, 0xd3, 0x73, 0x9d, 0xd8, 0x0b, 0xfc, 0xc5, 0xfd, 0xe7, 0x9d, 0x66, 0xbb, 0xe1, 0x3c, 0xbf,
|
||||
0x58, 0xa7, 0x3e, 0x0d, 0x9d, 0x98, 0x56, 0x17, 0xda, 0x61, 0x10, 0x07, 0xe4, 0xdd, 0x9a, 0xdb,
|
||||
0x42, 0xc2, 0x8d, 0xff, 0xf1, 0xd3, 0x6e, 0x75, 0x61, 0xff, 0xd2, 0x42, 0x7b, 0xaf, 0xbe, 0xc0,
|
||||
0xb8, 0x2d, 0x18, 0xdc, 0x16, 0x12, 0x6e, 0x73, 0x6f, 0x37, 0x74, 0xa9, 0x07, 0xf5, 0x60, 0x91,
|
||||
0x33, 0xdd, 0xed, 0xd4, 0xf8, 0x2f, 0xfe, 0x83, 0xff, 0x25, 0x84, 0xcd, 0xd9, 0x7b, 0x2f, 0x46,
|
||||
0x0b, 0x5e, 0xc0, 0xd4, 0x5b, 0x74, 0x83, 0x90, 0x2e, 0xee, 0xf7, 0x28, 0x34, 0xf7, 0x82, 0xa6,
|
||||
0x69, 0x39, 0x6e, 0xc3, 0xf3, 0x69, 0xd8, 0xd5, 0x7d, 0x6a, 0xd1, 0xd8, 0xe9, 0xd7, 0x6a, 0x71,
|
||||
0x50, 0xab, 0xb0, 0xe3, 0xc7, 0x5e, 0x8b, 0xf6, 0x34, 0x78, 0xe7, 0x51, 0x0d, 0x22, 0xb7, 0x41,
|
||||
0x5b, 0x4e, 0xb6, 0x9d, 0xfd, 0x1a, 0x4c, 0x2d, 0xdd, 0xd9, 0x5e, 0xea, 0xc4, 0x8d, 0xe5, 0xc0,
|
||||
0xaf, 0x79, 0x75, 0xf2, 0x0e, 0x98, 0x70, 0x9b, 0x9d, 0x28, 0xa6, 0xe1, 0x86, 0xd3, 0xa2, 0xb3,
|
||||
0xd6, 0x45, 0xeb, 0xb9, 0x72, 0xe5, 0xcc, 0xd7, 0x0f, 0xe7, 0x9f, 0xba, 0x7f, 0x38, 0x3f, 0xb1,
|
||||
0xac, 0x51, 0x68, 0xd2, 0x91, 0xff, 0x0b, 0xe3, 0x61, 0xd0, 0xa4, 0x4b, 0xb8, 0x31, 0x5b, 0xe0,
|
||||
0x4d, 0x4e, 0xc9, 0x26, 0xe3, 0x28, 0xc0, 0x98, 0xe0, 0xed, 0xbf, 0x28, 0x00, 0x2c, 0xb5, 0xdb,
|
||||
0x5b, 0x61, 0x70, 0x97, 0xba, 0x31, 0x79, 0x15, 0x4a, 0x6c, 0x14, 0xaa, 0x4e, 0xec, 0x70, 0x69,
|
||||
0x13, 0x97, 0xfe, 0xff, 0x82, 0xe8, 0xcc, 0x82, 0xd9, 0x19, 0xfd, 0xe5, 0x18, 0xf5, 0xc2, 0xfe,
|
||||
0xf3, 0x0b, 0x9b, 0xbb, 0xac, 0xfd, 0x3a, 0x8d, 0x9d, 0x0a, 0x91, 0xc2, 0x40, 0xc3, 0x50, 0x71,
|
||||
0x25, 0x3e, 0x8c, 0x44, 0x6d, 0xea, 0x72, 0xc5, 0x26, 0x2e, 0xad, 0x2d, 0x0c, 0x33, 0x45, 0x16,
|
||||
0xb4, 0xe6, 0xdb, 0x6d, 0xea, 0x56, 0x26, 0xa5, 0xe4, 0x11, 0xf6, 0x0b, 0xb9, 0x1c, 0xb2, 0x0f,
|
||||
0x63, 0x51, 0xec, 0xc4, 0x9d, 0x68, 0xb6, 0xc8, 0x25, 0x6e, 0xe4, 0x26, 0x91, 0x73, 0xad, 0x4c,
|
||||
0x4b, 0x99, 0x63, 0xe2, 0x37, 0x4a, 0x69, 0xf6, 0x5f, 0x5b, 0x30, 0xad, 0x89, 0xd7, 0xbc, 0x28,
|
||||
0x26, 0xef, 0xef, 0x19, 0xdc, 0x85, 0xe3, 0x0d, 0x2e, 0x6b, 0xcd, 0x87, 0xf6, 0xb4, 0x14, 0x56,
|
||||
0x4a, 0x20, 0xc6, 0xc0, 0xb6, 0x60, 0xd4, 0x8b, 0x69, 0x2b, 0x9a, 0x2d, 0x5c, 0x2c, 0x3e, 0x37,
|
||||
0x71, 0xe9, 0x5a, 0x5e, 0xfd, 0xac, 0x4c, 0x49, 0xa1, 0xa3, 0xab, 0x8c, 0x3d, 0x0a, 0x29, 0xf6,
|
||||
0xf7, 0xc1, 0xec, 0x1f, 0x1b, 0x70, 0xf2, 0x3c, 0x4c, 0x44, 0x41, 0x27, 0x74, 0x29, 0xd2, 0x76,
|
||||
0x10, 0xcd, 0x5a, 0x17, 0x8b, 0x6c, 0xea, 0xb1, 0x99, 0xba, 0xad, 0xc1, 0x68, 0xd2, 0x90, 0xcf,
|
||||
0x5a, 0x30, 0x59, 0xa5, 0x51, 0xec, 0xf9, 0x5c, 0x7e, 0xa2, 0xfc, 0xce, 0xd0, 0xca, 0x27, 0xc0,
|
||||
0x15, 0xcd, 0xbc, 0x72, 0x56, 0x76, 0x64, 0xd2, 0x00, 0x46, 0x98, 0x92, 0xcf, 0x56, 0x5c, 0x95,
|
||||
0x46, 0x6e, 0xe8, 0xb5, 0xd9, 0x6f, 0x3e, 0x67, 0x8c, 0x15, 0xb7, 0xa2, 0x51, 0x68, 0xd2, 0x11,
|
||||
0x1f, 0x46, 0xd9, 0x8a, 0x8a, 0x66, 0x47, 0xb8, 0xfe, 0xab, 0xc3, 0xe9, 0x2f, 0x07, 0x95, 0x2d,
|
||||
0x56, 0x3d, 0xfa, 0xec, 0x57, 0x84, 0x42, 0x0c, 0xf9, 0x8c, 0x05, 0xb3, 0x72, 0xc5, 0x23, 0x15,
|
||||
0x03, 0x7a, 0xa7, 0xe1, 0xc5, 0xb4, 0xe9, 0x45, 0xf1, 0xec, 0x28, 0xd7, 0x61, 0xf1, 0x78, 0x73,
|
||||
0xeb, 0x6a, 0x18, 0x74, 0xda, 0x37, 0x3c, 0xbf, 0x5a, 0xb9, 0x28, 0x25, 0xcd, 0x2e, 0x0f, 0x60,
|
||||
0x8c, 0x03, 0x45, 0x92, 0x2f, 0x5a, 0x30, 0xe7, 0x3b, 0x2d, 0x1a, 0xb5, 0x1d, 0xf6, 0x69, 0x05,
|
||||
0xba, 0xd2, 0x74, 0xdc, 0x3d, 0xae, 0xd1, 0xd8, 0xa3, 0x69, 0x64, 0x4b, 0x8d, 0xe6, 0x36, 0x06,
|
||||
0xb2, 0xc6, 0x87, 0x88, 0x25, 0xbf, 0x6a, 0xc1, 0x4c, 0x10, 0xb6, 0x1b, 0x8e, 0x4f, 0xab, 0x09,
|
||||
0x36, 0x9a, 0x1d, 0xe7, 0x4b, 0xef, 0x03, 0xc3, 0x7d, 0xa2, 0xcd, 0x2c, 0xdb, 0xf5, 0xc0, 0xf7,
|
||||
0xe2, 0x20, 0xdc, 0xa6, 0x71, 0xec, 0xf9, 0xf5, 0xa8, 0x72, 0xee, 0xfe, 0xe1, 0xfc, 0x4c, 0x0f,
|
||||
0x15, 0xf6, 0xea, 0x43, 0x3e, 0x04, 0x13, 0x51, 0xd7, 0x77, 0xef, 0x78, 0x7e, 0x35, 0xb8, 0x17,
|
||||
0xcd, 0x96, 0xf2, 0x58, 0xbe, 0xdb, 0x8a, 0xa1, 0x5c, 0x80, 0x5a, 0x00, 0x9a, 0xd2, 0xfa, 0x7f,
|
||||
0x38, 0x3d, 0x95, 0xca, 0x79, 0x7f, 0x38, 0x3d, 0x99, 0x1e, 0x22, 0x96, 0x7c, 0xd2, 0x82, 0xa9,
|
||||
0xc8, 0xab, 0xfb, 0x4e, 0xdc, 0x09, 0xe9, 0x0d, 0xda, 0x8d, 0x66, 0x81, 0x2b, 0x72, 0x7d, 0xc8,
|
||||
0x51, 0x31, 0x58, 0x56, 0xce, 0x49, 0x1d, 0xa7, 0x4c, 0x68, 0x84, 0x69, 0xb9, 0xfd, 0x16, 0x9a,
|
||||
0x9e, 0xd6, 0x13, 0xf9, 0x2e, 0x34, 0x3d, 0xa9, 0x07, 0x8a, 0xb4, 0xff, 0xb8, 0x00, 0xa7, 0xb3,
|
||||
0x7b, 0x10, 0xf9, 0x75, 0x0b, 0x4e, 0xdd, 0xbd, 0x17, 0xef, 0x04, 0x7b, 0xd4, 0x8f, 0x2a, 0x5d,
|
||||
0x66, 0x29, 0xb8, 0xf5, 0x9d, 0xb8, 0xe4, 0xe6, 0xbb, 0xdb, 0x2d, 0x5c, 0x4f, 0x4b, 0xb9, 0xec,
|
||||
0xc7, 0x61, 0xb7, 0xf2, 0xb4, 0xec, 0xcf, 0xa9, 0xeb, 0x77, 0x76, 0x4c, 0x2c, 0x66, 0x95, 0x9a,
|
||||
0xfb, 0x94, 0x05, 0x67, 0xfb, 0xb1, 0x20, 0xa7, 0xa1, 0xb8, 0x47, 0xbb, 0xc2, 0xc1, 0x41, 0xf6,
|
||||
0x27, 0xf9, 0x29, 0x18, 0xdd, 0x77, 0x9a, 0x1d, 0x2a, 0x1d, 0x85, 0xab, 0xc3, 0x75, 0x44, 0x69,
|
||||
0x86, 0x82, 0xeb, 0xbb, 0x0a, 0x2f, 0x5a, 0xf6, 0x9f, 0x16, 0x61, 0xc2, 0xd8, 0x2a, 0x9e, 0x80,
|
||||
0xf3, 0x13, 0xa4, 0x9c, 0x9f, 0xf5, 0xdc, 0x76, 0xb9, 0x81, 0xde, 0xcf, 0xbd, 0x8c, 0xf7, 0xb3,
|
||||
0x99, 0x9f, 0xc8, 0x87, 0xba, 0x3f, 0x24, 0x86, 0x72, 0xd0, 0x66, 0xce, 0x2d, 0xdb, 0x45, 0x47,
|
||||
0xf2, 0xf8, 0x84, 0x9b, 0x09, 0xbb, 0xca, 0xd4, 0xfd, 0xc3, 0xf9, 0xb2, 0xfa, 0x89, 0x5a, 0x90,
|
||||
0xfd, 0x4d, 0x0b, 0xce, 0x1a, 0x3a, 0x2e, 0x07, 0x7e, 0xd5, 0xe3, 0x9f, 0xf6, 0x22, 0x8c, 0xc4,
|
||||
0xdd, 0x76, 0xe2, 0x41, 0xab, 0x91, 0xda, 0xe9, 0xb6, 0x29, 0x72, 0x0c, 0xf3, 0x99, 0x5b, 0x34,
|
||||
0x8a, 0x9c, 0x3a, 0xcd, 0xfa, 0xcc, 0xeb, 0x02, 0x8c, 0x09, 0x9e, 0x84, 0x40, 0x9a, 0x4e, 0x14,
|
||||
0xef, 0x84, 0x8e, 0x1f, 0x71, 0xf6, 0x3b, 0x5e, 0x8b, 0xca, 0x01, 0xfe, 0x7f, 0xc7, 0x9b, 0x31,
|
||||
0xac, 0x45, 0xe5, 0xfc, 0xfd, 0xc3, 0x79, 0xb2, 0xd6, 0xc3, 0x09, 0xfb, 0x70, 0xb7, 0xbf, 0x68,
|
||||
0xc1, 0xf9, 0xfe, 0x6e, 0x0d, 0x79, 0x33, 0x8c, 0x45, 0x34, 0xdc, 0xa7, 0xa1, 0xec, 0x9d, 0xfe,
|
||||
0x24, 0x1c, 0x8a, 0x12, 0x4b, 0x16, 0xa1, 0xac, 0x4c, 0xae, 0xec, 0xe3, 0x8c, 0x24, 0x2d, 0x6b,
|
||||
0x3b, 0xad, 0x69, 0xd8, 0xa0, 0xb1, 0x1f, 0xd2, 0x09, 0x52, 0x83, 0xc6, 0xe3, 0x0d, 0x8e, 0xb1,
|
||||
0xff, 0xc6, 0x82, 0x53, 0x86, 0x56, 0x4f, 0xc0, 0xcb, 0xf5, 0xd3, 0x5e, 0xee, 0x6a, 0x6e, 0xf3,
|
||||
0x79, 0x80, 0x9b, 0xfb, 0x47, 0xa3, 0x30, 0x63, 0xce, 0x7a, 0x6e, 0x8e, 0x79, 0x80, 0x45, 0xdb,
|
||||
0xc1, 0x2d, 0x5c, 0x93, 0x63, 0xae, 0x03, 0x2c, 0x01, 0xc6, 0x04, 0xcf, 0x06, 0xb1, 0xed, 0xc4,
|
||||
0x0d, 0x39, 0xe0, 0x6a, 0x10, 0xb7, 0x9c, 0xb8, 0x81, 0x1c, 0x43, 0x5e, 0x86, 0xe9, 0xd8, 0x09,
|
||||
0xeb, 0x34, 0x46, 0xba, 0xef, 0x45, 0xc9, 0x7a, 0x29, 0x57, 0xce, 0x4b, 0xda, 0xe9, 0x9d, 0x14,
|
||||
0x16, 0x33, 0xd4, 0xe4, 0x35, 0x18, 0x69, 0xd0, 0x66, 0x4b, 0xfa, 0x35, 0xdb, 0xf9, 0xad, 0x70,
|
||||
0xde, 0xd7, 0x6b, 0xb4, 0xd9, 0xaa, 0x94, 0x98, 0xca, 0xec, 0x2f, 0xe4, 0xa2, 0xc8, 0xcf, 0x5a,
|
||||
0x50, 0xde, 0xeb, 0x44, 0x71, 0xd0, 0xf2, 0x3e, 0x48, 0x67, 0x4b, 0x5c, 0xf0, 0x4f, 0xe6, 0x2c,
|
||||
0xf8, 0x46, 0xc2, 0x5f, 0xac, 0x77, 0xf5, 0x13, 0xb5, 0x64, 0xae, 0x47, 0xd5, 0x0b, 0xa9, 0x1b,
|
||||
0x07, 0x61, 0x77, 0x16, 0x1e, 0x8b, 0x1e, 0x2b, 0x09, 0x7f, 0xa1, 0x87, 0xfa, 0x89, 0x5a, 0x32,
|
||||
0xe9, 0xc2, 0x58, 0xbb, 0xd9, 0xa9, 0x7b, 0xfe, 0xec, 0x04, 0xd7, 0xe1, 0x56, 0xce, 0x3a, 0x6c,
|
||||
0x71, 0xe6, 0x15, 0x60, 0xab, 0x5a, 0xfc, 0x8d, 0x52, 0x20, 0x79, 0x16, 0x46, 0xdd, 0x86, 0x13,
|
||||
0xc6, 0xb3, 0x93, 0x7c, 0xd2, 0xa8, 0x59, 0xbc, 0xcc, 0x80, 0x28, 0x70, 0xf6, 0x2f, 0x17, 0x60,
|
||||
0x6e, 0x70, 0xc7, 0xc4, 0x74, 0x76, 0x3b, 0x61, 0x24, 0x0c, 0x64, 0xc9, 0x9c, 0xce, 0x1c, 0x8c,
|
||||
0x09, 0x9e, 0x7c, 0xdc, 0x82, 0xf1, 0xbb, 0x51, 0xe0, 0xfb, 0x34, 0x96, 0xbb, 0xd8, 0xed, 0x9c,
|
||||
0xfb, 0x7a, 0x5d, 0x70, 0xd7, 0x3a, 0x48, 0x00, 0x26, 0x72, 0x99, 0xba, 0xf4, 0xc0, 0x6d, 0x76,
|
||||
0xaa, 0x89, 0x69, 0x52, 0xa4, 0x97, 0x05, 0x18, 0x13, 0x3c, 0x23, 0xf5, 0x7c, 0x41, 0x3a, 0x92,
|
||||
0x26, 0x5d, 0xf5, 0x25, 0xa9, 0xc4, 0xdb, 0xbf, 0x35, 0x0a, 0xe7, 0xfa, 0xce, 0x7e, 0xb2, 0x00,
|
||||
0xc0, 0x9d, 0x86, 0x2b, 0x1e, 0x8b, 0xf0, 0x44, 0x58, 0x3b, 0xcd, 0xf6, 0xf8, 0xdb, 0x0a, 0x8a,
|
||||
0x06, 0x05, 0xf9, 0x28, 0x40, 0xdb, 0x09, 0x9d, 0x16, 0x8d, 0x69, 0x98, 0x18, 0xaa, 0x1b, 0xc3,
|
||||
0x8d, 0x12, 0xd3, 0x63, 0x2b, 0xe1, 0xa9, 0x9d, 0x0c, 0x05, 0x8a, 0xd0, 0x10, 0xc9, 0x82, 0xd8,
|
||||
0x90, 0x36, 0xa9, 0x13, 0xd1, 0x0d, 0x6d, 0xbf, 0x55, 0x10, 0x8b, 0x1a, 0x85, 0x26, 0x1d, 0xdb,
|
||||
0x48, 0x78, 0x2f, 0x22, 0x39, 0x56, 0x6a, 0x23, 0xe1, 0xfd, 0x8c, 0x50, 0x62, 0xc9, 0xe7, 0x2c,
|
||||
0x98, 0xae, 0x79, 0x4d, 0xaa, 0xa5, 0xcb, 0x90, 0x73, 0x73, 0xf8, 0x4e, 0x5e, 0x31, 0xf9, 0x6a,
|
||||
0x13, 0x98, 0x02, 0x47, 0x98, 0x11, 0xcf, 0x3e, 0xf3, 0x3e, 0x0d, 0xb9, 0xed, 0x1c, 0x4b, 0x7f,
|
||||
0xe6, 0xdb, 0x02, 0x8c, 0x09, 0x9e, 0x2c, 0xc1, 0xa9, 0xb6, 0x13, 0x45, 0xcb, 0x21, 0xad, 0x52,
|
||||
0x3f, 0xf6, 0x9c, 0xa6, 0x08, 0x08, 0x4b, 0xda, 0x8b, 0xdd, 0x4a, 0xa3, 0x31, 0x4b, 0x4f, 0xde,
|
||||
0x0b, 0x4f, 0x7b, 0x75, 0x3f, 0x08, 0xe9, 0xba, 0x17, 0x45, 0x9e, 0x5f, 0xd7, 0xd3, 0x80, 0x9b,
|
||||
0xc2, 0x52, 0x65, 0x5e, 0xb2, 0x7a, 0x7a, 0xb5, 0x3f, 0x19, 0x0e, 0x6a, 0x4f, 0xde, 0x06, 0xa5,
|
||||
0x68, 0xcf, 0x6b, 0x2f, 0x87, 0xd5, 0x68, 0xb6, 0xcc, 0x79, 0xa9, 0xcd, 0x70, 0x5b, 0xc2, 0x51,
|
||||
0x51, 0xd8, 0x5f, 0x2e, 0xc0, 0xec, 0xa0, 0xf5, 0x43, 0x22, 0xb6, 0x4a, 0xe2, 0xdb, 0x4e, 0x18,
|
||||
0xc9, 0x58, 0x60, 0xc8, 0x90, 0x52, 0xf2, 0xbd, 0xed, 0x84, 0xe6, 0x7a, 0xe3, 0x02, 0x30, 0x91,
|
||||
0x44, 0xee, 0xc2, 0x48, 0xdc, 0x74, 0x72, 0xca, 0x41, 0x19, 0x12, 0xb5, 0xc7, 0xb6, 0xb6, 0x14,
|
||||
0x21, 0x97, 0x41, 0x9e, 0x81, 0x91, 0xa6, 0xb7, 0xcb, 0x3c, 0x5b, 0xb6, 0x20, 0xf9, 0x16, 0xb5,
|
||||
0xe6, 0xed, 0x46, 0xc8, 0xa1, 0xf6, 0xbf, 0x8e, 0xf5, 0x31, 0x79, 0x6a, 0x13, 0x21, 0x97, 0x00,
|
||||
0x98, 0x07, 0xb3, 0x15, 0xd2, 0x9a, 0x77, 0x20, 0x37, 0x71, 0xb5, 0xac, 0x36, 0x14, 0x06, 0x0d,
|
||||
0xaa, 0xa4, 0xcd, 0x76, 0xa7, 0xc6, 0xda, 0x14, 0x7a, 0xdb, 0x08, 0x0c, 0x1a, 0x54, 0xe4, 0x05,
|
||||
0x18, 0xf3, 0x5a, 0x4e, 0x9d, 0x26, 0x6a, 0x3e, 0xc3, 0xd6, 0xd3, 0x2a, 0x87, 0x3c, 0x38, 0x9c,
|
||||
0x9f, 0x56, 0x0a, 0x71, 0x10, 0x4a, 0x5a, 0xf2, 0x6b, 0x16, 0x4c, 0xba, 0x41, 0xab, 0x15, 0xf8,
|
||||
0x6b, 0xce, 0x2e, 0x6d, 0x26, 0x69, 0xa5, 0xbb, 0x8f, 0x6b, 0x8b, 0x5d, 0x58, 0x36, 0x84, 0x89,
|
||||
0xa0, 0x4e, 0x25, 0xcb, 0x4c, 0x14, 0xa6, 0xb4, 0x32, 0x97, 0xdd, 0xe8, 0x11, 0xcb, 0xee, 0x77,
|
||||
0x2d, 0x98, 0x11, 0x6d, 0x97, 0x7c, 0x3f, 0x88, 0x65, 0xb6, 0x4f, 0xe4, 0x85, 0x82, 0xc7, 0xdc,
|
||||
0x2d, 0x43, 0xa2, 0xe8, 0xdb, 0x1b, 0xa4, 0x9a, 0x33, 0x3d, 0x78, 0xec, 0x55, 0x92, 0x5c, 0x85,
|
||||
0x99, 0x5a, 0x10, 0xba, 0xd4, 0x1c, 0x08, 0x69, 0x33, 0x14, 0xa3, 0x2b, 0x59, 0x02, 0xec, 0x6d,
|
||||
0x43, 0x6e, 0xc3, 0x79, 0x03, 0x68, 0x8e, 0x83, 0x30, 0x1b, 0x17, 0x24, 0xb7, 0xf3, 0x57, 0xfa,
|
||||
0x52, 0xe1, 0x80, 0xd6, 0x73, 0xef, 0x81, 0x99, 0x9e, 0xef, 0xd7, 0x27, 0xa2, 0x3e, 0x6b, 0x46,
|
||||
0xd4, 0x65, 0x23, 0x10, 0x9e, 0x5b, 0x81, 0xf3, 0xfd, 0x47, 0xea, 0x24, 0x5c, 0xec, 0x5f, 0xb4,
|
||||
0xe0, 0xe9, 0x01, 0x9e, 0x8b, 0x0a, 0x25, 0xac, 0x41, 0xa1, 0x04, 0x71, 0xa0, 0x48, 0xfd, 0x7d,
|
||||
0x69, 0x38, 0xae, 0x0c, 0x37, 0x23, 0x2e, 0xfb, 0xfb, 0xe2, 0x43, 0x8f, 0xdf, 0x3f, 0x9c, 0x2f,
|
||||
0x5e, 0xf6, 0xf7, 0x91, 0xf1, 0xb6, 0x7f, 0x7e, 0x2c, 0x15, 0xad, 0x6c, 0x27, 0x01, 0x32, 0x57,
|
||||
0x54, 0xc6, 0x2a, 0x9b, 0x39, 0xcf, 0x45, 0x23, 0x1a, 0x13, 0x69, 0x6f, 0x29, 0x8e, 0x7c, 0xca,
|
||||
0xe2, 0x99, 0xe6, 0x24, 0x8a, 0x93, 0xce, 0xd4, 0xe3, 0x49, 0x7c, 0x9b, 0xf9, 0xeb, 0x04, 0x88,
|
||||
0xa6, 0x74, 0xb6, 0x92, 0xdb, 0x22, 0xd1, 0x93, 0x75, 0xa9, 0x92, 0x5c, 0x74, 0x82, 0x27, 0x07,
|
||||
0x00, 0x51, 0xd7, 0x77, 0xb7, 0x82, 0xa6, 0xe7, 0x76, 0x65, 0x68, 0x9f, 0x43, 0xb6, 0x52, 0xf0,
|
||||
0x13, 0x7e, 0x95, 0xfe, 0x8d, 0x86, 0x2c, 0xf2, 0x15, 0x0b, 0x66, 0xc4, 0xc6, 0xb9, 0xe2, 0xd5,
|
||||
0x6a, 0x34, 0xa4, 0xbe, 0x4b, 0x13, 0xd7, 0xe3, 0xce, 0x70, 0x1a, 0x24, 0x89, 0xb6, 0xd5, 0x2c,
|
||||
0x7b, 0xbd, 0xc4, 0x7b, 0x50, 0xd8, 0xab, 0x0c, 0xa9, 0xc2, 0x88, 0xe7, 0xd7, 0x02, 0x69, 0xd8,
|
||||
0x2a, 0xc3, 0x29, 0xb5, 0xea, 0xd7, 0x02, 0xbd, 0x56, 0xd8, 0x2f, 0xe4, 0xdc, 0xc9, 0x1a, 0x9c,
|
||||
0x0d, 0x65, 0xf4, 0x77, 0xcd, 0x8b, 0x98, 0x0b, 0xbf, 0xe6, 0xb5, 0xbc, 0x98, 0x1b, 0xa5, 0x62,
|
||||
0x65, 0xf6, 0xfe, 0xe1, 0xfc, 0x59, 0xec, 0x83, 0xc7, 0xbe, 0xad, 0xec, 0xd7, 0xcb, 0xe9, 0x10,
|
||||
0x57, 0x24, 0x70, 0x3e, 0x0c, 0xe5, 0x50, 0xa5, 0xcc, 0x85, 0x03, 0xb1, 0x96, 0xcf, 0x18, 0xcb,
|
||||
0xcc, 0x91, 0xca, 0x3d, 0xe8, 0xe4, 0xb8, 0x96, 0xc8, 0x1c, 0x09, 0xf6, 0xe5, 0xe5, 0xb2, 0xc8,
|
||||
0x61, 0x7e, 0x49, 0xa9, 0x3a, 0x49, 0xd6, 0xf5, 0x5d, 0xe4, 0x32, 0x48, 0x08, 0x63, 0x0d, 0xea,
|
||||
0x34, 0xe3, 0x86, 0xcc, 0xe1, 0x5c, 0x1f, 0xd6, 0x8d, 0x65, 0xbc, 0xb2, 0xf9, 0x31, 0x01, 0x45,
|
||||
0x29, 0x89, 0x1c, 0xc0, 0x78, 0x43, 0x7c, 0x04, 0xb9, 0xb7, 0xaf, 0x0f, 0x3b, 0xb8, 0xa9, 0x2f,
|
||||
0xab, 0xd7, 0xaf, 0x04, 0x60, 0x22, 0x8e, 0xfc, 0x9c, 0x05, 0xe0, 0x26, 0x89, 0xb1, 0x64, 0xf9,
|
||||
0x60, 0x6e, 0x76, 0x47, 0xe5, 0xdc, 0xb4, 0x6b, 0xa4, 0x40, 0x11, 0x1a, 0x92, 0xc9, 0xab, 0x30,
|
||||
0x19, 0x52, 0x37, 0xf0, 0x5d, 0xaf, 0x49, 0xab, 0x4b, 0x31, 0xf7, 0xdc, 0x4f, 0x96, 0x40, 0x3b,
|
||||
0xcd, 0xfc, 0x13, 0x34, 0x78, 0x60, 0x8a, 0x23, 0x79, 0xdd, 0x82, 0x69, 0x95, 0x1c, 0x64, 0x1f,
|
||||
0x84, 0xca, 0x24, 0xc9, 0x5a, 0x4e, 0xa9, 0x48, 0xce, 0xb3, 0x42, 0x58, 0x84, 0x92, 0x86, 0x61,
|
||||
0x46, 0x2e, 0x79, 0x05, 0x20, 0xd8, 0xe5, 0x89, 0x38, 0xd6, 0xd5, 0xd2, 0x89, 0xbb, 0x3a, 0x2d,
|
||||
0x72, 0xca, 0x09, 0x07, 0x34, 0xb8, 0x91, 0x1b, 0x00, 0x62, 0xd9, 0xec, 0x74, 0xdb, 0x94, 0x87,
|
||||
0x0d, 0xe5, 0xca, 0x5b, 0x93, 0xc1, 0xdf, 0x56, 0x98, 0x07, 0x87, 0xf3, 0xbd, 0x01, 0x2e, 0xcf,
|
||||
0x80, 0x1a, 0xcd, 0xc9, 0x87, 0x60, 0x3c, 0xea, 0xb4, 0x5a, 0x8e, 0xca, 0xa7, 0x6c, 0xe5, 0xb7,
|
||||
0x23, 0x0a, 0xbe, 0x7a, 0x6e, 0x4a, 0x00, 0x26, 0x12, 0x6d, 0x1f, 0x48, 0x2f, 0x3d, 0x79, 0x01,
|
||||
0x26, 0xe9, 0x41, 0x4c, 0x43, 0xdf, 0x69, 0xde, 0xc2, 0xb5, 0x24, 0x02, 0xe7, 0x1f, 0xff, 0xb2,
|
||||
0x01, 0xc7, 0x14, 0x15, 0xb1, 0x95, 0xe7, 0x5d, 0xe0, 0xf4, 0xa0, 0x3d, 0xef, 0xc4, 0xcf, 0xb6,
|
||||
0xff, 0xb3, 0x90, 0xf2, 0x08, 0x76, 0x42, 0x4a, 0x49, 0x00, 0xa3, 0x7e, 0x50, 0x55, 0x46, 0xef,
|
||||
0x7a, 0x3e, 0x46, 0x6f, 0x23, 0xa8, 0x1a, 0x67, 0xb9, 0xec, 0x57, 0x84, 0x42, 0x0e, 0x3f, 0xec,
|
||||
0x4a, 0x4e, 0x05, 0x39, 0x42, 0x3a, 0x41, 0x79, 0x4a, 0x56, 0x87, 0x5d, 0x9b, 0xa6, 0x20, 0x4c,
|
||||
0xcb, 0x25, 0x7b, 0x30, 0xda, 0x08, 0xa2, 0x58, 0xc4, 0x2a, 0x43, 0x7b, 0x61, 0xd7, 0x82, 0x28,
|
||||
0xe6, 0x5b, 0x98, 0xea, 0x36, 0x83, 0x44, 0x28, 0x64, 0xd8, 0xdf, 0xb3, 0x52, 0xf9, 0x96, 0x3b,
|
||||
0x4e, 0xec, 0x36, 0x2e, 0xef, 0x53, 0x9f, 0xcd, 0x67, 0x33, 0x59, 0xff, 0xa3, 0x66, 0xb2, 0xfe,
|
||||
0xc1, 0xe1, 0xfc, 0x5b, 0x06, 0x15, 0xd7, 0xdc, 0x63, 0x1c, 0x16, 0x38, 0x0b, 0x23, 0xaf, 0xff,
|
||||
0x31, 0x0b, 0x26, 0x0c, 0xf5, 0xe4, 0x86, 0x92, 0x63, 0xde, 0x58, 0x39, 0x57, 0x06, 0x10, 0x4d,
|
||||
0x91, 0xf6, 0x17, 0x2c, 0x18, 0xaf, 0x38, 0xee, 0x5e, 0x50, 0xab, 0xb1, 0x00, 0xbf, 0xda, 0x91,
|
||||
0xc7, 0x22, 0xa2, 0x7f, 0x2a, 0xc0, 0x5f, 0x91, 0x70, 0x54, 0x14, 0x6c, 0x0e, 0xd7, 0x1c, 0x37,
|
||||
0x0e, 0x42, 0xae, 0x76, 0x51, 0xcc, 0xe1, 0x2b, 0x1c, 0x82, 0x12, 0x43, 0xde, 0x01, 0x13, 0x2d,
|
||||
0xe7, 0x20, 0x69, 0x9c, 0x4d, 0xf6, 0xac, 0x6b, 0x14, 0x9a, 0x74, 0xf6, 0x1f, 0x96, 0x61, 0x5c,
|
||||
0x9e, 0x3f, 0x1e, 0xfb, 0x04, 0x21, 0xf1, 0xe2, 0x0b, 0x03, 0xbd, 0xf8, 0x08, 0xc6, 0x5c, 0x5e,
|
||||
0xba, 0x24, 0xb7, 0xd2, 0x21, 0xd3, 0x5e, 0x52, 0x41, 0x51, 0x0d, 0xa5, 0xd5, 0x12, 0xbf, 0x51,
|
||||
0x8a, 0x22, 0x9f, 0xb7, 0xe0, 0x94, 0x1b, 0xf8, 0x3e, 0x75, 0xb5, 0x9d, 0x1f, 0xc9, 0xe3, 0x84,
|
||||
0x6d, 0x39, 0xcd, 0x54, 0xa7, 0x88, 0x32, 0x08, 0xcc, 0x8a, 0x27, 0x2f, 0xc1, 0x94, 0x18, 0xb3,
|
||||
0xdb, 0xa9, 0xf8, 0x58, 0x9f, 0x39, 0x9b, 0x48, 0x4c, 0xd3, 0x92, 0x05, 0x91, 0x67, 0xe0, 0x87,
|
||||
0x30, 0x22, 0x46, 0x96, 0xf9, 0x46, 0x75, 0x4a, 0x13, 0xa1, 0x41, 0x41, 0x42, 0x20, 0x21, 0xad,
|
||||
0x85, 0x34, 0x6a, 0x20, 0x7d, 0xad, 0x43, 0xa3, 0x98, 0xef, 0x31, 0xe3, 0x8f, 0x76, 0x1e, 0x85,
|
||||
0x3d, 0x9c, 0xb0, 0x0f, 0x77, 0xb2, 0x27, 0x1d, 0xdd, 0x52, 0x1e, 0xcb, 0x49, 0x7e, 0xe6, 0x81,
|
||||
0xfe, 0xee, 0x3c, 0x8c, 0x46, 0x0d, 0x27, 0xac, 0xf2, 0xbd, 0xad, 0x58, 0x29, 0x33, 0x5b, 0xb2,
|
||||
0xcd, 0x00, 0x28, 0xe0, 0x64, 0x05, 0x4e, 0x67, 0x4e, 0xcc, 0x23, 0xbe, 0x7b, 0x95, 0x2a, 0xb3,
|
||||
0x92, 0xdd, 0xe9, 0xcc, 0x59, 0x7b, 0x84, 0x3d, 0x2d, 0xcc, 0x20, 0x68, 0xe2, 0x88, 0x20, 0xa8,
|
||||
0x0b, 0x63, 0x4d, 0x91, 0x08, 0x98, 0xe4, 0xa6, 0xf2, 0x66, 0x2e, 0x03, 0xb0, 0x60, 0x26, 0x60,
|
||||
0xd4, 0x6c, 0x97, 0x09, 0x05, 0x29, 0x90, 0x7c, 0x86, 0x19, 0x34, 0x23, 0x77, 0x30, 0xc5, 0x15,
|
||||
0xb8, 0x9d, 0x8f, 0x02, 0x3d, 0xa9, 0x12, 0x6d, 0xdd, 0x8c, 0x44, 0x84, 0x29, 0x7f, 0xee, 0xc7,
|
||||
0x60, 0xe2, 0x51, 0xf3, 0x0e, 0x2f, 0xc3, 0xe9, 0xa1, 0x32, 0x0e, 0xdf, 0xb7, 0x20, 0xf9, 0xae,
|
||||
0xcb, 0x8e, 0xdb, 0xa0, 0x6c, 0xca, 0x90, 0x97, 0x61, 0x5a, 0x85, 0x11, 0xcb, 0x41, 0xc7, 0x8f,
|
||||
0x39, 0xaf, 0xa2, 0xce, 0x25, 0x63, 0x0a, 0x8b, 0x19, 0x6a, 0xb2, 0x08, 0x65, 0x36, 0x4e, 0xa2,
|
||||
0xa9, 0x30, 0xbb, 0x2a, 0x54, 0x59, 0xda, 0x5a, 0x95, 0xad, 0x34, 0x0d, 0x09, 0x60, 0xa6, 0xe9,
|
||||
0x44, 0x31, 0xd7, 0x80, 0x45, 0x15, 0x8f, 0x78, 0x1a, 0xcc, 0x0b, 0x86, 0xd6, 0xb2, 0x8c, 0xb0,
|
||||
0x97, 0xb7, 0xfd, 0xcd, 0x11, 0x98, 0x4a, 0x59, 0x46, 0xb6, 0xab, 0x74, 0x22, 0xe6, 0xfa, 0xa8,
|
||||
0x14, 0x8b, 0xda, 0x55, 0x6e, 0x49, 0x38, 0x2a, 0x0a, 0x46, 0xdd, 0x76, 0xa2, 0xe8, 0x5e, 0x10,
|
||||
0x56, 0xa5, 0x29, 0x57, 0xd4, 0x5b, 0x12, 0x8e, 0x8a, 0x82, 0xed, 0x2f, 0xbb, 0xd4, 0x09, 0x69,
|
||||
0xc8, 0x0b, 0x28, 0xb2, 0xfb, 0x4b, 0x45, 0xa3, 0xd0, 0xa4, 0xe3, 0x46, 0x39, 0x6e, 0x46, 0xcb,
|
||||
0x4d, 0x8f, 0xfa, 0xb1, 0x50, 0x33, 0x1f, 0xa3, 0xbc, 0xb3, 0xb6, 0x6d, 0x32, 0xd5, 0x46, 0x39,
|
||||
0x83, 0xc0, 0xac, 0x78, 0xf2, 0x09, 0x0b, 0xa6, 0x9c, 0x7b, 0x91, 0xae, 0xaf, 0xe5, 0x56, 0x79,
|
||||
0xe8, 0x4d, 0x2a, 0x55, 0xb2, 0x5b, 0x99, 0x61, 0xe6, 0x3d, 0x05, 0xc2, 0xb4, 0x50, 0xf2, 0x25,
|
||||
0x0b, 0x08, 0x3d, 0xa0, 0xee, 0x56, 0x18, 0xec, 0x7b, 0xd5, 0xe4, 0x1b, 0xca, 0xf0, 0x67, 0x48,
|
||||
0x6f, 0xfb, 0x72, 0x0f, 0x5f, 0x61, 0xd5, 0x7b, 0xe1, 0xd8, 0x47, 0x07, 0xfb, 0xaf, 0x8a, 0x30,
|
||||
0x61, 0x18, 0xe3, 0xbe, 0x3b, 0xab, 0xf5, 0x03, 0xb6, 0xb3, 0x16, 0x4e, 0xb0, 0xb3, 0x7e, 0x14,
|
||||
0xca, 0x6e, 0x62, 0x28, 0xf2, 0xa9, 0x07, 0xce, 0x9a, 0x1f, 0x6d, 0x2b, 0x14, 0x08, 0xb5, 0x4c,
|
||||
0x72, 0x15, 0x66, 0x0c, 0x36, 0xd2, 0xc8, 0x8c, 0x70, 0x23, 0xa3, 0x12, 0x4d, 0x4b, 0x59, 0x02,
|
||||
0xec, 0x6d, 0x43, 0x9e, 0x67, 0x5e, 0xad, 0x27, 0xfb, 0x25, 0xa2, 0x78, 0x59, 0x6b, 0xbb, 0xb4,
|
||||
0xb5, 0x9a, 0x80, 0xd1, 0xa4, 0xb1, 0xbf, 0x69, 0xa9, 0x8f, 0xfb, 0x04, 0x0a, 0x35, 0xee, 0xa6,
|
||||
0x0b, 0x35, 0x2e, 0xe7, 0x32, 0xcc, 0x03, 0x8a, 0x34, 0x36, 0x60, 0x7c, 0x39, 0x68, 0xb5, 0x1c,
|
||||
0xbf, 0x4a, 0xde, 0x04, 0xe3, 0xae, 0xf8, 0x53, 0x86, 0x89, 0x13, 0x6c, 0xff, 0x96, 0x58, 0x4c,
|
||||
0x70, 0xe4, 0x19, 0x18, 0x71, 0xc2, 0x7a, 0x12, 0x1a, 0xf2, 0xb3, 0xa3, 0xa5, 0xb0, 0x1e, 0x21,
|
||||
0x87, 0xda, 0x5f, 0x2c, 0x00, 0x2c, 0x07, 0xad, 0xb6, 0x13, 0xd2, 0xea, 0x4e, 0xf0, 0xbf, 0x39,
|
||||
0x62, 0x11, 0x31, 0x7c, 0xda, 0x02, 0xc2, 0x46, 0x25, 0xf0, 0xa9, 0x1f, 0xab, 0xc3, 0x57, 0xb6,
|
||||
0x5f, 0xba, 0x09, 0x54, 0x6e, 0x3e, 0x7a, 0x0d, 0x24, 0x08, 0xd4, 0x34, 0xc7, 0x88, 0x22, 0x9e,
|
||||
0x4d, 0x76, 0xfc, 0x62, 0xba, 0xa6, 0x81, 0x1f, 0x94, 0x4a, 0x07, 0xc0, 0xfe, 0x5a, 0x01, 0xce,
|
||||
0x0b, 0xb3, 0xb5, 0xee, 0xf8, 0x4e, 0x9d, 0xb6, 0x98, 0x56, 0xc7, 0x3d, 0x6d, 0x70, 0x99, 0xfb,
|
||||
0xea, 0x25, 0x25, 0x0c, 0xc3, 0x4e, 0x4e, 0x31, 0xa9, 0xc4, 0x34, 0x5a, 0xf5, 0xbd, 0x18, 0x39,
|
||||
0x73, 0x12, 0x41, 0x29, 0xb9, 0xe1, 0x21, 0x8d, 0x4d, 0x4e, 0x82, 0xd4, 0xba, 0xbb, 0x2a, 0xd9,
|
||||
0xa3, 0x12, 0xc4, 0x36, 0xf7, 0x66, 0xe0, 0xee, 0x21, 0x6d, 0x07, 0xdc, 0xb0, 0x18, 0x27, 0xc8,
|
||||
0x6b, 0x12, 0x8e, 0x8a, 0xc2, 0xfe, 0x9a, 0x05, 0x59, 0x93, 0xcb, 0xa3, 0x41, 0x51, 0x33, 0x98,
|
||||
0x8d, 0x06, 0xd3, 0x25, 0x7e, 0x27, 0xa8, 0x98, 0x7b, 0x3f, 0x4c, 0x38, 0x71, 0x4c, 0x5b, 0x6d,
|
||||
0x11, 0x9a, 0x14, 0x1f, 0x2d, 0xfd, 0xb5, 0x1e, 0x54, 0xbd, 0x9a, 0xc7, 0x43, 0x12, 0x93, 0x9d,
|
||||
0x7d, 0x13, 0x4a, 0xc9, 0x89, 0xcf, 0x31, 0x3e, 0xfd, 0xb3, 0x29, 0x77, 0x72, 0xc0, 0xe4, 0x7a,
|
||||
0x50, 0x80, 0x3e, 0x7b, 0x26, 0xeb, 0xb2, 0xb6, 0x2e, 0xa9, 0x2e, 0x9f, 0xcc, 0xc2, 0x90, 0x03,
|
||||
0x71, 0xda, 0x25, 0xf2, 0x2c, 0xef, 0xcd, 0x7b, 0xcf, 0xd7, 0x07, 0x60, 0x13, 0x52, 0x3f, 0x75,
|
||||
0x08, 0x46, 0x2e, 0x01, 0xe8, 0x4d, 0x41, 0x16, 0x7a, 0xa8, 0x4c, 0xad, 0xde, 0x3b, 0xd0, 0xa0,
|
||||
0x62, 0x2e, 0xa0, 0xe7, 0x47, 0xb1, 0xd3, 0x6c, 0x5e, 0xf3, 0xfc, 0x58, 0xc6, 0xb2, 0xca, 0x60,
|
||||
0xac, 0x6a, 0x14, 0x9a, 0x74, 0x73, 0xef, 0x34, 0xbe, 0xcb, 0x49, 0xdc, 0xfa, 0x4f, 0x17, 0x60,
|
||||
0xfa, 0xaa, 0xdf, 0xd9, 0xba, 0xba, 0xd5, 0xd9, 0x6d, 0x7a, 0xee, 0x0d, 0xda, 0x65, 0x1f, 0x6d,
|
||||
0x8f, 0x76, 0x57, 0x57, 0xe4, 0xb0, 0xab, 0x8f, 0x76, 0x83, 0x01, 0x51, 0xe0, 0x98, 0x9a, 0x35,
|
||||
0xcf, 0xaf, 0xd3, 0xb0, 0x1d, 0x7a, 0xd2, 0x77, 0x37, 0xd4, 0xbc, 0xa2, 0x51, 0x68, 0xd2, 0x31,
|
||||
0xde, 0xc1, 0x3d, 0x9f, 0x86, 0x59, 0x6b, 0xb3, 0xc9, 0x80, 0x28, 0x70, 0x8c, 0x28, 0x0e, 0x3b,
|
||||
0x51, 0x2c, 0x47, 0x4c, 0x11, 0xed, 0x30, 0x20, 0x0a, 0x1c, 0x9b, 0x1e, 0x51, 0x67, 0x97, 0x67,
|
||||
0x61, 0x33, 0xe7, 0xe1, 0xdb, 0x02, 0x8c, 0x09, 0x9e, 0x91, 0xee, 0xd1, 0xee, 0x0a, 0xdb, 0x7b,
|
||||
0x33, 0x15, 0x2b, 0x37, 0x04, 0x18, 0x13, 0xbc, 0xfd, 0xf7, 0x16, 0x90, 0xf4, 0x70, 0x3c, 0x81,
|
||||
0xed, 0xfb, 0xb5, 0xf4, 0xf6, 0x3d, 0x64, 0xc2, 0x3c, 0xad, 0xfe, 0x80, 0x5d, 0xfc, 0x57, 0x2c,
|
||||
0x98, 0x34, 0xcf, 0x4e, 0x48, 0x3d, 0x63, 0x88, 0x36, 0xd3, 0x86, 0xe8, 0xc1, 0xe1, 0xfc, 0x8f,
|
||||
0xf7, 0xbb, 0xae, 0x58, 0xf7, 0xe2, 0xa0, 0x1d, 0xbd, 0x9d, 0xfa, 0x75, 0xcf, 0xa7, 0x3c, 0x33,
|
||||
0x28, 0xce, 0x5c, 0x52, 0x07, 0x33, 0xcb, 0x41, 0x95, 0x3e, 0x82, 0x25, 0xb3, 0xef, 0xc0, 0x4c,
|
||||
0x4f, 0x99, 0xd2, 0x31, 0x8c, 0xce, 0x91, 0x55, 0xa0, 0x36, 0xc2, 0x04, 0x63, 0xbc, 0xd9, 0x16,
|
||||
0x87, 0x23, 0xcb, 0x30, 0x23, 0xaa, 0xad, 0x98, 0xa4, 0x6d, 0xb7, 0x41, 0x5b, 0xaa, 0xf4, 0x8c,
|
||||
0x07, 0x8a, 0xb7, 0xb3, 0x48, 0xec, 0xa5, 0xb7, 0x3f, 0x63, 0xc1, 0x54, 0xaa, 0x72, 0x2c, 0x27,
|
||||
0xf3, 0xc8, 0x57, 0x5a, 0xc0, 0x8f, 0xf2, 0x42, 0xcf, 0x17, 0xb9, 0xbe, 0x92, 0xb1, 0xd2, 0x34,
|
||||
0x0a, 0x4d, 0x3a, 0xfb, 0x0b, 0x05, 0x28, 0x25, 0x59, 0xe1, 0x63, 0xa8, 0xf2, 0x29, 0x0b, 0xa6,
|
||||
0x54, 0x70, 0xce, 0x5d, 0x76, 0x31, 0x19, 0x37, 0x86, 0xcf, 0x4b, 0xab, 0xf3, 0x5e, 0xe6, 0xb2,
|
||||
0xab, 0xd8, 0x01, 0x4d, 0x61, 0x98, 0x96, 0x4d, 0x6e, 0x03, 0x44, 0xdd, 0x28, 0xa6, 0x2d, 0x23,
|
||||
0x78, 0xb0, 0x8d, 0x15, 0xb7, 0xe0, 0x06, 0x21, 0x65, 0xeb, 0x6b, 0x23, 0xa8, 0xd2, 0x6d, 0x45,
|
||||
0xa9, 0x8d, 0xab, 0x86, 0xa1, 0xc1, 0xc9, 0xfe, 0xcd, 0x02, 0x9c, 0xce, 0xaa, 0x44, 0xde, 0x07,
|
||||
0x93, 0x89, 0x74, 0xe3, 0xe6, 0x67, 0x92, 0x0a, 0x9f, 0x44, 0x03, 0xf7, 0xe0, 0x70, 0x7e, 0xbe,
|
||||
0xf7, 0xea, 0xeb, 0x82, 0x49, 0x82, 0x29, 0x66, 0x22, 0x43, 0x22, 0x53, 0x79, 0x95, 0xee, 0x52,
|
||||
0xbb, 0x2d, 0xd3, 0x1c, 0x46, 0x86, 0xc4, 0xc4, 0x62, 0x86, 0x9a, 0x6c, 0xc1, 0x59, 0x03, 0xb2,
|
||||
0x41, 0xbd, 0x7a, 0x63, 0x37, 0x08, 0xc5, 0x15, 0x83, 0x62, 0xe5, 0x19, 0xc9, 0xe5, 0x2c, 0xf6,
|
||||
0xa1, 0xc1, 0xbe, 0x2d, 0x99, 0xd3, 0xe2, 0x3a, 0x6d, 0xc7, 0xf5, 0xe2, 0xae, 0x8c, 0x86, 0x94,
|
||||
0x6d, 0x5a, 0x96, 0x70, 0x54, 0x14, 0xf6, 0x3a, 0x8c, 0x1c, 0x73, 0x06, 0x1d, 0x6b, 0xaf, 0xbf,
|
||||
0x09, 0x25, 0xc6, 0x8e, 0xd9, 0xa2, 0xbc, 0x58, 0x06, 0x50, 0x4a, 0x6e, 0x9c, 0x10, 0x1b, 0x8a,
|
||||
0x9e, 0x93, 0x24, 0xa1, 0x54, 0xb7, 0x56, 0xa3, 0xa8, 0xc3, 0x3d, 0x19, 0x86, 0x24, 0xcf, 0x42,
|
||||
0x91, 0x1e, 0xb4, 0xb3, 0xd9, 0xa6, 0xcb, 0x07, 0x6d, 0x2f, 0xa4, 0x11, 0x23, 0xa2, 0x07, 0x6d,
|
||||
0x32, 0x07, 0x05, 0xaf, 0x2a, 0x37, 0x29, 0x90, 0x34, 0x85, 0xd5, 0x15, 0x2c, 0x78, 0x55, 0xfb,
|
||||
0x00, 0xca, 0xea, 0x8a, 0x0b, 0xd9, 0x4b, 0x6c, 0xb7, 0x95, 0xc7, 0x31, 0x4e, 0xc2, 0x77, 0x80,
|
||||
0xd5, 0xee, 0x00, 0xe8, 0x3a, 0xbd, 0xbc, 0xec, 0xcb, 0x45, 0x18, 0x71, 0x03, 0x59, 0xde, 0x5b,
|
||||
0xd2, 0x6c, 0xb8, 0xd1, 0xe6, 0x18, 0xfb, 0x0e, 0x4c, 0xdf, 0xf0, 0x83, 0x7b, 0x3e, 0xdb, 0x4c,
|
||||
0xaf, 0x78, 0xb4, 0x59, 0x65, 0x8c, 0x6b, 0xec, 0x8f, 0xac, 0x8b, 0xc0, 0xb1, 0x28, 0x70, 0xea,
|
||||
0x1e, 0x48, 0x61, 0xd0, 0x3d, 0x10, 0xfb, 0x63, 0x16, 0x9c, 0x56, 0x05, 0x64, 0x89, 0x35, 0x7e,
|
||||
0x11, 0x26, 0x77, 0x3b, 0x5e, 0xb3, 0x2a, 0x7f, 0x4b, 0x11, 0xaa, 0x44, 0xae, 0x62, 0xe0, 0x30,
|
||||
0x45, 0xc9, 0xdc, 0xad, 0x5d, 0xcf, 0x77, 0xc2, 0xee, 0x96, 0x36, 0xff, 0xca, 0x22, 0x54, 0x14,
|
||||
0x06, 0x0d, 0x2a, 0xfb, 0xcf, 0x8b, 0xa0, 0xaf, 0xb7, 0x10, 0x4f, 0x56, 0x42, 0x58, 0x79, 0xe4,
|
||||
0xaa, 0xb6, 0xbb, 0xbe, 0xab, 0x2f, 0xd2, 0x94, 0x32, 0x85, 0x10, 0x9f, 0xb4, 0x98, 0xa3, 0xe7,
|
||||
0xc5, 0x9e, 0xc3, 0xd7, 0xa7, 0x8c, 0x8e, 0xb6, 0x72, 0x3a, 0x2c, 0x5f, 0x15, 0x9c, 0x83, 0xd0,
|
||||
0x74, 0x1d, 0x95, 0x30, 0x34, 0x25, 0x93, 0x57, 0xe5, 0xf1, 0x42, 0x31, 0xb7, 0x3a, 0x9a, 0x52,
|
||||
0xe6, 0x4c, 0xa1, 0x0d, 0xa3, 0x21, 0x8d, 0xc3, 0xa4, 0x82, 0xe9, 0xc6, 0xb0, 0x87, 0xad, 0x71,
|
||||
0xd8, 0xdd, 0x8e, 0x59, 0x04, 0x56, 0x37, 0xfc, 0x1b, 0x0e, 0x46, 0x21, 0xc8, 0x8e, 0x80, 0xf4,
|
||||
0x8e, 0xc5, 0x09, 0x53, 0xb7, 0x8b, 0x50, 0x76, 0x3a, 0x71, 0xd0, 0x62, 0xc3, 0xc4, 0x3f, 0x4f,
|
||||
0xc9, 0x48, 0x4e, 0x27, 0x08, 0xd4, 0x34, 0xf6, 0xe7, 0x46, 0x21, 0x53, 0x9a, 0x40, 0x0e, 0xcc,
|
||||
0xab, 0x59, 0x56, 0xbe, 0x57, 0xb3, 0x94, 0x32, 0xfd, 0xae, 0x67, 0x91, 0x3a, 0x8c, 0xb6, 0x1b,
|
||||
0x4e, 0x94, 0x2c, 0xbf, 0x9b, 0xc9, 0x30, 0x6d, 0x31, 0xe0, 0x83, 0xc3, 0xf9, 0x9f, 0x38, 0x9e,
|
||||
0x3b, 0xc7, 0xe6, 0xea, 0xa2, 0xa8, 0xd3, 0xd4, 0xa2, 0x39, 0x0f, 0x14, 0xfc, 0x4d, 0x87, 0xae,
|
||||
0x78, 0x44, 0x68, 0xfa, 0x71, 0x4b, 0xd4, 0xb3, 0x21, 0x8d, 0x3a, 0xcd, 0x58, 0xce, 0x86, 0x9b,
|
||||
0x39, 0xae, 0x32, 0xc1, 0x58, 0x17, 0xb6, 0x89, 0xdf, 0x68, 0x08, 0x25, 0xef, 0x83, 0x72, 0x14,
|
||||
0x3b, 0x61, 0xfc, 0x88, 0x65, 0x30, 0x6a, 0xd0, 0xb7, 0x13, 0x26, 0xa8, 0xf9, 0x91, 0x57, 0x00,
|
||||
0x6a, 0x9e, 0xef, 0x45, 0x8d, 0x47, 0x3c, 0x15, 0xe4, 0x8a, 0x5f, 0x51, 0x1c, 0xd0, 0xe0, 0xc6,
|
||||
0xac, 0x1b, 0x9f, 0xdb, 0x22, 0x8f, 0x59, 0xe2, 0xdb, 0x97, 0xb2, 0x6e, 0xa8, 0x30, 0x68, 0x50,
|
||||
0xd9, 0x1f, 0x81, 0x33, 0xd9, 0x6b, 0xd1, 0x32, 0xc2, 0xab, 0x87, 0x41, 0xa7, 0x9d, 0x35, 0xdf,
|
||||
0xfc, 0xda, 0x2c, 0x0a, 0x1c, 0x33, 0xdf, 0x7b, 0x9e, 0x5f, 0xcd, 0x9a, 0xef, 0x1b, 0x9e, 0x5f,
|
||||
0x45, 0x8e, 0x39, 0xc6, 0x9d, 0xb5, 0xdf, 0xb7, 0xe0, 0xe2, 0x51, 0xb7, 0xb7, 0x59, 0xf4, 0x7e,
|
||||
0xcf, 0x09, 0x7d, 0x79, 0x1d, 0x86, 0xdb, 0x8e, 0x3b, 0x4e, 0xe8, 0x23, 0x87, 0x92, 0x2e, 0x8c,
|
||||
0x89, 0xd2, 0x3f, 0xe9, 0x90, 0xde, 0xcc, 0xf7, 0x2e, 0x39, 0x0b, 0x91, 0x54, 0xd2, 0x45, 0x94,
|
||||
0x1d, 0xa2, 0x14, 0x68, 0x7f, 0xc7, 0x02, 0xb2, 0xb9, 0x4f, 0xc3, 0xd0, 0xab, 0x1a, 0xc5, 0x8a,
|
||||
0xe4, 0x05, 0x98, 0xbc, 0xbb, 0xbd, 0xb9, 0xb1, 0x15, 0x78, 0x3e, 0xbf, 0x8f, 0x61, 0x94, 0xc8,
|
||||
0x5c, 0x37, 0xe0, 0x98, 0xa2, 0x62, 0x41, 0xc6, 0xdd, 0xd7, 0xd8, 0x96, 0x73, 0xf9, 0xa0, 0x1d,
|
||||
0xd2, 0x28, 0x52, 0x2f, 0x30, 0xc8, 0x20, 0xe3, 0xfa, 0xcd, 0x0c, 0x12, 0x7b, 0xe9, 0xc9, 0x26,
|
||||
0x9c, 0x6b, 0xf1, 0x04, 0x5c, 0x95, 0xef, 0xb4, 0x91, 0xc8, 0xc6, 0x85, 0x49, 0xc1, 0xfb, 0x1b,
|
||||
0xee, 0x1f, 0xce, 0x9f, 0x5b, 0xef, 0x47, 0x80, 0xfd, 0xdb, 0xd9, 0x5f, 0x2d, 0xc0, 0x84, 0xf1,
|
||||
0x02, 0xc2, 0x31, 0x7c, 0x8a, 0xcc, 0xa3, 0x0d, 0x85, 0x63, 0x3e, 0xda, 0xf0, 0x1c, 0x94, 0xda,
|
||||
0x41, 0xd3, 0x73, 0x3d, 0x55, 0x9d, 0x3f, 0xc9, 0xcf, 0xc0, 0x24, 0x0c, 0x15, 0x96, 0xdc, 0x83,
|
||||
0xb2, 0xba, 0xca, 0x2c, 0xeb, 0xf5, 0xf2, 0xf2, 0xaa, 0xd4, 0xe2, 0xd5, 0x57, 0x94, 0xb5, 0x2c,
|
||||
0x62, 0xc3, 0x18, 0x9f, 0xf9, 0x49, 0x86, 0x9f, 0x17, 0x80, 0xf0, 0x25, 0x11, 0xa1, 0xc4, 0xd8,
|
||||
0xff, 0x34, 0x0a, 0x65, 0xa4, 0xed, 0x60, 0x39, 0xa4, 0xd5, 0x88, 0xbc, 0x11, 0x8a, 0x9d, 0xb0,
|
||||
0x29, 0x07, 0x4b, 0xa5, 0x7f, 0x6e, 0xe1, 0x1a, 0x32, 0x78, 0x6a, 0xbb, 0x29, 0x9c, 0xe8, 0xa4,
|
||||
0xb0, 0x78, 0xe4, 0x49, 0xe1, 0x4b, 0x30, 0x15, 0x45, 0x8d, 0xad, 0xd0, 0xdb, 0x77, 0x62, 0x36,
|
||||
0x89, 0x65, 0xae, 0x44, 0x1f, 0xcd, 0x6c, 0x5f, 0xd3, 0x48, 0x4c, 0xd3, 0x92, 0xab, 0x30, 0xa3,
|
||||
0xcf, 0xeb, 0x68, 0x18, 0xf3, 0xd4, 0x88, 0xc8, 0xa2, 0xa8, 0x93, 0x11, 0x7d, 0xc2, 0x27, 0x09,
|
||||
0xb0, 0xb7, 0x0d, 0x59, 0x81, 0xd3, 0x29, 0x20, 0x53, 0x44, 0xa4, 0x58, 0x54, 0x2d, 0x40, 0x8a,
|
||||
0x0f, 0xd3, 0xa5, 0xa7, 0x05, 0x59, 0x87, 0x33, 0xe2, 0xfb, 0xf2, 0x2b, 0xf0, 0xaa, 0x47, 0xe3,
|
||||
0x9c, 0xd1, 0xff, 0x91, 0x8c, 0xce, 0x5c, 0xed, 0x25, 0xc1, 0x7e, 0xed, 0xd8, 0x0c, 0x55, 0xe0,
|
||||
0xd5, 0x15, 0x69, 0x29, 0xd5, 0x0c, 0x55, 0x6c, 0x56, 0xab, 0x68, 0xd2, 0x91, 0xf7, 0xc2, 0xd3,
|
||||
0xfa, 0xa7, 0xc8, 0xac, 0x09, 0xf7, 0x61, 0x45, 0x96, 0x42, 0xa8, 0x9b, 0x46, 0x57, 0xfb, 0x92,
|
||||
0x55, 0x71, 0x50, 0x7b, 0xb2, 0x0b, 0x73, 0x0a, 0x75, 0x99, 0x99, 0x83, 0x76, 0xe8, 0x45, 0xb4,
|
||||
0xe2, 0x44, 0xf4, 0x56, 0xd8, 0xe4, 0xc5, 0x13, 0x65, 0xfd, 0x8c, 0xc3, 0x55, 0x2f, 0xbe, 0xd6,
|
||||
0x8f, 0x12, 0xd7, 0xf0, 0x21, 0x5c, 0x98, 0xb7, 0x42, 0x7d, 0x67, 0xb7, 0x49, 0x37, 0x97, 0x57,
|
||||
0x79, 0x49, 0x85, 0xe1, 0xad, 0x5c, 0x4e, 0x10, 0xa8, 0x69, 0x94, 0x7b, 0x3e, 0x39, 0xd0, 0x3d,
|
||||
0xff, 0xb6, 0x05, 0x53, 0x6a, 0xb2, 0x3f, 0x81, 0x3c, 0x58, 0x33, 0x9d, 0x07, 0xbb, 0x3a, 0xac,
|
||||
0x9b, 0x28, 0x35, 0x1f, 0x10, 0x4c, 0x7d, 0xaf, 0x0c, 0xc0, 0x1f, 0xc6, 0xf1, 0x78, 0xa9, 0xee,
|
||||
0x45, 0x18, 0x09, 0x69, 0x3b, 0xc8, 0x5a, 0x3e, 0x9e, 0xc3, 0xe7, 0x98, 0x1f, 0xdc, 0xe5, 0xdc,
|
||||
0xef, 0xe4, 0x78, 0xf4, 0x7f, 0xf6, 0xe4, 0x78, 0x1b, 0xce, 0x79, 0x7e, 0x44, 0xdd, 0x4e, 0x28,
|
||||
0x77, 0xce, 0x6b, 0x41, 0xa4, 0xac, 0x43, 0xa9, 0xf2, 0x46, 0xc9, 0xe8, 0xdc, 0x6a, 0x3f, 0x22,
|
||||
0xec, 0xdf, 0x96, 0x0d, 0x69, 0x82, 0x90, 0x77, 0x82, 0x74, 0x88, 0x2f, 0xe1, 0xa8, 0x28, 0xf4,
|
||||
0x82, 0x58, 0xab, 0x25, 0x97, 0x7e, 0x32, 0x0b, 0x62, 0xed, 0xca, 0x36, 0x6a, 0x9a, 0xfe, 0x56,
|
||||
0xb1, 0x9c, 0x93, 0x55, 0x84, 0x13, 0x5b, 0xc5, 0x64, 0x7d, 0x4e, 0x0c, 0x7c, 0x46, 0x21, 0xd9,
|
||||
0xac, 0x27, 0x07, 0x6e, 0xd6, 0x2f, 0xc3, 0xb4, 0xe7, 0x37, 0x68, 0xe8, 0xc5, 0xb4, 0xca, 0xd7,
|
||||
0xc2, 0xec, 0x14, 0x1f, 0x08, 0x95, 0x7d, 0x5a, 0x4d, 0x61, 0x31, 0x43, 0x9d, 0x36, 0x2a, 0xd3,
|
||||
0xc7, 0x30, 0x2a, 0x03, 0x4c, 0xf9, 0xa9, 0x7c, 0x4c, 0xf9, 0xe9, 0xe1, 0x4d, 0xf9, 0xcc, 0x63,
|
||||
0x35, 0xe5, 0x24, 0x17, 0x53, 0xfe, 0x2c, 0x8c, 0xb6, 0xc3, 0xe0, 0xa0, 0x3b, 0x7b, 0x26, 0xed,
|
||||
0x9e, 0x6f, 0x31, 0x20, 0x0a, 0x9c, 0x59, 0x40, 0x77, 0xf6, 0xe1, 0x05, 0x74, 0xf6, 0xeb, 0x05,
|
||||
0x38, 0xa7, 0x2d, 0x1d, 0x9b, 0x5f, 0x5e, 0x8d, 0xad, 0x75, 0x7e, 0x33, 0x53, 0x14, 0x6d, 0x18,
|
||||
0x89, 0x4f, 0x9d, 0x43, 0x55, 0x18, 0x34, 0xa8, 0x78, 0xfe, 0x90, 0x86, 0xbc, 0xec, 0x37, 0x6b,
|
||||
0x06, 0x97, 0x25, 0x1c, 0x15, 0x05, 0x7f, 0x55, 0x8f, 0x86, 0xb1, 0x3c, 0x93, 0xc9, 0x56, 0x34,
|
||||
0x2d, 0x6b, 0x14, 0x9a, 0x74, 0xcc, 0x5d, 0x74, 0x93, 0x25, 0xc8, 0x4c, 0xe1, 0xa4, 0x70, 0x17,
|
||||
0xd5, 0xaa, 0x53, 0xd8, 0x44, 0x1d, 0x9e, 0x28, 0x1e, 0xed, 0x55, 0x87, 0x67, 0x21, 0x14, 0x85,
|
||||
0xfd, 0x1f, 0x16, 0xbc, 0xa1, 0xef, 0x50, 0x3c, 0x81, 0xed, 0xed, 0x20, 0xbd, 0xbd, 0x6d, 0x0f,
|
||||
0xbf, 0xbd, 0xf5, 0xf4, 0x62, 0xc0, 0x56, 0xf7, 0x97, 0x16, 0x4c, 0x6b, 0xfa, 0x27, 0xd0, 0x55,
|
||||
0x2f, 0xd7, 0xf7, 0xf1, 0xb4, 0xea, 0xa2, 0x1c, 0x35, 0xd5, 0xb7, 0x6f, 0xf3, 0xbe, 0x89, 0x60,
|
||||
0x6e, 0xc9, 0x4d, 0x1e, 0xa0, 0x39, 0x22, 0x88, 0xe9, 0xc2, 0x18, 0xbf, 0xc2, 0x1f, 0xe5, 0x13,
|
||||
0x54, 0xa6, 0xe5, 0xf3, 0x13, 0x20, 0x1d, 0x54, 0xf2, 0x9f, 0x11, 0x4a, 0x81, 0xbc, 0x28, 0xdd,
|
||||
0x8b, 0x98, 0xbd, 0xac, 0xca, 0x94, 0xab, 0x2e, 0x4a, 0x97, 0x70, 0x54, 0x14, 0x76, 0x0b, 0x66,
|
||||
0xd3, 0xcc, 0x57, 0x68, 0x8d, 0xe7, 0xee, 0x8e, 0xd5, 0xcd, 0x45, 0x28, 0x3b, 0xbc, 0xd5, 0x5a,
|
||||
0xc7, 0xc9, 0xbe, 0x42, 0xb3, 0x94, 0x20, 0x50, 0xd3, 0xd8, 0xbf, 0x61, 0xc1, 0x99, 0x3e, 0x9d,
|
||||
0xc9, 0x31, 0xd5, 0x1c, 0x6b, 0x2b, 0x30, 0xe0, 0x65, 0xa0, 0x2a, 0xad, 0x39, 0x49, 0x76, 0xc8,
|
||||
0xb0, 0x6a, 0x2b, 0x02, 0x8c, 0x09, 0xde, 0xfe, 0x67, 0x0b, 0x4e, 0xa5, 0x75, 0x8d, 0xc8, 0x75,
|
||||
0x20, 0xa2, 0x33, 0x2b, 0x5e, 0xe4, 0x06, 0xfb, 0x34, 0xec, 0xb2, 0x9e, 0x0b, 0xad, 0xe7, 0x24,
|
||||
0x27, 0xb2, 0xd4, 0x43, 0x81, 0x7d, 0x5a, 0xf1, 0xda, 0xdf, 0xaa, 0x1a, 0xed, 0x64, 0xa6, 0xdc,
|
||||
0xce, 0x73, 0xa6, 0xe8, 0x8f, 0x69, 0x46, 0xd0, 0x4a, 0x24, 0x9a, 0xf2, 0xed, 0xef, 0x8c, 0x80,
|
||||
0x3a, 0x8b, 0xe2, 0x79, 0x88, 0x9c, 0xb2, 0x38, 0xa9, 0xa7, 0x8a, 0x8a, 0x27, 0x78, 0xaa, 0x68,
|
||||
0xe4, 0x61, 0x39, 0x02, 0xf1, 0x6e, 0x8e, 0xf6, 0x45, 0x0d, 0xa3, 0xbf, 0xa3, 0x51, 0x68, 0xd2,
|
||||
0x31, 0x4d, 0x9a, 0xde, 0x3e, 0x15, 0x8d, 0xc6, 0xd2, 0x9a, 0xac, 0x25, 0x08, 0xd4, 0x34, 0x4c,
|
||||
0x93, 0xaa, 0x57, 0xab, 0xc9, 0x48, 0x51, 0x69, 0xc2, 0x46, 0x07, 0x39, 0x86, 0x51, 0x34, 0x82,
|
||||
0x60, 0x4f, 0xfa, 0x7f, 0x8a, 0xe2, 0x5a, 0x10, 0xec, 0x21, 0xc7, 0x30, 0x8f, 0xc5, 0x0f, 0xc2,
|
||||
0x96, 0xd3, 0xf4, 0x3e, 0x48, 0xab, 0x4a, 0x8a, 0xf4, 0xfb, 0x94, 0xc7, 0xb2, 0xd1, 0x4b, 0x82,
|
||||
0xfd, 0xda, 0xb1, 0x19, 0xd8, 0x0e, 0x69, 0xd5, 0x73, 0x63, 0x93, 0x1b, 0xa4, 0x67, 0xe0, 0x56,
|
||||
0x0f, 0x05, 0xf6, 0x69, 0x45, 0x96, 0xe0, 0x54, 0x72, 0x96, 0x98, 0xd4, 0x90, 0x08, 0x67, 0x50,
|
||||
0xf9, 0xe1, 0x98, 0x46, 0x63, 0x96, 0x9e, 0x59, 0x9b, 0x96, 0xac, 0xe4, 0xe1, 0x6e, 0xa2, 0x61,
|
||||
0x6d, 0x92, 0x0a, 0x1f, 0x54, 0x14, 0xf6, 0xc7, 0x8b, 0x6c, 0x77, 0x1c, 0x70, 0x3b, 0xf7, 0x89,
|
||||
0x65, 0x0d, 0xd3, 0x33, 0x72, 0xe4, 0x18, 0x33, 0xf2, 0x05, 0x98, 0xbc, 0x1b, 0x05, 0xbe, 0xca,
|
||||
0xc8, 0x8d, 0x0e, 0xcc, 0xc8, 0x19, 0x54, 0xfd, 0x33, 0x72, 0x63, 0x79, 0x65, 0xe4, 0xc6, 0x1f,
|
||||
0x31, 0x23, 0xf7, 0x27, 0xa3, 0x70, 0x5e, 0x9d, 0x27, 0xd3, 0xf8, 0x5e, 0x10, 0xee, 0x79, 0x7e,
|
||||
0x9d, 0x9f, 0xc1, 0x7e, 0xc5, 0x82, 0x49, 0xb1, 0x5e, 0xe4, 0xc3, 0x08, 0xe2, 0xcc, 0xb1, 0x96,
|
||||
0xd3, 0xdd, 0xb5, 0x94, 0xb0, 0x85, 0x1d, 0x43, 0x50, 0xe6, 0x95, 0x0a, 0x13, 0x85, 0x29, 0x8d,
|
||||
0xc8, 0x87, 0x01, 0x92, 0x17, 0xb3, 0x6a, 0x39, 0xbd, 0x1b, 0x96, 0xe8, 0x87, 0xb4, 0xa6, 0x7d,
|
||||
0xd3, 0x1d, 0x25, 0x04, 0x0d, 0x81, 0xe4, 0x75, 0x4b, 0xdd, 0x15, 0x11, 0xa7, 0x59, 0xaf, 0x3e,
|
||||
0x96, 0xb1, 0x39, 0xce, 0xd5, 0x11, 0x84, 0x71, 0xcf, 0xaf, 0xb3, 0x79, 0x22, 0x93, 0x98, 0x6f,
|
||||
0xe9, 0x57, 0xbf, 0xb0, 0x16, 0x38, 0xd5, 0x8a, 0xd3, 0x74, 0x7c, 0x97, 0x86, 0xab, 0x82, 0xdc,
|
||||
0x7c, 0x36, 0x89, 0x03, 0x30, 0x61, 0xd4, 0x73, 0x39, 0x73, 0xf4, 0x38, 0x97, 0x33, 0xe7, 0xde,
|
||||
0x03, 0x33, 0x3d, 0x1f, 0xf3, 0x44, 0x57, 0x47, 0x1e, 0xfd, 0xd6, 0x89, 0xfd, 0x07, 0x63, 0x7a,
|
||||
0xd3, 0xda, 0x08, 0xaa, 0xe2, 0x8a, 0x60, 0xa8, 0xbf, 0xa8, 0xf4, 0x3d, 0x73, 0x9c, 0x22, 0xc6,
|
||||
0xd3, 0x4b, 0x0a, 0x88, 0xa6, 0x48, 0x36, 0x47, 0xdb, 0x4e, 0x48, 0xfd, 0xc7, 0x3d, 0x47, 0xb7,
|
||||
0x94, 0x10, 0x34, 0x04, 0x92, 0x46, 0xea, 0xb8, 0xf5, 0xca, 0xf0, 0xc7, 0xad, 0xcc, 0x1d, 0xee,
|
||||
0x7b, 0x95, 0xeb, 0xf3, 0x16, 0x4c, 0xfb, 0xa9, 0x99, 0x2b, 0x8f, 0xdc, 0x76, 0x1e, 0xc7, 0xaa,
|
||||
0x10, 0x57, 0xb3, 0xd3, 0x30, 0xcc, 0xc8, 0xef, 0xb7, 0xa5, 0x8d, 0x9e, 0x70, 0x4b, 0xd3, 0x77,
|
||||
0x8d, 0xc7, 0x06, 0xdd, 0x35, 0x26, 0xbe, 0x7a, 0x65, 0x60, 0x3c, 0xf7, 0x57, 0x06, 0xa0, 0xcf,
|
||||
0x0b, 0x03, 0x77, 0xa0, 0xec, 0x86, 0xd4, 0x89, 0x1f, 0xf1, 0xc2, 0x39, 0x7f, 0xec, 0x6e, 0x39,
|
||||
0x61, 0x80, 0x9a, 0x97, 0xfd, 0x67, 0x45, 0x38, 0x9d, 0x8c, 0x48, 0x72, 0x14, 0xc5, 0xf6, 0x47,
|
||||
0x21, 0x57, 0x3b, 0xb7, 0x6a, 0x7f, 0xbc, 0x96, 0x20, 0x50, 0xd3, 0x30, 0x7f, 0xac, 0x13, 0xd1,
|
||||
0xcd, 0x36, 0xf5, 0xd7, 0xbc, 0xdd, 0x88, 0x8f, 0xb8, 0x51, 0x42, 0x76, 0x4b, 0xa3, 0xd0, 0xa4,
|
||||
0x63, 0xce, 0xb8, 0xf0, 0x8b, 0xa3, 0xec, 0xc9, 0xae, 0xf4, 0xb7, 0x31, 0xc1, 0x93, 0x2f, 0xf7,
|
||||
0x7d, 0x2e, 0x24, 0x9f, 0x9a, 0x86, 0x9e, 0x13, 0xb8, 0x13, 0xbe, 0x13, 0xf2, 0x39, 0x0b, 0x4e,
|
||||
0xed, 0xa5, 0xea, 0x57, 0x12, 0x93, 0x3c, 0x64, 0xa5, 0x65, 0xba, 0x28, 0x46, 0x4f, 0xe1, 0x34,
|
||||
0x3c, 0xc2, 0xac, 0x74, 0xfb, 0xdf, 0x2c, 0x30, 0xcd, 0xd3, 0xf1, 0x3c, 0x2b, 0xe3, 0x01, 0xa8,
|
||||
0xc2, 0x11, 0x0f, 0x40, 0x25, 0x4e, 0x58, 0xf1, 0x78, 0x4e, 0xff, 0xc8, 0x09, 0x9c, 0xfe, 0xd1,
|
||||
0x81, 0x5e, 0xdb, 0x1b, 0xa1, 0xd8, 0xf1, 0xaa, 0xd2, 0x6f, 0xd7, 0x87, 0x61, 0xab, 0x2b, 0xc8,
|
||||
0xe0, 0xf6, 0xef, 0x8d, 0xea, 0x38, 0x5d, 0x1e, 0xc5, 0xff, 0x50, 0x74, 0xbb, 0xa6, 0x0a, 0x67,
|
||||
0x45, 0xcf, 0x37, 0x7a, 0x0a, 0x67, 0xdf, 0x7d, 0xf2, 0x4a, 0x0b, 0x31, 0x40, 0x83, 0xea, 0x66,
|
||||
0xc7, 0x8f, 0x28, 0xb3, 0xb8, 0x0b, 0x25, 0x16, 0xda, 0xf0, 0x84, 0x5b, 0x29, 0xa5, 0x54, 0xe9,
|
||||
0x9a, 0x84, 0x3f, 0x38, 0x9c, 0x7f, 0xd7, 0xc9, 0xd5, 0x4a, 0x5a, 0xa3, 0xe2, 0x4f, 0x22, 0x28,
|
||||
0xb3, 0xbf, 0x79, 0x45, 0x88, 0x0c, 0x9a, 0x6e, 0x29, 0x5b, 0x94, 0x20, 0x72, 0x29, 0x37, 0xd1,
|
||||
0x72, 0x88, 0x0f, 0x65, 0xfe, 0x54, 0x11, 0x17, 0x2a, 0x62, 0xab, 0x2d, 0x55, 0x97, 0x91, 0x20,
|
||||
0x1e, 0x1c, 0xce, 0xbf, 0x74, 0x72, 0xa1, 0xaa, 0x39, 0x6a, 0x11, 0xf6, 0xdf, 0x15, 0xf5, 0xdc,
|
||||
0x95, 0xf5, 0xd2, 0x3f, 0x14, 0x73, 0xf7, 0xc5, 0xcc, 0xdc, 0xbd, 0xd8, 0x33, 0x77, 0xa7, 0xf5,
|
||||
0x73, 0x3e, 0xa9, 0xd9, 0xf8, 0xa4, 0x37, 0xd8, 0xa3, 0xe3, 0x78, 0xee, 0x59, 0xbc, 0xd6, 0xf1,
|
||||
0x42, 0x1a, 0x6d, 0x85, 0x1d, 0xdf, 0xf3, 0xeb, 0xf2, 0x51, 0x47, 0xc3, 0xb3, 0x48, 0xa1, 0x31,
|
||||
0x4b, 0x6f, 0x7f, 0x95, 0x9f, 0x77, 0x1a, 0xc5, 0x65, 0xec, 0x2b, 0x37, 0xf9, 0x6b, 0x4f, 0xa2,
|
||||
0xa2, 0x54, 0x7d, 0x65, 0xf1, 0xc4, 0x93, 0xc0, 0x91, 0x7b, 0x30, 0xbe, 0x2b, 0x5e, 0x9c, 0xc8,
|
||||
0xe7, 0x8a, 0x93, 0x7c, 0xbe, 0x82, 0x5f, 0x26, 0x4d, 0xde, 0xb2, 0x78, 0xa0, 0xff, 0xc4, 0x44,
|
||||
0x9a, 0xfd, 0x4b, 0x45, 0x38, 0x95, 0x79, 0x8b, 0x88, 0x05, 0xfc, 0xc9, 0xc3, 0x53, 0xd9, 0xec,
|
||||
0xbc, 0x7a, 0xd4, 0x58, 0x51, 0x90, 0x0f, 0x00, 0x54, 0x69, 0xbb, 0x19, 0x74, 0xb9, 0xe3, 0x32,
|
||||
0x72, 0x62, 0xc7, 0x45, 0xf9, 0xba, 0x2b, 0x8a, 0x0b, 0x1a, 0x1c, 0x65, 0x19, 0xed, 0xa8, 0x78,
|
||||
0x4f, 0x23, 0x5d, 0x46, 0x6b, 0xdc, 0xf4, 0x1b, 0x7b, 0xb2, 0x37, 0xfd, 0x3c, 0x38, 0x25, 0x54,
|
||||
0x54, 0x25, 0x5c, 0x8f, 0x50, 0xa9, 0x75, 0x86, 0xcd, 0xa8, 0x95, 0x34, 0x1b, 0xcc, 0xf2, 0xb5,
|
||||
0x3f, 0x5b, 0x60, 0xee, 0x9b, 0x18, 0xec, 0xf5, 0x24, 0x39, 0xfe, 0x66, 0x18, 0x73, 0x3a, 0x71,
|
||||
0x23, 0xe8, 0x79, 0x01, 0x64, 0x89, 0x43, 0x51, 0x62, 0xc9, 0x1a, 0x8c, 0x54, 0x9d, 0x38, 0x79,
|
||||
0x94, 0xff, 0x24, 0xca, 0xe9, 0x4c, 0x98, 0x13, 0x53, 0xe4, 0x5c, 0xc8, 0x33, 0x30, 0x12, 0x3b,
|
||||
0xf5, 0xd4, 0x0b, 0x9e, 0x3b, 0x4e, 0x3d, 0x42, 0x0e, 0x35, 0x77, 0x97, 0x91, 0x23, 0x76, 0x97,
|
||||
0x97, 0x8c, 0x7f, 0x17, 0x61, 0x9c, 0xba, 0xf4, 0xfe, 0x8b, 0x07, 0x51, 0xd8, 0x9f, 0xa2, 0xb5,
|
||||
0x7f, 0x04, 0x26, 0xcd, 0x7f, 0x01, 0x71, 0xac, 0xbb, 0x46, 0xf6, 0x3f, 0x8e, 0xc0, 0x54, 0xaa,
|
||||
0xcc, 0x2f, 0x35, 0xcb, 0xad, 0x23, 0x67, 0x39, 0x3f, 0x4f, 0xeb, 0xf8, 0x54, 0x16, 0x71, 0x1a,
|
||||
0xe7, 0x69, 0x1d, 0x9f, 0xa2, 0xc0, 0xb1, 0xaf, 0x52, 0x0d, 0xbb, 0xd8, 0xf1, 0x65, 0x56, 0x5e,
|
||||
0x7d, 0x95, 0x15, 0x0e, 0x45, 0x89, 0x65, 0x01, 0xec, 0x64, 0xc4, 0x8d, 0xa2, 0xb0, 0x11, 0x72,
|
||||
0xd5, 0x5c, 0xcf, 0xe3, 0xd5, 0x34, 0x59, 0xd2, 0xca, 0x03, 0x7a, 0x13, 0x82, 0x29, 0x89, 0xe4,
|
||||
0x13, 0x96, 0xf9, 0x5e, 0xdc, 0x58, 0x1e, 0xa7, 0x49, 0xd9, 0x2a, 0x4a, 0xb1, 0x82, 0x1e, 0xfe,
|
||||
0x6c, 0x5c, 0xa4, 0x16, 0xf0, 0xf8, 0xe3, 0x59, 0xc0, 0xd0, 0x67, 0xf1, 0xbe, 0x15, 0xca, 0x2d,
|
||||
0xc7, 0xf7, 0x6a, 0x34, 0x8a, 0xc5, 0xbf, 0x6f, 0x29, 0x8b, 0xe8, 0x69, 0x3d, 0x01, 0xa2, 0xc6,
|
||||
0xf3, 0x7f, 0x92, 0xc4, 0x3b, 0x26, 0x82, 0x98, 0xb2, 0xf1, 0x4f, 0x92, 0x34, 0x18, 0x4d, 0x1a,
|
||||
0xfb, 0xb7, 0x2d, 0x38, 0xd7, 0x77, 0x30, 0x7e, 0x70, 0xd3, 0x9f, 0xf6, 0xef, 0x14, 0xe0, 0x4c,
|
||||
0x9f, 0x32, 0x58, 0xd2, 0x7d, 0x6c, 0xcf, 0x0a, 0xca, 0x3a, 0xdb, 0xa9, 0x81, 0x73, 0xe3, 0x64,
|
||||
0xdb, 0x90, 0xde, 0x0a, 0x8a, 0x4f, 0x74, 0x2b, 0xb0, 0xbf, 0x5a, 0x00, 0xe3, 0x01, 0x4c, 0xf2,
|
||||
0x11, 0xb3, 0xe2, 0xdb, 0xca, 0xab, 0x3a, 0x59, 0x30, 0x57, 0x15, 0xe3, 0x62, 0xd4, 0xfa, 0x15,
|
||||
0x90, 0x67, 0xe7, 0x6b, 0xe1, 0xe8, 0xf9, 0x4a, 0x9a, 0x49, 0x69, 0x7d, 0x31, 0xff, 0xd2, 0xfa,
|
||||
0x72, 0x4f, 0x59, 0xfd, 0x2f, 0x58, 0x62, 0xa6, 0x65, 0xba, 0xa4, 0x2d, 0xac, 0xf5, 0x10, 0x0b,
|
||||
0xfb, 0x36, 0x28, 0x45, 0xb4, 0x59, 0x63, 0x9e, 0x9d, 0xb4, 0xc4, 0xfa, 0xbd, 0x6d, 0x09, 0x47,
|
||||
0x45, 0xc1, 0xef, 0xce, 0x36, 0x9b, 0xc1, 0xbd, 0xcb, 0xad, 0x76, 0xdc, 0x95, 0x36, 0x59, 0xdf,
|
||||
0x9d, 0x55, 0x18, 0x34, 0xa8, 0xec, 0x7f, 0xb7, 0xc4, 0xe7, 0x94, 0x3e, 0xfa, 0x8b, 0x99, 0x3b,
|
||||
0x8d, 0xc7, 0x77, 0x6f, 0x7f, 0x06, 0xc0, 0x55, 0x6f, 0x12, 0xe4, 0xf3, 0x2e, 0xa6, 0x7e, 0xe3,
|
||||
0xc0, 0x7c, 0xac, 0x31, 0x81, 0xa1, 0x21, 0x2f, 0xb5, 0x78, 0x8a, 0x47, 0x2d, 0x1e, 0xfb, 0x5f,
|
||||
0x2c, 0x48, 0x6d, 0x16, 0xa4, 0x0d, 0xa3, 0x4c, 0x83, 0x6e, 0x3e, 0x2f, 0x28, 0x98, 0xac, 0xd9,
|
||||
0xc2, 0x92, 0xd3, 0x82, 0xff, 0x89, 0x42, 0x10, 0x69, 0x4a, 0xef, 0xbc, 0x90, 0xc7, 0x2b, 0x1f,
|
||||
0xa6, 0x40, 0xe6, 0xdf, 0xcb, 0x7f, 0x88, 0xa1, 0x3c, 0x7d, 0xfb, 0x45, 0x98, 0xe9, 0x51, 0x8a,
|
||||
0xdf, 0x48, 0x0a, 0x92, 0x67, 0x23, 0x8c, 0x19, 0xc8, 0xef, 0x47, 0xa2, 0xc0, 0x31, 0x07, 0xff,
|
||||
0x74, 0x96, 0x3d, 0xf9, 0x92, 0x05, 0x33, 0x51, 0x96, 0xdf, 0xe3, 0x1a, 0x3b, 0x95, 0xb9, 0xea,
|
||||
0x41, 0x61, 0xaf, 0x12, 0xf6, 0x7f, 0x49, 0xf3, 0x24, 0xfe, 0x81, 0x98, 0xda, 0x5c, 0xac, 0x81,
|
||||
0x9b, 0x0b, 0x5b, 0x62, 0x6e, 0x83, 0x56, 0x3b, 0xcd, 0x9e, 0xda, 0x9c, 0x6d, 0x09, 0x47, 0x45,
|
||||
0x91, 0x7a, 0x1f, 0xaf, 0x78, 0xe4, 0xfb, 0x78, 0x2f, 0xc0, 0xa4, 0xf9, 0x34, 0x0a, 0x4f, 0xa1,
|
||||
0xc9, 0xc3, 0x07, 0xf3, 0x15, 0x15, 0x4c, 0x51, 0x65, 0xde, 0x57, 0x1b, 0x3d, 0xf2, 0x7d, 0xb5,
|
||||
0xe7, 0xa0, 0x24, 0xdf, 0x0a, 0x4b, 0xf2, 0xbb, 0xa2, 0xf0, 0x47, 0xc2, 0x50, 0x61, 0x99, 0x81,
|
||||
0x68, 0x39, 0x7e, 0xc7, 0x69, 0xb2, 0x11, 0x92, 0xf5, 0x80, 0x6a, 0x65, 0xad, 0x2b, 0x0c, 0x1a,
|
||||
0x54, 0xac, 0xc7, 0xb1, 0xd7, 0xa2, 0xaf, 0x04, 0x7e, 0x92, 0x19, 0x51, 0x3d, 0xde, 0x91, 0x70,
|
||||
0x54, 0x14, 0xf6, 0x3f, 0x58, 0x90, 0x7d, 0xe8, 0x28, 0x55, 0x83, 0x68, 0x1d, 0x59, 0x83, 0x98,
|
||||
0xae, 0xaf, 0x2a, 0x1c, 0xab, 0xbe, 0xca, 0x2c, 0x7d, 0x2a, 0x3e, 0xb4, 0xf4, 0xe9, 0x4d, 0xfa,
|
||||
0x5e, 0xbb, 0xa8, 0x91, 0x9a, 0xe8, 0x77, 0xa7, 0x9d, 0xd8, 0x30, 0xe6, 0x3a, 0xaa, 0xc4, 0x7b,
|
||||
0x52, 0xb8, 0x55, 0xcb, 0x4b, 0x9c, 0x48, 0x62, 0x2a, 0xbb, 0x5f, 0xff, 0xee, 0x85, 0xa7, 0xbe,
|
||||
0xf1, 0xdd, 0x0b, 0x4f, 0x7d, 0xeb, 0xbb, 0x17, 0x9e, 0xfa, 0xd8, 0xfd, 0x0b, 0xd6, 0xd7, 0xef,
|
||||
0x5f, 0xb0, 0xbe, 0x71, 0xff, 0x82, 0xf5, 0xad, 0xfb, 0x17, 0xac, 0xef, 0xdc, 0xbf, 0x60, 0x7d,
|
||||
0xfe, 0x6f, 0x2f, 0x3c, 0xf5, 0xca, 0xbb, 0x87, 0xf9, 0x8f, 0xb5, 0xff, 0x1d, 0x00, 0x00, 0xff,
|
||||
0xff, 0xd1, 0x9f, 0xce, 0xf7, 0xf0, 0x76, 0x00, 0x00,
|
||||
// 6831 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x7d, 0x59, 0x6c, 0x24, 0xc9,
|
||||
0x71, 0xe8, 0x56, 0x37, 0x8f, 0xee, 0xe0, 0x31, 0x64, 0xce, 0xb1, 0x14, 0xdf, 0x6a, 0x38, 0xa8,
|
||||
0x85, 0xa4, 0x7d, 0x4f, 0x12, 0xf9, 0x76, 0xde, 0x4a, 0x6f, 0xad, 0x95, 0x57, 0x62, 0x93, 0x73,
|
||||
0x70, 0x86, 0x1c, 0x72, 0x82, 0x9c, 0x19, 0x6b, 0x25, 0xcb, 0x5b, 0xac, 0xce, 0xee, 0xae, 0x61,
|
||||
0x77, 0x55, 0x6f, 0x55, 0x35, 0x87, 0x2d, 0x59, 0x17, 0x20, 0x5b, 0x0b, 0xe8, 0x84, 0xe4, 0x0f,
|
||||
0x09, 0x30, 0x6c, 0xf9, 0x80, 0x01, 0x7f, 0x08, 0xb6, 0x7f, 0x7c, 0xc0, 0xf0, 0x87, 0xe5, 0x1f,
|
||||
0x19, 0xfe, 0xb0, 0x00, 0x1b, 0x96, 0x6c, 0xc1, 0xb4, 0x34, 0xb6, 0x21, 0xdb, 0x80, 0x6d, 0xf8,
|
||||
0xf8, 0xf1, 0xc0, 0x1f, 0x46, 0x1e, 0x95, 0x99, 0x55, 0xdd, 0x3d, 0x24, 0xa7, 0x6b, 0xc6, 0x82,
|
||||
0xe0, 0x3f, 0x76, 0x44, 0x64, 0x44, 0x64, 0x56, 0x66, 0x64, 0x44, 0x64, 0x64, 0x12, 0xd6, 0xeb,
|
||||
0x5e, 0xdc, 0xe8, 0xec, 0x2e, 0xba, 0x41, 0x6b, 0xc9, 0x09, 0xeb, 0x41, 0x3b, 0x0c, 0xee, 0xf2,
|
||||
0x3f, 0xde, 0xee, 0x56, 0x97, 0xf6, 0x2f, 0x2e, 0xb5, 0xf7, 0xea, 0x4b, 0x4e, 0xdb, 0x8b, 0x96,
|
||||
0x9c, 0x76, 0xbb, 0xe9, 0xb9, 0x4e, 0xec, 0x05, 0xfe, 0xd2, 0xfe, 0xf3, 0x4e, 0xb3, 0xdd, 0x70,
|
||||
0x9e, 0x5f, 0xaa, 0x53, 0x9f, 0x86, 0x4e, 0x4c, 0xab, 0x8b, 0xed, 0x30, 0x88, 0x03, 0xf2, 0x6e,
|
||||
0xcd, 0x6d, 0x31, 0xe1, 0xc6, 0xff, 0xf8, 0x09, 0xb7, 0xba, 0xb8, 0x7f, 0x71, 0xb1, 0xbd, 0x57,
|
||||
0x5f, 0x64, 0xdc, 0x16, 0x0d, 0x6e, 0x8b, 0x09, 0xb7, 0xf9, 0xb7, 0x1b, 0xba, 0xd4, 0x83, 0x7a,
|
||||
0xb0, 0xc4, 0x99, 0xee, 0x76, 0x6a, 0xfc, 0x17, 0xff, 0xc1, 0xff, 0x12, 0xc2, 0xe6, 0xed, 0xbd,
|
||||
0x17, 0xa3, 0x45, 0x2f, 0x60, 0xea, 0x2d, 0xb9, 0x41, 0x48, 0x97, 0xf6, 0x7b, 0x14, 0x9a, 0x7f,
|
||||
0x41, 0xd3, 0xb4, 0x1c, 0xb7, 0xe1, 0xf9, 0x34, 0xec, 0xea, 0x3e, 0xb5, 0x68, 0xec, 0xf4, 0x6b,
|
||||
0xb5, 0x34, 0xa8, 0x55, 0xd8, 0xf1, 0x63, 0xaf, 0x45, 0x7b, 0x1a, 0xbc, 0xf3, 0xa8, 0x06, 0x91,
|
||||
0xdb, 0xa0, 0x2d, 0x27, 0xdb, 0xce, 0x7e, 0x0d, 0xa6, 0x96, 0xef, 0x6c, 0x2f, 0x77, 0xe2, 0xc6,
|
||||
0x4a, 0xe0, 0xd7, 0xbc, 0x3a, 0x79, 0x07, 0x4c, 0xb8, 0xcd, 0x4e, 0x14, 0xd3, 0xf0, 0x86, 0xd3,
|
||||
0xa2, 0x73, 0xd6, 0x05, 0xeb, 0xb9, 0x72, 0xe5, 0xf4, 0x37, 0x0e, 0x17, 0x9e, 0xba, 0x7f, 0xb8,
|
||||
0x30, 0xb1, 0xa2, 0x51, 0x68, 0xd2, 0x91, 0xff, 0x0d, 0xe3, 0x61, 0xd0, 0xa4, 0xcb, 0x78, 0x63,
|
||||
0xae, 0xc0, 0x9b, 0x9c, 0x92, 0x4d, 0xc6, 0x51, 0x80, 0x31, 0xc1, 0xdb, 0x7f, 0x56, 0x00, 0x58,
|
||||
0x6e, 0xb7, 0xb7, 0xc2, 0xe0, 0x2e, 0x75, 0x63, 0xf2, 0x2a, 0x94, 0xd8, 0x28, 0x54, 0x9d, 0xd8,
|
||||
0xe1, 0xd2, 0x26, 0x2e, 0xfe, 0xdf, 0x45, 0xd1, 0x99, 0x45, 0xb3, 0x33, 0xfa, 0xcb, 0x31, 0xea,
|
||||
0xc5, 0xfd, 0xe7, 0x17, 0x37, 0x77, 0x59, 0xfb, 0x0d, 0x1a, 0x3b, 0x15, 0x22, 0x85, 0x81, 0x86,
|
||||
0xa1, 0xe2, 0x4a, 0x7c, 0x18, 0x89, 0xda, 0xd4, 0xe5, 0x8a, 0x4d, 0x5c, 0x5c, 0x5f, 0x1c, 0x66,
|
||||
0x8a, 0x2c, 0x6a, 0xcd, 0xb7, 0xdb, 0xd4, 0xad, 0x4c, 0x4a, 0xc9, 0x23, 0xec, 0x17, 0x72, 0x39,
|
||||
0x64, 0x1f, 0xc6, 0xa2, 0xd8, 0x89, 0x3b, 0xd1, 0x5c, 0x91, 0x4b, 0xbc, 0x91, 0x9b, 0x44, 0xce,
|
||||
0xb5, 0x32, 0x2d, 0x65, 0x8e, 0x89, 0xdf, 0x28, 0xa5, 0xd9, 0x7f, 0x69, 0xc1, 0xb4, 0x26, 0x5e,
|
||||
0xf7, 0xa2, 0x98, 0x7c, 0xa0, 0x67, 0x70, 0x17, 0x8f, 0x37, 0xb8, 0xac, 0x35, 0x1f, 0xda, 0x19,
|
||||
0x29, 0xac, 0x94, 0x40, 0x8c, 0x81, 0x6d, 0xc1, 0xa8, 0x17, 0xd3, 0x56, 0x34, 0x57, 0xb8, 0x50,
|
||||
0x7c, 0x6e, 0xe2, 0xe2, 0xd5, 0xbc, 0xfa, 0x59, 0x99, 0x92, 0x42, 0x47, 0xd7, 0x18, 0x7b, 0x14,
|
||||
0x52, 0xec, 0xdf, 0x9c, 0x30, 0xfb, 0xc7, 0x06, 0x9c, 0x3c, 0x0f, 0x13, 0x51, 0xd0, 0x09, 0x5d,
|
||||
0x8a, 0xb4, 0x1d, 0x44, 0x73, 0xd6, 0x85, 0x22, 0x9b, 0x7a, 0x6c, 0xa6, 0x6e, 0x6b, 0x30, 0x9a,
|
||||
0x34, 0xe4, 0x73, 0x16, 0x4c, 0x56, 0x69, 0x14, 0x7b, 0x3e, 0x97, 0x9f, 0x28, 0xbf, 0x33, 0xb4,
|
||||
0xf2, 0x09, 0x70, 0x55, 0x33, 0xaf, 0x9c, 0x91, 0x1d, 0x99, 0x34, 0x80, 0x11, 0xa6, 0xe4, 0xb3,
|
||||
0x15, 0x57, 0xa5, 0x91, 0x1b, 0x7a, 0x6d, 0xf6, 0x9b, 0xcf, 0x19, 0x63, 0xc5, 0xad, 0x6a, 0x14,
|
||||
0x9a, 0x74, 0xc4, 0x87, 0x51, 0xb6, 0xa2, 0xa2, 0xb9, 0x11, 0xae, 0xff, 0xda, 0x70, 0xfa, 0xcb,
|
||||
0x41, 0x65, 0x8b, 0x55, 0x8f, 0x3e, 0xfb, 0x15, 0xa1, 0x10, 0x43, 0x3e, 0x6b, 0xc1, 0x9c, 0x5c,
|
||||
0xf1, 0x48, 0xc5, 0x80, 0xde, 0x69, 0x78, 0x31, 0x6d, 0x7a, 0x51, 0x3c, 0x37, 0xca, 0x75, 0x58,
|
||||
0x3a, 0xde, 0xdc, 0xba, 0x12, 0x06, 0x9d, 0xf6, 0x75, 0xcf, 0xaf, 0x56, 0x2e, 0x48, 0x49, 0x73,
|
||||
0x2b, 0x03, 0x18, 0xe3, 0x40, 0x91, 0xe4, 0x4b, 0x16, 0xcc, 0xfb, 0x4e, 0x8b, 0x46, 0x6d, 0x87,
|
||||
0x7d, 0x5a, 0x81, 0xae, 0x34, 0x1d, 0x77, 0x8f, 0x6b, 0x34, 0xf6, 0x68, 0x1a, 0xd9, 0x52, 0xa3,
|
||||
0xf9, 0x1b, 0x03, 0x59, 0xe3, 0x43, 0xc4, 0x92, 0x5f, 0xb2, 0x60, 0x36, 0x08, 0xdb, 0x0d, 0xc7,
|
||||
0xa7, 0xd5, 0x04, 0x1b, 0xcd, 0x8d, 0xf3, 0xa5, 0xf7, 0xc1, 0xe1, 0x3e, 0xd1, 0x66, 0x96, 0xed,
|
||||
0x46, 0xe0, 0x7b, 0x71, 0x10, 0x6e, 0xd3, 0x38, 0xf6, 0xfc, 0x7a, 0x54, 0x39, 0x7b, 0xff, 0x70,
|
||||
0x61, 0xb6, 0x87, 0x0a, 0x7b, 0xf5, 0x21, 0x1f, 0x86, 0x89, 0xa8, 0xeb, 0xbb, 0x77, 0x3c, 0xbf,
|
||||
0x1a, 0xdc, 0x8b, 0xe6, 0x4a, 0x79, 0x2c, 0xdf, 0x6d, 0xc5, 0x50, 0x2e, 0x40, 0x2d, 0x00, 0x4d,
|
||||
0x69, 0xfd, 0x3f, 0x9c, 0x9e, 0x4a, 0xe5, 0xbc, 0x3f, 0x9c, 0x9e, 0x4c, 0x0f, 0x11, 0x4b, 0x3e,
|
||||
0x65, 0xc1, 0x54, 0xe4, 0xd5, 0x7d, 0x27, 0xee, 0x84, 0xf4, 0x3a, 0xed, 0x46, 0x73, 0xc0, 0x15,
|
||||
0xb9, 0x36, 0xe4, 0xa8, 0x18, 0x2c, 0x2b, 0x67, 0xa5, 0x8e, 0x53, 0x26, 0x34, 0xc2, 0xb4, 0xdc,
|
||||
0x7e, 0x0b, 0x4d, 0x4f, 0xeb, 0x89, 0x7c, 0x17, 0x9a, 0x9e, 0xd4, 0x03, 0x45, 0x92, 0xf7, 0xc2,
|
||||
0x8c, 0x00, 0xa9, 0x91, 0x8d, 0xe6, 0x26, 0xb9, 0xa1, 0x3d, 0x73, 0xff, 0x70, 0x61, 0x66, 0x3b,
|
||||
0x83, 0xc3, 0x1e, 0x6a, 0xfb, 0x0f, 0x0b, 0x30, 0x93, 0xdd, 0xc5, 0xc8, 0xaf, 0x58, 0x70, 0xea,
|
||||
0xee, 0xbd, 0x78, 0x27, 0xd8, 0xa3, 0x7e, 0x54, 0xe9, 0x32, 0x5b, 0xc3, 0xed, 0xf7, 0xc4, 0x45,
|
||||
0x37, 0xdf, 0xfd, 0x72, 0xf1, 0x5a, 0x5a, 0xca, 0x25, 0x3f, 0x0e, 0xbb, 0x95, 0xa7, 0xe5, 0x88,
|
||||
0x9c, 0xba, 0x76, 0x67, 0xc7, 0xc4, 0x62, 0x56, 0xa9, 0xf9, 0x4f, 0x5b, 0x70, 0xa6, 0x1f, 0x0b,
|
||||
0x32, 0x03, 0xc5, 0x3d, 0xda, 0x15, 0x2e, 0x12, 0xb2, 0x3f, 0xc9, 0x8f, 0xc3, 0xe8, 0xbe, 0xd3,
|
||||
0xec, 0x50, 0xe9, 0x6a, 0x5c, 0x19, 0xae, 0x23, 0x4a, 0x33, 0x14, 0x5c, 0xdf, 0x55, 0x78, 0xd1,
|
||||
0xb2, 0xff, 0xb8, 0x08, 0x13, 0xc6, 0x66, 0xf3, 0x04, 0xdc, 0xa7, 0x20, 0xe5, 0x3e, 0x6d, 0xe4,
|
||||
0xb6, 0x4f, 0x0e, 0xf4, 0x9f, 0xee, 0x65, 0xfc, 0xa7, 0xcd, 0xfc, 0x44, 0x3e, 0xd4, 0x81, 0x22,
|
||||
0x31, 0x94, 0x83, 0x36, 0x73, 0x8f, 0xd9, 0x3e, 0x3c, 0x92, 0xc7, 0x27, 0xdc, 0x4c, 0xd8, 0x55,
|
||||
0xa6, 0xee, 0x1f, 0x2e, 0x94, 0xd5, 0x4f, 0xd4, 0x82, 0xec, 0x6f, 0x59, 0x70, 0xc6, 0xd0, 0x71,
|
||||
0x25, 0xf0, 0xab, 0x1e, 0xff, 0xb4, 0x17, 0x60, 0x24, 0xee, 0xb6, 0x13, 0x1f, 0x5c, 0x8d, 0xd4,
|
||||
0x4e, 0xb7, 0x4d, 0x91, 0x63, 0x98, 0xd7, 0xdd, 0xa2, 0x51, 0xe4, 0xd4, 0x69, 0xd6, 0xeb, 0xde,
|
||||
0x10, 0x60, 0x4c, 0xf0, 0x24, 0x04, 0xd2, 0x74, 0xa2, 0x78, 0x27, 0x74, 0xfc, 0x88, 0xb3, 0xdf,
|
||||
0xf1, 0x5a, 0x54, 0x0e, 0xf0, 0xff, 0x39, 0xde, 0x8c, 0x61, 0x2d, 0x2a, 0xe7, 0xee, 0x1f, 0x2e,
|
||||
0x90, 0xf5, 0x1e, 0x4e, 0xd8, 0x87, 0xbb, 0xfd, 0x25, 0x0b, 0xce, 0xf5, 0x77, 0x8c, 0xc8, 0x9b,
|
||||
0x61, 0x2c, 0xa2, 0xe1, 0x3e, 0x0d, 0x65, 0xef, 0xf4, 0x27, 0xe1, 0x50, 0x94, 0x58, 0xb2, 0x04,
|
||||
0x65, 0x65, 0xb4, 0x65, 0x1f, 0x67, 0x25, 0x69, 0x59, 0x5b, 0x7a, 0x4d, 0xc3, 0x06, 0x8d, 0xfd,
|
||||
0x90, 0x6e, 0x94, 0x1a, 0x34, 0x1e, 0xb1, 0x70, 0x8c, 0xfd, 0x57, 0x16, 0x9c, 0x32, 0xb4, 0x7a,
|
||||
0x02, 0x7e, 0xb2, 0x9f, 0xf6, 0x93, 0xd7, 0x72, 0x9b, 0xcf, 0x03, 0x1c, 0xe5, 0x3f, 0x18, 0x85,
|
||||
0x59, 0x73, 0xd6, 0x73, 0x7b, 0xcc, 0x43, 0x34, 0xda, 0x0e, 0x6e, 0xe1, 0xba, 0x1c, 0x73, 0x1d,
|
||||
0xa2, 0x09, 0x30, 0x26, 0x78, 0x36, 0x88, 0x6d, 0x27, 0x6e, 0xc8, 0x01, 0x57, 0x83, 0xb8, 0xe5,
|
||||
0xc4, 0x0d, 0xe4, 0x18, 0xf2, 0x32, 0x4c, 0xc7, 0x4e, 0x58, 0xa7, 0x31, 0xd2, 0x7d, 0x2f, 0x4a,
|
||||
0xd6, 0x4b, 0xb9, 0x72, 0x4e, 0xd2, 0x4e, 0xef, 0xa4, 0xb0, 0x98, 0xa1, 0x26, 0xaf, 0xc1, 0x48,
|
||||
0x83, 0x36, 0x5b, 0xd2, 0x33, 0xda, 0xce, 0x6f, 0x85, 0xf3, 0xbe, 0x5e, 0xa5, 0xcd, 0x56, 0xa5,
|
||||
0xc4, 0x54, 0x66, 0x7f, 0x21, 0x17, 0x45, 0x7e, 0xca, 0x82, 0xf2, 0x5e, 0x27, 0x8a, 0x83, 0x96,
|
||||
0xf7, 0x21, 0x3a, 0x57, 0xe2, 0x82, 0x7f, 0x2c, 0x67, 0xc1, 0xd7, 0x13, 0xfe, 0x62, 0xbd, 0xab,
|
||||
0x9f, 0xa8, 0x25, 0x73, 0x3d, 0xaa, 0x5e, 0x48, 0xdd, 0x38, 0x08, 0xbb, 0x73, 0xf0, 0x58, 0xf4,
|
||||
0x58, 0x4d, 0xf8, 0x0b, 0x3d, 0xd4, 0x4f, 0xd4, 0x92, 0x49, 0x17, 0xc6, 0xda, 0xcd, 0x4e, 0xdd,
|
||||
0xf3, 0xe7, 0x26, 0xb8, 0x0e, 0xb7, 0x72, 0xd6, 0x61, 0x8b, 0x33, 0xaf, 0x00, 0x5b, 0xd5, 0xe2,
|
||||
0x6f, 0x94, 0x02, 0xc9, 0xb3, 0x30, 0xea, 0x36, 0x9c, 0x30, 0x9e, 0x9b, 0xe4, 0x93, 0x46, 0xcd,
|
||||
0xe2, 0x15, 0x06, 0x44, 0x81, 0xb3, 0x7f, 0xa1, 0x00, 0xf3, 0x83, 0x3b, 0x26, 0xa6, 0xb3, 0xdb,
|
||||
0x09, 0x23, 0x61, 0x20, 0x4b, 0xe6, 0x74, 0xe6, 0x60, 0x4c, 0xf0, 0xe4, 0x13, 0x16, 0x8c, 0xdf,
|
||||
0x8d, 0x02, 0xdf, 0xa7, 0xb1, 0xdc, 0xc5, 0x6e, 0xe7, 0xdc, 0xd7, 0x6b, 0x82, 0xbb, 0xd6, 0x41,
|
||||
0x02, 0x30, 0x91, 0xcb, 0xd4, 0xa5, 0x07, 0x6e, 0xb3, 0x53, 0x4d, 0x4c, 0x93, 0x22, 0xbd, 0x24,
|
||||
0xc0, 0x98, 0xe0, 0x19, 0xa9, 0xe7, 0x0b, 0xd2, 0x91, 0x34, 0xe9, 0x9a, 0x2f, 0x49, 0x25, 0xde,
|
||||
0xfe, 0xf5, 0x51, 0x38, 0xdb, 0x77, 0xf6, 0x93, 0x45, 0x00, 0xee, 0x34, 0x5c, 0xf6, 0x58, 0x8c,
|
||||
0x28, 0x02, 0xe3, 0x69, 0xb6, 0xc7, 0xdf, 0x56, 0x50, 0x34, 0x28, 0xc8, 0xc7, 0x00, 0xda, 0x4e,
|
||||
0xe8, 0xb4, 0x68, 0x4c, 0xc3, 0xc4, 0x50, 0x5d, 0x1f, 0x6e, 0x94, 0x98, 0x1e, 0x5b, 0x09, 0x4f,
|
||||
0xed, 0x64, 0x28, 0x50, 0x84, 0x86, 0x48, 0x16, 0x06, 0x87, 0xb4, 0x49, 0x9d, 0x88, 0x7b, 0x8e,
|
||||
0xd9, 0x30, 0x18, 0x35, 0x0a, 0x4d, 0x3a, 0xb6, 0x91, 0xf0, 0x5e, 0x44, 0x72, 0xac, 0xd4, 0x46,
|
||||
0xc2, 0xfb, 0x19, 0xa1, 0xc4, 0x92, 0xcf, 0x5b, 0x30, 0x5d, 0xf3, 0x9a, 0x54, 0x4b, 0x97, 0x41,
|
||||
0xeb, 0xe6, 0xf0, 0x9d, 0xbc, 0x6c, 0xf2, 0xd5, 0x26, 0x30, 0x05, 0x8e, 0x30, 0x23, 0x9e, 0x7d,
|
||||
0xe6, 0x7d, 0x1a, 0x72, 0xdb, 0x39, 0x96, 0xfe, 0xcc, 0xb7, 0x05, 0x18, 0x13, 0x3c, 0x59, 0x86,
|
||||
0x53, 0x6d, 0x27, 0x8a, 0x56, 0x42, 0x5a, 0xa5, 0x7e, 0xec, 0x39, 0x4d, 0x11, 0x52, 0x96, 0xb4,
|
||||
0x17, 0xbb, 0x95, 0x46, 0x63, 0x96, 0x9e, 0xbc, 0x0f, 0x9e, 0xf6, 0xea, 0x7e, 0x10, 0xd2, 0x0d,
|
||||
0x2f, 0x8a, 0x3c, 0xbf, 0xae, 0xa7, 0x01, 0x37, 0x85, 0xa5, 0xca, 0x82, 0x64, 0xf5, 0xf4, 0x5a,
|
||||
0x7f, 0x32, 0x1c, 0xd4, 0x9e, 0xbc, 0x0d, 0x4a, 0xd1, 0x9e, 0xd7, 0x5e, 0x09, 0xab, 0xd1, 0x5c,
|
||||
0x99, 0xf3, 0x52, 0x9b, 0xe1, 0xb6, 0x84, 0xa3, 0xa2, 0xb0, 0xbf, 0x52, 0x80, 0xb9, 0x41, 0xeb,
|
||||
0x87, 0x44, 0x6c, 0x95, 0xc4, 0xb7, 0x9d, 0x30, 0x92, 0xb1, 0xc0, 0x90, 0x41, 0xa9, 0xe4, 0x7b,
|
||||
0xdb, 0x09, 0xcd, 0xf5, 0xc6, 0x05, 0x60, 0x22, 0x89, 0xdc, 0x85, 0x91, 0xb8, 0xe9, 0xe4, 0x94,
|
||||
0xc5, 0x32, 0x24, 0x6a, 0x8f, 0x6d, 0x7d, 0x39, 0x42, 0x2e, 0x83, 0x3c, 0x03, 0x23, 0x4d, 0x6f,
|
||||
0x97, 0x79, 0xb6, 0x6c, 0x41, 0xf2, 0x2d, 0x6a, 0xdd, 0xdb, 0x8d, 0x90, 0x43, 0xed, 0x7f, 0x1e,
|
||||
0xeb, 0x63, 0xf2, 0xd4, 0x26, 0x42, 0x2e, 0x02, 0x30, 0x0f, 0x66, 0x2b, 0xa4, 0x35, 0xef, 0x40,
|
||||
0x6e, 0xe2, 0x6a, 0x59, 0xdd, 0x50, 0x18, 0x34, 0xa8, 0x92, 0x36, 0xdb, 0x9d, 0x1a, 0x6b, 0x53,
|
||||
0xe8, 0x6d, 0x23, 0x30, 0x68, 0x50, 0x91, 0x17, 0x60, 0xcc, 0x6b, 0x39, 0x75, 0x9a, 0xa8, 0xf9,
|
||||
0x0c, 0x5b, 0x4f, 0x6b, 0x1c, 0xf2, 0xe0, 0x70, 0x61, 0x5a, 0x29, 0xc4, 0x41, 0x28, 0x69, 0xc9,
|
||||
0x2f, 0x5b, 0x30, 0xe9, 0x06, 0xad, 0x56, 0xe0, 0xaf, 0x3b, 0xbb, 0xb4, 0x99, 0x24, 0xa6, 0xee,
|
||||
0x3e, 0xae, 0x2d, 0x76, 0x71, 0xc5, 0x10, 0x26, 0x82, 0x3a, 0x95, 0x6e, 0x33, 0x51, 0x98, 0xd2,
|
||||
0xca, 0x5c, 0x76, 0xa3, 0x47, 0x2c, 0xbb, 0xdf, 0xb6, 0x60, 0x56, 0xb4, 0x5d, 0xf6, 0xfd, 0x20,
|
||||
0x96, 0xf9, 0x42, 0x91, 0x59, 0x0a, 0x1e, 0x73, 0xb7, 0x0c, 0x89, 0xa2, 0x6f, 0x6f, 0x90, 0x6a,
|
||||
0xce, 0xf6, 0xe0, 0xb1, 0x57, 0x49, 0x72, 0x05, 0x66, 0x6b, 0x41, 0xe8, 0x52, 0x73, 0x20, 0xa4,
|
||||
0xcd, 0x50, 0x8c, 0x2e, 0x67, 0x09, 0xb0, 0xb7, 0x0d, 0xb9, 0x0d, 0xe7, 0x0c, 0xa0, 0x39, 0x0e,
|
||||
0xc2, 0x6c, 0x9c, 0x97, 0xdc, 0xce, 0x5d, 0xee, 0x4b, 0x85, 0x03, 0x5a, 0xcf, 0xbf, 0x07, 0x66,
|
||||
0x7b, 0xbe, 0x5f, 0x9f, 0x88, 0xfa, 0x8c, 0x19, 0x51, 0x97, 0x8d, 0x40, 0x78, 0x7e, 0x15, 0xce,
|
||||
0xf5, 0x1f, 0xa9, 0x93, 0x70, 0xb1, 0x7f, 0xce, 0x82, 0xa7, 0x07, 0x78, 0x2e, 0x2a, 0x94, 0xb0,
|
||||
0x06, 0x85, 0x12, 0xc4, 0x81, 0x22, 0xf5, 0xf7, 0xa5, 0xe1, 0xb8, 0x3c, 0xdc, 0x8c, 0xb8, 0xe4,
|
||||
0xef, 0x8b, 0x0f, 0x3d, 0x7e, 0xff, 0x70, 0xa1, 0x78, 0xc9, 0xdf, 0x47, 0xc6, 0xdb, 0xfe, 0x99,
|
||||
0xb1, 0x54, 0xb4, 0xb2, 0x9d, 0x04, 0xc8, 0x5c, 0x51, 0x19, 0xab, 0x6c, 0xe6, 0x3c, 0x17, 0x8d,
|
||||
0x68, 0x4c, 0x24, 0xce, 0xa5, 0x38, 0xf2, 0x69, 0x8b, 0xe7, 0xaa, 0x93, 0x28, 0x4e, 0x3a, 0x53,
|
||||
0x8f, 0x27, 0x75, 0x6e, 0x66, 0xc0, 0x13, 0x20, 0x9a, 0xd2, 0xd9, 0x4a, 0x6e, 0x8b, 0x44, 0x4f,
|
||||
0xd6, 0xa5, 0x4a, 0xb2, 0xd9, 0x09, 0x9e, 0x1c, 0x00, 0x44, 0x5d, 0xdf, 0xdd, 0x0a, 0x9a, 0x9e,
|
||||
0xdb, 0x95, 0xa1, 0x7d, 0x0e, 0xf9, 0x4e, 0xc1, 0x4f, 0xf8, 0x55, 0xfa, 0x37, 0x1a, 0xb2, 0xc8,
|
||||
0x57, 0x2d, 0x98, 0x15, 0x1b, 0xe7, 0xaa, 0x57, 0xab, 0xd1, 0x90, 0xfa, 0x2e, 0x4d, 0x5c, 0x8f,
|
||||
0x3b, 0xc3, 0x69, 0x90, 0xa4, 0xea, 0xd6, 0xb2, 0xec, 0xf5, 0x12, 0xef, 0x41, 0x61, 0xaf, 0x32,
|
||||
0xa4, 0x0a, 0x23, 0x9e, 0x5f, 0x0b, 0xa4, 0x61, 0xab, 0x0c, 0xa7, 0xd4, 0x9a, 0x5f, 0x0b, 0xf4,
|
||||
0x5a, 0x61, 0xbf, 0x90, 0x73, 0x27, 0xeb, 0x70, 0x26, 0x94, 0xd1, 0xdf, 0x55, 0x2f, 0x62, 0x2e,
|
||||
0xfc, 0xba, 0xd7, 0xf2, 0x62, 0x6e, 0x94, 0x8a, 0x95, 0xb9, 0xfb, 0x87, 0x0b, 0x67, 0xb0, 0x0f,
|
||||
0x1e, 0xfb, 0xb6, 0xb2, 0x5f, 0x2f, 0xa7, 0x43, 0x5c, 0x91, 0xc0, 0xf9, 0x08, 0x94, 0x43, 0x95,
|
||||
0x74, 0x17, 0x0e, 0xc4, 0x7a, 0x3e, 0x63, 0x2c, 0x33, 0x47, 0x2a, 0xf7, 0xa0, 0xd3, 0xeb, 0x5a,
|
||||
0x22, 0x73, 0x24, 0xd8, 0x97, 0x97, 0xcb, 0x22, 0x87, 0xf9, 0x25, 0xa5, 0xea, 0x24, 0x59, 0xd7,
|
||||
0x77, 0x91, 0xcb, 0x20, 0x21, 0x8c, 0x35, 0xa8, 0xd3, 0x8c, 0x1b, 0x32, 0x87, 0x73, 0x6d, 0x58,
|
||||
0x37, 0x96, 0xf1, 0xca, 0xe6, 0xc7, 0x04, 0x14, 0xa5, 0x24, 0x72, 0x00, 0xe3, 0x0d, 0xf1, 0x11,
|
||||
0xe4, 0xde, 0xbe, 0x31, 0xec, 0xe0, 0xa6, 0xbe, 0xac, 0x5e, 0xbf, 0x12, 0x80, 0x89, 0x38, 0xf2,
|
||||
0xd3, 0x16, 0x80, 0x9b, 0x24, 0xc6, 0x92, 0xe5, 0x83, 0xb9, 0xd9, 0x1d, 0x95, 0x73, 0xd3, 0xae,
|
||||
0x91, 0x02, 0x45, 0x68, 0x48, 0x26, 0xaf, 0xc2, 0x64, 0x48, 0xdd, 0xc0, 0x77, 0xbd, 0x26, 0xad,
|
||||
0x2e, 0xc7, 0xdc, 0x73, 0x3f, 0x59, 0x02, 0x6d, 0x86, 0xf9, 0x27, 0x68, 0xf0, 0xc0, 0x14, 0x47,
|
||||
0xf2, 0xba, 0x05, 0xd3, 0x2a, 0x39, 0xc8, 0x3e, 0x08, 0x95, 0x49, 0x92, 0xf5, 0x9c, 0x52, 0x91,
|
||||
0x9c, 0x67, 0x85, 0xb0, 0x08, 0x25, 0x0d, 0xc3, 0x8c, 0x5c, 0xf2, 0x0a, 0x40, 0xb0, 0xcb, 0x13,
|
||||
0x71, 0xac, 0xab, 0xa5, 0x13, 0x77, 0x75, 0x5a, 0xe4, 0x94, 0x13, 0x0e, 0x68, 0x70, 0x23, 0xd7,
|
||||
0x01, 0xc4, 0xb2, 0xd9, 0xe9, 0xb6, 0x29, 0x0f, 0x1b, 0xca, 0x95, 0xb7, 0x26, 0x83, 0xbf, 0xad,
|
||||
0x30, 0x0f, 0x0e, 0x17, 0x7a, 0x03, 0x5c, 0x9e, 0x01, 0x35, 0x9a, 0x93, 0x0f, 0xc3, 0x78, 0xd4,
|
||||
0x69, 0xb5, 0x1c, 0x95, 0x4f, 0xd9, 0xca, 0x6f, 0x47, 0x14, 0x7c, 0xf5, 0xdc, 0x94, 0x00, 0x4c,
|
||||
0x24, 0xda, 0x3e, 0x90, 0x5e, 0x7a, 0xf2, 0x02, 0x4c, 0xd2, 0x83, 0x98, 0x86, 0xbe, 0xd3, 0xbc,
|
||||
0x85, 0xeb, 0x49, 0x04, 0xce, 0x3f, 0xfe, 0x25, 0x03, 0x8e, 0x29, 0x2a, 0x62, 0x2b, 0xcf, 0xbb,
|
||||
0xc0, 0xe9, 0x41, 0x7b, 0xde, 0x89, 0x9f, 0x6d, 0xff, 0x47, 0x21, 0xe5, 0x11, 0xec, 0x84, 0x94,
|
||||
0x92, 0x00, 0x46, 0xfd, 0xa0, 0xaa, 0x8c, 0xde, 0xb5, 0x7c, 0x8c, 0xde, 0x8d, 0xa0, 0x6a, 0x9c,
|
||||
0x06, 0xb3, 0x5f, 0x11, 0x0a, 0x39, 0xfc, 0xb8, 0x2c, 0x39, 0x57, 0xe4, 0x08, 0xe9, 0x04, 0xe5,
|
||||
0x29, 0x59, 0x1d, 0x97, 0x6d, 0x9a, 0x82, 0x30, 0x2d, 0x97, 0xec, 0xc1, 0x68, 0x23, 0x88, 0x62,
|
||||
0x11, 0xab, 0x0c, 0xed, 0x85, 0x5d, 0x0d, 0xa2, 0x98, 0x6f, 0x61, 0xaa, 0xdb, 0x0c, 0x12, 0xa1,
|
||||
0x90, 0x61, 0x7f, 0xdf, 0x4a, 0xe5, 0x5b, 0xee, 0x38, 0xb1, 0xdb, 0xb8, 0xb4, 0x4f, 0x7d, 0x36,
|
||||
0x9f, 0xcd, 0x64, 0xfd, 0xff, 0x37, 0x93, 0xf5, 0x0f, 0x0e, 0x17, 0xde, 0x32, 0xa8, 0x3c, 0xe7,
|
||||
0x1e, 0xe3, 0xb0, 0xc8, 0x59, 0x18, 0x79, 0xfd, 0x8f, 0x5b, 0x30, 0x61, 0xa8, 0x27, 0x37, 0x94,
|
||||
0x1c, 0xf3, 0xc6, 0xca, 0xb9, 0x32, 0x80, 0x68, 0x8a, 0xb4, 0xbf, 0x68, 0xc1, 0x78, 0xc5, 0x71,
|
||||
0xf7, 0x82, 0x5a, 0x8d, 0x05, 0xf8, 0xd5, 0x8e, 0x3c, 0x16, 0x11, 0xfd, 0x53, 0x01, 0xfe, 0xaa,
|
||||
0x84, 0xa3, 0xa2, 0x60, 0x73, 0xb8, 0xe6, 0xb8, 0x71, 0x10, 0x72, 0xb5, 0x8b, 0x62, 0x0e, 0x5f,
|
||||
0xe6, 0x10, 0x94, 0x18, 0xf2, 0x0e, 0x98, 0x68, 0x39, 0x07, 0x49, 0xe3, 0x6c, 0xb2, 0x67, 0x43,
|
||||
0xa3, 0xd0, 0xa4, 0xb3, 0x7f, 0xbf, 0x0c, 0xe3, 0xf2, 0x04, 0xf3, 0xd8, 0x27, 0x08, 0x89, 0x17,
|
||||
0x5f, 0x18, 0xe8, 0xc5, 0x47, 0x30, 0xe6, 0xf2, 0xe2, 0x27, 0xb9, 0x95, 0x0e, 0x99, 0xf6, 0x92,
|
||||
0x0a, 0x8a, 0x7a, 0x2a, 0xad, 0x96, 0xf8, 0x8d, 0x52, 0x14, 0xf9, 0x82, 0x05, 0xa7, 0xdc, 0xc0,
|
||||
0xf7, 0xa9, 0xab, 0xed, 0xfc, 0x48, 0x1e, 0x27, 0x6c, 0x2b, 0x69, 0xa6, 0x3a, 0x45, 0x94, 0x41,
|
||||
0x60, 0x56, 0x3c, 0x79, 0x09, 0xa6, 0xc4, 0x98, 0xdd, 0x4e, 0xc5, 0xc7, 0xfa, 0xd4, 0xda, 0x44,
|
||||
0x62, 0x9a, 0x96, 0x2c, 0x8a, 0x3c, 0x83, 0x3c, 0x1f, 0x1e, 0xd3, 0xf9, 0x46, 0xe3, 0x64, 0xd8,
|
||||
0xa0, 0x20, 0x21, 0x90, 0x90, 0xd6, 0x42, 0x1a, 0x35, 0x90, 0xbe, 0xd6, 0xa1, 0x51, 0xcc, 0xf7,
|
||||
0x98, 0xf1, 0x47, 0x3b, 0x8f, 0xc2, 0x1e, 0x4e, 0xd8, 0x87, 0x3b, 0xd9, 0x93, 0x8e, 0x6e, 0x29,
|
||||
0x8f, 0xe5, 0x24, 0x3f, 0xf3, 0x40, 0x7f, 0x77, 0x01, 0x46, 0xa3, 0x86, 0x13, 0x56, 0xf9, 0xde,
|
||||
0x56, 0xac, 0x94, 0x99, 0x2d, 0xd9, 0x66, 0x00, 0x14, 0x70, 0xb2, 0x0a, 0x33, 0x99, 0x33, 0xf7,
|
||||
0x88, 0xef, 0x5e, 0xa5, 0xca, 0x9c, 0x64, 0x37, 0x93, 0x39, 0xad, 0x8f, 0xb0, 0xa7, 0x85, 0x19,
|
||||
0x04, 0x4d, 0x1c, 0x11, 0x04, 0x75, 0x61, 0xac, 0x29, 0x12, 0x01, 0x93, 0xdc, 0x54, 0xde, 0xcc,
|
||||
0x65, 0x00, 0x16, 0xcd, 0x04, 0x8c, 0x9a, 0xed, 0x32, 0xa1, 0x20, 0x05, 0x92, 0xcf, 0x32, 0x83,
|
||||
0x66, 0xe4, 0x0e, 0xa6, 0xb8, 0x02, 0xb7, 0xf3, 0x51, 0xa0, 0x27, 0x55, 0xa2, 0xad, 0x9b, 0x91,
|
||||
0x88, 0x30, 0xe5, 0xcf, 0xff, 0x08, 0x4c, 0x3c, 0x6a, 0xde, 0xe1, 0x65, 0x98, 0x19, 0x2a, 0xe3,
|
||||
0xf0, 0xef, 0x16, 0x24, 0xdf, 0x75, 0xc5, 0x71, 0x1b, 0x94, 0x4d, 0x19, 0xf2, 0x32, 0x4c, 0xab,
|
||||
0x30, 0x62, 0x25, 0xe8, 0xf8, 0x31, 0xe7, 0x55, 0xd4, 0xb9, 0x64, 0x4c, 0x61, 0x31, 0x43, 0x4d,
|
||||
0x96, 0xa0, 0xcc, 0xc6, 0x49, 0x34, 0x15, 0x66, 0x57, 0x85, 0x2a, 0xcb, 0x5b, 0x6b, 0xb2, 0x95,
|
||||
0xa6, 0x21, 0x01, 0xcc, 0x36, 0x9d, 0x28, 0xe6, 0x1a, 0xb0, 0xa8, 0xe2, 0x11, 0x4f, 0x83, 0x79,
|
||||
0xc9, 0xd1, 0x7a, 0x96, 0x11, 0xf6, 0xf2, 0xb6, 0xbf, 0x35, 0x02, 0x53, 0x29, 0xcb, 0xc8, 0x76,
|
||||
0x95, 0x4e, 0xc4, 0x5c, 0x1f, 0x95, 0x62, 0x51, 0xbb, 0xca, 0x2d, 0x09, 0x47, 0x45, 0xc1, 0xa8,
|
||||
0xdb, 0x4e, 0x14, 0xdd, 0x0b, 0xc2, 0xaa, 0x34, 0xe5, 0x8a, 0x7a, 0x4b, 0xc2, 0x51, 0x51, 0xb0,
|
||||
0xfd, 0x65, 0x97, 0x3a, 0x21, 0x0d, 0x79, 0x01, 0x45, 0x76, 0x7f, 0xa9, 0x68, 0x14, 0x9a, 0x74,
|
||||
0xdc, 0x28, 0xc7, 0xcd, 0x68, 0xa5, 0xe9, 0x51, 0x3f, 0x16, 0x6a, 0xe6, 0x63, 0x94, 0x77, 0xd6,
|
||||
0xb7, 0x4d, 0xa6, 0xda, 0x28, 0x67, 0x10, 0x98, 0x15, 0x4f, 0x3e, 0x69, 0xc1, 0x94, 0x73, 0x2f,
|
||||
0xd2, 0x15, 0xba, 0xdc, 0x2a, 0x0f, 0xbd, 0x49, 0xa5, 0x8a, 0x7e, 0x2b, 0xb3, 0xcc, 0xbc, 0xa7,
|
||||
0x40, 0x98, 0x16, 0x4a, 0xbe, 0x6c, 0x01, 0xa1, 0x07, 0xd4, 0xdd, 0x0a, 0x83, 0x7d, 0xaf, 0x9a,
|
||||
0x7c, 0x43, 0x19, 0xfe, 0x0c, 0xe9, 0x6d, 0x5f, 0xea, 0xe1, 0x2b, 0xac, 0x7a, 0x2f, 0x1c, 0xfb,
|
||||
0xe8, 0x60, 0xff, 0x45, 0x11, 0x26, 0x0c, 0x63, 0xdc, 0x77, 0x67, 0xb5, 0x7e, 0xc0, 0x76, 0xd6,
|
||||
0xc2, 0x09, 0x76, 0xd6, 0x8f, 0x41, 0xd9, 0x4d, 0x0c, 0x45, 0x3e, 0x15, 0xc5, 0x59, 0xf3, 0xa3,
|
||||
0x6d, 0x85, 0x02, 0xa1, 0x96, 0x49, 0xae, 0xc0, 0xac, 0xc1, 0x46, 0x1a, 0x99, 0x11, 0x6e, 0x64,
|
||||
0x54, 0xa2, 0x69, 0x39, 0x4b, 0x80, 0xbd, 0x6d, 0xc8, 0xf3, 0xcc, 0xab, 0xf5, 0x64, 0xbf, 0x44,
|
||||
0x14, 0x2f, 0xab, 0x75, 0x97, 0xb7, 0xd6, 0x12, 0x30, 0x9a, 0x34, 0xf6, 0xb7, 0x2c, 0xf5, 0x71,
|
||||
0x9f, 0x40, 0xa1, 0xc6, 0xdd, 0x74, 0xa1, 0xc6, 0xa5, 0x5c, 0x86, 0x79, 0x40, 0x91, 0xc6, 0x0d,
|
||||
0x18, 0x5f, 0x09, 0x5a, 0x2d, 0xc7, 0xaf, 0x92, 0x37, 0xc1, 0xb8, 0x2b, 0xfe, 0x94, 0x61, 0xe2,
|
||||
0x04, 0xdb, 0xbf, 0x25, 0x16, 0x13, 0x1c, 0x79, 0x06, 0x46, 0x9c, 0xb0, 0x9e, 0x84, 0x86, 0xfc,
|
||||
0xec, 0x68, 0x39, 0xac, 0x47, 0xc8, 0xa1, 0xf6, 0x97, 0x0a, 0x00, 0x2b, 0x41, 0xab, 0xed, 0x84,
|
||||
0xb4, 0xba, 0x13, 0xfc, 0x4f, 0x8e, 0x58, 0x44, 0x0c, 0x9f, 0xb1, 0x80, 0xb0, 0x51, 0x09, 0x7c,
|
||||
0xea, 0xc7, 0xea, 0xf0, 0x95, 0xed, 0x97, 0x6e, 0x02, 0x95, 0x9b, 0x8f, 0x5e, 0x03, 0x09, 0x02,
|
||||
0x35, 0xcd, 0x31, 0xa2, 0x88, 0x67, 0x93, 0x1d, 0xbf, 0x98, 0xae, 0x69, 0xe0, 0x07, 0xa5, 0xd2,
|
||||
0x01, 0xb0, 0xbf, 0x5e, 0x80, 0x73, 0xc2, 0x6c, 0x6d, 0x38, 0xbe, 0x53, 0xa7, 0x2d, 0xa6, 0xd5,
|
||||
0x71, 0x4f, 0x1b, 0x5c, 0xe6, 0xbe, 0x7a, 0x49, 0x09, 0xc3, 0xb0, 0x93, 0x53, 0x4c, 0x2a, 0x31,
|
||||
0x8d, 0xd6, 0x7c, 0x2f, 0x46, 0xce, 0x9c, 0x44, 0x50, 0x4a, 0xee, 0x88, 0x48, 0x63, 0x93, 0x93,
|
||||
0x20, 0xb5, 0xee, 0xae, 0x48, 0xf6, 0xa8, 0x04, 0xb1, 0xcd, 0xbd, 0x19, 0xb8, 0x7b, 0x48, 0xdb,
|
||||
0x01, 0x37, 0x2c, 0xc6, 0x09, 0xf2, 0xba, 0x84, 0xa3, 0xa2, 0xb0, 0xbf, 0x6e, 0x41, 0xd6, 0xe4,
|
||||
0xf2, 0x68, 0x50, 0xd4, 0x0c, 0x66, 0xa3, 0xc1, 0x74, 0x89, 0xdf, 0x09, 0x2a, 0xe6, 0x3e, 0x00,
|
||||
0x13, 0x4e, 0x1c, 0xd3, 0x56, 0x5b, 0x84, 0x26, 0xc5, 0x47, 0x4b, 0x7f, 0x6d, 0x04, 0x55, 0xaf,
|
||||
0xe6, 0xf1, 0x90, 0xc4, 0x64, 0x67, 0xdf, 0x84, 0x52, 0x72, 0xe2, 0x73, 0x8c, 0x4f, 0xff, 0x6c,
|
||||
0xca, 0x9d, 0x1c, 0x30, 0xb9, 0x1e, 0x14, 0xa0, 0xcf, 0x9e, 0xc9, 0xba, 0xac, 0xad, 0x4b, 0xaa,
|
||||
0xcb, 0x27, 0xb3, 0x30, 0xe4, 0x40, 0x9c, 0x76, 0x89, 0x3c, 0xcb, 0xfb, 0xf2, 0xde, 0xf3, 0xf5,
|
||||
0x01, 0xd8, 0x84, 0xd4, 0x4f, 0x1d, 0x82, 0x91, 0x8b, 0x00, 0x7a, 0x53, 0x90, 0x85, 0x1e, 0x2a,
|
||||
0x53, 0xab, 0xf7, 0x0e, 0x34, 0xa8, 0x98, 0x0b, 0xe8, 0xf9, 0x51, 0xec, 0x34, 0x9b, 0x57, 0x3d,
|
||||
0x3f, 0x96, 0xb1, 0xac, 0x32, 0x18, 0x6b, 0x1a, 0x85, 0x26, 0xdd, 0xfc, 0x3b, 0x8d, 0xef, 0x72,
|
||||
0x12, 0xb7, 0xfe, 0x33, 0x05, 0x98, 0xbe, 0xe2, 0x77, 0xb6, 0xae, 0x6c, 0x75, 0x76, 0x9b, 0x9e,
|
||||
0x7b, 0x9d, 0x76, 0xd9, 0x47, 0xdb, 0xa3, 0xdd, 0xb5, 0x55, 0x39, 0xec, 0xea, 0xa3, 0x5d, 0x67,
|
||||
0x40, 0x14, 0x38, 0xa6, 0x66, 0xcd, 0xf3, 0xeb, 0x34, 0x6c, 0x87, 0x9e, 0xf4, 0xdd, 0x0d, 0x35,
|
||||
0x2f, 0x6b, 0x14, 0x9a, 0x74, 0x8c, 0x77, 0x70, 0xcf, 0xa7, 0x61, 0xd6, 0xda, 0x6c, 0x32, 0x20,
|
||||
0x0a, 0x1c, 0x23, 0x8a, 0xc3, 0x4e, 0x14, 0xcb, 0x11, 0x53, 0x44, 0x3b, 0x0c, 0x88, 0x02, 0xc7,
|
||||
0xa6, 0x47, 0xd4, 0xd9, 0xe5, 0x59, 0xd8, 0xcc, 0x79, 0xf8, 0xb6, 0x00, 0x63, 0x82, 0x67, 0xa4,
|
||||
0x7b, 0xb4, 0xbb, 0xca, 0xf6, 0xde, 0x4c, 0xc5, 0xca, 0x75, 0x01, 0xc6, 0x04, 0x6f, 0xff, 0xad,
|
||||
0x05, 0x24, 0x3d, 0x1c, 0x4f, 0x60, 0xfb, 0x7e, 0x2d, 0xbd, 0x7d, 0x0f, 0x99, 0x30, 0x4f, 0xab,
|
||||
0x3f, 0x60, 0x17, 0xff, 0x45, 0x0b, 0x26, 0xcd, 0xb3, 0x13, 0x52, 0xcf, 0x18, 0xa2, 0xcd, 0xb4,
|
||||
0x21, 0x7a, 0x70, 0xb8, 0xf0, 0xa3, 0xfd, 0x2e, 0x3c, 0xd6, 0xbd, 0x38, 0x68, 0x47, 0x6f, 0xa7,
|
||||
0x7e, 0xdd, 0xf3, 0x29, 0xcf, 0x0c, 0x8a, 0x33, 0x97, 0xd4, 0xc1, 0xcc, 0x4a, 0x50, 0xa5, 0x8f,
|
||||
0x60, 0xc9, 0xec, 0x3b, 0x30, 0xdb, 0x53, 0xa6, 0x74, 0x0c, 0xa3, 0x73, 0x64, 0x15, 0xa8, 0x8d,
|
||||
0x30, 0xc1, 0x18, 0x6f, 0xb6, 0xc5, 0xe1, 0xc8, 0x0a, 0xcc, 0x8a, 0x6a, 0x2b, 0x26, 0x69, 0xdb,
|
||||
0x6d, 0xd0, 0x96, 0x2a, 0x3d, 0xe3, 0x81, 0xe2, 0xed, 0x2c, 0x12, 0x7b, 0xe9, 0xed, 0xcf, 0x5a,
|
||||
0x30, 0x95, 0xaa, 0x1c, 0xcb, 0xc9, 0x3c, 0xf2, 0x95, 0x16, 0xf0, 0xa3, 0xbc, 0xd0, 0xf3, 0x45,
|
||||
0xae, 0xaf, 0x64, 0xac, 0x34, 0x8d, 0x42, 0x93, 0xce, 0xfe, 0x62, 0x01, 0x4a, 0x49, 0x56, 0xf8,
|
||||
0x18, 0xaa, 0x7c, 0xda, 0x82, 0x29, 0x15, 0x9c, 0x73, 0x97, 0x5d, 0x4c, 0xc6, 0x1b, 0xc3, 0xe7,
|
||||
0xa5, 0xd5, 0x79, 0x2f, 0x73, 0xd9, 0x55, 0xec, 0x80, 0xa6, 0x30, 0x4c, 0xcb, 0x26, 0xb7, 0x01,
|
||||
0xa2, 0x6e, 0x14, 0xd3, 0x96, 0x11, 0x3c, 0xd8, 0xc6, 0x8a, 0x5b, 0x74, 0x83, 0x90, 0xb2, 0xf5,
|
||||
0x75, 0x23, 0xa8, 0xd2, 0x6d, 0x45, 0xa9, 0x8d, 0xab, 0x86, 0xa1, 0xc1, 0xc9, 0xfe, 0xb5, 0x02,
|
||||
0xcc, 0x64, 0x55, 0x22, 0xef, 0x87, 0xc9, 0x44, 0xba, 0x71, 0x77, 0x34, 0x49, 0x85, 0x4f, 0xa2,
|
||||
0x81, 0x7b, 0x70, 0xb8, 0xb0, 0xd0, 0x7b, 0x79, 0x76, 0xd1, 0x24, 0xc1, 0x14, 0x33, 0x91, 0x21,
|
||||
0x91, 0xa9, 0xbc, 0x4a, 0x77, 0xb9, 0xdd, 0x96, 0x69, 0x0e, 0x23, 0x43, 0x62, 0x62, 0x31, 0x43,
|
||||
0x4d, 0xb6, 0xe0, 0x8c, 0x01, 0xb9, 0x41, 0xbd, 0x7a, 0x63, 0x37, 0x08, 0xc5, 0x15, 0x83, 0x62,
|
||||
0xe5, 0x19, 0xc9, 0xe5, 0x0c, 0xf6, 0xa1, 0xc1, 0xbe, 0x2d, 0x99, 0xd3, 0xe2, 0x3a, 0x6d, 0xc7,
|
||||
0xf5, 0xe2, 0xae, 0x8c, 0x86, 0x94, 0x6d, 0x5a, 0x91, 0x70, 0x54, 0x14, 0xf6, 0x06, 0x8c, 0x1c,
|
||||
0x73, 0x06, 0x1d, 0x6b, 0xaf, 0xbf, 0x09, 0x25, 0xc6, 0x8e, 0xd9, 0xa2, 0xbc, 0x58, 0x06, 0x50,
|
||||
0x4a, 0x6e, 0x9c, 0x10, 0x1b, 0x8a, 0x9e, 0x93, 0x24, 0xa1, 0x54, 0xb7, 0xd6, 0xa2, 0xa8, 0xc3,
|
||||
0x3d, 0x19, 0x86, 0x24, 0xcf, 0x42, 0x91, 0x1e, 0xb4, 0xb3, 0xd9, 0xa6, 0x4b, 0x07, 0x6d, 0x2f,
|
||||
0xa4, 0x11, 0x23, 0xa2, 0x07, 0x6d, 0x32, 0x0f, 0x05, 0xaf, 0x2a, 0x37, 0x29, 0x90, 0x34, 0x85,
|
||||
0xb5, 0x55, 0x2c, 0x78, 0x55, 0xfb, 0x00, 0xca, 0xea, 0x8a, 0x0b, 0xd9, 0x4b, 0x6c, 0xb7, 0x95,
|
||||
0xc7, 0x31, 0x4e, 0xc2, 0x77, 0x80, 0xd5, 0xee, 0x00, 0xe8, 0x3a, 0xbd, 0xbc, 0xec, 0xcb, 0x05,
|
||||
0x18, 0x71, 0x03, 0x59, 0xde, 0x5b, 0xd2, 0x6c, 0xb8, 0xd1, 0xe6, 0x18, 0xfb, 0x0e, 0x4c, 0x5f,
|
||||
0xf7, 0x83, 0x7b, 0x3e, 0xdb, 0x4c, 0x2f, 0x7b, 0xb4, 0x59, 0x65, 0x8c, 0x6b, 0xec, 0x8f, 0xac,
|
||||
0x8b, 0xc0, 0xb1, 0x28, 0x70, 0xea, 0x1e, 0x48, 0x61, 0xd0, 0x3d, 0x10, 0xfb, 0xe3, 0x16, 0xcc,
|
||||
0xa8, 0x02, 0xb2, 0xc4, 0x1a, 0xbf, 0x08, 0x93, 0xbb, 0x1d, 0xaf, 0x59, 0x95, 0xbf, 0xa5, 0x08,
|
||||
0x55, 0x22, 0x57, 0x31, 0x70, 0x98, 0xa2, 0x64, 0xee, 0xd6, 0xae, 0xe7, 0x3b, 0x61, 0x77, 0x4b,
|
||||
0x9b, 0x7f, 0x65, 0x11, 0x2a, 0x0a, 0x83, 0x06, 0x95, 0xfd, 0xa7, 0x45, 0xd0, 0xd7, 0x5b, 0x88,
|
||||
0x27, 0x2b, 0x21, 0xac, 0x3c, 0x72, 0x55, 0xdb, 0x5d, 0xdf, 0xd5, 0x17, 0x69, 0x4a, 0x99, 0x42,
|
||||
0x88, 0x4f, 0x59, 0xcc, 0xd1, 0xf3, 0x62, 0xcf, 0xe1, 0xeb, 0x53, 0x46, 0x47, 0x5b, 0x39, 0x1d,
|
||||
0x96, 0xaf, 0x09, 0xce, 0x41, 0x68, 0xba, 0x8e, 0x4a, 0x18, 0x9a, 0x92, 0xc9, 0xab, 0xf2, 0x78,
|
||||
0xa1, 0x98, 0x5b, 0x1d, 0x4d, 0x29, 0x73, 0xa6, 0xd0, 0x86, 0xd1, 0x90, 0xc6, 0x61, 0x52, 0xc1,
|
||||
0x74, 0x7d, 0xd8, 0xc3, 0xd6, 0x38, 0xec, 0x6e, 0xc7, 0x2c, 0x02, 0xab, 0x1b, 0xfe, 0x0d, 0x07,
|
||||
0xa3, 0x10, 0x64, 0x47, 0x40, 0x7a, 0xc7, 0xe2, 0x84, 0xa9, 0xdb, 0x25, 0x28, 0x3b, 0x9d, 0x38,
|
||||
0x68, 0xb1, 0x61, 0xe2, 0x9f, 0xa7, 0x64, 0x24, 0xa7, 0x13, 0x04, 0x6a, 0x1a, 0xfb, 0xf3, 0xa3,
|
||||
0x90, 0x29, 0x4d, 0x20, 0x07, 0xe6, 0xd5, 0x2c, 0x2b, 0xdf, 0xab, 0x59, 0x4a, 0x99, 0x7e, 0xd7,
|
||||
0xb3, 0x48, 0x1d, 0x46, 0xdb, 0x0d, 0x27, 0x4a, 0x96, 0xdf, 0xcd, 0x64, 0x98, 0xb6, 0x18, 0xf0,
|
||||
0xc1, 0xe1, 0xc2, 0x7b, 0x8f, 0xe7, 0xce, 0xb1, 0xb9, 0xba, 0x24, 0xea, 0x34, 0xb5, 0x68, 0xce,
|
||||
0x03, 0x05, 0x7f, 0xd3, 0xa1, 0x2b, 0x1e, 0x11, 0x9a, 0x7e, 0xc2, 0x12, 0xf5, 0x6c, 0x48, 0xa3,
|
||||
0x4e, 0x33, 0x96, 0xb3, 0xe1, 0x66, 0x8e, 0xab, 0x4c, 0x30, 0xd6, 0x85, 0x6d, 0xe2, 0x37, 0x1a,
|
||||
0x42, 0xc9, 0xfb, 0xa1, 0x1c, 0xc5, 0x4e, 0x18, 0x3f, 0x62, 0x19, 0x8c, 0x1a, 0xf4, 0xed, 0x84,
|
||||
0x09, 0x6a, 0x7e, 0xe4, 0x15, 0x80, 0x9a, 0xe7, 0x7b, 0x51, 0xe3, 0x11, 0x4f, 0x05, 0xb9, 0xe2,
|
||||
0x97, 0x15, 0x07, 0x34, 0xb8, 0x31, 0xeb, 0xc6, 0xe7, 0xb6, 0xc8, 0x63, 0x96, 0xf8, 0xf6, 0xa5,
|
||||
0xac, 0x1b, 0x2a, 0x0c, 0x1a, 0x54, 0xf6, 0x47, 0xe1, 0x74, 0xf6, 0x62, 0xb5, 0x8c, 0xf0, 0xea,
|
||||
0x61, 0xd0, 0x69, 0x67, 0xcd, 0x37, 0xbf, 0x78, 0x8b, 0x02, 0xc7, 0xcc, 0xf7, 0x9e, 0xe7, 0x57,
|
||||
0xb3, 0xe6, 0xfb, 0xba, 0xe7, 0x57, 0x91, 0x63, 0x8e, 0x71, 0x67, 0xed, 0x77, 0x2d, 0xb8, 0x70,
|
||||
0xd4, 0xfd, 0x6f, 0x16, 0xbd, 0xdf, 0x73, 0x42, 0x5f, 0x5e, 0x87, 0xe1, 0xb6, 0xe3, 0x8e, 0x13,
|
||||
0xfa, 0xc8, 0xa1, 0xa4, 0x0b, 0x63, 0xa2, 0xf4, 0x4f, 0x3a, 0xa4, 0x37, 0xf3, 0xbd, 0x8d, 0xce,
|
||||
0x42, 0x24, 0x95, 0x74, 0x11, 0x65, 0x87, 0x28, 0x05, 0xda, 0xdf, 0xb5, 0x80, 0x6c, 0xee, 0xd3,
|
||||
0x30, 0xf4, 0xaa, 0x46, 0xb1, 0x22, 0x79, 0x01, 0x26, 0xef, 0x6e, 0x6f, 0xde, 0xd8, 0x0a, 0x3c,
|
||||
0x9f, 0xdf, 0xc7, 0x30, 0x4a, 0x64, 0xae, 0x19, 0x70, 0x4c, 0x51, 0xb1, 0x20, 0xe3, 0xee, 0x6b,
|
||||
0x6c, 0xcb, 0xb9, 0x74, 0xd0, 0x0e, 0x69, 0x14, 0xa9, 0x37, 0x1c, 0x64, 0x90, 0x71, 0xed, 0x66,
|
||||
0x06, 0x89, 0xbd, 0xf4, 0x64, 0x13, 0xce, 0xb6, 0x78, 0x02, 0xae, 0xca, 0x77, 0xda, 0x48, 0x64,
|
||||
0xe3, 0xc2, 0xa4, 0xe0, 0xfd, 0x0d, 0xf7, 0x0f, 0x17, 0xce, 0x6e, 0xf4, 0x23, 0xc0, 0xfe, 0xed,
|
||||
0xec, 0xaf, 0x15, 0x60, 0xc2, 0x78, 0x43, 0xe1, 0x18, 0x3e, 0x45, 0xe6, 0xd9, 0x87, 0xc2, 0x31,
|
||||
0x9f, 0x7d, 0x78, 0x0e, 0x4a, 0xed, 0xa0, 0xe9, 0xb9, 0x9e, 0xaa, 0xce, 0x9f, 0xe4, 0x67, 0x60,
|
||||
0x12, 0x86, 0x0a, 0x4b, 0xee, 0x41, 0x59, 0x5d, 0x65, 0x96, 0xf5, 0x7a, 0x79, 0x79, 0x55, 0x6a,
|
||||
0xf1, 0xea, 0x2b, 0xca, 0x5a, 0x16, 0xb1, 0x61, 0x8c, 0xcf, 0xfc, 0x24, 0xc3, 0xcf, 0x0b, 0x40,
|
||||
0xf8, 0x92, 0x88, 0x50, 0x62, 0xec, 0x7f, 0x18, 0x85, 0x32, 0xd2, 0x76, 0xb0, 0x12, 0xd2, 0x6a,
|
||||
0x44, 0xde, 0x08, 0xc5, 0x4e, 0xd8, 0x94, 0x83, 0xa5, 0xd2, 0x3f, 0xb7, 0x70, 0x1d, 0x19, 0x3c,
|
||||
0xb5, 0xdd, 0x14, 0x4e, 0x74, 0x52, 0x58, 0x3c, 0xf2, 0xa4, 0xf0, 0x25, 0x98, 0x8a, 0xa2, 0xc6,
|
||||
0x56, 0xe8, 0xed, 0x3b, 0x31, 0x9b, 0xc4, 0x32, 0x57, 0xa2, 0x8f, 0x66, 0xb6, 0xaf, 0x6a, 0x24,
|
||||
0xa6, 0x69, 0xc9, 0x15, 0x98, 0xd5, 0xe7, 0x75, 0x34, 0x8c, 0x79, 0x6a, 0x44, 0x64, 0x51, 0xd4,
|
||||
0xc9, 0x88, 0x3e, 0xe1, 0x93, 0x04, 0xd8, 0xdb, 0x86, 0xac, 0xc2, 0x4c, 0x0a, 0xc8, 0x14, 0x11,
|
||||
0x29, 0x16, 0x55, 0x0b, 0x90, 0xe2, 0xc3, 0x74, 0xe9, 0x69, 0x41, 0x36, 0xe0, 0xb4, 0xf8, 0xbe,
|
||||
0xfc, 0x0a, 0xbc, 0xea, 0xd1, 0x38, 0x67, 0xf4, 0xbf, 0x24, 0xa3, 0xd3, 0x57, 0x7a, 0x49, 0xb0,
|
||||
0x5f, 0x3b, 0x36, 0x43, 0x15, 0x78, 0x6d, 0x55, 0x5a, 0x4a, 0x35, 0x43, 0x15, 0x9b, 0xb5, 0x2a,
|
||||
0x9a, 0x74, 0xe4, 0x7d, 0xf0, 0xb4, 0xfe, 0x29, 0x32, 0x6b, 0xc2, 0x7d, 0x58, 0x95, 0xa5, 0x10,
|
||||
0xea, 0xa6, 0xd1, 0x95, 0xbe, 0x64, 0x55, 0x1c, 0xd4, 0x9e, 0xec, 0xc2, 0xbc, 0x42, 0x5d, 0x62,
|
||||
0xe6, 0xa0, 0x1d, 0x7a, 0x11, 0xad, 0x38, 0x11, 0xbd, 0x15, 0x36, 0x79, 0xf1, 0x44, 0x59, 0x3f,
|
||||
0x04, 0x71, 0xc5, 0x8b, 0xaf, 0xf6, 0xa3, 0xc4, 0x75, 0x7c, 0x08, 0x17, 0xe6, 0xad, 0x50, 0xdf,
|
||||
0xd9, 0x6d, 0xd2, 0xcd, 0x95, 0x35, 0x5e, 0x52, 0x61, 0x78, 0x2b, 0x97, 0x12, 0x04, 0x6a, 0x1a,
|
||||
0xe5, 0x9e, 0x4f, 0x0e, 0x74, 0xcf, 0xbf, 0x63, 0xc1, 0x94, 0x9a, 0xec, 0x4f, 0x20, 0x0f, 0xd6,
|
||||
0x4c, 0xe7, 0xc1, 0xae, 0x0c, 0xeb, 0x26, 0x4a, 0xcd, 0x07, 0x04, 0x53, 0xdf, 0x2f, 0x03, 0xf0,
|
||||
0xa7, 0x75, 0x3c, 0x5e, 0xaa, 0x7b, 0x01, 0x46, 0x42, 0xda, 0x0e, 0xb2, 0x96, 0x8f, 0xe7, 0xf0,
|
||||
0x39, 0xe6, 0x07, 0x77, 0x39, 0xf7, 0x3b, 0x39, 0x1e, 0xfd, 0xef, 0x3d, 0x39, 0xde, 0x86, 0xb3,
|
||||
0x9e, 0x1f, 0x51, 0xb7, 0x13, 0xca, 0x9d, 0xf3, 0x6a, 0x10, 0x29, 0xeb, 0x50, 0xaa, 0xbc, 0x51,
|
||||
0x32, 0x3a, 0xbb, 0xd6, 0x8f, 0x08, 0xfb, 0xb7, 0x65, 0x43, 0x9a, 0x20, 0xe4, 0x9d, 0x20, 0x1d,
|
||||
0xe2, 0x4b, 0x38, 0x2a, 0x0a, 0xbd, 0x20, 0xd6, 0x6b, 0xc9, 0xa5, 0x9f, 0xcc, 0x82, 0x58, 0xbf,
|
||||
0xbc, 0x8d, 0x9a, 0xa6, 0xbf, 0x55, 0x2c, 0xe7, 0x64, 0x15, 0xe1, 0xc4, 0x56, 0x31, 0x59, 0x9f,
|
||||
0x13, 0x03, 0x9f, 0x51, 0x48, 0x36, 0xeb, 0xc9, 0x81, 0x9b, 0xf5, 0xcb, 0x30, 0xed, 0xf9, 0x0d,
|
||||
0x1a, 0x7a, 0x31, 0xad, 0xf2, 0xb5, 0x30, 0x37, 0xc5, 0x07, 0x42, 0x65, 0x9f, 0xd6, 0x52, 0x58,
|
||||
0xcc, 0x50, 0xa7, 0x8d, 0xca, 0xf4, 0x31, 0x8c, 0xca, 0x00, 0x53, 0x7e, 0x2a, 0x1f, 0x53, 0x3e,
|
||||
0x33, 0xbc, 0x29, 0x9f, 0x7d, 0xac, 0xa6, 0x9c, 0xe4, 0x62, 0xca, 0x9f, 0x85, 0xd1, 0x76, 0x18,
|
||||
0x1c, 0x74, 0xe7, 0x4e, 0xa7, 0xdd, 0xf3, 0x2d, 0x06, 0x44, 0x81, 0x33, 0x0b, 0xe8, 0xce, 0x3c,
|
||||
0xbc, 0x80, 0xce, 0x7e, 0xbd, 0x00, 0x67, 0xb5, 0xa5, 0x63, 0xf3, 0xcb, 0xab, 0xb1, 0xb5, 0xce,
|
||||
0x6f, 0x66, 0x8a, 0xa2, 0x0d, 0x23, 0xf1, 0xa9, 0x73, 0xa8, 0x0a, 0x83, 0x06, 0x15, 0xcf, 0x1f,
|
||||
0xd2, 0x90, 0x97, 0xfd, 0x66, 0xcd, 0xe0, 0x8a, 0x84, 0xa3, 0xa2, 0xe0, 0xef, 0xf2, 0xd1, 0x30,
|
||||
0x96, 0x67, 0x32, 0xd9, 0x8a, 0xa6, 0x15, 0x8d, 0x42, 0x93, 0x8e, 0xb9, 0x8b, 0x6e, 0xb2, 0x04,
|
||||
0x99, 0x29, 0x9c, 0x14, 0xee, 0xa2, 0x5a, 0x75, 0x0a, 0x9b, 0xa8, 0xc3, 0x13, 0xc5, 0xa3, 0xbd,
|
||||
0xea, 0xf0, 0x2c, 0x84, 0xa2, 0xb0, 0xff, 0xcd, 0x82, 0x37, 0xf4, 0x1d, 0x8a, 0x27, 0xb0, 0xbd,
|
||||
0x1d, 0xa4, 0xb7, 0xb7, 0xed, 0xe1, 0xb7, 0xb7, 0x9e, 0x5e, 0x0c, 0xd8, 0xea, 0xfe, 0xdc, 0x82,
|
||||
0x69, 0x4d, 0xff, 0x04, 0xba, 0xea, 0xe5, 0xfa, 0xc2, 0x9e, 0x56, 0x5d, 0x94, 0xa3, 0xa6, 0xfa,
|
||||
0xf6, 0x1d, 0xde, 0x37, 0x11, 0xcc, 0x2d, 0xbb, 0xc9, 0x03, 0x34, 0x47, 0x04, 0x31, 0x5d, 0x18,
|
||||
0xe3, 0x57, 0xf8, 0xa3, 0x7c, 0x82, 0xca, 0xb4, 0x7c, 0x7e, 0x02, 0xa4, 0x83, 0x4a, 0xfe, 0x33,
|
||||
0x42, 0x29, 0x90, 0x17, 0xa5, 0x7b, 0x11, 0xb3, 0x97, 0x55, 0x99, 0x72, 0xd5, 0x45, 0xe9, 0x12,
|
||||
0x8e, 0x8a, 0xc2, 0x6e, 0xc1, 0x5c, 0x9a, 0xf9, 0x2a, 0xad, 0xf1, 0xdc, 0xdd, 0xb1, 0xba, 0xb9,
|
||||
0x04, 0x65, 0x87, 0xb7, 0x5a, 0xef, 0x38, 0xd9, 0x57, 0x68, 0x96, 0x13, 0x04, 0x6a, 0x1a, 0xfb,
|
||||
0x57, 0x2d, 0x38, 0xdd, 0xa7, 0x33, 0x39, 0xa6, 0x9a, 0x63, 0x6d, 0x05, 0x06, 0xbc, 0x0c, 0x54,
|
||||
0xa5, 0x35, 0x27, 0xc9, 0x0e, 0x19, 0x56, 0x6d, 0x55, 0x80, 0x31, 0xc1, 0xdb, 0xff, 0x68, 0xc1,
|
||||
0xa9, 0xb4, 0xae, 0x11, 0xb9, 0x06, 0x44, 0x74, 0x66, 0xd5, 0x8b, 0xdc, 0x60, 0x9f, 0x86, 0x5d,
|
||||
0xd6, 0x73, 0xa1, 0xf5, 0xbc, 0xe4, 0x44, 0x96, 0x7b, 0x28, 0xb0, 0x4f, 0x2b, 0x5e, 0xfb, 0x5b,
|
||||
0x55, 0xa3, 0x9d, 0xcc, 0x94, 0xdb, 0x79, 0xce, 0x14, 0xfd, 0x31, 0xcd, 0x08, 0x5a, 0x89, 0x44,
|
||||
0x53, 0xbe, 0xfd, 0xdd, 0x11, 0x50, 0x67, 0x51, 0x3c, 0x0f, 0x91, 0x53, 0x16, 0x27, 0xf5, 0x54,
|
||||
0x51, 0xf1, 0x04, 0x4f, 0x15, 0x8d, 0x3c, 0x2c, 0x47, 0x20, 0xde, 0xcd, 0xd1, 0xbe, 0xa8, 0x61,
|
||||
0xf4, 0x77, 0x34, 0x0a, 0x4d, 0x3a, 0xa6, 0x49, 0xd3, 0xdb, 0xa7, 0xa2, 0xd1, 0x58, 0x5a, 0x93,
|
||||
0xf5, 0x04, 0x81, 0x9a, 0x86, 0x69, 0x52, 0xf5, 0x6a, 0x35, 0x19, 0x29, 0x2a, 0x4d, 0xd8, 0xe8,
|
||||
0x20, 0xc7, 0x30, 0x8a, 0x46, 0x10, 0xec, 0x49, 0xff, 0x4f, 0x51, 0x5c, 0x0d, 0x82, 0x3d, 0xe4,
|
||||
0x18, 0xe6, 0xb1, 0xf8, 0x41, 0xd8, 0x72, 0x9a, 0xde, 0x87, 0x68, 0x55, 0x49, 0x91, 0x7e, 0x9f,
|
||||
0xf2, 0x58, 0x6e, 0xf4, 0x92, 0x60, 0xbf, 0x76, 0x6c, 0x06, 0xb6, 0x43, 0x5a, 0xf5, 0xdc, 0xd8,
|
||||
0xe4, 0x06, 0xe9, 0x19, 0xb8, 0xd5, 0x43, 0x81, 0x7d, 0x5a, 0x91, 0x65, 0x38, 0x95, 0x9c, 0x25,
|
||||
0x26, 0x35, 0x24, 0xc2, 0x19, 0x54, 0x7e, 0x38, 0xa6, 0xd1, 0x98, 0xa5, 0x67, 0xd6, 0xa6, 0x25,
|
||||
0x2b, 0x79, 0xb8, 0x9b, 0x68, 0x58, 0x9b, 0xa4, 0xc2, 0x07, 0x15, 0x85, 0xfd, 0x89, 0x22, 0xdb,
|
||||
0x1d, 0x07, 0xdc, 0xce, 0x7d, 0x62, 0x59, 0xc3, 0xf4, 0x8c, 0x1c, 0x39, 0xc6, 0x8c, 0x7c, 0x01,
|
||||
0x26, 0xef, 0x46, 0x81, 0xaf, 0x32, 0x72, 0xa3, 0x03, 0x33, 0x72, 0x06, 0x55, 0xff, 0x8c, 0xdc,
|
||||
0x58, 0x5e, 0x19, 0xb9, 0xf1, 0x47, 0xcc, 0xc8, 0xfd, 0xd1, 0x28, 0x9c, 0x53, 0xe7, 0xc9, 0x34,
|
||||
0xbe, 0x17, 0x84, 0x7b, 0x9e, 0x5f, 0xe7, 0x67, 0xb0, 0x5f, 0xb5, 0x60, 0x52, 0xac, 0x17, 0xf9,
|
||||
0x30, 0x82, 0x38, 0x73, 0xac, 0xe5, 0x74, 0x77, 0x2d, 0x25, 0x6c, 0x71, 0xc7, 0x10, 0x94, 0x79,
|
||||
0xa5, 0xc2, 0x44, 0x61, 0x4a, 0x23, 0xf2, 0x11, 0x80, 0xe4, 0xc5, 0xac, 0x5a, 0x4e, 0xef, 0x86,
|
||||
0x25, 0xfa, 0x21, 0xad, 0x69, 0xdf, 0x74, 0x47, 0x09, 0x41, 0x43, 0x20, 0x79, 0xdd, 0x52, 0x77,
|
||||
0x45, 0xc4, 0x69, 0xd6, 0xab, 0x8f, 0x65, 0x6c, 0x8e, 0x73, 0x75, 0x04, 0x61, 0xdc, 0xf3, 0xeb,
|
||||
0x6c, 0x9e, 0xc8, 0x24, 0xe6, 0x5b, 0xfa, 0xd5, 0x2f, 0xac, 0x07, 0x4e, 0xb5, 0xe2, 0x34, 0x1d,
|
||||
0xdf, 0xa5, 0xe1, 0x9a, 0x20, 0x37, 0x9f, 0x4d, 0xe2, 0x00, 0x4c, 0x18, 0xf5, 0x5c, 0xce, 0x1c,
|
||||
0x3d, 0xce, 0xe5, 0xcc, 0xf9, 0xf7, 0xc0, 0x6c, 0xcf, 0xc7, 0x3c, 0xd1, 0xd5, 0x91, 0x47, 0xbf,
|
||||
0x75, 0x62, 0xff, 0xde, 0x98, 0xde, 0xb4, 0x6e, 0x04, 0x55, 0x71, 0x45, 0x30, 0xd4, 0x5f, 0x54,
|
||||
0xfa, 0x9e, 0x39, 0x4e, 0x11, 0xe3, 0xe9, 0x25, 0x05, 0x44, 0x53, 0x24, 0x9b, 0xa3, 0x6d, 0x27,
|
||||
0xa4, 0xfe, 0xe3, 0x9e, 0xa3, 0x5b, 0x4a, 0x08, 0x1a, 0x02, 0x49, 0x23, 0x75, 0xdc, 0x7a, 0x79,
|
||||
0xf8, 0xe3, 0x56, 0xe6, 0x0e, 0xf7, 0xbd, 0xca, 0xf5, 0x05, 0x0b, 0xa6, 0xfd, 0xd4, 0xcc, 0x95,
|
||||
0x47, 0x6e, 0x3b, 0x8f, 0x63, 0x55, 0x88, 0xab, 0xd9, 0x69, 0x18, 0x66, 0xe4, 0xf7, 0xdb, 0xd2,
|
||||
0x46, 0x4f, 0xb8, 0xa5, 0xe9, 0xbb, 0xc6, 0x63, 0x83, 0xee, 0x1a, 0x13, 0x5f, 0xbd, 0x32, 0x30,
|
||||
0x9e, 0xfb, 0x2b, 0x03, 0xd0, 0xe7, 0x85, 0x81, 0x3b, 0x50, 0x76, 0x43, 0xea, 0xc4, 0x8f, 0x78,
|
||||
0xe1, 0x9c, 0x3f, 0x76, 0xb7, 0x92, 0x30, 0x40, 0xcd, 0xcb, 0xfe, 0x93, 0x22, 0xcc, 0x24, 0x23,
|
||||
0x92, 0x1c, 0x45, 0xb1, 0xfd, 0x51, 0xc8, 0xd5, 0xce, 0xad, 0xda, 0x1f, 0xaf, 0x26, 0x08, 0xd4,
|
||||
0x34, 0xcc, 0x1f, 0xeb, 0x44, 0x74, 0xb3, 0x4d, 0xfd, 0x75, 0x6f, 0x37, 0xe2, 0x23, 0x6e, 0x94,
|
||||
0x90, 0xdd, 0xd2, 0x28, 0x34, 0xe9, 0x98, 0x33, 0x2e, 0xfc, 0xe2, 0x28, 0x7b, 0xb2, 0x2b, 0xfd,
|
||||
0x6d, 0x4c, 0xf0, 0xe4, 0x2b, 0x7d, 0x9f, 0x0b, 0xc9, 0xa7, 0xa6, 0xa1, 0xe7, 0x04, 0xee, 0x84,
|
||||
0xef, 0x84, 0x7c, 0xde, 0x82, 0x53, 0x7b, 0xa9, 0xfa, 0x95, 0xc4, 0x24, 0x0f, 0x59, 0x69, 0x99,
|
||||
0x2e, 0x8a, 0xd1, 0x53, 0x38, 0x0d, 0x8f, 0x30, 0x2b, 0xdd, 0xfe, 0x17, 0x0b, 0x4c, 0xf3, 0x74,
|
||||
0x3c, 0xcf, 0xca, 0x78, 0x00, 0xaa, 0x70, 0xc4, 0x03, 0x50, 0x89, 0x13, 0x56, 0x3c, 0x9e, 0xd3,
|
||||
0x3f, 0x72, 0x02, 0xa7, 0x7f, 0x74, 0xa0, 0xd7, 0xf6, 0x46, 0x28, 0x76, 0xbc, 0xaa, 0xf4, 0xdb,
|
||||
0xf5, 0x61, 0xd8, 0xda, 0x2a, 0x32, 0xb8, 0xfd, 0x3b, 0xa3, 0x3a, 0x4e, 0x97, 0x47, 0xf1, 0x3f,
|
||||
0x14, 0xdd, 0xae, 0xa9, 0xc2, 0x59, 0xd1, 0xf3, 0x1b, 0x3d, 0x85, 0xb3, 0xef, 0x3e, 0x79, 0xa5,
|
||||
0x85, 0x18, 0xa0, 0x41, 0x75, 0xb3, 0xe3, 0x47, 0x94, 0x59, 0xdc, 0x85, 0x12, 0x0b, 0x6d, 0x78,
|
||||
0xc2, 0xad, 0x94, 0x52, 0xaa, 0x74, 0x55, 0xc2, 0x1f, 0x1c, 0x2e, 0xbc, 0xeb, 0xe4, 0x6a, 0x25,
|
||||
0xad, 0x51, 0xf1, 0x27, 0x11, 0x94, 0xd9, 0xdf, 0xbc, 0x22, 0x44, 0x06, 0x4d, 0xb7, 0x94, 0x2d,
|
||||
0x4a, 0x10, 0xb9, 0x94, 0x9b, 0x68, 0x39, 0xc4, 0x87, 0x32, 0x7f, 0xaa, 0x88, 0x0b, 0x15, 0xb1,
|
||||
0xd5, 0x96, 0xaa, 0xcb, 0x48, 0x10, 0x0f, 0x0e, 0x17, 0x5e, 0x3a, 0xb9, 0x50, 0xd5, 0x1c, 0xb5,
|
||||
0x08, 0xfb, 0x6f, 0x8a, 0x7a, 0xee, 0xca, 0x7a, 0xe9, 0x1f, 0x8a, 0xb9, 0xfb, 0x62, 0x66, 0xee,
|
||||
0x5e, 0xe8, 0x99, 0xbb, 0xd3, 0xfa, 0x39, 0x9f, 0xd4, 0x6c, 0x7c, 0xd2, 0x1b, 0xec, 0xd1, 0x71,
|
||||
0x3c, 0xf7, 0x2c, 0x5e, 0xeb, 0x78, 0x21, 0x8d, 0xb6, 0xc2, 0x8e, 0xef, 0xf9, 0x75, 0xf9, 0xa8,
|
||||
0xa3, 0xe1, 0x59, 0xa4, 0xd0, 0x98, 0xa5, 0xb7, 0xbf, 0xc6, 0xcf, 0x3b, 0x8d, 0xe2, 0x32, 0xf6,
|
||||
0x95, 0x9b, 0xfc, 0xb5, 0x27, 0x51, 0x51, 0xaa, 0xbe, 0xb2, 0x78, 0xe2, 0x49, 0xe0, 0xc8, 0x3d,
|
||||
0x18, 0xdf, 0x15, 0x2f, 0x4e, 0xe4, 0x73, 0xc5, 0x49, 0x3e, 0x5f, 0xc1, 0x2f, 0x93, 0x26, 0x6f,
|
||||
0x59, 0x3c, 0xd0, 0x7f, 0x62, 0x22, 0xcd, 0xfe, 0xf9, 0x22, 0x9c, 0xca, 0xbc, 0x45, 0xc4, 0x02,
|
||||
0xfe, 0xe4, 0xe1, 0xa9, 0x6c, 0x76, 0x5e, 0x3d, 0x6a, 0xac, 0x28, 0xc8, 0x07, 0x01, 0xaa, 0xb4,
|
||||
0xdd, 0x0c, 0xba, 0xdc, 0x71, 0x19, 0x39, 0xb1, 0xe3, 0xa2, 0x7c, 0xdd, 0x55, 0xc5, 0x05, 0x0d,
|
||||
0x8e, 0xb2, 0x8c, 0x76, 0x54, 0xbc, 0xa7, 0x91, 0x2e, 0xa3, 0x35, 0x6e, 0xfa, 0x8d, 0x3d, 0xd9,
|
||||
0x9b, 0x7e, 0x1e, 0x9c, 0x12, 0x2a, 0xaa, 0x12, 0xae, 0x47, 0xa8, 0xd4, 0x3a, 0xcd, 0x66, 0xd4,
|
||||
0x6a, 0x9a, 0x0d, 0x66, 0xf9, 0xda, 0x9f, 0x2b, 0x30, 0xf7, 0x4d, 0x0c, 0xf6, 0x46, 0x92, 0x1c,
|
||||
0x7f, 0x33, 0x8c, 0x39, 0x9d, 0xb8, 0x11, 0xf4, 0xbc, 0x00, 0xb2, 0xcc, 0xa1, 0x28, 0xb1, 0x64,
|
||||
0x1d, 0x46, 0xaa, 0x4e, 0x9c, 0x3c, 0xca, 0x7f, 0x12, 0xe5, 0x74, 0x26, 0xcc, 0x89, 0x29, 0x72,
|
||||
0x2e, 0xe4, 0x19, 0x18, 0x89, 0x9d, 0x7a, 0xea, 0x05, 0xcf, 0x1d, 0xa7, 0x1e, 0x21, 0x87, 0x9a,
|
||||
0xbb, 0xcb, 0xc8, 0x11, 0xbb, 0xcb, 0x4b, 0xc6, 0x3f, 0x9c, 0x30, 0x4e, 0x5d, 0x7a, 0xff, 0x49,
|
||||
0x84, 0x28, 0xec, 0x4f, 0xd1, 0xda, 0xff, 0x0f, 0x26, 0xcd, 0x7f, 0x22, 0x71, 0xac, 0xbb, 0x46,
|
||||
0xf6, 0xdf, 0x8f, 0xc0, 0x54, 0xaa, 0xcc, 0x2f, 0x35, 0xcb, 0xad, 0x23, 0x67, 0x39, 0x3f, 0x4f,
|
||||
0xeb, 0xf8, 0x54, 0x16, 0x71, 0x1a, 0xe7, 0x69, 0x1d, 0x9f, 0xa2, 0xc0, 0xb1, 0xaf, 0x52, 0x0d,
|
||||
0xbb, 0xd8, 0xf1, 0x65, 0x56, 0x5e, 0x7d, 0x95, 0x55, 0x0e, 0x45, 0x89, 0x65, 0x01, 0xec, 0x64,
|
||||
0xc4, 0x8d, 0xa2, 0xb0, 0x11, 0x72, 0xd5, 0x5c, 0xcb, 0xe3, 0xd5, 0x34, 0x59, 0xd2, 0xca, 0x03,
|
||||
0x7a, 0x13, 0x82, 0x29, 0x89, 0xe4, 0x93, 0x96, 0xf9, 0x5e, 0xdc, 0x58, 0x1e, 0xa7, 0x49, 0xd9,
|
||||
0x2a, 0x4a, 0xb1, 0x82, 0x1e, 0xfe, 0x6c, 0x5c, 0xa4, 0x16, 0xf0, 0xf8, 0xe3, 0x59, 0xc0, 0xd0,
|
||||
0x67, 0xf1, 0xbe, 0x15, 0xca, 0x2d, 0xc7, 0xf7, 0x6a, 0x34, 0x8a, 0xc5, 0x3f, 0x80, 0x29, 0x8b,
|
||||
0xe8, 0x69, 0x23, 0x01, 0xa2, 0xc6, 0xf3, 0x7f, 0xb3, 0xc4, 0x3b, 0x26, 0x82, 0x98, 0xb2, 0xf1,
|
||||
0x6f, 0x96, 0x34, 0x18, 0x4d, 0x1a, 0xfb, 0x37, 0x2c, 0x38, 0xdb, 0x77, 0x30, 0x7e, 0x70, 0xd3,
|
||||
0x9f, 0xf6, 0x6f, 0x15, 0xe0, 0x74, 0x9f, 0x32, 0x58, 0xd2, 0x7d, 0x6c, 0xcf, 0x0a, 0xca, 0x3a,
|
||||
0xdb, 0xa9, 0x81, 0x73, 0xe3, 0x64, 0xdb, 0x90, 0xde, 0x0a, 0x8a, 0x4f, 0x74, 0x2b, 0xb0, 0xbf,
|
||||
0x56, 0x00, 0xe3, 0x01, 0x4c, 0xf2, 0x51, 0xb3, 0xe2, 0xdb, 0xca, 0xab, 0x3a, 0x59, 0x30, 0x57,
|
||||
0x15, 0xe3, 0x62, 0xd4, 0xfa, 0x15, 0x90, 0x67, 0xe7, 0x6b, 0xe1, 0xe8, 0xf9, 0x4a, 0x9a, 0x49,
|
||||
0x69, 0x7d, 0x31, 0xff, 0xd2, 0xfa, 0x72, 0x4f, 0x59, 0xfd, 0xcf, 0x5a, 0x62, 0xa6, 0x65, 0xba,
|
||||
0xa4, 0x2d, 0xac, 0xf5, 0x10, 0x0b, 0xfb, 0x36, 0x28, 0x45, 0xb4, 0x59, 0x63, 0x9e, 0x9d, 0xb4,
|
||||
0xc4, 0xfa, 0xbd, 0x6d, 0x09, 0x47, 0x45, 0xc1, 0xef, 0xce, 0x36, 0x9b, 0xc1, 0xbd, 0x4b, 0xad,
|
||||
0x76, 0xdc, 0x95, 0x36, 0x59, 0xdf, 0x9d, 0x55, 0x18, 0x34, 0xa8, 0xec, 0x7f, 0xb5, 0xc4, 0xe7,
|
||||
0x94, 0x3e, 0xfa, 0x8b, 0x99, 0x3b, 0x8d, 0xc7, 0x77, 0x6f, 0x7f, 0x12, 0xc0, 0x55, 0x6f, 0x12,
|
||||
0xe4, 0xf3, 0x2e, 0xa6, 0x7e, 0xe3, 0xc0, 0x7c, 0xac, 0x31, 0x81, 0xa1, 0x21, 0x2f, 0xb5, 0x78,
|
||||
0x8a, 0x47, 0x2d, 0x1e, 0xfb, 0x9f, 0x2c, 0x48, 0x6d, 0x16, 0xa4, 0x0d, 0xa3, 0x4c, 0x83, 0x6e,
|
||||
0x3e, 0x2f, 0x28, 0x98, 0xac, 0xd9, 0xc2, 0x92, 0xd3, 0x82, 0xff, 0x89, 0x42, 0x10, 0x69, 0x4a,
|
||||
0xef, 0xbc, 0x90, 0xc7, 0x2b, 0x1f, 0xa6, 0x40, 0xe6, 0xdf, 0xcb, 0x7f, 0x88, 0xa1, 0x3c, 0x7d,
|
||||
0xfb, 0x45, 0x98, 0xed, 0x51, 0x8a, 0xdf, 0x48, 0x0a, 0x92, 0x67, 0x23, 0x8c, 0x19, 0xc8, 0xef,
|
||||
0x47, 0xa2, 0xc0, 0x31, 0x07, 0x7f, 0x26, 0xcb, 0x9e, 0x7c, 0xd9, 0x82, 0xd9, 0x28, 0xcb, 0xef,
|
||||
0x71, 0x8d, 0x9d, 0xca, 0x5c, 0xf5, 0xa0, 0xb0, 0x57, 0x09, 0xfb, 0x3f, 0xa5, 0x79, 0x12, 0xff,
|
||||
0x82, 0x4c, 0x6d, 0x2e, 0xd6, 0xc0, 0xcd, 0x85, 0x2d, 0x31, 0xb7, 0x41, 0xab, 0x9d, 0x66, 0x4f,
|
||||
0x6d, 0xce, 0xb6, 0x84, 0xa3, 0xa2, 0x48, 0xbd, 0x8f, 0x57, 0x3c, 0xf2, 0x7d, 0xbc, 0x17, 0x60,
|
||||
0xd2, 0x7c, 0x1a, 0x85, 0xa7, 0xd0, 0xe4, 0xe1, 0x83, 0xf9, 0x8a, 0x0a, 0xa6, 0xa8, 0x32, 0xef,
|
||||
0xab, 0x8d, 0x1e, 0xf9, 0xbe, 0xda, 0x73, 0x50, 0x92, 0x6f, 0x85, 0x25, 0xf9, 0x5d, 0x51, 0xf8,
|
||||
0x23, 0x61, 0xa8, 0xb0, 0xcc, 0x40, 0xb4, 0x1c, 0xbf, 0xe3, 0x34, 0xd9, 0x08, 0xc9, 0x7a, 0x40,
|
||||
0xb5, 0xb2, 0x36, 0x14, 0x06, 0x0d, 0x2a, 0xd6, 0xe3, 0xd8, 0x6b, 0xd1, 0x57, 0x02, 0x3f, 0xc9,
|
||||
0x8c, 0xa8, 0x1e, 0xef, 0x48, 0x38, 0x2a, 0x0a, 0xfb, 0xef, 0x2c, 0xc8, 0x3e, 0x74, 0x94, 0xaa,
|
||||
0x41, 0xb4, 0x8e, 0xac, 0x41, 0x4c, 0xd7, 0x57, 0x15, 0x8e, 0x55, 0x5f, 0x65, 0x96, 0x3e, 0x15,
|
||||
0x1f, 0x5a, 0xfa, 0xf4, 0x26, 0x7d, 0xaf, 0x5d, 0xd4, 0x48, 0x4d, 0xf4, 0xbb, 0xd3, 0x4e, 0x6c,
|
||||
0x18, 0x73, 0x1d, 0x55, 0xe2, 0x3d, 0x29, 0xdc, 0xaa, 0x95, 0x65, 0x4e, 0x24, 0x31, 0x95, 0xdd,
|
||||
0x6f, 0x7c, 0xef, 0xfc, 0x53, 0xdf, 0xfc, 0xde, 0xf9, 0xa7, 0xbe, 0xfd, 0xbd, 0xf3, 0x4f, 0x7d,
|
||||
0xfc, 0xfe, 0x79, 0xeb, 0x1b, 0xf7, 0xcf, 0x5b, 0xdf, 0xbc, 0x7f, 0xde, 0xfa, 0xf6, 0xfd, 0xf3,
|
||||
0xd6, 0x77, 0xef, 0x9f, 0xb7, 0xbe, 0xf0, 0xd7, 0xe7, 0x9f, 0x7a, 0xe5, 0xdd, 0xc3, 0xfc, 0xcf,
|
||||
0xdb, 0xff, 0x0a, 0x00, 0x00, 0xff, 0xff, 0xb9, 0x8e, 0x56, 0xe9, 0x32, 0x77, 0x00, 0x00,
|
||||
}
|
||||
|
||||
func (m *AWSAuthConfig) Marshal() (dAtA []byte, err error) {
|
||||
|
|
@ -3186,6 +3187,15 @@ func (m *AppProjectSpec) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
|||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if len(m.SourceNamespaces) > 0 {
|
||||
for iNdEx := len(m.SourceNamespaces) - 1; iNdEx >= 0; iNdEx-- {
|
||||
i -= len(m.SourceNamespaces[iNdEx])
|
||||
copy(dAtA[i:], m.SourceNamespaces[iNdEx])
|
||||
i = encodeVarintGenerated(dAtA, i, uint64(len(m.SourceNamespaces[iNdEx])))
|
||||
i--
|
||||
dAtA[i] = 0x62
|
||||
}
|
||||
}
|
||||
if len(m.ClusterResourceBlacklist) > 0 {
|
||||
for iNdEx := len(m.ClusterResourceBlacklist) - 1; iNdEx >= 0; iNdEx-- {
|
||||
{
|
||||
|
|
@ -8235,6 +8245,12 @@ func (m *AppProjectSpec) Size() (n int) {
|
|||
n += 1 + l + sovGenerated(uint64(l))
|
||||
}
|
||||
}
|
||||
if len(m.SourceNamespaces) > 0 {
|
||||
for _, s := range m.SourceNamespaces {
|
||||
l = len(s)
|
||||
n += 1 + l + sovGenerated(uint64(l))
|
||||
}
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
|
|
@ -10132,6 +10148,7 @@ func (this *AppProjectSpec) String() string {
|
|||
`NamespaceResourceWhitelist:` + repeatedStringForNamespaceResourceWhitelist + `,`,
|
||||
`SignatureKeys:` + repeatedStringForSignatureKeys + `,`,
|
||||
`ClusterResourceBlacklist:` + repeatedStringForClusterResourceBlacklist + `,`,
|
||||
`SourceNamespaces:` + fmt.Sprintf("%v", this.SourceNamespaces) + `,`,
|
||||
`}`,
|
||||
}, "")
|
||||
return s
|
||||
|
|
@ -12284,6 +12301,38 @@ func (m *AppProjectSpec) Unmarshal(dAtA []byte) error {
|
|||
return err
|
||||
}
|
||||
iNdEx = postIndex
|
||||
case 12:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field SourceNamespaces", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowGenerated
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthGenerated
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthGenerated
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.SourceNamespaces = append(m.SourceNamespaces, string(dAtA[iNdEx:postIndex]))
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipGenerated(dAtA[iNdEx:])
|
||||
|
|
|
|||
|
|
@ -82,6 +82,9 @@ message AppProjectSpec {
|
|||
|
||||
// ClusterResourceBlacklist contains list of blacklisted cluster level resources
|
||||
repeated k8s.io.apimachinery.pkg.apis.meta.v1.GroupKind clusterResourceBlacklist = 11;
|
||||
|
||||
// SourceNamespaces defines the namespaces application resources are allowed to be created in
|
||||
repeated string sourceNamespaces = 12;
|
||||
}
|
||||
|
||||
// AppProjectStatus contains status information for AppProject CRs
|
||||
|
|
|
|||
|
|
@ -377,6 +377,21 @@ func schema_pkg_apis_application_v1alpha1_AppProjectSpec(ref common.ReferenceCal
|
|||
},
|
||||
},
|
||||
},
|
||||
"sourceNamespaces": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "SourceNamespaces defines the namespaces application resources are allowed to be created in",
|
||||
Type: []string{"array"},
|
||||
Items: &spec.SchemaOrArray{
|
||||
Schema: &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Default: "",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1669,6 +1669,8 @@ type AppProjectSpec struct {
|
|||
SignatureKeys []SignatureKey `json:"signatureKeys,omitempty" protobuf:"bytes,10,opt,name=signatureKeys"`
|
||||
// ClusterResourceBlacklist contains list of blacklisted cluster level resources
|
||||
ClusterResourceBlacklist []metav1.GroupKind `json:"clusterResourceBlacklist,omitempty" protobuf:"bytes,11,opt,name=clusterResourceBlacklist"`
|
||||
// SourceNamespaces defines the namespaces application resources are allowed to be created in
|
||||
SourceNamespaces []string `json:"sourceNamespaces,omitempty" protobuf:"bytes,12,opt,name=sourceNamespaces"`
|
||||
}
|
||||
|
||||
// SyncWindows is a collection of sync windows in this project
|
||||
|
|
@ -2520,3 +2522,37 @@ func (d *ApplicationDestination) MarshalJSON() ([]byte, error) {
|
|||
}
|
||||
return json.Marshal(&struct{ *Alias }{Alias: (*Alias)(dest)})
|
||||
}
|
||||
|
||||
// InstanceName returns the name of the application as used in the instance
|
||||
// tracking values, i.e. in the format <namespace>_<name>. When the namespace
|
||||
// of the application is similar to the value of defaultNs, only the name of
|
||||
// the application is returned to keep backwards compatibility.
|
||||
func (a *Application) InstanceName(defaultNs string) string {
|
||||
// When app has no namespace set, or the namespace is the default ns, we
|
||||
// return just the application name
|
||||
if a.Namespace == "" || a.Namespace == defaultNs {
|
||||
return a.Name
|
||||
}
|
||||
return a.Namespace + "_" + a.Name
|
||||
}
|
||||
|
||||
// QualifiedName returns the full qualified name of the application, including
|
||||
// the name of the namespace it is created in delimited by a forward slash,
|
||||
// i.e. <namespace>/<appname>
|
||||
func (a *Application) QualifiedName() string {
|
||||
if a.Namespace == "" {
|
||||
return a.Name
|
||||
} else {
|
||||
return a.Namespace + "/" + a.Name
|
||||
}
|
||||
}
|
||||
|
||||
// RBACName returns the full qualified RBAC resource name for the application
|
||||
// in a backwards-compatible way.
|
||||
func (a *Application) RBACName(defaultNS string) string {
|
||||
if defaultNS != "" && a.Namespace != defaultNS && a.Namespace != "" {
|
||||
return fmt.Sprintf("%s/%s/%s", a.Spec.GetProject(), a.Namespace, a.Name)
|
||||
} else {
|
||||
return fmt.Sprintf("%s/%s", a.Spec.GetProject(), a.Name)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2883,3 +2883,160 @@ func TestGetCAPath(t *testing.T) {
|
|||
assert.Empty(t, path)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppProjectIsSourceNamespacePermitted(t *testing.T) {
|
||||
app1 := &Application{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "app1",
|
||||
Namespace: "argocd",
|
||||
},
|
||||
Spec: ApplicationSpec{},
|
||||
}
|
||||
app2 := &Application{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "app2",
|
||||
Namespace: "some-ns",
|
||||
},
|
||||
Spec: ApplicationSpec{},
|
||||
}
|
||||
app3 := &Application{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "app2",
|
||||
Namespace: "",
|
||||
},
|
||||
Spec: ApplicationSpec{},
|
||||
}
|
||||
app4 := &Application{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "app2",
|
||||
Namespace: "other-ns",
|
||||
},
|
||||
Spec: ApplicationSpec{},
|
||||
}
|
||||
app5 := &Application{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "app2",
|
||||
Namespace: "some-ns1",
|
||||
},
|
||||
Spec: ApplicationSpec{},
|
||||
}
|
||||
app6 := &Application{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "app2",
|
||||
Namespace: "some-ns2",
|
||||
},
|
||||
Spec: ApplicationSpec{},
|
||||
}
|
||||
app7 := &Application{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "app2",
|
||||
Namespace: "someotherns",
|
||||
},
|
||||
Spec: ApplicationSpec{},
|
||||
}
|
||||
t.Run("App in same namespace as controller", func(t *testing.T) {
|
||||
proj := &AppProject{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "default",
|
||||
Namespace: "argocd",
|
||||
},
|
||||
Spec: AppProjectSpec{
|
||||
SourceNamespaces: []string{"other-ns"},
|
||||
},
|
||||
}
|
||||
// app1 is installed to argocd namespace, controller as well
|
||||
assert.True(t, proj.IsAppNamespacePermitted(app1, "argocd"))
|
||||
// app2 is installed to some-ns namespace, controller as well
|
||||
assert.True(t, proj.IsAppNamespacePermitted(app2, "some-ns"))
|
||||
// app3 has no namespace set, so will be implicitly created in controller's namespace
|
||||
assert.True(t, proj.IsAppNamespacePermitted(app3, "argocd"))
|
||||
})
|
||||
t.Run("App not permitted when sourceNamespaces is empty", func(t *testing.T) {
|
||||
proj := &AppProject{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "default",
|
||||
Namespace: "argocd",
|
||||
},
|
||||
Spec: AppProjectSpec{
|
||||
SourceNamespaces: []string{},
|
||||
},
|
||||
}
|
||||
// app1 is installed to argocd namespace
|
||||
assert.True(t, proj.IsAppNamespacePermitted(app1, "argocd"))
|
||||
// app2 is installed to some-ns, controller running in argocd
|
||||
assert.False(t, proj.IsAppNamespacePermitted(app2, "argocd"))
|
||||
})
|
||||
|
||||
t.Run("App permitted when sourceNamespaces has app namespace", func(t *testing.T) {
|
||||
proj := &AppProject{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "default",
|
||||
Namespace: "argocd",
|
||||
},
|
||||
Spec: AppProjectSpec{
|
||||
SourceNamespaces: []string{"some-ns"},
|
||||
},
|
||||
}
|
||||
// app2 is installed to some-ns, controller running in argocd
|
||||
assert.True(t, proj.IsAppNamespacePermitted(app2, "argocd"))
|
||||
// app4 is installed to other-ns, controller running in argocd
|
||||
assert.False(t, proj.IsAppNamespacePermitted(app4, "argocd"))
|
||||
})
|
||||
|
||||
t.Run("App permitted by glob pattern", func(t *testing.T) {
|
||||
proj := &AppProject{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "default",
|
||||
Namespace: "argocd",
|
||||
},
|
||||
Spec: AppProjectSpec{
|
||||
SourceNamespaces: []string{"some-*"},
|
||||
},
|
||||
}
|
||||
// app5 is installed to some-ns1, controller running in argocd
|
||||
assert.True(t, proj.IsAppNamespacePermitted(app5, "argocd"))
|
||||
// app6 is installed to some-ns2, controller running in argocd
|
||||
assert.True(t, proj.IsAppNamespacePermitted(app6, "argocd"))
|
||||
// app7 is installed to someotherns, controller running in argocd
|
||||
assert.False(t, proj.IsAppNamespacePermitted(app7, "argocd"))
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func Test_RBACName(t *testing.T) {
|
||||
testApp := func(namespace, project string) *Application {
|
||||
return &Application{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-app",
|
||||
Namespace: namespace,
|
||||
},
|
||||
Spec: ApplicationSpec{
|
||||
Project: project,
|
||||
},
|
||||
}
|
||||
}
|
||||
t.Run("App in same namespace as controller when ns is argocd", func(t *testing.T) {
|
||||
a := testApp("argocd", "default")
|
||||
assert.Equal(t, "default/test-app", a.RBACName("argocd"))
|
||||
})
|
||||
t.Run("App in same namespace as controller when ns is not argocd", func(t *testing.T) {
|
||||
a := testApp("some-ns", "default")
|
||||
assert.Equal(t, "default/test-app", a.RBACName("some-ns"))
|
||||
})
|
||||
t.Run("App in different namespace as controller when ns is argocd", func(t *testing.T) {
|
||||
a := testApp("some-ns", "default")
|
||||
assert.Equal(t, "default/some-ns/test-app", a.RBACName("argocd"))
|
||||
})
|
||||
t.Run("App in different namespace as controller when ns is not argocd", func(t *testing.T) {
|
||||
a := testApp("some-ns", "default")
|
||||
assert.Equal(t, "default/some-ns/test-app", a.RBACName("other-ns"))
|
||||
})
|
||||
t.Run("App in same namespace as controller when project is not yet set", func(t *testing.T) {
|
||||
a := testApp("argocd", "")
|
||||
assert.Equal(t, "default/test-app", a.RBACName("argocd"))
|
||||
})
|
||||
t.Run("App in same namespace as controller when ns is not yet set", func(t *testing.T) {
|
||||
a := testApp("", "")
|
||||
assert.Equal(t, "default/test-app", a.RBACName("argocd"))
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -149,6 +149,11 @@ func (in *AppProjectSpec) DeepCopyInto(out *AppProjectSpec) {
|
|||
*out = make([]v1.GroupKind, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.SourceNamespaces != nil {
|
||||
in, out := &in.SourceNamespaces, &out.SourceNamespaces
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -752,8 +752,14 @@ func helmTemplate(appPath string, repoRoot string, env *v1alpha1.Env, q *apiclie
|
|||
defer manifestGenerateLock.Unlock(appPath)
|
||||
}
|
||||
|
||||
// We use the app name as Helm's release name property, which must not
|
||||
// contain any underscore characters and must not exceed 53 characters.
|
||||
// We are not interested in the fully qualified application name while
|
||||
// templating, thus, we just use the name part of the identifier.
|
||||
appName, _ := argo.ParseAppInstanceName(q.AppName, "")
|
||||
|
||||
templateOpts := &helm.TemplateOpts{
|
||||
Name: q.AppName,
|
||||
Name: appName,
|
||||
Namespace: q.Namespace,
|
||||
KubeVersion: text.SemVer(q.KubeVersion),
|
||||
APIVersions: q.ApiVersions,
|
||||
|
|
|
|||
|
|
@ -44,12 +44,12 @@ import (
|
|||
"github.com/argoproj/argo-cd/v2/reposerver/apiclient"
|
||||
servercache "github.com/argoproj/argo-cd/v2/server/cache"
|
||||
"github.com/argoproj/argo-cd/v2/server/rbacpolicy"
|
||||
apputil "github.com/argoproj/argo-cd/v2/util/app"
|
||||
"github.com/argoproj/argo-cd/v2/util/argo"
|
||||
argoutil "github.com/argoproj/argo-cd/v2/util/argo"
|
||||
"github.com/argoproj/argo-cd/v2/util/db"
|
||||
"github.com/argoproj/argo-cd/v2/util/env"
|
||||
"github.com/argoproj/argo-cd/v2/util/git"
|
||||
"github.com/argoproj/argo-cd/v2/util/glob"
|
||||
"github.com/argoproj/argo-cd/v2/util/io"
|
||||
ioutil "github.com/argoproj/argo-cd/v2/util/io"
|
||||
"github.com/argoproj/argo-cd/v2/util/lua"
|
||||
|
|
@ -72,21 +72,22 @@ var (
|
|||
|
||||
// Server provides an Application service
|
||||
type Server struct {
|
||||
ns string
|
||||
kubeclientset kubernetes.Interface
|
||||
appclientset appclientset.Interface
|
||||
appLister applisters.ApplicationNamespaceLister
|
||||
appInformer cache.SharedIndexInformer
|
||||
appBroadcaster *broadcasterHandler
|
||||
repoClientset apiclient.Clientset
|
||||
kubectl kube.Kubectl
|
||||
db db.ArgoDB
|
||||
enf *rbac.Enforcer
|
||||
projectLock sync.KeyLock
|
||||
auditLogger *argo.AuditLogger
|
||||
settingsMgr *settings.SettingsManager
|
||||
cache *servercache.Cache
|
||||
projInformer cache.SharedIndexInformer
|
||||
ns string
|
||||
kubeclientset kubernetes.Interface
|
||||
appclientset appclientset.Interface
|
||||
appLister applisters.ApplicationLister
|
||||
appInformer cache.SharedIndexInformer
|
||||
appBroadcaster *broadcasterHandler
|
||||
repoClientset apiclient.Clientset
|
||||
kubectl kube.Kubectl
|
||||
db db.ArgoDB
|
||||
enf *rbac.Enforcer
|
||||
projectLock sync.KeyLock
|
||||
auditLogger *argo.AuditLogger
|
||||
settingsMgr *settings.SettingsManager
|
||||
cache *servercache.Cache
|
||||
projInformer cache.SharedIndexInformer
|
||||
enabledNamespaces []string
|
||||
}
|
||||
|
||||
// NewServer returns a new instance of the Application service
|
||||
|
|
@ -94,7 +95,7 @@ func NewServer(
|
|||
namespace string,
|
||||
kubeclientset kubernetes.Interface,
|
||||
appclientset appclientset.Interface,
|
||||
appLister applisters.ApplicationNamespaceLister,
|
||||
appLister applisters.ApplicationLister,
|
||||
appInformer cache.SharedIndexInformer,
|
||||
repoClientset apiclient.Clientset,
|
||||
cache *servercache.Cache,
|
||||
|
|
@ -104,25 +105,27 @@ func NewServer(
|
|||
projectLock sync.KeyLock,
|
||||
settingsMgr *settings.SettingsManager,
|
||||
projInformer cache.SharedIndexInformer,
|
||||
enabledNamespaces []string,
|
||||
) (application.ApplicationServiceServer, AppResourceTreeFn) {
|
||||
appBroadcaster := &broadcasterHandler{}
|
||||
appInformer.AddEventHandler(appBroadcaster)
|
||||
s := &Server{
|
||||
ns: namespace,
|
||||
appclientset: appclientset,
|
||||
appLister: appLister,
|
||||
appInformer: appInformer,
|
||||
appBroadcaster: appBroadcaster,
|
||||
kubeclientset: kubeclientset,
|
||||
cache: cache,
|
||||
db: db,
|
||||
repoClientset: repoClientset,
|
||||
kubectl: kubectl,
|
||||
enf: enf,
|
||||
projectLock: projectLock,
|
||||
auditLogger: argo.NewAuditLogger(namespace, kubeclientset, "argocd-server"),
|
||||
settingsMgr: settingsMgr,
|
||||
projInformer: projInformer,
|
||||
ns: namespace,
|
||||
appclientset: appclientset,
|
||||
appLister: appLister,
|
||||
appInformer: appInformer,
|
||||
appBroadcaster: appBroadcaster,
|
||||
kubeclientset: kubeclientset,
|
||||
cache: cache,
|
||||
db: db,
|
||||
repoClientset: repoClientset,
|
||||
kubectl: kubectl,
|
||||
enf: enf,
|
||||
projectLock: projectLock,
|
||||
auditLogger: argo.NewAuditLogger(namespace, kubeclientset, "argocd-server"),
|
||||
settingsMgr: settingsMgr,
|
||||
projInformer: projInformer,
|
||||
enabledNamespaces: enabledNamespaces,
|
||||
}
|
||||
return s, s.GetAppResources
|
||||
}
|
||||
|
|
@ -133,16 +136,27 @@ func (s *Server) List(ctx context.Context, q *application.ApplicationQuery) (*ap
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("error converting selector to labels map: %w", err)
|
||||
}
|
||||
apps, err := s.appLister.List(labelsMap.AsSelector())
|
||||
var apps []*appv1.Application
|
||||
if q.GetAppNamespace() == "" {
|
||||
apps, err = s.appLister.List(labelsMap.AsSelector())
|
||||
} else {
|
||||
apps, err = s.appLister.Applications(q.GetAppNamespace()).List(labelsMap.AsSelector())
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error listing apps with selectors: %w", err)
|
||||
}
|
||||
newItems := make([]appv1.Application, 0)
|
||||
for _, a := range apps {
|
||||
if s.enf.Enforce(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionGet, apputil.AppRBACName(*a)) {
|
||||
// Skip any application that is neither in the conrol plane's namespace
|
||||
// nor in the list of enabled namespaces.
|
||||
if a.Namespace != s.ns && !glob.MatchStringInList(s.enabledNamespaces, a.Namespace, false) {
|
||||
continue
|
||||
}
|
||||
if s.enf.Enforce(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionGet, a.RBACName(s.ns)) {
|
||||
newItems = append(newItems, *a)
|
||||
}
|
||||
}
|
||||
|
||||
if q.Name != nil {
|
||||
newItems, err = argoutil.FilterByName(newItems, *q.Name)
|
||||
if err != nil {
|
||||
|
|
@ -175,14 +189,15 @@ func (s *Server) Create(ctx context.Context, q *application.ApplicationCreateReq
|
|||
if q.GetApplication() == nil {
|
||||
return nil, fmt.Errorf("error creating application: application is nil in request")
|
||||
}
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionCreate, apputil.AppRBACName(*q.Application)); err != nil {
|
||||
a := q.GetApplication()
|
||||
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionCreate, a.RBACName(s.ns)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.projectLock.RLock(q.Application.Spec.Project)
|
||||
defer s.projectLock.RUnlock(q.Application.Spec.Project)
|
||||
s.projectLock.RLock(a.Spec.GetProject())
|
||||
defer s.projectLock.RUnlock(a.Spec.GetProject())
|
||||
|
||||
a := q.GetApplication()
|
||||
validate := true
|
||||
if q.Validate != nil {
|
||||
validate = *q.Validate
|
||||
|
|
@ -191,7 +206,14 @@ func (s *Server) Create(ctx context.Context, q *application.ApplicationCreateReq
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("error while validating and normalizing app: %w", err)
|
||||
}
|
||||
created, err := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Create(ctx, a, metav1.CreateOptions{})
|
||||
|
||||
appNs := s.appNamespaceOrDefault(a.Namespace)
|
||||
|
||||
if !s.isNamespaceEnabled(appNs) {
|
||||
return nil, namespaceNotPermittedError(appNs)
|
||||
}
|
||||
|
||||
created, err := s.appclientset.ArgoprojV1alpha1().Applications(appNs).Create(ctx, a, metav1.CreateOptions{})
|
||||
if err == nil {
|
||||
s.logAppEvent(created, ctx, argo.EventReasonResourceCreated, "created application")
|
||||
s.waitSync(created)
|
||||
|
|
@ -200,10 +222,11 @@ func (s *Server) Create(ctx context.Context, q *application.ApplicationCreateReq
|
|||
if !apierr.IsAlreadyExists(err) {
|
||||
return nil, fmt.Errorf("error creating application: %w", err)
|
||||
}
|
||||
|
||||
// act idempotent if existing spec matches new spec
|
||||
existing, err := s.appLister.Get(a.Name)
|
||||
existing, err := s.appLister.Applications(appNs).Get(a.Name)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "unable to check existing application details: %v", err)
|
||||
return nil, status.Errorf(codes.Internal, "unable to check existing application details (%s): %v", appNs, err)
|
||||
}
|
||||
equalSpecs := reflect.DeepEqual(existing.Spec, a.Spec) &&
|
||||
reflect.DeepEqual(existing.Labels, a.Labels) &&
|
||||
|
|
@ -216,7 +239,7 @@ func (s *Server) Create(ctx context.Context, q *application.ApplicationCreateReq
|
|||
if q.Upsert == nil || !*q.Upsert {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "existing application spec is different, use upsert flag to force update")
|
||||
}
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionUpdate, apputil.AppRBACName(*a)); err != nil {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionUpdate, a.RBACName(s.ns)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
updated, err := s.updateApp(existing, a, ctx, true)
|
||||
|
|
@ -253,7 +276,7 @@ func (s *Server) queryRepoServer(ctx context.Context, a *v1alpha1.Application, a
|
|||
if err != nil {
|
||||
return fmt.Errorf("error getting kustomize settings options: %w", err)
|
||||
}
|
||||
proj, err := argo.GetAppProject(&a.Spec, applisters.NewAppProjectLister(s.projInformer.GetIndexer()), s.ns, s.settingsMgr, s.db, ctx)
|
||||
proj, err := argo.GetAppProject(a, applisters.NewAppProjectLister(s.projInformer.GetIndexer()), s.ns, s.settingsMgr, s.db, ctx)
|
||||
if err != nil {
|
||||
if apierr.IsNotFound(err) {
|
||||
return status.Errorf(codes.InvalidArgument, "application references project %s which does not exist", a.Spec.Project)
|
||||
|
|
@ -291,14 +314,23 @@ func (s *Server) queryRepoServer(ctx context.Context, a *v1alpha1.Application, a
|
|||
|
||||
// GetManifests returns application manifests
|
||||
func (s *Server) GetManifests(ctx context.Context, q *application.ApplicationManifestQuery) (*apiclient.ManifestResponse, error) {
|
||||
a, err := s.appLister.Get(*q.Name)
|
||||
if q.Name == nil || *q.Name == "" {
|
||||
return nil, fmt.Errorf("invalid request: application name is missing")
|
||||
}
|
||||
appName := q.GetName()
|
||||
appNs := s.appNamespaceOrDefault(q.GetAppNamespace())
|
||||
a, err := s.appLister.Applications(appNs).Get(appName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting application: %w", err)
|
||||
}
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionGet, apputil.AppRBACName(*a)); err != nil {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionGet, a.RBACName(s.ns)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !s.isNamespaceEnabled(a.Namespace) {
|
||||
return nil, namespaceNotPermittedError(a.Namespace)
|
||||
}
|
||||
|
||||
var manifestInfo *apiclient.ManifestResponse
|
||||
err = s.queryRepoServer(ctx, a, func(
|
||||
client apiclient.RepoServerServiceClient, repo *appv1.Repository, helmRepos []*appv1.Repository, helmCreds []*appv1.RepoCreds, helmOptions *appv1.HelmOptions, kustomizeOptions *appv1.KustomizeOptions, enableGenerateManifests map[string]bool) error {
|
||||
|
|
@ -334,7 +366,7 @@ func (s *Server) GetManifests(ctx context.Context, q *application.ApplicationMan
|
|||
Repo: repo,
|
||||
Revision: revision,
|
||||
AppLabelKey: appInstanceLabelKey,
|
||||
AppName: a.Name,
|
||||
AppName: a.InstanceName(s.ns),
|
||||
Namespace: a.Spec.Destination.Namespace,
|
||||
ApplicationSource: &a.Spec.Source,
|
||||
Repos: helmRepos,
|
||||
|
|
@ -381,17 +413,20 @@ func (s *Server) GetManifests(ctx context.Context, q *application.ApplicationMan
|
|||
|
||||
// Get returns an application by name
|
||||
func (s *Server) Get(ctx context.Context, q *application.ApplicationQuery) (*appv1.Application, error) {
|
||||
appName := q.GetName()
|
||||
appNs := s.appNamespaceOrDefault(q.GetAppNamespace())
|
||||
|
||||
// We must use a client Get instead of an informer Get, because it's common to call Get immediately
|
||||
// following a Watch (which is not yet powered by an informer), and the Get must reflect what was
|
||||
// previously seen by the client.
|
||||
a, err := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Get(ctx, q.GetName(), metav1.GetOptions{
|
||||
a, err := s.appclientset.ArgoprojV1alpha1().Applications(appNs).Get(ctx, appName, metav1.GetOptions{
|
||||
ResourceVersion: q.GetResourceVersion(),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting application: %w", err)
|
||||
}
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionGet, apputil.AppRBACName(*a)); err != nil {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionGet, a.RBACName(s.ns)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if q.Refresh == nil {
|
||||
|
|
@ -402,16 +437,16 @@ func (s *Server) Get(ctx context.Context, q *application.ApplicationQuery) (*app
|
|||
if *q.Refresh == string(appv1.RefreshTypeHard) {
|
||||
refreshType = appv1.RefreshTypeHard
|
||||
}
|
||||
appIf := s.appclientset.ArgoprojV1alpha1().Applications(s.ns)
|
||||
appIf := s.appclientset.ArgoprojV1alpha1().Applications(appNs)
|
||||
|
||||
// subscribe early with buffered channel to ensure we don't miss events
|
||||
events := make(chan *appv1.ApplicationWatchEvent, watchAPIBufferSize)
|
||||
unsubscribe := s.appBroadcaster.Subscribe(events, func(event *appv1.ApplicationWatchEvent) bool {
|
||||
return event.Application.Name == q.GetName()
|
||||
return event.Application.Name == appName && event.Application.Namespace == appNs
|
||||
})
|
||||
defer unsubscribe()
|
||||
|
||||
app, err := argoutil.RefreshApp(appIf, *q.Name, refreshType)
|
||||
app, err := argoutil.RefreshApp(appIf, appName, refreshType)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error refreshing the app: %w", err)
|
||||
}
|
||||
|
|
@ -430,7 +465,7 @@ func (s *Server) Get(ctx context.Context, q *application.ApplicationQuery) (*app
|
|||
_, err := client.GetAppDetails(ctx, &apiclient.RepoServerAppDetailsQuery{
|
||||
Repo: repo,
|
||||
Source: &app.Spec.Source,
|
||||
AppName: app.Name,
|
||||
AppName: appName,
|
||||
KustomizeOptions: kustomizeOptions,
|
||||
Repos: helmRepos,
|
||||
NoCache: true,
|
||||
|
|
@ -469,11 +504,13 @@ func (s *Server) Get(ctx context.Context, q *application.ApplicationQuery) (*app
|
|||
|
||||
// ListResourceEvents returns a list of event resources
|
||||
func (s *Server) ListResourceEvents(ctx context.Context, q *application.ApplicationResourceEventsQuery) (*v1.EventList, error) {
|
||||
a, err := s.appLister.Get(*q.Name)
|
||||
appName := q.GetName()
|
||||
appNs := s.appNamespaceOrDefault(q.GetAppNamespace())
|
||||
a, err := s.appLister.Applications(appNs).Get(appName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting application: %w", err)
|
||||
}
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionGet, apputil.AppRBACName(*a)); err != nil {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionGet, a.RBACName(s.ns)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var (
|
||||
|
|
@ -537,7 +574,7 @@ func (s *Server) validateAndUpdateApp(ctx context.Context, newApp *appv1.Applica
|
|||
s.projectLock.RLock(newApp.Spec.GetProject())
|
||||
defer s.projectLock.RUnlock(newApp.Spec.GetProject())
|
||||
|
||||
app, err := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Get(ctx, newApp.Name, metav1.GetOptions{})
|
||||
app, err := s.appclientset.ArgoprojV1alpha1().Applications(newApp.Namespace).Get(ctx, newApp.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting application: %w", err)
|
||||
}
|
||||
|
|
@ -586,7 +623,7 @@ func (s *Server) waitSync(app *appv1.Application) {
|
|||
return
|
||||
}
|
||||
for {
|
||||
if currApp, err := s.appLister.Get(app.Name); err == nil {
|
||||
if currApp, err := s.appLister.Applications(app.Namespace).Get(app.Name); err == nil {
|
||||
currVersion, err := strconv.Atoi(currApp.ResourceVersion)
|
||||
if err == nil && currVersion >= minVersion {
|
||||
return
|
||||
|
|
@ -613,7 +650,7 @@ func (s *Server) updateApp(app *appv1.Application, newApp *appv1.Application, ct
|
|||
|
||||
app.Finalizers = newApp.Finalizers
|
||||
|
||||
res, err := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Update(ctx, app, metav1.UpdateOptions{})
|
||||
res, err := s.appclientset.ArgoprojV1alpha1().Applications(app.Namespace).Update(ctx, app, metav1.UpdateOptions{})
|
||||
if err == nil {
|
||||
s.logAppEvent(app, ctx, argo.EventReasonResourceUpdated, "updated application spec")
|
||||
s.waitSync(res)
|
||||
|
|
@ -623,7 +660,7 @@ func (s *Server) updateApp(app *appv1.Application, newApp *appv1.Application, ct
|
|||
return nil, err
|
||||
}
|
||||
|
||||
app, err = s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Get(ctx, newApp.Name, metav1.GetOptions{})
|
||||
app, err = s.appclientset.ArgoprojV1alpha1().Applications(app.Namespace).Get(ctx, newApp.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting application: %w", err)
|
||||
}
|
||||
|
|
@ -633,7 +670,11 @@ func (s *Server) updateApp(app *appv1.Application, newApp *appv1.Application, ct
|
|||
|
||||
// Update updates an application
|
||||
func (s *Server) Update(ctx context.Context, q *application.ApplicationUpdateRequest) (*appv1.Application, error) {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionUpdate, apputil.AppRBACName(*q.Application)); err != nil {
|
||||
if q.GetApplication() == nil {
|
||||
return nil, fmt.Errorf("error creating application: application is nil in request")
|
||||
}
|
||||
a := q.GetApplication()
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionUpdate, a.RBACName(s.ns)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
|
@ -649,11 +690,13 @@ func (s *Server) UpdateSpec(ctx context.Context, q *application.ApplicationUpdat
|
|||
if q.GetSpec() == nil {
|
||||
return nil, fmt.Errorf("error updating application spec: spec is nil in request")
|
||||
}
|
||||
a, err := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Get(ctx, *q.Name, metav1.GetOptions{})
|
||||
appName := q.GetName()
|
||||
appNs := s.appNamespaceOrDefault(q.GetAppNamespace())
|
||||
a, err := s.appclientset.ArgoprojV1alpha1().Applications(appNs).Get(ctx, appName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting application: %w", err)
|
||||
}
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionUpdate, apputil.AppRBACName(*a)); err != nil {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionUpdate, a.RBACName(s.ns)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
a.Spec = *q.GetSpec()
|
||||
|
|
@ -670,13 +713,14 @@ func (s *Server) UpdateSpec(ctx context.Context, q *application.ApplicationUpdat
|
|||
|
||||
// Patch patches an application
|
||||
func (s *Server) Patch(ctx context.Context, q *application.ApplicationPatchRequest) (*appv1.Application, error) {
|
||||
|
||||
app, err := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Get(ctx, *q.Name, metav1.GetOptions{})
|
||||
appName := q.GetName()
|
||||
appNs := s.appNamespaceOrDefault(q.GetAppNamespace())
|
||||
app, err := s.appclientset.ArgoprojV1alpha1().Applications(appNs).Get(ctx, appName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting application: %w", err)
|
||||
}
|
||||
|
||||
if err = s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionUpdate, apputil.AppRBACName(*app)); err != nil {
|
||||
if err = s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionUpdate, app.RBACName(s.ns)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
|
@ -716,7 +760,9 @@ func (s *Server) Patch(ctx context.Context, q *application.ApplicationPatchReque
|
|||
|
||||
// Delete removes an application and all associated resources
|
||||
func (s *Server) Delete(ctx context.Context, q *application.ApplicationDeleteRequest) (*application.ApplicationResponse, error) {
|
||||
a, err := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Get(ctx, *q.Name, metav1.GetOptions{})
|
||||
appName := q.GetName()
|
||||
appNs := s.appNamespaceOrDefault(q.GetAppNamespace())
|
||||
a, err := s.appclientset.ArgoprojV1alpha1().Applications(appNs).Get(ctx, appName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting application: %w", err)
|
||||
}
|
||||
|
|
@ -724,7 +770,7 @@ func (s *Server) Delete(ctx context.Context, q *application.ApplicationDeleteReq
|
|||
s.projectLock.RLock(a.Spec.Project)
|
||||
defer s.projectLock.RUnlock(a.Spec.Project)
|
||||
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionDelete, apputil.AppRBACName(*a)); err != nil {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionDelete, a.RBACName(s.ns)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
|
@ -768,7 +814,7 @@ func (s *Server) Delete(ctx context.Context, q *application.ApplicationDeleteReq
|
|||
}
|
||||
}
|
||||
|
||||
err = s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Delete(ctx, *q.Name, metav1.DeleteOptions{})
|
||||
err = s.appclientset.ArgoprojV1alpha1().Applications(appNs).Delete(ctx, appName, metav1.DeleteOptions{})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error deleting application: %w", err)
|
||||
}
|
||||
|
|
@ -777,6 +823,8 @@ func (s *Server) Delete(ctx context.Context, q *application.ApplicationDeleteReq
|
|||
}
|
||||
|
||||
func (s *Server) Watch(q *application.ApplicationQuery, ws application.ApplicationService_WatchServer) error {
|
||||
appName := q.GetName()
|
||||
appNs := s.appNamespaceOrDefault(q.GetAppNamespace())
|
||||
logCtx := log.NewEntry(log.New())
|
||||
if q.Name != nil {
|
||||
logCtx = logCtx.WithField("application", *q.Name)
|
||||
|
|
@ -807,12 +855,12 @@ func (s *Server) Watch(q *application.ApplicationQuery, ws application.Applicati
|
|||
if appVersion, err := strconv.Atoi(a.ResourceVersion); err == nil && appVersion < minVersion {
|
||||
return
|
||||
}
|
||||
matchedEvent := (q.GetName() == "" || a.Name == q.GetName()) && selector.Matches(labels.Set(a.Labels))
|
||||
matchedEvent := (appName == "" || (a.Name == appName && a.Namespace == appNs)) && selector.Matches(labels.Set(a.Labels))
|
||||
if !matchedEvent {
|
||||
return
|
||||
}
|
||||
|
||||
if !s.enf.Enforce(claims, rbacpolicy.ResourceApplications, rbacpolicy.ActionGet, apputil.AppRBACName(a)) {
|
||||
if !s.enf.Enforce(claims, rbacpolicy.ResourceApplications, rbacpolicy.ActionGet, a.RBACName(s.ns)) {
|
||||
// do not emit apps user does not have accessing
|
||||
return
|
||||
}
|
||||
|
|
@ -837,7 +885,7 @@ func (s *Server) Watch(q *application.ApplicationQuery, ws application.Applicati
|
|||
return fmt.Errorf("error listing apps with selector: %w", err)
|
||||
}
|
||||
sort.Slice(apps, func(i, j int) bool {
|
||||
return apps[i].Name < apps[j].Name
|
||||
return apps[i].QualifiedName() < apps[j].QualifiedName()
|
||||
})
|
||||
for i := range apps {
|
||||
sendIfPermitted(*apps[i], watch.Added)
|
||||
|
|
@ -856,14 +904,18 @@ func (s *Server) Watch(q *application.ApplicationQuery, ws application.Applicati
|
|||
}
|
||||
|
||||
func (s *Server) validateAndNormalizeApp(ctx context.Context, app *appv1.Application, validate bool) error {
|
||||
proj, err := argo.GetAppProject(&app.Spec, applisters.NewAppProjectLister(s.projInformer.GetIndexer()), s.ns, s.settingsMgr, s.db, ctx)
|
||||
proj, err := argo.GetAppProject(app, applisters.NewAppProjectLister(s.projInformer.GetIndexer()), s.ns, s.settingsMgr, s.db, ctx)
|
||||
if err != nil {
|
||||
if apierr.IsNotFound(err) {
|
||||
return status.Errorf(codes.InvalidArgument, "application references project %s which does not exist", app.Spec.Project)
|
||||
}
|
||||
return fmt.Errorf("error getting application's project: %w", err)
|
||||
}
|
||||
currApp, err := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Get(ctx, app.Name, metav1.GetOptions{})
|
||||
if app.GetName() == "" {
|
||||
return fmt.Errorf("resource name may not be empty")
|
||||
}
|
||||
appNs := s.appNamespaceOrDefault(app.Namespace)
|
||||
currApp, err := s.appclientset.ArgoprojV1alpha1().Applications(appNs).Get(ctx, app.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
if !apierr.IsNotFound(err) {
|
||||
return fmt.Errorf("error getting application by name: %w", err)
|
||||
|
|
@ -875,11 +927,11 @@ func (s *Server) validateAndNormalizeApp(ctx context.Context, app *appv1.Applica
|
|||
if currApp != nil && currApp.Spec.GetProject() != app.Spec.GetProject() {
|
||||
// When changing projects, caller must have application create & update privileges in new project
|
||||
// NOTE: the update check was already verified in the caller to this function
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionCreate, apputil.AppRBACName(*app)); err != nil {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionCreate, app.RBACName(s.ns)); err != nil {
|
||||
return err
|
||||
}
|
||||
// They also need 'update' privileges in the old project
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionUpdate, apputil.AppRBACName(*currApp)); err != nil {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionUpdate, currApp.RBACName(s.ns)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
@ -949,8 +1001,9 @@ func (s *Server) getCachedAppState(ctx context.Context, a *appv1.Application, ge
|
|||
return errors.New(argoutil.FormatAppConditions(conditions))
|
||||
}
|
||||
_, err = s.Get(ctx, &application.ApplicationQuery{
|
||||
Name: pointer.StringPtr(a.Name),
|
||||
Refresh: pointer.StringPtr(string(appv1.RefreshTypeNormal)),
|
||||
Name: pointer.StringPtr(a.GetName()),
|
||||
AppNamespace: pointer.StringPtr(a.GetNamespace()),
|
||||
Refresh: pointer.StringPtr(string(appv1.RefreshTypeNormal)),
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("error getting application by query: %w", err)
|
||||
|
|
@ -963,7 +1016,7 @@ func (s *Server) getCachedAppState(ctx context.Context, a *appv1.Application, ge
|
|||
func (s *Server) GetAppResources(ctx context.Context, a *appv1.Application) (*appv1.ApplicationTree, error) {
|
||||
var tree appv1.ApplicationTree
|
||||
err := s.getCachedAppState(ctx, a, func() error {
|
||||
return s.cache.GetAppResourcesTree(a.Name, &tree)
|
||||
return s.cache.GetAppResourcesTree(a.InstanceName(s.ns), &tree)
|
||||
})
|
||||
if err != nil {
|
||||
return &tree, fmt.Errorf("error getting cached app state: %w", err)
|
||||
|
|
@ -972,11 +1025,13 @@ func (s *Server) GetAppResources(ctx context.Context, a *appv1.Application) (*ap
|
|||
}
|
||||
|
||||
func (s *Server) getAppLiveResource(ctx context.Context, action string, q *application.ApplicationResourceRequest) (*appv1.ResourceNode, *rest.Config, *appv1.Application, error) {
|
||||
a, err := s.appLister.Get(*q.Name)
|
||||
appName := q.GetName()
|
||||
appNs := s.appNamespaceOrDefault(q.GetAppNamespace())
|
||||
a, err := s.appLister.Applications(appNs).Get(appName)
|
||||
if err != nil {
|
||||
return nil, nil, nil, fmt.Errorf("error getting app by name: %w", err)
|
||||
}
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, action, apputil.AppRBACName(*a)); err != nil {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, action, a.RBACName(s.ns)); err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
|
|
@ -1037,6 +1092,7 @@ func replaceSecretValues(obj *unstructured.Unstructured) (*unstructured.Unstruct
|
|||
func (s *Server) PatchResource(ctx context.Context, q *application.ApplicationResourcePatchRequest) (*application.ApplicationResourceResponse, error) {
|
||||
resourceRequest := &application.ApplicationResourceRequest{
|
||||
Name: q.Name,
|
||||
AppNamespace: q.AppNamespace,
|
||||
Namespace: q.Namespace,
|
||||
ResourceName: q.ResourceName,
|
||||
Kind: q.Kind,
|
||||
|
|
@ -1047,7 +1103,7 @@ func (s *Server) PatchResource(ctx context.Context, q *application.ApplicationRe
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting app live resource: %w", err)
|
||||
}
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionUpdate, apputil.AppRBACName(*a)); err != nil {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionUpdate, a.RBACName(s.ns)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
|
@ -1078,6 +1134,7 @@ func (s *Server) PatchResource(ctx context.Context, q *application.ApplicationRe
|
|||
func (s *Server) DeleteResource(ctx context.Context, q *application.ApplicationResourceDeleteRequest) (*application.ApplicationResponse, error) {
|
||||
resourceRequest := &application.ApplicationResourceRequest{
|
||||
Name: q.Name,
|
||||
AppNamespace: q.AppNamespace,
|
||||
Namespace: q.Namespace,
|
||||
ResourceName: q.ResourceName,
|
||||
Kind: q.Kind,
|
||||
|
|
@ -1088,7 +1145,7 @@ func (s *Server) DeleteResource(ctx context.Context, q *application.ApplicationR
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting live resource for delete: %w", err)
|
||||
}
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionDelete, apputil.AppRBACName(*a)); err != nil {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionDelete, a.RBACName(s.ns)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var deleteOption metav1.DeleteOptions
|
||||
|
|
@ -1112,23 +1169,27 @@ func (s *Server) DeleteResource(ctx context.Context, q *application.ApplicationR
|
|||
}
|
||||
|
||||
func (s *Server) ResourceTree(ctx context.Context, q *application.ResourcesQuery) (*appv1.ApplicationTree, error) {
|
||||
a, err := s.appLister.Get(q.GetApplicationName())
|
||||
appName := q.GetApplicationName()
|
||||
appNs := s.appNamespaceOrDefault(q.GetAppNamespace())
|
||||
a, err := s.appLister.Applications(appNs).Get(appName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting application by name: %w", err)
|
||||
}
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionGet, apputil.AppRBACName(*a)); err != nil {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionGet, a.RBACName(s.ns)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s.GetAppResources(ctx, a)
|
||||
}
|
||||
|
||||
func (s *Server) WatchResourceTree(q *application.ResourcesQuery, ws application.ApplicationService_WatchResourceTreeServer) error {
|
||||
a, err := s.appLister.Get(q.GetApplicationName())
|
||||
appName := q.GetApplicationName()
|
||||
appNs := s.appNamespaceOrDefault(q.GetAppNamespace())
|
||||
a, err := s.appLister.Applications(appNs).Get(appName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error getting application by name: %w", err)
|
||||
}
|
||||
|
||||
if err := s.enf.EnforceErr(ws.Context().Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionGet, apputil.AppRBACName(*a)); err != nil {
|
||||
if err := s.enf.EnforceErr(ws.Context().Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionGet, a.RBACName(s.ns)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
@ -1143,11 +1204,13 @@ func (s *Server) WatchResourceTree(q *application.ResourcesQuery, ws application
|
|||
}
|
||||
|
||||
func (s *Server) RevisionMetadata(ctx context.Context, q *application.RevisionMetadataQuery) (*v1alpha1.RevisionMetadata, error) {
|
||||
a, err := s.appLister.Get(q.GetName())
|
||||
appName := q.GetName()
|
||||
appNs := s.appNamespaceOrDefault(q.GetAppNamespace())
|
||||
a, err := s.appLister.Applications(appNs).Get(appName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting app by name: %w", err)
|
||||
}
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionGet, apputil.AppRBACName(*a)); err != nil {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionGet, a.RBACName(s.ns)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
repo, err := s.db.GetRepository(ctx, a.Spec.Source.RepoURL)
|
||||
|
|
@ -1156,7 +1219,7 @@ func (s *Server) RevisionMetadata(ctx context.Context, q *application.RevisionMe
|
|||
}
|
||||
// We need to get some information with the project associated to the app,
|
||||
// so we'll know whether GPG signatures are enforced.
|
||||
proj, err := argo.GetAppProject(&a.Spec, applisters.NewAppProjectLister(s.projInformer.GetIndexer()), a.Namespace, s.settingsMgr, s.db, ctx)
|
||||
proj, err := argo.GetAppProject(a, applisters.NewAppProjectLister(s.projInformer.GetIndexer()), s.ns, s.settingsMgr, s.db, ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting app project: %w", err)
|
||||
}
|
||||
|
|
@ -1180,16 +1243,18 @@ func isMatchingResource(q *application.ResourcesQuery, key kube.ResourceKey) boo
|
|||
}
|
||||
|
||||
func (s *Server) ManagedResources(ctx context.Context, q *application.ResourcesQuery) (*application.ManagedResourcesResponse, error) {
|
||||
a, err := s.appLister.Get(*q.ApplicationName)
|
||||
appName := q.GetApplicationName()
|
||||
appNs := s.appNamespaceOrDefault(q.GetAppNamespace())
|
||||
a, err := s.appLister.Applications(appNs).Get(appName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting application: %w", err)
|
||||
}
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionGet, apputil.AppRBACName(*a)); err != nil {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionGet, a.RBACName(s.ns)); err != nil {
|
||||
return nil, fmt.Errorf("error verifying rbac: %w", err)
|
||||
}
|
||||
items := make([]*appv1.ResourceDiff, 0)
|
||||
err = s.getCachedAppState(ctx, a, func() error {
|
||||
return s.cache.GetAppManagedResources(a.Name, &items)
|
||||
return s.cache.GetAppManagedResources(a.InstanceName(s.ns), &items)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting cached app state: %w", err)
|
||||
|
|
@ -1239,12 +1304,14 @@ func (s *Server) PodLogs(q *application.ApplicationPodLogsQuery, ws application.
|
|||
}
|
||||
}
|
||||
|
||||
a, err := s.appLister.Get(q.GetName())
|
||||
appName := q.GetName()
|
||||
appNs := s.appNamespaceOrDefault(q.GetAppNamespace())
|
||||
a, err := s.appLister.Applications(appNs).Get(appName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error getting application by name: %w", err)
|
||||
}
|
||||
|
||||
if err := s.enf.EnforceErr(ws.Context().Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionGet, apputil.AppRBACName(*a)); err != nil {
|
||||
if err := s.enf.EnforceErr(ws.Context().Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionGet, a.RBACName(s.ns)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
@ -1259,7 +1326,7 @@ func (s *Server) PodLogs(q *application.ApplicationPodLogsQuery, ws application.
|
|||
}
|
||||
|
||||
if serverRBACLogEnforceEnable {
|
||||
if err := s.enf.EnforceErr(ws.Context().Value("claims"), rbacpolicy.ResourceLogs, rbacpolicy.ActionGet, apputil.AppRBACName(*a)); err != nil {
|
||||
if err := s.enf.EnforceErr(ws.Context().Value("claims"), rbacpolicy.ResourceLogs, rbacpolicy.ActionGet, a.RBACName(s.ns)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
@ -1436,13 +1503,15 @@ func isTheSelectedOne(currentNode *appv1.ResourceNode, q *application.Applicatio
|
|||
|
||||
// Sync syncs an application to its target state
|
||||
func (s *Server) Sync(ctx context.Context, syncReq *application.ApplicationSyncRequest) (*appv1.Application, error) {
|
||||
appIf := s.appclientset.ArgoprojV1alpha1().Applications(s.ns)
|
||||
a, err := appIf.Get(ctx, *syncReq.Name, metav1.GetOptions{})
|
||||
appName := syncReq.GetName()
|
||||
appNs := s.appNamespaceOrDefault(syncReq.GetAppNamespace())
|
||||
appIf := s.appclientset.ArgoprojV1alpha1().Applications(appNs)
|
||||
a, err := appIf.Get(ctx, appName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting application by name: %w", err)
|
||||
}
|
||||
|
||||
proj, err := argo.GetAppProject(&a.Spec, applisters.NewAppProjectLister(s.projInformer.GetIndexer()), a.Namespace, s.settingsMgr, s.db, ctx)
|
||||
proj, err := argo.GetAppProject(a, applisters.NewAppProjectLister(s.projInformer.GetIndexer()), s.ns, s.settingsMgr, s.db, ctx)
|
||||
if err != nil {
|
||||
if apierr.IsNotFound(err) {
|
||||
return a, status.Errorf(codes.InvalidArgument, "application references project %s which does not exist", a.Spec.Project)
|
||||
|
|
@ -1454,11 +1523,11 @@ func (s *Server) Sync(ctx context.Context, syncReq *application.ApplicationSyncR
|
|||
return a, status.Errorf(codes.PermissionDenied, "cannot sync: blocked by sync window")
|
||||
}
|
||||
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionSync, apputil.AppRBACName(*a)); err != nil {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionSync, a.RBACName(s.ns)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if syncReq.Manifests != nil {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionOverride, apputil.AppRBACName(*a)); err != nil {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionOverride, a.RBACName(s.ns)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if a.Spec.SyncPolicy != nil && a.Spec.SyncPolicy.Automated != nil && !syncReq.GetDryRun() {
|
||||
|
|
@ -1521,7 +1590,7 @@ func (s *Server) Sync(ctx context.Context, syncReq *application.ApplicationSyncR
|
|||
op.Retry = *retry
|
||||
}
|
||||
|
||||
a, err = argo.SetAppOperation(appIf, *syncReq.Name, &op)
|
||||
a, err = argo.SetAppOperation(appIf, appName, &op)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error setting app operation: %w", err)
|
||||
}
|
||||
|
|
@ -1538,12 +1607,14 @@ func (s *Server) Sync(ctx context.Context, syncReq *application.ApplicationSyncR
|
|||
}
|
||||
|
||||
func (s *Server) Rollback(ctx context.Context, rollbackReq *application.ApplicationRollbackRequest) (*appv1.Application, error) {
|
||||
appIf := s.appclientset.ArgoprojV1alpha1().Applications(s.ns)
|
||||
a, err := appIf.Get(ctx, *rollbackReq.Name, metav1.GetOptions{})
|
||||
appName := rollbackReq.GetName()
|
||||
appNs := s.appNamespaceOrDefault(rollbackReq.GetAppNamespace())
|
||||
appIf := s.appclientset.ArgoprojV1alpha1().Applications(appNs)
|
||||
a, err := appIf.Get(ctx, appName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting application by name: %w", err)
|
||||
}
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionSync, apputil.AppRBACName(*a)); err != nil {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionSync, a.RBACName(s.ns)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if a.DeletionTimestamp != nil {
|
||||
|
|
@ -1561,7 +1632,7 @@ func (s *Server) Rollback(ctx context.Context, rollbackReq *application.Applicat
|
|||
}
|
||||
}
|
||||
if deploymentInfo == nil {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "application %s does not have deployment with id %v", a.Name, rollbackReq.GetId())
|
||||
return nil, status.Errorf(codes.InvalidArgument, "application %s does not have deployment with id %v", a.QualifiedName(), rollbackReq.GetId())
|
||||
}
|
||||
if deploymentInfo.Source.IsZero() {
|
||||
// Since source type was introduced to history starting with v0.12, and is now required for
|
||||
|
|
@ -1586,7 +1657,7 @@ func (s *Server) Rollback(ctx context.Context, rollbackReq *application.Applicat
|
|||
},
|
||||
InitiatedBy: appv1.OperationInitiator{Username: session.Username(ctx)},
|
||||
}
|
||||
a, err = argo.SetAppOperation(appIf, *rollbackReq.Name, &op)
|
||||
a, err = argo.SetAppOperation(appIf, appName, &op)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error setting app operation: %w", err)
|
||||
}
|
||||
|
|
@ -1633,11 +1704,13 @@ func (s *Server) resolveRevision(ctx context.Context, app *appv1.Application, sy
|
|||
}
|
||||
|
||||
func (s *Server) TerminateOperation(ctx context.Context, termOpReq *application.OperationTerminateRequest) (*application.OperationTerminateResponse, error) {
|
||||
a, err := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Get(ctx, *termOpReq.Name, metav1.GetOptions{})
|
||||
appName := termOpReq.GetName()
|
||||
appNs := s.appNamespaceOrDefault(termOpReq.GetAppNamespace())
|
||||
a, err := s.appclientset.ArgoprojV1alpha1().Applications(appNs).Get(ctx, appName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting application by name: %w", err)
|
||||
}
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionSync, apputil.AppRBACName(*a)); err != nil {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionSync, a.RBACName(s.ns)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
|
@ -1646,7 +1719,7 @@ func (s *Server) TerminateOperation(ctx context.Context, termOpReq *application.
|
|||
return nil, status.Errorf(codes.InvalidArgument, "Unable to terminate operation. No operation is in progress")
|
||||
}
|
||||
a.Status.OperationState.Phase = common.OperationTerminating
|
||||
updated, err := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Update(ctx, a, metav1.UpdateOptions{})
|
||||
updated, err := s.appclientset.ArgoprojV1alpha1().Applications(appNs).Update(ctx, a, metav1.UpdateOptions{})
|
||||
if err == nil {
|
||||
s.waitSync(updated)
|
||||
s.logAppEvent(a, ctx, argo.EventReasonResourceUpdated, "terminated running operation")
|
||||
|
|
@ -1657,7 +1730,7 @@ func (s *Server) TerminateOperation(ctx context.Context, termOpReq *application.
|
|||
}
|
||||
log.Warnf("failed to set operation for app %q due to update conflict. retrying again...", *termOpReq.Name)
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
a, err = s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Get(ctx, *termOpReq.Name, metav1.GetOptions{})
|
||||
a, err = s.appclientset.ArgoprojV1alpha1().Applications(appNs).Get(ctx, appName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting application by name: %w", err)
|
||||
}
|
||||
|
|
@ -1734,6 +1807,7 @@ func (s *Server) getAvailableActions(resourceOverrides map[string]appv1.Resource
|
|||
func (s *Server) RunResourceAction(ctx context.Context, q *application.ResourceActionRunRequest) (*application.ApplicationResponse, error) {
|
||||
resourceRequest := &application.ApplicationResourceRequest{
|
||||
Name: q.Name,
|
||||
AppNamespace: q.AppNamespace,
|
||||
Namespace: q.Namespace,
|
||||
ResourceName: q.ResourceName,
|
||||
Kind: q.Kind,
|
||||
|
|
@ -1870,17 +1944,19 @@ func (s *Server) plugins() ([]*v1alpha1.ConfigManagementPlugin, error) {
|
|||
}
|
||||
|
||||
func (s *Server) GetApplicationSyncWindows(ctx context.Context, q *application.ApplicationSyncWindowsQuery) (*application.ApplicationSyncWindowsResponse, error) {
|
||||
appIf := s.appclientset.ArgoprojV1alpha1().Applications(s.ns)
|
||||
a, err := appIf.Get(ctx, *q.Name, metav1.GetOptions{})
|
||||
appName := q.GetName()
|
||||
appNs := s.appNamespaceOrDefault(q.GetAppNamespace())
|
||||
appIf := s.appclientset.ArgoprojV1alpha1().Applications(appNs)
|
||||
a, err := appIf.Get(ctx, appName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting application by name: %w", err)
|
||||
}
|
||||
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionGet, apputil.AppRBACName(*a)); err != nil {
|
||||
if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionGet, a.RBACName(s.ns)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
proj, err := argo.GetAppProject(&a.Spec, applisters.NewAppProjectLister(s.projInformer.GetIndexer()), a.Namespace, s.settingsMgr, s.db, ctx)
|
||||
proj, err := argo.GetAppProject(a, applisters.NewAppProjectLister(s.projInformer.GetIndexer()), s.ns, s.settingsMgr, s.db, ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting app project: %w", err)
|
||||
}
|
||||
|
|
@ -1928,3 +2004,19 @@ func getPropagationPolicyFinalizer(policy string) string {
|
|||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) appNamespaceOrDefault(appNs string) string {
|
||||
if appNs == "" {
|
||||
return s.ns
|
||||
} else {
|
||||
return appNs
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) isNamespaceEnabled(namespace string) bool {
|
||||
return namespace == s.ns || glob.MatchStringInList(s.enabledNamespaces, namespace, false)
|
||||
}
|
||||
|
||||
func namespaceNotPermittedError(namespace string) error {
|
||||
return fmt.Errorf("namespace '%s' is not permitted", namespace)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,11 +27,14 @@ message ApplicationQuery {
|
|||
optional string selector = 5;
|
||||
// the repoURL to restrict returned list applications
|
||||
optional string repo = 6;
|
||||
// the application's namespace
|
||||
optional string appNamespace = 7;
|
||||
}
|
||||
|
||||
message NodeQuery {
|
||||
// the application's name
|
||||
optional string name = 1;
|
||||
optional string appNamespace = 2;
|
||||
}
|
||||
|
||||
message RevisionMetadataQuery{
|
||||
|
|
@ -39,6 +42,8 @@ message RevisionMetadataQuery{
|
|||
required string name = 1;
|
||||
// the revision of the app
|
||||
required string revision = 2;
|
||||
// the application's namespace
|
||||
optional string appNamespace = 3;
|
||||
}
|
||||
|
||||
// ApplicationEventsQuery is a query for application resource events
|
||||
|
|
@ -47,12 +52,14 @@ message ApplicationResourceEventsQuery {
|
|||
optional string resourceNamespace = 2;
|
||||
optional string resourceName = 3;
|
||||
optional string resourceUID = 4;
|
||||
optional string appNamespace = 5;
|
||||
}
|
||||
|
||||
// ManifestQuery is a query for manifest resources
|
||||
message ApplicationManifestQuery {
|
||||
required string name = 1;
|
||||
optional string revision = 2;
|
||||
optional string appNamespace = 3;
|
||||
}
|
||||
|
||||
message ApplicationResponse {}
|
||||
|
|
@ -72,6 +79,7 @@ message ApplicationDeleteRequest {
|
|||
required string name = 1;
|
||||
optional bool cascade = 2;
|
||||
optional string propagationPolicy = 3;
|
||||
optional string appNamespace = 4;
|
||||
}
|
||||
|
||||
message SyncOptions {
|
||||
|
|
@ -90,6 +98,7 @@ message ApplicationSyncRequest {
|
|||
repeated github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.Info infos = 9;
|
||||
optional github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.RetryStrategy retryStrategy = 10;
|
||||
optional SyncOptions syncOptions = 11;
|
||||
optional string appNamespace = 12;
|
||||
}
|
||||
|
||||
// ApplicationUpdateSpecRequest is a request to update application spec
|
||||
|
|
@ -97,6 +106,7 @@ message ApplicationUpdateSpecRequest {
|
|||
required string name = 1;
|
||||
required github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.ApplicationSpec spec = 2;
|
||||
optional bool validate = 3;
|
||||
optional string appNamespace = 4;
|
||||
}
|
||||
|
||||
// ApplicationPatchRequest is a request to patch an application
|
||||
|
|
@ -104,6 +114,7 @@ message ApplicationPatchRequest {
|
|||
required string name = 1;
|
||||
required string patch = 2;
|
||||
required string patchType = 3;
|
||||
optional string appNamespace = 5;
|
||||
}
|
||||
|
||||
message ApplicationRollbackRequest {
|
||||
|
|
@ -111,6 +122,7 @@ message ApplicationRollbackRequest {
|
|||
required int64 id = 2;
|
||||
optional bool dryRun = 3;
|
||||
optional bool prune = 4;
|
||||
optional string appNamespace = 6;
|
||||
}
|
||||
|
||||
message ApplicationResourceRequest {
|
||||
|
|
@ -120,6 +132,7 @@ message ApplicationResourceRequest {
|
|||
required string version = 4;
|
||||
optional string group = 5;
|
||||
required string kind = 6;
|
||||
optional string appNamespace = 7;
|
||||
}
|
||||
|
||||
message ApplicationResourcePatchRequest {
|
||||
|
|
@ -131,6 +144,7 @@ message ApplicationResourcePatchRequest {
|
|||
required string kind = 6;
|
||||
required string patch = 7;
|
||||
required string patchType = 8;
|
||||
optional string appNamespace = 9;
|
||||
}
|
||||
|
||||
message ApplicationResourceDeleteRequest {
|
||||
|
|
@ -142,6 +156,7 @@ message ApplicationResourceDeleteRequest {
|
|||
required string kind = 6;
|
||||
optional bool force = 7;
|
||||
optional bool orphan = 8;
|
||||
optional string appNamespace = 9;
|
||||
}
|
||||
|
||||
message ResourceActionRunRequest {
|
||||
|
|
@ -152,6 +167,7 @@ message ResourceActionRunRequest {
|
|||
optional string group = 5;
|
||||
required string kind = 6;
|
||||
required string action = 7;
|
||||
optional string appNamespace = 8;
|
||||
}
|
||||
|
||||
message ResourceActionsListResponse {
|
||||
|
|
@ -177,6 +193,7 @@ message ApplicationPodLogsQuery {
|
|||
optional string group = 12;
|
||||
optional string resourceName = 13 ;
|
||||
optional bool previous = 14;
|
||||
optional string appNamespace = 15;
|
||||
}
|
||||
|
||||
message LogEntry {
|
||||
|
|
@ -190,10 +207,12 @@ message LogEntry {
|
|||
|
||||
message OperationTerminateRequest {
|
||||
required string name = 1;
|
||||
optional string appNamespace = 2;
|
||||
}
|
||||
|
||||
message ApplicationSyncWindowsQuery {
|
||||
required string name = 1;
|
||||
optional string appNamespace = 2;
|
||||
}
|
||||
|
||||
message ApplicationSyncWindowsResponse {
|
||||
|
|
@ -221,6 +240,7 @@ message ResourcesQuery {
|
|||
optional string version = 4;
|
||||
optional string group = 5;
|
||||
optional string kind = 6;
|
||||
optional string appNamespace = 7;
|
||||
}
|
||||
|
||||
message ManagedResourcesResponse {
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ import (
|
|||
"github.com/argoproj/argo-cd/v2/reposerver/apiclient/mocks"
|
||||
"github.com/argoproj/argo-cd/v2/server/rbacpolicy"
|
||||
"github.com/argoproj/argo-cd/v2/test"
|
||||
"github.com/argoproj/argo-cd/v2/util/argo"
|
||||
"github.com/argoproj/argo-cd/v2/util/assets"
|
||||
"github.com/argoproj/argo-cd/v2/util/cache"
|
||||
"github.com/argoproj/argo-cd/v2/util/db"
|
||||
|
|
@ -201,7 +202,7 @@ func newTestAppServerWithEnforcerConfigure(f func(*rbac.Enforcer), objects ...ru
|
|||
testNamespace,
|
||||
kubeclientset,
|
||||
fakeAppsClientset,
|
||||
factory.Argoproj().V1alpha1().Applications().Lister().Applications(testNamespace),
|
||||
factory.Argoproj().V1alpha1().Applications().Lister(),
|
||||
appInformer,
|
||||
mockRepoClient,
|
||||
nil,
|
||||
|
|
@ -211,6 +212,7 @@ func newTestAppServerWithEnforcerConfigure(f func(*rbac.Enforcer), objects ...ru
|
|||
sync.NewKeyLock(),
|
||||
settingsMgr,
|
||||
projInformer,
|
||||
[]string{},
|
||||
)
|
||||
return server.(*Server)
|
||||
}
|
||||
|
|
@ -749,8 +751,14 @@ func TestServer_GetApplicationSyncWindowsState(t *testing.T) {
|
|||
func TestGetCachedAppState(t *testing.T) {
|
||||
testApp := newTestApp()
|
||||
testApp.ObjectMeta.ResourceVersion = "1"
|
||||
testApp.Spec.Project = "none"
|
||||
appServer := newTestAppServer(testApp)
|
||||
testApp.Spec.Project = "test-proj"
|
||||
testProj := &appsv1.AppProject{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-proj",
|
||||
Namespace: testNamespace,
|
||||
},
|
||||
}
|
||||
appServer := newTestAppServer(testApp, testProj)
|
||||
fakeClientSet := appServer.appclientset.(*apps.Clientset)
|
||||
t.Run("NoError", func(t *testing.T) {
|
||||
err := appServer.getCachedAppState(context.Background(), testApp, func() error {
|
||||
|
|
@ -901,7 +909,8 @@ func TestLogsGetSelectedPod(t *testing.T) {
|
|||
// refreshAnnotationRemover runs an infinite loop until it detects and removes refresh annotation or given context is done
|
||||
func refreshAnnotationRemover(t *testing.T, ctx context.Context, patched *int32, appServer *Server, appName string, ch chan string) {
|
||||
for ctx.Err() == nil {
|
||||
a, err := appServer.appLister.Get(appName)
|
||||
aName, appNs := argo.ParseAppQualifiedName(appName, appServer.ns)
|
||||
a, err := appServer.appLister.Applications(appNs).Get(aName)
|
||||
require.NoError(t, err)
|
||||
a = a.DeepCopy()
|
||||
if a.GetAnnotations() != nil && a.GetAnnotations()[appsv1.AnnotationKeyRefresh] != "" {
|
||||
|
|
|
|||
|
|
@ -28,16 +28,17 @@ import (
|
|||
)
|
||||
|
||||
type terminalHandler struct {
|
||||
appLister applisters.ApplicationNamespaceLister
|
||||
appLister applisters.ApplicationLister
|
||||
db db.ArgoDB
|
||||
enf *rbac.Enforcer
|
||||
cache *servercache.Cache
|
||||
appResourceTreeFn func(ctx context.Context, app *appv1.Application) (*appv1.ApplicationTree, error)
|
||||
allowedShells []string
|
||||
namespace string
|
||||
}
|
||||
|
||||
// NewHandler returns a new terminal handler.
|
||||
func NewHandler(appLister applisters.ApplicationNamespaceLister, db db.ArgoDB, enf *rbac.Enforcer, cache *servercache.Cache,
|
||||
func NewHandler(appLister applisters.ApplicationLister, namespace string, db db.ArgoDB, enf *rbac.Enforcer, cache *servercache.Cache,
|
||||
appResourceTree AppResourceTreeFn, allowedShells []string) *terminalHandler {
|
||||
return &terminalHandler{
|
||||
appLister: appLister,
|
||||
|
|
@ -46,6 +47,7 @@ func NewHandler(appLister applisters.ApplicationNamespaceLister, db db.ArgoDB, e
|
|||
cache: cache,
|
||||
appResourceTreeFn: appResourceTree,
|
||||
allowedShells: allowedShells,
|
||||
namespace: namespace,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -143,7 +145,7 @@ func (s *terminalHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||
fieldLog := log.WithFields(log.Fields{"application": app, "userName": sessionmgr.Username(ctx), "container": container,
|
||||
"podName": podName, "namespace": namespace, "cluster": project})
|
||||
|
||||
a, err := s.appLister.Get(app)
|
||||
a, err := s.appLister.Applications(s.namespace).Get(app)
|
||||
if err != nil {
|
||||
if apierr.IsNotFound(err) {
|
||||
http.Error(w, "App not found", http.StatusNotFound)
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ type Server struct {
|
|||
repoClientset apiclient.Clientset
|
||||
enf *rbac.Enforcer
|
||||
cache *servercache.Cache
|
||||
appLister applisters.ApplicationNamespaceLister
|
||||
appLister applisters.ApplicationLister
|
||||
projLister applisters.AppProjectNamespaceLister
|
||||
settings *settings.SettingsManager
|
||||
}
|
||||
|
|
@ -46,7 +46,7 @@ func NewServer(
|
|||
db db.ArgoDB,
|
||||
enf *rbac.Enforcer,
|
||||
cache *servercache.Cache,
|
||||
appLister applisters.ApplicationNamespaceLister,
|
||||
appLister applisters.ApplicationLister,
|
||||
projLister applisters.AppProjectNamespaceLister,
|
||||
settings *settings.SettingsManager,
|
||||
) *Server {
|
||||
|
|
@ -287,8 +287,8 @@ func (s *Server) GetAppDetails(ctx context.Context, q *repositorypkg.RepoAppDeta
|
|||
if err := s.enf.EnforceErr(claims, rbacpolicy.ResourceRepositories, rbacpolicy.ActionGet, createRBACObject(repo.Project, repo.Repo)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
app, err := s.appLister.Get(q.AppName)
|
||||
appName, appNs := argo.ParseAppQualifiedName(q.AppName, s.settings.GetNamespace())
|
||||
app, err := s.appLister.Applications(appNs).Get(appName)
|
||||
appRBACObj := createRBACObject(q.AppProject, q.AppName)
|
||||
// ensure caller has read privileges to app
|
||||
if err := s.enf.EnforceErr(claims, rbacpolicy.ResourceApplications, rbacpolicy.ActionGet, appRBACObj); err != nil {
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ var (
|
|||
}
|
||||
)
|
||||
|
||||
func newAppAndProjLister(objects ...runtime.Object) (applisters.ApplicationNamespaceLister, applisters.AppProjectNamespaceLister) {
|
||||
func newAppAndProjLister(objects ...runtime.Object) (applisters.ApplicationLister, applisters.AppProjectNamespaceLister) {
|
||||
fakeAppsClientset := fakeapps.NewSimpleClientset(objects...)
|
||||
factory := appinformer.NewSharedInformerFactoryWithOptions(fakeAppsClientset, 0, appinformer.WithNamespace(""), appinformer.WithTweakListOptions(func(options *metav1.ListOptions) {}))
|
||||
projInformer := factory.Argoproj().V1alpha1().AppProjects()
|
||||
|
|
@ -136,7 +136,7 @@ func newAppAndProjLister(objects ...runtime.Object) (applisters.ApplicationNames
|
|||
_ = appsInformer.Informer().GetStore().Add(obj)
|
||||
}
|
||||
}
|
||||
appLister := appsInformer.Lister().Applications(testNamespace)
|
||||
appLister := appsInformer.Lister()
|
||||
projLister := projInformer.Lister().AppProjects(testNamespace)
|
||||
return appLister, projLister
|
||||
}
|
||||
|
|
|
|||
|
|
@ -167,7 +167,7 @@ type ArgoCDServer struct {
|
|||
projLister applisters.AppProjectNamespaceLister
|
||||
policyEnforcer *rbacpolicy.RBACPolicyEnforcer
|
||||
appInformer cache.SharedIndexInformer
|
||||
appLister applisters.ApplicationNamespaceLister
|
||||
appLister applisters.ApplicationLister
|
||||
db db.ArgoDB
|
||||
|
||||
// stopCh is the channel which when closed, will shutdown the Argo CD server
|
||||
|
|
@ -200,6 +200,7 @@ type ArgoCDServerOpts struct {
|
|||
XFrameOptions string
|
||||
ContentSecurityPolicy string
|
||||
ListenHost string
|
||||
ApplicationNamespaces []string
|
||||
}
|
||||
|
||||
// initializeDefaultProject creates the default project if it does not already exist
|
||||
|
|
@ -231,12 +232,18 @@ func NewServer(ctx context.Context, opts ArgoCDServerOpts) *ArgoCDServer {
|
|||
err = initializeDefaultProject(opts)
|
||||
errors.CheckError(err)
|
||||
|
||||
factory := appinformer.NewSharedInformerFactoryWithOptions(opts.AppClientset, 0, appinformer.WithNamespace(opts.Namespace), appinformer.WithTweakListOptions(func(options *metav1.ListOptions) {}))
|
||||
projInformer := factory.Argoproj().V1alpha1().AppProjects().Informer()
|
||||
projLister := factory.Argoproj().V1alpha1().AppProjects().Lister().AppProjects(opts.Namespace)
|
||||
appInformerNs := opts.Namespace
|
||||
if len(opts.ApplicationNamespaces) > 0 {
|
||||
appInformerNs = ""
|
||||
}
|
||||
projFactory := appinformer.NewSharedInformerFactoryWithOptions(opts.AppClientset, 0, appinformer.WithNamespace(opts.Namespace), appinformer.WithTweakListOptions(func(options *metav1.ListOptions) {}))
|
||||
appFactory := appinformer.NewSharedInformerFactoryWithOptions(opts.AppClientset, 0, appinformer.WithNamespace(appInformerNs), appinformer.WithTweakListOptions(func(options *metav1.ListOptions) {}))
|
||||
|
||||
appInformer := factory.Argoproj().V1alpha1().Applications().Informer()
|
||||
appLister := factory.Argoproj().V1alpha1().Applications().Lister().Applications(opts.Namespace)
|
||||
projInformer := projFactory.Argoproj().V1alpha1().AppProjects().Informer()
|
||||
projLister := projFactory.Argoproj().V1alpha1().AppProjects().Lister().AppProjects(opts.Namespace)
|
||||
|
||||
appInformer := appFactory.Argoproj().V1alpha1().Applications().Informer()
|
||||
appLister := appFactory.Argoproj().V1alpha1().Applications().Lister()
|
||||
|
||||
userStateStorage := util_session.NewUserStateStorage(opts.RedisClient)
|
||||
sessionMgr := util_session.NewSessionManager(settingsMgr, projLister, opts.DexServerAddr, opts.DexTLSConfig, userStateStorage)
|
||||
|
|
@ -440,6 +447,7 @@ func (a *ArgoCDServer) Run(ctx context.Context, listeners *Listeners) {
|
|||
// Start the muxed listeners for our servers
|
||||
log.Infof("argocd %s serving on port %d (url: %s, tls: %v, namespace: %s, sso: %v)",
|
||||
common.GetVersion(), a.ListenPort, a.settings.URL, a.useTLS(), a.Namespace, a.settings.IsSSOConfigured())
|
||||
log.Infof("Enabled application namespace patterns: %s", a.allowedApplicationNamespacesAsString())
|
||||
|
||||
go func() { a.checkServeErr("grpcS", grpcS.Serve(grpcL)) }()
|
||||
go func() { a.checkServeErr("httpS", httpS.Serve(httpL)) }()
|
||||
|
|
@ -687,7 +695,8 @@ func (a *ArgoCDServer) newGRPCServer() (*grpc.Server, application.AppResourceTre
|
|||
a.enf,
|
||||
projectLock,
|
||||
a.settingsMgr,
|
||||
a.projInformer)
|
||||
a.projInformer,
|
||||
a.ApplicationNamespaces)
|
||||
projectService := project.NewServer(a.Namespace, a.KubeClientset, a.AppClientset, a.enf, projectLock, a.sessionMgr, a.policyEnforcer, a.projInformer, a.settingsMgr, a.db)
|
||||
settingsService := settings.NewServer(a.settingsMgr, a, a.DisableAuth)
|
||||
accountService := account.NewServer(a.sessionMgr, a.settingsMgr, a.enf)
|
||||
|
|
@ -812,7 +821,7 @@ func (a *ArgoCDServer) newHTTPServer(ctx context.Context, port int, grpcWebHandl
|
|||
}
|
||||
mux.Handle("/api/", handler)
|
||||
|
||||
terminalHandler := application.NewHandler(a.appLister, a.db, a.enf, a.Cache, appResourceTreeFn, a.settings.ExecShells)
|
||||
terminalHandler := application.NewHandler(a.appLister, a.Namespace, a.db, a.enf, a.Cache, appResourceTreeFn, a.settings.ExecShells)
|
||||
mux.HandleFunc("/terminal", func(writer http.ResponseWriter, request *http.Request) {
|
||||
argocdSettings, err := a.settingsMgr.GetSettings()
|
||||
if err != nil {
|
||||
|
|
@ -1262,3 +1271,14 @@ func bug21955WorkaroundInterceptor(ctx context.Context, req interface{}, _ *grpc
|
|||
}
|
||||
return handler(ctx, req)
|
||||
}
|
||||
|
||||
// allowedNamespacesAsString returns a string containing comma-separated list
|
||||
// of allowed application namespaces
|
||||
func (a *ArgoCDServer) allowedApplicationNamespacesAsString() string {
|
||||
ns := a.Namespace
|
||||
if len(a.ArgoCDServerOpts.ApplicationNamespaces) > 0 {
|
||||
ns += ", "
|
||||
ns += strings.Join(a.ArgoCDServerOpts.ApplicationNamespaces, ", ")
|
||||
}
|
||||
return ns
|
||||
}
|
||||
|
|
|
|||
|
|
@ -125,6 +125,7 @@ func (s *Server) Get(ctx context.Context, q *settingspkg.SettingsQuery) (*settin
|
|||
set.UiBannerURL = argoCDSettings.UiBannerURL
|
||||
set.UiBannerPermanent = argoCDSettings.UiBannerPermanent
|
||||
set.UiBannerPosition = argoCDSettings.UiBannerPosition
|
||||
set.ControllerNamespace = s.mgr.GetNamespace()
|
||||
}
|
||||
if argoCDSettings.DexConfig != "" {
|
||||
var cfg settingspkg.DexConfig
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ message Settings {
|
|||
string uiBannerPosition = 20;
|
||||
string statusBadgeRootUrl = 21;
|
||||
bool execEnabled = 22;
|
||||
string controllerNamespace = 23;
|
||||
}
|
||||
|
||||
message GoogleAnalyticsConfig {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
controller: [ "$BIN_MODE" == 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_SSH_DATA_PATH=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} ARGOCD_BINARY_NAME=argocd-application-controller $COMMAND --loglevel debug --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081}"
|
||||
api-server: [ "$BIN_MODE" == 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_BINARY_NAME=argocd-server $COMMAND --loglevel debug --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --disable-auth=${ARGOCD_E2E_DISABLE_AUTH:-'true'} --insecure --dex-server http://localhost:${ARGOCD_E2E_DEX_PORT:-5556} --repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081} --port ${ARGOCD_E2E_APISERVER_PORT:-8080} "
|
||||
controller: [ "$BIN_MODE" == 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_SSH_DATA_PATH=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} ARGOCD_BINARY_NAME=argocd-application-controller $COMMAND --loglevel debug --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081} --application-namespaces=${ARGOCD_APPLICATION_NAMESPACES:-''}"
|
||||
api-server: [ "$BIN_MODE" == 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_BINARY_NAME=argocd-server $COMMAND --loglevel debug --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --disable-auth=${ARGOCD_E2E_DISABLE_AUTH:-'true'} --insecure --dex-server http://localhost:${ARGOCD_E2E_DEX_PORT:-5556} --repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081} --port ${ARGOCD_E2E_APISERVER_PORT:-8080} --application-namespaces=${ARGOCD_APPLICATION_NAMESPACES:-''} "
|
||||
dex: sh -c "test $ARGOCD_IN_CI = true && exit 0; ARGOCD_BINARY_NAME=argocd-dex go run github.com/argoproj/argo-cd/cmd gendexcfg -o `pwd`/dist/dex.yaml && docker run --rm -p ${ARGOCD_E2E_DEX_PORT:-5556}:${ARGOCD_E2E_DEX_PORT:-5556} -v `pwd`/dist/dex.yaml:/dex.yaml ghcr.io/dexidp/dex:v2.30.0 serve /dex.yaml"
|
||||
redis: sh -c "/usr/local/bin/redis-server --save "" --appendonly no --port ${ARGOCD_E2E_REDIS_PORT:-6379}"
|
||||
repo-server: [ "$BIN_MODE" == 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_GNUPGHOME=${ARGOCD_GNUPGHOME:-/tmp/argocd-local/gpg/keys} ARGOCD_PLUGINSOCKFILEPATH=${ARGOCD_PLUGINSOCKFILEPATH:-./test/cmp} ARGOCD_GPG_DATA_PATH=${ARGOCD_GPG_DATA_PATH:-/tmp/argocd-local/gpg/source} ARGOCD_BINARY_NAME=argocd-repo-server $COMMAND --loglevel debug --port ${ARGOCD_E2E_REPOSERVER_PORT:-8081} --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379}"
|
||||
|
|
|
|||
102
test/e2e/app_autosync_ns_test.go
Normal file
102
test/e2e/app_autosync_ns_test.go
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
package e2e
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
. "github.com/argoproj/gitops-engine/pkg/sync/common"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
|
||||
. "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/v2/test/e2e/fixture"
|
||||
. "github.com/argoproj/argo-cd/v2/test/e2e/fixture/app"
|
||||
"github.com/argoproj/argo-cd/v2/util/errors"
|
||||
)
|
||||
|
||||
func TestNSAutoSyncSelfHealDisabled(t *testing.T) {
|
||||
Given(t).
|
||||
SetTrackingMethod("annotation").
|
||||
Path(guestbookPath).
|
||||
SetAppNamespace(fixture.AppNamespace()).
|
||||
// TODO: There is a bug with annotation tracking method that prevents
|
||||
// controller from picking up changes in the cluster.
|
||||
When().
|
||||
// app should be auto-synced once created
|
||||
CreateFromFile(func(app *Application) {
|
||||
app.Spec.SyncPolicy = &SyncPolicy{Automated: &SyncPolicyAutomated{SelfHeal: false}}
|
||||
}).
|
||||
Then().
|
||||
Expect(SyncStatusIs(SyncStatusCodeSynced)).
|
||||
// app should be auto-synced if git change detected
|
||||
When().
|
||||
PatchFile("guestbook-ui-deployment.yaml", `[{"op": "replace", "path": "/spec/revisionHistoryLimit", "value": 1}]`).
|
||||
Refresh(RefreshTypeNormal).
|
||||
Then().
|
||||
Expect(SyncStatusIs(SyncStatusCodeSynced)).
|
||||
// app should not be auto-synced if k8s change detected
|
||||
When().
|
||||
And(func() {
|
||||
errors.FailOnErr(fixture.KubeClientset.AppsV1().Deployments(fixture.DeploymentNamespace()).Patch(context.Background(),
|
||||
"guestbook-ui", types.MergePatchType, []byte(`{"spec": {"revisionHistoryLimit": 0}}`), v1.PatchOptions{}))
|
||||
}).
|
||||
Then().
|
||||
Expect(SyncStatusIs(SyncStatusCodeOutOfSync))
|
||||
}
|
||||
|
||||
func TestNSAutoSyncSelfHealEnabled(t *testing.T) {
|
||||
Given(t).
|
||||
SetTrackingMethod("annotation").
|
||||
Path(guestbookPath).
|
||||
SetAppNamespace(fixture.AppNamespace()).
|
||||
When().
|
||||
// app should be auto-synced once created
|
||||
CreateFromFile(func(app *Application) {
|
||||
app.Spec.SyncPolicy = &SyncPolicy{
|
||||
Automated: &SyncPolicyAutomated{SelfHeal: true},
|
||||
Retry: &RetryStrategy{Limit: 0},
|
||||
}
|
||||
}).
|
||||
Then().
|
||||
Expect(OperationPhaseIs(OperationSucceeded)).
|
||||
Expect(SyncStatusIs(SyncStatusCodeSynced)).
|
||||
When().
|
||||
// app should be auto-synced once k8s change detected
|
||||
And(func() {
|
||||
errors.FailOnErr(fixture.KubeClientset.AppsV1().Deployments(fixture.DeploymentNamespace()).Patch(context.Background(),
|
||||
"guestbook-ui", types.MergePatchType, []byte(`{"spec": {"revisionHistoryLimit": 0}}`), v1.PatchOptions{}))
|
||||
}).
|
||||
Refresh(RefreshTypeNormal).
|
||||
Then().
|
||||
Expect(OperationPhaseIs(OperationSucceeded)).
|
||||
Expect(SyncStatusIs(SyncStatusCodeSynced)).
|
||||
When().
|
||||
// app should be attempted to auto-synced once and marked with error after failed attempt detected
|
||||
PatchFile("guestbook-ui-deployment.yaml", `[{"op": "replace", "path": "/spec/revisionHistoryLimit", "value": "badValue"}]`).
|
||||
Refresh(RefreshTypeNormal).
|
||||
Then().
|
||||
Expect(OperationPhaseIs(OperationFailed)).
|
||||
When().
|
||||
// Trigger refresh again to make sure controller notices previously failed sync attempt before expectation timeout expires
|
||||
Refresh(RefreshTypeNormal).
|
||||
Then().
|
||||
Expect(SyncStatusIs(SyncStatusCodeOutOfSync)).
|
||||
Expect(Condition(ApplicationConditionSyncError, "Failed sync attempt")).
|
||||
When().
|
||||
// SyncError condition should be removed after successful sync
|
||||
PatchFile("guestbook-ui-deployment.yaml", `[{"op": "replace", "path": "/spec/revisionHistoryLimit", "value": 1}]`).
|
||||
Refresh(RefreshTypeNormal).
|
||||
Then().
|
||||
Expect(OperationPhaseIs(OperationSucceeded)).
|
||||
When().
|
||||
// Trigger refresh twice to make sure controller notices successful attempt and removes condition
|
||||
Refresh(RefreshTypeNormal).
|
||||
Then().
|
||||
Expect(SyncStatusIs(SyncStatusCodeSynced)).
|
||||
And(func(app *Application) {
|
||||
assert.Len(t, app.Status.Conditions, 0)
|
||||
})
|
||||
|
||||
}
|
||||
|
|
@ -38,6 +38,7 @@ func TestAutoSyncSelfHealDisabled(t *testing.T) {
|
|||
errors.FailOnErr(fixture.KubeClientset.AppsV1().Deployments(fixture.DeploymentNamespace()).Patch(context.Background(),
|
||||
"guestbook-ui", types.MergePatchType, []byte(`{"spec": {"revisionHistoryLimit": 0}}`), v1.PatchOptions{}))
|
||||
}).
|
||||
Refresh(RefreshTypeNormal).
|
||||
Then().
|
||||
Expect(SyncStatusIs(SyncStatusCodeOutOfSync))
|
||||
}
|
||||
|
|
|
|||
2213
test/e2e/app_management_ns_test.go
Normal file
2213
test/e2e/app_management_ns_test.go
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -273,7 +273,6 @@ func TestSyncToSignedCommitKeyWithKnownKey(t *testing.T) {
|
|||
|
||||
func TestAppCreation(t *testing.T) {
|
||||
ctx := Given(t)
|
||||
|
||||
ctx.
|
||||
Path(guestbookPath).
|
||||
When().
|
||||
|
|
@ -326,7 +325,7 @@ func TestAppCreationWithoutForceUpdate(t *testing.T) {
|
|||
Then().
|
||||
Expect(SyncStatusIs(SyncStatusCodeOutOfSync)).
|
||||
And(func(app *Application) {
|
||||
assert.Equal(t, Name(), app.Name)
|
||||
assert.Equal(t, ctx.AppName(), app.Name)
|
||||
assert.Equal(t, RepoURL(RepoURLTypeFile), app.Spec.Source.RepoURL)
|
||||
assert.Equal(t, guestbookPath, app.Spec.Source.Path)
|
||||
assert.Equal(t, DeploymentNamespace(), app.Spec.Destination.Namespace)
|
||||
|
|
@ -512,21 +511,20 @@ func TestAppRollbackSuccessful(t *testing.T) {
|
|||
Source: app.Spec.Source,
|
||||
}}
|
||||
patch, _, err := diff.CreateTwoWayMergePatch(app, appWithHistory, &Application{})
|
||||
assert.NoError(t, err)
|
||||
|
||||
require.NoError(t, err)
|
||||
app, err = AppClientset.ArgoprojV1alpha1().Applications(ArgoCDNamespace).Patch(context.Background(), app.Name, types.MergePatchType, patch, metav1.PatchOptions{})
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
|
||||
// sync app and make sure it reaches InSync state
|
||||
_, err = RunCli("app", "rollback", app.Name, "1")
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
|
||||
}).
|
||||
Expect(Event(EventReasonOperationStarted, "rollback")).
|
||||
Expect(SyncStatusIs(SyncStatusCodeSynced)).
|
||||
And(func(app *Application) {
|
||||
assert.Equal(t, SyncStatusCodeSynced, app.Status.Sync.Status)
|
||||
assert.NotNil(t, app.Status.OperationState.SyncResult)
|
||||
require.NotNil(t, app.Status.OperationState.SyncResult)
|
||||
assert.Equal(t, 2, len(app.Status.OperationState.SyncResult.Resources))
|
||||
assert.Equal(t, OperationSucceeded, app.Status.OperationState.Phase)
|
||||
assert.Equal(t, 3, len(app.Status.History))
|
||||
|
|
@ -1179,7 +1177,9 @@ func TestPermissions(t *testing.T) {
|
|||
And(func(app *Application) {
|
||||
closer, cdClient := ArgoCDClientset.NewApplicationClientOrDie()
|
||||
defer io.Close(closer)
|
||||
tree, err := cdClient.ResourceTree(context.Background(), &applicationpkg.ResourcesQuery{ApplicationName: &app.Name})
|
||||
appName, appNs := argo.ParseAppQualifiedName(app.Name, "")
|
||||
fmt.Printf("APP NAME: %s\n", appName)
|
||||
tree, err := cdClient.ResourceTree(context.Background(), &applicationpkg.ResourcesQuery{ApplicationName: &appName, AppNamespace: &appNs})
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, tree.Nodes, 0)
|
||||
assert.Len(t, tree.OrphanedNodes, 0)
|
||||
|
|
@ -1204,6 +1204,7 @@ func TestPermissions(t *testing.T) {
|
|||
|
||||
func TestPermissionWithScopedRepo(t *testing.T) {
|
||||
projName := "argo-project"
|
||||
fixture.EnsureCleanState(t)
|
||||
projectFixture.
|
||||
Given(t).
|
||||
Name(projName).
|
||||
|
|
@ -2012,7 +2013,8 @@ func TestAppLogs(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestAppWaitOperationInProgress(t *testing.T) {
|
||||
Given(t).
|
||||
ctx := Given(t)
|
||||
ctx.
|
||||
And(func() {
|
||||
SetResourceOverrides(map[string]ResourceOverride{
|
||||
"batch/Job": {
|
||||
|
|
@ -2033,7 +2035,7 @@ func TestAppWaitOperationInProgress(t *testing.T) {
|
|||
Expect(OperationPhaseIs(OperationRunning)).
|
||||
When().
|
||||
And(func() {
|
||||
_, err := RunCli("app", "wait", Name(), "--suspended")
|
||||
_, err := RunCli("app", "wait", ctx.AppName(), "--suspended")
|
||||
errors.CheckError(err)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
105
test/e2e/app_namespaces_test.go
Normal file
105
test/e2e/app_namespaces_test.go
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
package e2e
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
. "github.com/argoproj/gitops-engine/pkg/sync/common"
|
||||
"github.com/stretchr/testify/assert"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
|
||||
. "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
. "github.com/argoproj/argo-cd/v2/test/e2e/fixture"
|
||||
. "github.com/argoproj/argo-cd/v2/test/e2e/fixture/app"
|
||||
. "github.com/argoproj/argo-cd/v2/util/argo"
|
||||
. "github.com/argoproj/argo-cd/v2/util/errors"
|
||||
)
|
||||
|
||||
func TestAppCreationInOtherNamespace(t *testing.T) {
|
||||
ctx := Given(t)
|
||||
ctx.
|
||||
Path(guestbookPath).
|
||||
SetAppNamespace(ArgoCDAppNamespace).
|
||||
When().
|
||||
CreateApp().
|
||||
Then().
|
||||
Expect(SyncStatusIs(SyncStatusCodeOutOfSync)).
|
||||
And(func(app *Application) {
|
||||
assert.Equal(t, ctx.AppName(), app.Name)
|
||||
assert.Equal(t, AppNamespace(), app.Namespace)
|
||||
assert.Equal(t, RepoURL(RepoURLTypeFile), app.Spec.Source.RepoURL)
|
||||
assert.Equal(t, guestbookPath, app.Spec.Source.Path)
|
||||
assert.Equal(t, DeploymentNamespace(), app.Spec.Destination.Namespace)
|
||||
assert.Equal(t, KubernetesInternalAPIServerAddr, app.Spec.Destination.Server)
|
||||
}).
|
||||
Expect(NamespacedEvent(ctx.AppNamespace(), EventReasonResourceCreated, "create")).
|
||||
And(func(_ *Application) {
|
||||
// app should be listed
|
||||
output, err := RunCli("app", "list")
|
||||
assert.NoError(t, err)
|
||||
assert.Contains(t, output, ctx.AppName())
|
||||
}).
|
||||
When().
|
||||
// ensure that create is idempotent
|
||||
CreateApp().
|
||||
Then().
|
||||
Given().
|
||||
Revision("master").
|
||||
When().
|
||||
// ensure that update replaces spec and merge labels and annotations
|
||||
And(func() {
|
||||
FailOnErr(AppClientset.ArgoprojV1alpha1().Applications(AppNamespace()).Patch(context.Background(),
|
||||
ctx.AppName(), types.MergePatchType, []byte(`{"metadata": {"labels": { "test": "label" }, "annotations": { "test": "annotation" }}}`), metav1.PatchOptions{}))
|
||||
}).
|
||||
CreateApp("--upsert").
|
||||
Then().
|
||||
And(func(app *Application) {
|
||||
assert.Equal(t, "label", app.Labels["test"])
|
||||
assert.Equal(t, "annotation", app.Annotations["test"])
|
||||
assert.Equal(t, "master", app.Spec.Source.TargetRevision)
|
||||
})
|
||||
}
|
||||
|
||||
func TestForbiddenNamespace(t *testing.T) {
|
||||
ctx := Given(t)
|
||||
ctx.
|
||||
Path(guestbookPath).
|
||||
SetAppNamespace("forbidden").
|
||||
When().
|
||||
IgnoreErrors().
|
||||
CreateApp().
|
||||
Then().
|
||||
Expect(DoesNotExist())
|
||||
}
|
||||
|
||||
func TestDeletingNamespacedAppStuckInSync(t *testing.T) {
|
||||
ctx := Given(t)
|
||||
ctx.And(func() {
|
||||
SetResourceOverrides(map[string]ResourceOverride{
|
||||
"ConfigMap": {
|
||||
HealthLua: `return { status = obj.annotations and obj.annotations['health'] or 'Progressing' }`,
|
||||
},
|
||||
})
|
||||
}).
|
||||
Async(true).
|
||||
SetAppNamespace(ArgoCDAppNamespace).
|
||||
Path("hook-custom-health").
|
||||
When().
|
||||
CreateApp().
|
||||
Sync().
|
||||
Then().
|
||||
// stuck in running state
|
||||
Expect(OperationPhaseIs(OperationRunning)).
|
||||
Expect(SyncStatusIs(SyncStatusCodeOutOfSync)).
|
||||
When().
|
||||
Delete(true).
|
||||
Then().
|
||||
// delete is ignored, still stuck in running state
|
||||
Expect(OperationPhaseIs(OperationRunning)).
|
||||
When().
|
||||
TerminateOp().
|
||||
Then().
|
||||
// delete is successful
|
||||
Expect(DoesNotExist())
|
||||
}
|
||||
|
|
@ -19,7 +19,8 @@ import (
|
|||
|
||||
// make sure we can echo back the Git creds
|
||||
func TestCustomToolWithGitCreds(t *testing.T) {
|
||||
Given(t).
|
||||
ctx := Given(t)
|
||||
ctx.
|
||||
// path does not matter, we ignore it
|
||||
ConfigManagementPlugin(
|
||||
ConfigManagementPlugin{
|
||||
|
|
@ -43,7 +44,7 @@ func TestCustomToolWithGitCreds(t *testing.T) {
|
|||
Expect(SyncStatusIs(SyncStatusCodeSynced)).
|
||||
Expect(HealthIs(health.HealthStatusHealthy)).
|
||||
And(func(app *Application) {
|
||||
output, err := Run("", "kubectl", "-n", DeploymentNamespace(), "get", "cm", Name(), "-o", "jsonpath={.metadata.annotations.GitAskpass}")
|
||||
output, err := Run("", "kubectl", "-n", DeploymentNamespace(), "get", "cm", ctx.AppName(), "-o", "jsonpath={.metadata.annotations.GitAskpass}")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "argocd", output)
|
||||
})
|
||||
|
|
@ -51,7 +52,8 @@ func TestCustomToolWithGitCreds(t *testing.T) {
|
|||
|
||||
// make sure we can echo back the Git creds
|
||||
func TestCustomToolWithGitCredsTemplate(t *testing.T) {
|
||||
Given(t).
|
||||
ctx := Given(t)
|
||||
ctx.
|
||||
// path does not matter, we ignore it
|
||||
ConfigManagementPlugin(
|
||||
ConfigManagementPlugin{
|
||||
|
|
@ -77,17 +79,17 @@ func TestCustomToolWithGitCredsTemplate(t *testing.T) {
|
|||
Expect(SyncStatusIs(SyncStatusCodeSynced)).
|
||||
Expect(HealthIs(health.HealthStatusHealthy)).
|
||||
And(func(app *Application) {
|
||||
output, err := Run("", "kubectl", "-n", DeploymentNamespace(), "get", "cm", Name(), "-o", "jsonpath={.metadata.annotations.GitAskpass}")
|
||||
output, err := Run("", "kubectl", "-n", DeploymentNamespace(), "get", "cm", ctx.AppName(), "-o", "jsonpath={.metadata.annotations.GitAskpass}")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "argocd", output)
|
||||
}).
|
||||
And(func(app *Application) {
|
||||
output, err := Run("", "kubectl", "-n", DeploymentNamespace(), "get", "cm", Name(), "-o", "jsonpath={.metadata.annotations.GitUsername}")
|
||||
output, err := Run("", "kubectl", "-n", DeploymentNamespace(), "get", "cm", ctx.AppName(), "-o", "jsonpath={.metadata.annotations.GitUsername}")
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, output)
|
||||
}).
|
||||
And(func(app *Application) {
|
||||
output, err := Run("", "kubectl", "-n", DeploymentNamespace(), "get", "cm", Name(), "-o", "jsonpath={.metadata.annotations.GitPassword}")
|
||||
output, err := Run("", "kubectl", "-n", DeploymentNamespace(), "get", "cm", ctx.AppName(), "-o", "jsonpath={.metadata.annotations.GitPassword}")
|
||||
assert.NoError(t, err)
|
||||
assert.Empty(t, output)
|
||||
})
|
||||
|
|
@ -95,7 +97,8 @@ func TestCustomToolWithGitCredsTemplate(t *testing.T) {
|
|||
|
||||
// make sure we can echo back the env
|
||||
func TestCustomToolWithEnv(t *testing.T) {
|
||||
Given(t).
|
||||
ctx := Given(t)
|
||||
ctx.
|
||||
// path does not matter, we ignore it
|
||||
ConfigManagementPlugin(
|
||||
ConfigManagementPlugin{
|
||||
|
|
@ -124,18 +127,18 @@ func TestCustomToolWithEnv(t *testing.T) {
|
|||
time.Sleep(1 * time.Second)
|
||||
}).
|
||||
And(func(app *Application) {
|
||||
output, err := Run("", "kubectl", "-n", DeploymentNamespace(), "get", "cm", Name(), "-o", "jsonpath={.metadata.annotations.Bar}")
|
||||
output, err := Run("", "kubectl", "-n", DeploymentNamespace(), "get", "cm", ctx.AppName(), "-o", "jsonpath={.metadata.annotations.Bar}")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "baz", output)
|
||||
}).
|
||||
And(func(app *Application) {
|
||||
output, err := Run("", "kubectl", "-n", DeploymentNamespace(), "get", "cm", Name(), "-o", "jsonpath={.metadata.annotations.Foo}")
|
||||
output, err := Run("", "kubectl", "-n", DeploymentNamespace(), "get", "cm", ctx.AppName(), "-o", "jsonpath={.metadata.annotations.Foo}")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "bar", output)
|
||||
}).
|
||||
And(func(app *Application) {
|
||||
expectedKubeVersion := GetVersions().ServerVersion.Format("%s.%s")
|
||||
output, err := Run("", "kubectl", "-n", DeploymentNamespace(), "get", "cm", Name(), "-o", "jsonpath={.metadata.annotations.KubeVersion}")
|
||||
output, err := Run("", "kubectl", "-n", DeploymentNamespace(), "get", "cm", ctx.AppName(), "-o", "jsonpath={.metadata.annotations.KubeVersion}")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, expectedKubeVersion, output)
|
||||
}).
|
||||
|
|
@ -144,7 +147,7 @@ func TestCustomToolWithEnv(t *testing.T) {
|
|||
expectedApiVersionSlice := strings.Split(expectedApiVersion, ",")
|
||||
sort.Strings(expectedApiVersionSlice)
|
||||
|
||||
output, err := Run("", "kubectl", "-n", DeploymentNamespace(), "get", "cm", Name(), "-o", "jsonpath={.metadata.annotations.KubeApiVersion}")
|
||||
output, err := Run("", "kubectl", "-n", DeploymentNamespace(), "get", "cm", ctx.AppName(), "-o", "jsonpath={.metadata.annotations.KubeApiVersion}")
|
||||
assert.NoError(t, err)
|
||||
outputSlice := strings.Split(output, ",")
|
||||
sort.Strings(outputSlice)
|
||||
|
|
@ -155,7 +158,8 @@ func TestCustomToolWithEnv(t *testing.T) {
|
|||
|
||||
//make sure we can sync and diff with --local
|
||||
func TestCustomToolSyncAndDiffLocal(t *testing.T) {
|
||||
Given(t).
|
||||
ctx := Given(t)
|
||||
ctx.
|
||||
// path does not matter, we ignore it
|
||||
ConfigManagementPlugin(
|
||||
ConfigManagementPlugin{
|
||||
|
|
@ -169,7 +173,7 @@ func TestCustomToolSyncAndDiffLocal(t *testing.T) {
|
|||
// does not matter what the path is
|
||||
Path("guestbook").
|
||||
When().
|
||||
CreateApp("--config-management-plugin", Name()).
|
||||
CreateApp("--config-management-plugin", ctx.AppName()).
|
||||
Sync("--local", "testdata/guestbook").
|
||||
Then().
|
||||
Expect(OperationPhaseIs(OperationSucceeded)).
|
||||
|
|
@ -179,10 +183,10 @@ func TestCustomToolSyncAndDiffLocal(t *testing.T) {
|
|||
time.Sleep(1 * time.Second)
|
||||
}).
|
||||
And(func(app *Application) {
|
||||
FailOnErr(RunCli("app", "sync", app.Name, "--local", "testdata/guestbook"))
|
||||
FailOnErr(RunCli("app", "sync", ctx.AppName(), "--local", "testdata/guestbook"))
|
||||
}).
|
||||
And(func(app *Application) {
|
||||
FailOnErr(RunCli("app", "diff", app.Name, "--local", "testdata/guestbook"))
|
||||
FailOnErr(RunCli("app", "diff", ctx.AppName(), "--local", "testdata/guestbook"))
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -239,7 +243,8 @@ func TestCMPDiscoverWithFindGlob(t *testing.T) {
|
|||
//Discover by Find command
|
||||
func TestCMPDiscoverWithFindCommandWithEnv(t *testing.T) {
|
||||
pluginName := "cmp-find-command"
|
||||
Given(t).
|
||||
ctx := Given(t)
|
||||
ctx.
|
||||
And(func() {
|
||||
go startCMPServer("./testdata/cmp-find-command")
|
||||
time.Sleep(1 * time.Second)
|
||||
|
|
@ -257,13 +262,13 @@ func TestCMPDiscoverWithFindCommandWithEnv(t *testing.T) {
|
|||
time.Sleep(1 * time.Second)
|
||||
}).
|
||||
And(func(app *Application) {
|
||||
output, err := Run("", "kubectl", "-n", DeploymentNamespace(), "get", "cm", Name(), "-o", "jsonpath={.metadata.annotations.Bar}")
|
||||
output, err := Run("", "kubectl", "-n", DeploymentNamespace(), "get", "cm", ctx.AppName(), "-o", "jsonpath={.metadata.annotations.Bar}")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "baz", output)
|
||||
}).
|
||||
And(func(app *Application) {
|
||||
expectedKubeVersion := GetVersions().ServerVersion.Format("%s.%s")
|
||||
output, err := Run("", "kubectl", "-n", DeploymentNamespace(), "get", "cm", Name(), "-o", "jsonpath={.metadata.annotations.KubeVersion}")
|
||||
output, err := Run("", "kubectl", "-n", DeploymentNamespace(), "get", "cm", ctx.AppName(), "-o", "jsonpath={.metadata.annotations.KubeVersion}")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, expectedKubeVersion, output)
|
||||
}).
|
||||
|
|
@ -272,7 +277,7 @@ func TestCMPDiscoverWithFindCommandWithEnv(t *testing.T) {
|
|||
expectedApiVersionSlice := strings.Split(expectedApiVersion, ",")
|
||||
sort.Strings(expectedApiVersionSlice)
|
||||
|
||||
output, err := Run("", "kubectl", "-n", DeploymentNamespace(), "get", "cm", Name(), "-o", "jsonpath={.metadata.annotations.KubeApiVersion}")
|
||||
output, err := Run("", "kubectl", "-n", DeploymentNamespace(), "get", "cm", ctx.AppName(), "-o", "jsonpath={.metadata.annotations.KubeApiVersion}")
|
||||
assert.NoError(t, err)
|
||||
outputSlice := strings.Split(output, ",")
|
||||
sort.Strings(outputSlice)
|
||||
|
|
|
|||
|
|
@ -54,11 +54,11 @@ func TestDeploymentWithAnnotationTrackingMode(t *testing.T) {
|
|||
When().
|
||||
Then().
|
||||
And(func(app *Application) {
|
||||
out, err := RunCli("app", "manifests", app.Name)
|
||||
out, err := RunCli("app", "manifests", ctx.AppName())
|
||||
assert.NoError(t, err)
|
||||
assert.Contains(t, out, fmt.Sprintf(`annotations:
|
||||
argocd.argoproj.io/tracking-id: %s:apps/Deployment:%s/nginx-deployment
|
||||
`, Name(), DeploymentNamespace()))
|
||||
`, ctx.AppName(), DeploymentNamespace()))
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -77,17 +77,18 @@ func TestDeploymentWithLabelTrackingMode(t *testing.T) {
|
|||
When().
|
||||
Then().
|
||||
And(func(app *Application) {
|
||||
out, err := RunCli("app", "manifests", app.Name)
|
||||
out, err := RunCli("app", "manifests", ctx.AppName())
|
||||
assert.NoError(t, err)
|
||||
assert.Contains(t, out, fmt.Sprintf(`labels:
|
||||
app: nginx
|
||||
app.kubernetes.io/instance: %s
|
||||
`, Name()))
|
||||
`, ctx.AppName()))
|
||||
})
|
||||
}
|
||||
|
||||
func TestDeploymentWithoutTrackingMode(t *testing.T) {
|
||||
Given(t).
|
||||
ctx := Given(t)
|
||||
ctx.
|
||||
Path("deployment").
|
||||
When().
|
||||
CreateApp().
|
||||
|
|
@ -99,11 +100,11 @@ func TestDeploymentWithoutTrackingMode(t *testing.T) {
|
|||
When().
|
||||
Then().
|
||||
And(func(app *Application) {
|
||||
out, err := RunCli("app", "manifests", app.Name)
|
||||
out, err := RunCli("app", "manifests", ctx.AppName())
|
||||
assert.NoError(t, err)
|
||||
assert.Contains(t, out, fmt.Sprintf(`labels:
|
||||
app: nginx
|
||||
app.kubernetes.io/instance: %s
|
||||
`, Name()))
|
||||
`, ctx.AppName()))
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,11 +74,14 @@ func (a *Actions) CreateFromPartialFile(data string, flags ...string) *Actions {
|
|||
args := append([]string{
|
||||
"app", "create",
|
||||
"-f", tmpFile.Name(),
|
||||
"--name", a.context.name,
|
||||
"--name", a.context.AppName(),
|
||||
"--repo", fixture.RepoURL(a.context.repoURLType),
|
||||
"--dest-server", a.context.destServer,
|
||||
"--dest-namespace", fixture.DeploymentNamespace(),
|
||||
}, flags...)
|
||||
if a.context.appNamespace != "" {
|
||||
args = append(args, "--app-namespace", a.context.appNamespace)
|
||||
}
|
||||
defer tmpFile.Close()
|
||||
a.runCli(args...)
|
||||
return a
|
||||
|
|
@ -87,7 +90,8 @@ func (a *Actions) CreateFromFile(handler func(app *Application), flags ...string
|
|||
a.context.t.Helper()
|
||||
app := &Application{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: a.context.name,
|
||||
Name: a.context.AppName(),
|
||||
Namespace: a.context.AppNamespace(),
|
||||
},
|
||||
Spec: ApplicationSpec{
|
||||
Project: a.context.project,
|
||||
|
|
@ -157,7 +161,7 @@ func (a *Actions) CreateApp(args ...string) *Actions {
|
|||
func (a *Actions) prepareCreateAppArgs(args []string) []string {
|
||||
a.context.t.Helper()
|
||||
args = append([]string{
|
||||
"app", "create", a.context.name,
|
||||
"app", "create", a.context.AppQualifiedName(),
|
||||
"--repo", fixture.RepoURL(a.context.repoURLType),
|
||||
}, args...)
|
||||
|
||||
|
|
@ -218,7 +222,7 @@ func (a *Actions) DeclarativeWithCustomRepo(filename string, repoURL string) *Ac
|
|||
values := map[string]interface{}{
|
||||
"ArgoCDNamespace": fixture.ArgoCDNamespace,
|
||||
"DeploymentNamespace": fixture.DeploymentNamespace(),
|
||||
"Name": a.context.name,
|
||||
"Name": a.context.AppName(),
|
||||
"Path": a.context.path,
|
||||
"Project": a.context.project,
|
||||
"RepoURL": repoURL,
|
||||
|
|
@ -230,13 +234,13 @@ func (a *Actions) DeclarativeWithCustomRepo(filename string, repoURL string) *Ac
|
|||
|
||||
func (a *Actions) PatchApp(patch string) *Actions {
|
||||
a.context.t.Helper()
|
||||
a.runCli("app", "patch", a.context.name, "--patch", patch)
|
||||
a.runCli("app", "patch", a.context.AppQualifiedName(), "--patch", patch)
|
||||
return a
|
||||
}
|
||||
|
||||
func (a *Actions) AppSet(flags ...string) *Actions {
|
||||
a.context.t.Helper()
|
||||
args := []string{"app", "set", a.context.name}
|
||||
args := []string{"app", "set", a.context.AppQualifiedName()}
|
||||
args = append(args, flags...)
|
||||
a.runCli(args...)
|
||||
return a
|
||||
|
|
@ -244,7 +248,7 @@ func (a *Actions) AppSet(flags ...string) *Actions {
|
|||
|
||||
func (a *Actions) AppUnSet(flags ...string) *Actions {
|
||||
a.context.t.Helper()
|
||||
args := []string{"app", "unset", a.context.name}
|
||||
args := []string{"app", "unset", a.context.AppQualifiedName()}
|
||||
args = append(args, flags...)
|
||||
a.runCli(args...)
|
||||
return a
|
||||
|
|
@ -254,7 +258,7 @@ func (a *Actions) Sync(args ...string) *Actions {
|
|||
a.context.t.Helper()
|
||||
args = append([]string{"app", "sync"}, args...)
|
||||
if a.context.name != "" {
|
||||
args = append(args, a.context.name)
|
||||
args = append(args, a.context.AppQualifiedName())
|
||||
}
|
||||
args = append(args, "--timeout", fmt.Sprintf("%v", a.context.timeout))
|
||||
|
||||
|
|
@ -291,7 +295,7 @@ func (a *Actions) Sync(args ...string) *Actions {
|
|||
|
||||
func (a *Actions) TerminateOp() *Actions {
|
||||
a.context.t.Helper()
|
||||
a.runCli("app", "terminate-op", a.context.name)
|
||||
a.runCli("app", "terminate-op", a.context.AppQualifiedName())
|
||||
return a
|
||||
}
|
||||
|
||||
|
|
@ -302,14 +306,14 @@ func (a *Actions) Refresh(refreshType RefreshType) *Actions {
|
|||
RefreshTypeHard: "--hard-refresh",
|
||||
}[refreshType]
|
||||
|
||||
a.runCli("app", "get", a.context.name, flag)
|
||||
a.runCli("app", "get", a.context.AppQualifiedName(), flag)
|
||||
|
||||
return a
|
||||
}
|
||||
|
||||
func (a *Actions) Delete(cascade bool) *Actions {
|
||||
a.context.t.Helper()
|
||||
a.runCli("app", "delete", a.context.name, fmt.Sprintf("--cascade=%v", cascade), "--yes")
|
||||
a.runCli("app", "delete", a.context.AppQualifiedName(), fmt.Sprintf("--cascade=%v", cascade), "--yes")
|
||||
return a
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ func (c *Consequences) app() *Application {
|
|||
}
|
||||
|
||||
func (c *Consequences) get() (*Application, error) {
|
||||
return fixture.AppClientset.ArgoprojV1alpha1().Applications(fixture.ArgoCDNamespace).Get(context.Background(), c.context.name, v1.GetOptions{})
|
||||
return fixture.AppClientset.ArgoprojV1alpha1().Applications(c.context.AppNamespace()).Get(context.Background(), c.context.AppName(), v1.GetOptions{})
|
||||
}
|
||||
|
||||
func (c *Consequences) resource(kind, name, namespace string) ResourceStatus {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import (
|
|||
"github.com/argoproj/argo-cd/v2/test/e2e/fixture/certs"
|
||||
"github.com/argoproj/argo-cd/v2/test/e2e/fixture/gpgkeys"
|
||||
"github.com/argoproj/argo-cd/v2/test/e2e/fixture/repos"
|
||||
"github.com/argoproj/argo-cd/v2/util/argo"
|
||||
"github.com/argoproj/argo-cd/v2/util/env"
|
||||
"github.com/argoproj/argo-cd/v2/util/settings"
|
||||
)
|
||||
|
|
@ -22,6 +23,7 @@ type Context struct {
|
|||
// seconds
|
||||
timeout int
|
||||
name string
|
||||
appNamespace string
|
||||
destServer string
|
||||
destName string
|
||||
env string
|
||||
|
|
@ -40,6 +42,11 @@ type Context struct {
|
|||
replace bool
|
||||
helmPassCredentials bool
|
||||
helmSkipCrds bool
|
||||
trackingMethod v1alpha1.TrackingMethod
|
||||
}
|
||||
|
||||
type ContextArgs struct {
|
||||
AppNamespace string
|
||||
}
|
||||
|
||||
func Given(t *testing.T) *Context {
|
||||
|
|
@ -47,11 +54,52 @@ func Given(t *testing.T) *Context {
|
|||
return GivenWithSameState(t)
|
||||
}
|
||||
|
||||
func GivenWithNamespace(t *testing.T, namespace string) *Context {
|
||||
ctx := Given(t)
|
||||
ctx.appNamespace = namespace
|
||||
return ctx
|
||||
}
|
||||
|
||||
func GivenWithSameState(t *testing.T) *Context {
|
||||
// ARGOCE_E2E_DEFAULT_TIMEOUT can be used to override the default timeout
|
||||
// for any context.
|
||||
timeout := env.ParseNumFromEnv("ARGOCD_E2E_DEFAULT_TIMEOUT", 10, 0, 180)
|
||||
return &Context{t: t, destServer: v1alpha1.KubernetesInternalAPIServerAddr, repoURLType: fixture.RepoURLTypeFile, name: fixture.Name(), timeout: timeout, project: "default", prune: true}
|
||||
return &Context{
|
||||
t: t,
|
||||
destServer: v1alpha1.KubernetesInternalAPIServerAddr,
|
||||
repoURLType: fixture.RepoURLTypeFile,
|
||||
name: fixture.Name(),
|
||||
timeout: timeout,
|
||||
project: "default",
|
||||
prune: true,
|
||||
trackingMethod: argo.TrackingMethodLabel,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Context) AppName() string {
|
||||
return c.name
|
||||
}
|
||||
|
||||
func (c *Context) AppQualifiedName() string {
|
||||
if c.appNamespace != "" {
|
||||
return c.appNamespace + "/" + c.AppName()
|
||||
} else {
|
||||
return c.AppName()
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Context) AppNamespace() string {
|
||||
if c.appNamespace != "" {
|
||||
return c.appNamespace
|
||||
} else {
|
||||
return fixture.TestNamespace()
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Context) SetAppNamespace(namespace string) *Context {
|
||||
c.appNamespace = namespace
|
||||
//fixture.SetParamInSettingConfigMap("application.resourceTrackingMethod", "annotation")
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Context) GPGPublicKeyAdded() *Context {
|
||||
|
|
@ -313,3 +361,7 @@ func (c *Context) SetTrackingMethod(trackingMethod string) *Context {
|
|||
fixture.SetTrackingMethod(trackingMethod)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Context) GetTrackingMethod() v1alpha1.TrackingMethod {
|
||||
return c.trackingMethod
|
||||
}
|
||||
|
|
|
|||
|
|
@ -218,12 +218,12 @@ func pods() (*v1.PodList, error) {
|
|||
return pods, err
|
||||
}
|
||||
|
||||
func Event(reason string, message string) Expectation {
|
||||
func event(namespace string, reason string, message string) Expectation {
|
||||
return func(c *Consequences) (state, string) {
|
||||
list, err := fixture.KubeClientset.CoreV1().Events(fixture.ArgoCDNamespace).List(context.Background(), metav1.ListOptions{
|
||||
list, err := fixture.KubeClientset.CoreV1().Events(namespace).List(context.Background(), metav1.ListOptions{
|
||||
FieldSelector: fields.SelectorFromSet(map[string]string{
|
||||
"involvedObject.name": c.context.name,
|
||||
"involvedObject.namespace": fixture.ArgoCDNamespace,
|
||||
"involvedObject.name": c.context.AppName(),
|
||||
"involvedObject.namespace": namespace,
|
||||
}).String(),
|
||||
})
|
||||
if err != nil {
|
||||
|
|
@ -240,6 +240,14 @@ func Event(reason string, message string) Expectation {
|
|||
}
|
||||
}
|
||||
|
||||
func Event(reason string, message string) Expectation {
|
||||
return event(fixture.ArgoCDNamespace, reason, message)
|
||||
}
|
||||
|
||||
func NamespacedEvent(namespace string, reason string, message string) Expectation {
|
||||
return event(namespace, reason, message)
|
||||
}
|
||||
|
||||
// asserts that the last command was successful
|
||||
func Success(message string) Expectation {
|
||||
return func(c *Consequences) (state, string) {
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ const (
|
|||
DefaultTestUserPassword = "password"
|
||||
testingLabel = "e2e.argoproj.io"
|
||||
ArgoCDNamespace = "argocd-e2e"
|
||||
ArgoCDAppNamespace = "argocd-e2e-external"
|
||||
|
||||
// ensure all repos are in one directory tree, so we can easily clean them up
|
||||
TmpDir = "/tmp/argo-e2e"
|
||||
|
|
@ -112,6 +113,10 @@ func TestNamespace() string {
|
|||
return GetEnvWithDefault("ARGOCD_E2E_NAMESPACE", ArgoCDNamespace)
|
||||
}
|
||||
|
||||
func AppNamespace() string {
|
||||
return GetEnvWithDefault("ARGOCD_E2E_APP_NAMESPACE", ArgoCDAppNamespace)
|
||||
}
|
||||
|
||||
// getKubeConfig creates new kubernetes client config using specified config path and config overrides variables
|
||||
func getKubeConfig(configPath string, overrides clientcmd.ConfigOverrides) *rest.Config {
|
||||
loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
|
||||
|
|
@ -511,6 +516,7 @@ func EnsureCleanState(t *testing.T) {
|
|||
// delete resources
|
||||
// kubectl delete apps --all
|
||||
CheckError(AppClientset.ArgoprojV1alpha1().Applications(TestNamespace()).DeleteCollection(context.Background(), v1.DeleteOptions{PropagationPolicy: &policy}, v1.ListOptions{}))
|
||||
CheckError(AppClientset.ArgoprojV1alpha1().Applications(AppNamespace()).DeleteCollection(context.Background(), v1.DeleteOptions{PropagationPolicy: &policy}, v1.ListOptions{}))
|
||||
// kubectl delete appprojects --field-selector metadata.name!=default
|
||||
CheckError(AppClientset.ArgoprojV1alpha1().AppProjects(TestNamespace()).DeleteCollection(context.Background(),
|
||||
v1.DeleteOptions{PropagationPolicy: &policy}, v1.ListOptions{FieldSelector: "metadata.name!=default"}))
|
||||
|
|
@ -556,6 +562,7 @@ func EnsureCleanState(t *testing.T) {
|
|||
SourceRepos: []string{"*"},
|
||||
Destinations: []v1alpha1.ApplicationDestination{{Namespace: "*", Server: "*"}},
|
||||
ClusterResourceWhitelist: []v1.GroupKind{{Group: "*", Kind: "*"}},
|
||||
SourceNamespaces: []string{AppNamespace()},
|
||||
})
|
||||
|
||||
// Create separate project for testing gpg signature verification
|
||||
|
|
@ -566,6 +573,7 @@ func EnsureCleanState(t *testing.T) {
|
|||
Destinations: []v1alpha1.ApplicationDestination{{Namespace: "*", Server: "*"}},
|
||||
ClusterResourceWhitelist: []v1.GroupKind{{Group: "*", Kind: "*"}},
|
||||
SignatureKeys: []v1alpha1.SignatureKey{{KeyID: GpgGoodKeyID}},
|
||||
SourceNamespaces: []string{AppNamespace()},
|
||||
})
|
||||
|
||||
// Recreate temp dir
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package project
|
|||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
|
@ -74,6 +75,9 @@ func (a *Actions) prepareCreateArgs(args []string) []string {
|
|||
args = append(args, "--dest", a.context.destination)
|
||||
}
|
||||
|
||||
if len(a.context.sourceNamespaces) > 0 {
|
||||
args = append(args, "--source-namespaces", strings.Join(a.context.sourceNamespaces, ","))
|
||||
}
|
||||
return args
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,10 +12,11 @@ import (
|
|||
type Context struct {
|
||||
t *testing.T
|
||||
// seconds
|
||||
timeout int
|
||||
name string
|
||||
destination string
|
||||
repos []string
|
||||
timeout int
|
||||
name string
|
||||
destination string
|
||||
repos []string
|
||||
sourceNamespaces []string
|
||||
}
|
||||
|
||||
func Given(t *testing.T) *Context {
|
||||
|
|
@ -49,6 +50,11 @@ func (c *Context) SourceRepositories(repos []string) *Context {
|
|||
return c
|
||||
}
|
||||
|
||||
func (c *Context) SourceNamespaces(namespaces []string) *Context {
|
||||
c.sourceNamespaces = namespaces
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Context) And(block func()) *Context {
|
||||
block()
|
||||
return c
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
package repos
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/argoproj/argo-cd/v2/test/e2e/fixture"
|
||||
)
|
||||
|
||||
|
|
@ -81,4 +83,7 @@ func (a *Actions) Then() *Consequences {
|
|||
func (a *Actions) runCli(args ...string) {
|
||||
a.context.t.Helper()
|
||||
a.lastOutput, a.lastError = fixture.RunCli(args...)
|
||||
if !a.ignoreErrors && a.lastError != nil {
|
||||
log.Fatal(a.lastOutput)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ func TestCreateRepositoryNonAdminUserPermissionDenied(t *testing.T) {
|
|||
When().
|
||||
Path(path).
|
||||
Project("argo-project").
|
||||
IgnoreErrors().
|
||||
Create().
|
||||
Then().
|
||||
AndCLIOutput(func(output string, err error) {
|
||||
|
|
@ -79,6 +80,7 @@ func TestCreateRepositoryNonAdminUserWithWrongProject(t *testing.T) {
|
|||
When().
|
||||
Path(path).
|
||||
Project("argo-project").
|
||||
IgnoreErrors().
|
||||
Create().
|
||||
Then().
|
||||
AndCLIOutput(func(output string, err error) {
|
||||
|
|
@ -165,6 +167,7 @@ func TestDeleteRepositoryRbacDenied(t *testing.T) {
|
|||
assert.Equal(t, r.Project, "argo-project")
|
||||
}).
|
||||
When().
|
||||
IgnoreErrors().
|
||||
Delete().
|
||||
Then().
|
||||
AndCLIOutput(func(output string, err error) {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ apiVersion: apiextensions.k8s.io/v1
|
|||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
name: clusterdummies.argoproj.io
|
||||
labels:
|
||||
e2e.argoproj.io: "true"
|
||||
spec:
|
||||
conversion:
|
||||
strategy: None
|
||||
|
|
@ -50,4 +52,4 @@ apiVersion: argoproj.io/v1alpha1
|
|||
kind: ClusterDummy
|
||||
metadata:
|
||||
name: cluster-dummy-crd-instance
|
||||
namespace: kube-system
|
||||
namespace: kube-system
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ apiVersion: apiextensions.k8s.io/v1
|
|||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
name: dummies.argoproj.io
|
||||
labels:
|
||||
e2e.argoproj.io: "true"
|
||||
spec:
|
||||
conversion:
|
||||
strategy: None
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ apiVersion: apps/v1
|
|||
kind: Deployment
|
||||
metadata:
|
||||
name: guestbook-ui
|
||||
labels:
|
||||
test: "true"
|
||||
spec:
|
||||
replicas: 0
|
||||
revisionHistoryLimit: 3
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ apiVersion: argoproj.io/v1alpha1
|
|||
kind: Application
|
||||
metadata:
|
||||
name: test-self-managed-apps
|
||||
namespace: argocd-e2e
|
||||
spec:
|
||||
project: default
|
||||
|
||||
|
|
|
|||
|
|
@ -202,6 +202,15 @@ export const ApplicationCreatePanel = (props: {
|
|||
component={Text}
|
||||
/>
|
||||
</div>
|
||||
<div className='argo-form-row'>
|
||||
<FormField
|
||||
formApi={api}
|
||||
label='Application Namespace'
|
||||
qeId='application-create-field-app-namespace'
|
||||
field='metadata.namespace'
|
||||
component={Text}
|
||||
/>
|
||||
</div>
|
||||
<div className='argo-form-row'>
|
||||
<FormField
|
||||
formApi={api}
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@ export const ApplicationDeploymentHistory = ({
|
|||
<React.Fragment>
|
||||
<RevisionMetadataRows
|
||||
applicationName={app.metadata.name}
|
||||
applicationNamespace={app.metadata.namespace}
|
||||
source={{...recentDeployments[index].source, targetRevision: recentDeployments[index].revision}}
|
||||
/>
|
||||
<DataLoader
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import {Timestamp} from '../../../shared/components/timestamp';
|
|||
import {ApplicationSource, RevisionMetadata} from '../../../shared/models';
|
||||
import {services} from '../../../shared/services';
|
||||
|
||||
export const RevisionMetadataRows = (props: {applicationName: string; source: ApplicationSource}) => {
|
||||
export const RevisionMetadataRows = (props: {applicationName: string; applicationNamespace: string; source: ApplicationSource}) => {
|
||||
if (props.source.chart) {
|
||||
return (
|
||||
<div>
|
||||
|
|
@ -20,7 +20,7 @@ export const RevisionMetadataRows = (props: {applicationName: string; source: Ap
|
|||
);
|
||||
}
|
||||
return (
|
||||
<DataLoader input={props} load={input => services.applications.revisionMetadata(input.applicationName, input.source.targetRevision)}>
|
||||
<DataLoader input={props} load={input => services.applications.revisionMetadata(input.applicationName, input.applicationNamespace, input.source.targetRevision)}>
|
||||
{(m: RevisionMetadata) => (
|
||||
<div>
|
||||
<div className='row'>
|
||||
|
|
|
|||
|
|
@ -62,16 +62,22 @@ export const SelectNode = (fullName: string, containerIndex = 0, tab: string = n
|
|||
appContext.navigation.goto('.', {node, tab}, {replace: true});
|
||||
};
|
||||
|
||||
export class ApplicationDetails extends React.Component<RouteComponentProps<{name: string}>, ApplicationDetailsState> {
|
||||
export class ApplicationDetails extends React.Component<RouteComponentProps<{appnamespace: string; name: string}>, ApplicationDetailsState> {
|
||||
public static contextTypes = {
|
||||
apis: PropTypes.object
|
||||
};
|
||||
|
||||
private appChanged = new BehaviorSubject<appModels.Application>(null);
|
||||
private appNamespace: string;
|
||||
|
||||
constructor(props: RouteComponentProps<{name: string}>) {
|
||||
constructor(props: RouteComponentProps<{appnamespace: string; name: string}>) {
|
||||
super(props);
|
||||
this.state = {page: 0, groupedResources: [], slidingPanelPage: 0, filteredGraph: [], truncateNameOnRight: false, collapsedNodes: []};
|
||||
if (typeof this.props.match.params.appnamespace === 'undefined') {
|
||||
this.appNamespace = '';
|
||||
} else {
|
||||
this.appNamespace = this.props.match.params.appnamespace;
|
||||
}
|
||||
}
|
||||
|
||||
private get showOperationState() {
|
||||
|
|
@ -145,7 +151,7 @@ export class ApplicationDetails extends React.Component<RouteComponentProps<{nam
|
|||
loadingRenderer={() => <Page title='Application Details'>Loading...</Page>}
|
||||
input={this.props.match.params.name}
|
||||
load={name =>
|
||||
combineLatest([this.loadAppInfo(name), services.viewPreferences.getPreferences(), q]).pipe(
|
||||
combineLatest([this.loadAppInfo(name, this.appNamespace), services.viewPreferences.getPreferences(), q]).pipe(
|
||||
map(items => {
|
||||
const pref = items[1].appDetails;
|
||||
const params = items[2];
|
||||
|
|
@ -432,7 +438,9 @@ export class ApplicationDetails extends React.Component<RouteComponentProps<{nam
|
|||
const resourceRow: any = {...resource, group: resource.group || ''};
|
||||
const liveState =
|
||||
typeof resource.group !== 'undefined' &&
|
||||
(await services.applications.getResource(application.metadata.name, resource).catch(() => null));
|
||||
(await services.applications
|
||||
.getResource(application.metadata.name, application.metadata.namespace, resource)
|
||||
.catch(() => null));
|
||||
if (liveState?.metadata?.annotations?.[models.AnnotationHookKey]) {
|
||||
resourceRow.syncOrder = liveState?.metadata.annotations[models.AnnotationHookKey];
|
||||
if (liveState?.metadata?.annotations?.[models.AnnotationSyncWaveKey]) {
|
||||
|
|
@ -543,7 +551,10 @@ export class ApplicationDetails extends React.Component<RouteComponentProps<{nam
|
|||
</SlidingPanel>
|
||||
<SlidingPanel isShown={!!this.state.revision} isMiddle={true} onClose={() => this.setState({revision: null})}>
|
||||
{this.state.revision && (
|
||||
<DataLoader load={() => services.applications.revisionMetadata(application.metadata.name, this.state.revision)}>
|
||||
<DataLoader
|
||||
load={() =>
|
||||
services.applications.revisionMetadata(application.metadata.name, application.metadata.namespace, this.state.revision)
|
||||
}>
|
||||
{metadata => (
|
||||
<div className='white-box' style={{marginTop: '1.5em'}}>
|
||||
<div className='white-box__details'>
|
||||
|
|
@ -646,7 +657,7 @@ export class ApplicationDetails extends React.Component<RouteComponentProps<{nam
|
|||
items={[
|
||||
{
|
||||
title: 'Hard Refresh',
|
||||
action: () => !refreshing && services.applications.get(app.metadata.name, 'hard')
|
||||
action: () => !refreshing && services.applications.get(app.metadata.name, app.metadata.namespace, 'hard')
|
||||
}
|
||||
]}
|
||||
anchor={() => <i className='fa fa-caret-down' />}
|
||||
|
|
@ -656,7 +667,7 @@ export class ApplicationDetails extends React.Component<RouteComponentProps<{nam
|
|||
disabled: !!refreshing,
|
||||
action: () => {
|
||||
if (!refreshing) {
|
||||
services.applications.get(app.metadata.name, 'normal');
|
||||
services.applications.get(app.metadata.name, app.metadata.namespace, 'normal');
|
||||
AppUtils.setAppRefreshing(app);
|
||||
this.appChanged.next(app);
|
||||
}
|
||||
|
|
@ -688,8 +699,8 @@ export class ApplicationDetails extends React.Component<RouteComponentProps<{nam
|
|||
return false;
|
||||
}
|
||||
|
||||
private loadAppInfo(name: string): Observable<{application: appModels.Application; tree: appModels.ApplicationTree}> {
|
||||
return from(services.applications.get(name))
|
||||
private loadAppInfo(name: string, appNamespace: string): Observable<{application: appModels.Application; tree: appModels.ApplicationTree}> {
|
||||
return from(services.applications.get(name, appNamespace))
|
||||
.pipe(
|
||||
mergeMap(app => {
|
||||
const fallbackTree = {
|
||||
|
|
@ -703,7 +714,7 @@ export class ApplicationDetails extends React.Component<RouteComponentProps<{nam
|
|||
this.appChanged.pipe(filter(item => !!item)),
|
||||
AppUtils.handlePageVisibility(() =>
|
||||
services.applications
|
||||
.watch({name})
|
||||
.watch({name, appNamespace})
|
||||
.pipe(
|
||||
map(watchEvent => {
|
||||
if (watchEvent.type === 'DELETED') {
|
||||
|
|
@ -718,10 +729,10 @@ export class ApplicationDetails extends React.Component<RouteComponentProps<{nam
|
|||
),
|
||||
merge(
|
||||
from([fallbackTree]),
|
||||
services.applications.resourceTree(name).catch(() => fallbackTree),
|
||||
services.applications.resourceTree(name, appNamespace).catch(() => fallbackTree),
|
||||
AppUtils.handlePageVisibility(() =>
|
||||
services.applications
|
||||
.watchResourceTree(name)
|
||||
.watchResourceTree(name, appNamespace)
|
||||
.pipe(repeat())
|
||||
.pipe(retryWhen(errors => errors.pipe(delay(500))))
|
||||
)
|
||||
|
|
@ -739,7 +750,7 @@ export class ApplicationDetails extends React.Component<RouteComponentProps<{nam
|
|||
}
|
||||
|
||||
private async updateApp(app: appModels.Application, query: {validate?: boolean}) {
|
||||
const latestApp = await services.applications.get(app.metadata.name);
|
||||
const latestApp = await services.applications.get(app.metadata.name, app.metadata.namespace);
|
||||
latestApp.metadata.labels = app.metadata.labels;
|
||||
latestApp.metadata.annotations = app.metadata.annotations;
|
||||
latestApp.spec = app.spec;
|
||||
|
|
@ -815,8 +826,8 @@ Are you sure you want to disable auto-sync and rollback application '${this.prop
|
|||
update.spec.syncPolicy = {automated: null};
|
||||
await services.applications.update(update);
|
||||
}
|
||||
await services.applications.rollback(this.props.match.params.name, revisionHistory.id);
|
||||
this.appChanged.next(await services.applications.get(this.props.match.params.name));
|
||||
await services.applications.rollback(this.props.match.params.name, this.appNamespace, revisionHistory.id);
|
||||
this.appChanged.next(await services.applications.get(this.props.match.params.name, this.appNamespace));
|
||||
this.setRollbackPanelVisible(-1);
|
||||
}
|
||||
} catch (e) {
|
||||
|
|
@ -832,6 +843,6 @@ Are you sure you want to disable auto-sync and rollback application '${this.prop
|
|||
}
|
||||
|
||||
private async deleteApplication() {
|
||||
await AppUtils.deleteApplication(this.props.match.params.name, this.appContext.apis);
|
||||
await AppUtils.deleteApplication(this.props.match.params.name, this.appNamespace, this.appContext.apis);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import {Context} from '../../../shared/context';
|
|||
import {PodsLogsViewer} from '../pod-logs-viewer/pod-logs-viewer';
|
||||
import './application-fullscreen-logs.scss';
|
||||
|
||||
export const ApplicationFullscreenLogs = (props: RouteComponentProps<{name: string; container: string; namespace: string}>) => {
|
||||
export const ApplicationFullscreenLogs = (props: RouteComponentProps<{name: string; appnamespace: string; container: string; namespace: string}>) => {
|
||||
const appContext = React.useContext(Context);
|
||||
return (
|
||||
<Query>
|
||||
|
|
@ -25,6 +25,7 @@ export const ApplicationFullscreenLogs = (props: RouteComponentProps<{name: stri
|
|||
<h4 style={{fontSize: '18px', textAlign: 'center'}}>{title}</h4>
|
||||
<PodsLogsViewer
|
||||
applicationName={props.match.params.name}
|
||||
applicationNamespace={props.match.params.appnamespace}
|
||||
containerName={props.match.params.container}
|
||||
namespace={props.match.params.namespace}
|
||||
group={group}
|
||||
|
|
|
|||
|
|
@ -4,10 +4,14 @@ import * as React from 'react';
|
|||
import {DataLoader, EventsList} from '../../../shared/components';
|
||||
import {services} from '../../../shared/services';
|
||||
|
||||
export const ApplicationResourceEvents = (props: {applicationName: string; resource?: {namespace: string; name: string; uid: string}}) => (
|
||||
export const ApplicationResourceEvents = (props: {applicationName: string; applicationNamespace: string; resource?: {namespace: string; name: string; uid: string}}) => (
|
||||
<div className='application-resource-events'>
|
||||
<DataLoader
|
||||
load={() => (props.resource ? services.applications.resourceEvents(props.applicationName, props.resource) : services.applications.events(props.applicationName))}
|
||||
load={() =>
|
||||
props.resource
|
||||
? services.applications.resourceEvents(props.applicationName, props.applicationNamespace, props.resource)
|
||||
: services.applications.events(props.applicationName, props.applicationNamespace)
|
||||
}
|
||||
loadingRenderer={() => <MockupList height={50} marginTop={10} />}>
|
||||
{events => <EventsList events={events} />}
|
||||
</DataLoader>
|
||||
|
|
|
|||
|
|
@ -574,7 +574,7 @@ function renderPodGroup(props: ApplicationResourceTreeProps, id: string, node: R
|
|||
</React.Fragment>
|
||||
),
|
||||
action: () => {
|
||||
deletePodAction(pod, props.appContext, props.app.metadata.name);
|
||||
deletePodAction(pod, props.appContext, props.app.metadata.name, props.app.metadata.namespace);
|
||||
}
|
||||
}
|
||||
]}
|
||||
|
|
|
|||
|
|
@ -92,7 +92,12 @@ export const ApplicationStatusPanel = ({application, showOperation, showConditio
|
|||
</div>
|
||||
<div className='application-status-panel__item-name'>
|
||||
{application.status && application.status.sync && application.status.sync.revision && (
|
||||
<RevisionMetadataPanel appName={application.metadata.name} type={application.spec.source.chart && 'helm'} revision={application.status.sync.revision} />
|
||||
<RevisionMetadataPanel
|
||||
appName={application.metadata.name}
|
||||
appNamespace={application.metadata.namespace}
|
||||
type={application.spec.source.chart && 'helm'}
|
||||
revision={application.status.sync.revision}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</React.Fragment>
|
||||
|
|
@ -127,6 +132,7 @@ export const ApplicationStatusPanel = ({application, showOperation, showConditio
|
|||
{(appOperationState.syncResult && appOperationState.syncResult.revision && (
|
||||
<RevisionMetadataPanel
|
||||
appName={application.metadata.name}
|
||||
appNamespace={application.metadata.namespace}
|
||||
type={application.spec.source.chart && 'helm'}
|
||||
revision={appOperationState.syncResult.revision}
|
||||
/>
|
||||
|
|
@ -158,9 +164,9 @@ export const ApplicationStatusPanel = ({application, showOperation, showConditio
|
|||
)}
|
||||
<DataLoader
|
||||
noLoaderOnInputChange={true}
|
||||
input={application.metadata.name}
|
||||
load={async name => {
|
||||
return await services.applications.getApplicationSyncWindowState(name);
|
||||
input={application}
|
||||
load={async app => {
|
||||
return await services.applications.getApplicationSyncWindowState(app.metadata.name, app.metadata.namespace);
|
||||
}}>
|
||||
{(data: models.ApplicationSyncWindowState) => (
|
||||
<React.Fragment>
|
||||
|
|
|
|||
|
|
@ -3,12 +3,12 @@ import * as React from 'react';
|
|||
import {Timestamp} from '../../../shared/components/timestamp';
|
||||
import {services} from '../../../shared/services';
|
||||
|
||||
export const RevisionMetadataPanel = (props: {appName: string; type: string; revision: string}) => {
|
||||
export const RevisionMetadataPanel = (props: {appName: string; appNamespace: string; type: string; revision: string}) => {
|
||||
if (props.type === 'helm') {
|
||||
return <React.Fragment />;
|
||||
}
|
||||
return (
|
||||
<DataLoader load={() => services.applications.revisionMetadata(props.appName, props.revision)} errorRenderer={() => <div />}>
|
||||
<DataLoader load={() => services.applications.revisionMetadata(props.appName, props.appNamespace, props.revision)} errorRenderer={() => <div />}>
|
||||
{m => (
|
||||
<Tooltip
|
||||
popperOptions={{
|
||||
|
|
|
|||
|
|
@ -96,6 +96,7 @@ export const ApplicationSyncPanel = ({application, selectedResource, hide}: {app
|
|||
try {
|
||||
await services.applications.sync(
|
||||
application.metadata.name,
|
||||
application.metadata.namespace,
|
||||
params.revision,
|
||||
syncFlags.Prune || false,
|
||||
syncFlags.DryRun || false,
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ export const ApplicationsContainer = (props: RouteComponentProps<any>) => (
|
|||
<Switch>
|
||||
<Route exact={true} path={`${props.match.path}`} component={ApplicationsList} />
|
||||
<Route exact={true} path={`${props.match.path}/:name`} component={ApplicationDetails} />
|
||||
<Route exact={true} path={`${props.match.path}/:appnamespace/:name`} component={ApplicationDetails} />
|
||||
<Route exact={true} path={`${props.match.path}/:name/:namespace/:container/logs`} component={ApplicationFullscreenLogs} />
|
||||
<Route exact={true} path={`${props.match.path}/:appnamespace/:name/:namespace/:container/logs`} component={ApplicationFullscreenLogs} />
|
||||
</Switch>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ const EVENTS_BUFFER_TIMEOUT = 500;
|
|||
const WATCH_RETRY_TIMEOUT = 500;
|
||||
const APP_FIELDS = [
|
||||
'metadata.name',
|
||||
'metadata.namespace',
|
||||
'metadata.annotations',
|
||||
'metadata.labels',
|
||||
'metadata.creationTimestamp',
|
||||
|
|
@ -43,8 +44,8 @@ const APP_FIELDS = [
|
|||
const APP_LIST_FIELDS = ['metadata.resourceVersion', ...APP_FIELDS.map(field => `items.${field}`)];
|
||||
const APP_WATCH_FIELDS = ['result.type', ...APP_FIELDS.map(field => `result.application.${field}`)];
|
||||
|
||||
function loadApplications(projects: string[]): Observable<models.Application[]> {
|
||||
return from(services.applications.list(projects, {fields: APP_LIST_FIELDS})).pipe(
|
||||
function loadApplications(projects: string[], appNamespace: string): Observable<models.Application[]> {
|
||||
return from(services.applications.list(projects, {appNamespace, fields: APP_LIST_FIELDS})).pipe(
|
||||
mergeMap(applicationsList => {
|
||||
const applications = applicationsList.items;
|
||||
return merge(
|
||||
|
|
@ -58,7 +59,7 @@ function loadApplications(projects: string[]): Observable<models.Application[]>
|
|||
.pipe(
|
||||
map(appChanges => {
|
||||
appChanges.forEach(appChange => {
|
||||
const index = applications.findIndex(item => item.metadata.name === appChange.application.metadata.name);
|
||||
const index = applications.findIndex(item => AppUtils.appInstanceName(item) === AppUtils.appInstanceName(appChange.application));
|
||||
switch (appChange.type) {
|
||||
case 'DELETED':
|
||||
if (index > -1) {
|
||||
|
|
@ -160,7 +161,9 @@ function filterApps(applications: models.Application[], pref: AppsListPreference
|
|||
const filterResults = getFilterResults(applications, pref);
|
||||
return {
|
||||
filterResults,
|
||||
filteredApps: filterResults.filter(app => (search === '' || app.metadata.name.includes(search)) && Object.values(app.filterResult).every(val => val))
|
||||
filteredApps: filterResults.filter(
|
||||
app => (search === '' || app.metadata.name.includes(search) || app.metadata.namespace.includes(search)) && Object.values(app.filterResult).every(val => val)
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -250,7 +253,7 @@ const SearchBar = (props: {content: string; ctx: ContextApis; apps: models.Appli
|
|||
}}
|
||||
onChange={e => ctx.navigation.goto('.', {search: e.target.value}, {replace: true})}
|
||||
value={content || ''}
|
||||
items={apps.map(app => app.metadata.name)}
|
||||
items={apps.map(app => app.metadata.namespace + '/' + app.metadata.name)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
@ -361,7 +364,7 @@ export const ApplicationsList = (props: RouteComponentProps<{}>) => {
|
|||
<DataLoader
|
||||
input={pref.projectsFilter?.join(',')}
|
||||
ref={loaderRef}
|
||||
load={() => AppUtils.handlePageVisibility(() => loadApplications(pref.projectsFilter))}
|
||||
load={() => AppUtils.handlePageVisibility(() => loadApplications(pref.projectsFilter, query.get('appNamespace')))}
|
||||
loadingRenderer={() => (
|
||||
<div className='argo-container'>
|
||||
<MockupList height={100} marginTop={30} />
|
||||
|
|
@ -489,16 +492,24 @@ export const ApplicationsList = (props: RouteComponentProps<{}>) => {
|
|||
(pref.view === 'tiles' && (
|
||||
<ApplicationTiles
|
||||
applications={data}
|
||||
syncApplication={appName => ctx.navigation.goto('.', {syncApp: appName}, {replace: true})}
|
||||
syncApplication={(appName, appNamespace) =>
|
||||
ctx.navigation.goto('.', {syncApp: appName, appNamespace}, {replace: true})
|
||||
}
|
||||
refreshApplication={refreshApp}
|
||||
deleteApplication={appName => AppUtils.deleteApplication(appName, ctx)}
|
||||
deleteApplication={(appName, appNamespace) =>
|
||||
AppUtils.deleteApplication(appName, appNamespace, ctx)
|
||||
}
|
||||
/>
|
||||
)) || (
|
||||
<ApplicationsTable
|
||||
applications={data}
|
||||
syncApplication={appName => ctx.navigation.goto('.', {syncApp: appName}, {replace: true})}
|
||||
syncApplication={(appName, appNamespace) =>
|
||||
ctx.navigation.goto('.', {syncApp: appName, appNamespace}, {replace: true})
|
||||
}
|
||||
refreshApplication={refreshApp}
|
||||
deleteApplication={appName => AppUtils.deleteApplication(appName, ctx)}
|
||||
deleteApplication={(appName, appNamespace) =>
|
||||
AppUtils.deleteApplication(appName, appNamespace, ctx)
|
||||
}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
@ -526,7 +537,8 @@ export const ApplicationsList = (props: RouteComponentProps<{}>) => {
|
|||
q.pipe(
|
||||
mergeMap(params => {
|
||||
const syncApp = params.get('syncApp');
|
||||
return (syncApp && from(services.applications.get(syncApp))) || from([null]);
|
||||
const appNamespace = params.get('appNamespace');
|
||||
return (syncApp && from(services.applications.get(syncApp, appNamespace))) || from([null]);
|
||||
})
|
||||
)
|
||||
}>
|
||||
|
|
|
|||
|
|
@ -14,9 +14,9 @@ require('./applications-table.scss');
|
|||
|
||||
export const ApplicationsTable = (props: {
|
||||
applications: models.Application[];
|
||||
syncApplication: (appName: string) => any;
|
||||
refreshApplication: (appName: string) => any;
|
||||
deleteApplication: (appName: string) => any;
|
||||
syncApplication: (appName: string, appNamespace: string) => any;
|
||||
refreshApplication: (appName: string, appNamespace: string) => any;
|
||||
deleteApplication: (appName: string, appNamespace: string) => any;
|
||||
}) => {
|
||||
const [selectedApp, navApp, reset] = useNav(props.applications.length);
|
||||
const ctxh = React.useContext(Context);
|
||||
|
|
@ -53,12 +53,12 @@ export const ApplicationsTable = (props: {
|
|||
<div className='applications-table argo-table-list argo-table-list--clickable'>
|
||||
{props.applications.map((app, i) => (
|
||||
<div
|
||||
key={app.metadata.name}
|
||||
key={AppUtils.appInstanceName(app)}
|
||||
className={`argo-table-list__row
|
||||
applications-list__entry applications-list__entry--health-${app.status.health.status} ${selectedApp === i ? 'applications-tiles__selected' : ''}`}>
|
||||
<div
|
||||
className={`row applications-list__table-row`}
|
||||
onClick={e => ctx.navigation.goto(`/applications/${app.metadata.name}`, {}, {event: e})}>
|
||||
onClick={e => ctx.navigation.goto(`/applications/${app.metadata.namespace}/${app.metadata.name}`, {}, {event: e})}>
|
||||
<div className='columns small-4'>
|
||||
<div className='row'>
|
||||
<div className=' columns small-2'>
|
||||
|
|
@ -125,9 +125,9 @@ export const ApplicationsTable = (props: {
|
|||
</button>
|
||||
)}
|
||||
items={[
|
||||
{title: 'Sync', action: () => props.syncApplication(app.metadata.name)},
|
||||
{title: 'Refresh', action: () => props.refreshApplication(app.metadata.name)},
|
||||
{title: 'Delete', action: () => props.deleteApplication(app.metadata.name)}
|
||||
{title: 'Sync', action: () => props.syncApplication(app.metadata.name, app.metadata.namespace)},
|
||||
{title: 'Refresh', action: () => props.refreshApplication(app.metadata.name, app.metadata.namespace)},
|
||||
{title: 'Delete', action: () => props.deleteApplication(app.metadata.name, app.metadata.namespace)}
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -14,9 +14,9 @@ require('./applications-tiles.scss');
|
|||
|
||||
export interface ApplicationTilesProps {
|
||||
applications: models.Application[];
|
||||
syncApplication: (appName: string) => any;
|
||||
refreshApplication: (appName: string) => any;
|
||||
deleteApplication: (appName: string) => any;
|
||||
syncApplication: (appName: string, appNamespace: string) => any;
|
||||
refreshApplication: (appName: string, appNamespace: string) => any;
|
||||
deleteApplication: (appName: string, appNamespace: string) => any;
|
||||
}
|
||||
|
||||
const useItemsPerContainer = (itemRef: any, containerRef: any): number => {
|
||||
|
|
@ -109,14 +109,18 @@ export const ApplicationTiles = ({applications, syncApplication, refreshApplicat
|
|||
className='applications-tiles argo-table-list argo-table-list--clickable row small-up-1 medium-up-2 large-up-3 xxxlarge-up-4'
|
||||
ref={appContainerRef}>
|
||||
{applications.map((app, i) => (
|
||||
<div key={app.metadata.name} className='column column-block'>
|
||||
<div key={AppUtils.appInstanceName(app)} className='column column-block'>
|
||||
<div
|
||||
ref={appRef.set ? null : appRef.ref}
|
||||
className={`argo-table-list__row applications-list__entry applications-list__entry--health-${app.status.health.status} ${
|
||||
selectedApp === i ? 'applications-tiles__selected' : ''
|
||||
}`}>
|
||||
<div className='row' onClick={e => ctx.navigation.goto(`/applications/${app.metadata.name}`, {view: pref.appDetails.view}, {event: e})}>
|
||||
<div className={`columns small-12 applications-list__info qe-applications-list-${app.metadata.name}`}>
|
||||
<div
|
||||
className='row'
|
||||
onClick={e =>
|
||||
ctx.navigation.goto(`/applications/${app.metadata.namespace}/${app.metadata.name}`, {view: pref.appDetails.view}, {event: e})
|
||||
}>
|
||||
<div className={`columns small-12 applications-list__info qe-applications-list-${AppUtils.appInstanceName(app)}`}>
|
||||
<div className='row'>
|
||||
<div
|
||||
className={
|
||||
|
|
@ -125,12 +129,12 @@ export const ApplicationTiles = ({applications, syncApplication, refreshApplicat
|
|||
: 'columns small-11'
|
||||
}>
|
||||
<i className={'icon argo-icon-' + (app.spec.source.chart != null ? 'helm' : 'git')} />
|
||||
{app.metadata.name.length > 30 ? (
|
||||
<Tooltip content={app.metadata.name}>
|
||||
<span className='applications-list__title'>{app.metadata.name}</span>
|
||||
{AppUtils.appQualifiedName(app).length > 30 ? (
|
||||
<Tooltip content={AppUtils.appInstanceName(app)}>
|
||||
<span className='applications-list__title'>{AppUtils.appQualifiedName(app)}</span>
|
||||
</Tooltip>
|
||||
) : (
|
||||
<span className='applications-list__title'>{app.metadata.name}</span>
|
||||
<span className='applications-list__title'>{AppUtils.appQualifiedName(app)}</span>
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
|
|
@ -261,7 +265,7 @@ export const ApplicationTiles = ({applications, syncApplication, refreshApplicat
|
|||
qe-id='applications-tiles-button-sync'
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
syncApplication(app.metadata.name);
|
||||
syncApplication(app.metadata.name, app.metadata.namespace);
|
||||
}}>
|
||||
<i className='fa fa-sync' /> Sync
|
||||
</a>
|
||||
|
|
@ -272,7 +276,7 @@ export const ApplicationTiles = ({applications, syncApplication, refreshApplicat
|
|||
{...AppUtils.refreshLinkAttrs(app)}
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
refreshApplication(app.metadata.name);
|
||||
refreshApplication(app.metadata.name, app.metadata.namespace);
|
||||
}}>
|
||||
<i className={classNames('fa fa-redo', {'status-icon--spin': AppUtils.isAppRefreshing(app)})} />{' '}
|
||||
<span className='show-for-xxlarge'>Refresh</span>
|
||||
|
|
@ -283,7 +287,7 @@ export const ApplicationTiles = ({applications, syncApplication, refreshApplicat
|
|||
qe-id='applications-tiles-button-delete'
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
deleteApplication(app.metadata.name);
|
||||
deleteApplication(app.metadata.name, app.metadata.namespace);
|
||||
}}>
|
||||
<i className='fa fa-times-circle' /> <span className='show-for-xxlarge'>Delete</span>
|
||||
</a>
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import './pod-logs-viewer.scss';
|
|||
const maxLines = 100;
|
||||
export interface PodLogsProps {
|
||||
namespace: string;
|
||||
applicationNamespace: string;
|
||||
applicationName: string;
|
||||
podName?: string;
|
||||
containerName: string;
|
||||
|
|
@ -112,7 +113,7 @@ export const PodsLogsViewer = (props: PodLogsProps & {fullscreen?: boolean}) =>
|
|||
};
|
||||
|
||||
const fullscreenURL =
|
||||
`/applications/${props.applicationName}/${props.namespace}/${props.containerName}/logs?` +
|
||||
`/applications/${props.applicationNamespace}/${props.applicationName}/${props.namespace}/${props.containerName}/logs?` +
|
||||
`podName=${props.podName}&group=${props.group}&kind=${props.kind}&name=${props.name}`;
|
||||
return (
|
||||
<DataLoader load={() => services.viewPreferences.getPreferences()}>
|
||||
|
|
@ -165,6 +166,7 @@ export const PodsLogsViewer = (props: PodLogsProps & {fullscreen?: boolean}) =>
|
|||
onClick={async () => {
|
||||
const downloadURL = services.applications.getDownloadLogsURL(
|
||||
props.applicationName,
|
||||
props.applicationNamespace,
|
||||
props.namespace,
|
||||
props.podName,
|
||||
{group: props.group, kind: props.kind, name: props.name},
|
||||
|
|
@ -294,6 +296,7 @@ export const PodsLogsViewer = (props: PodLogsProps & {fullscreen?: boolean}) =>
|
|||
let logsSource = services.applications
|
||||
.getContainerLogs(
|
||||
props.applicationName,
|
||||
props.applicationNamespace,
|
||||
props.namespace,
|
||||
props.podName,
|
||||
{group: props.group, kind: props.kind, name: props.name},
|
||||
|
|
|
|||
|
|
@ -108,6 +108,7 @@ export const ResourceDetails = (props: ResourceDetailsProps) => {
|
|||
name={node.name}
|
||||
namespace={podState.metadata.namespace}
|
||||
applicationName={application.metadata.name}
|
||||
applicationNamespace={application.metadata.namespace}
|
||||
containerName={AppUtils.getContainerName(podState, activeContainer)}
|
||||
page={{number: page, untilTimes}}
|
||||
setPage={pageData => appContext.navigation.goto('.', {page: pageData.number, untilTimes: pageData.untilTimes.join(',')})}
|
||||
|
|
@ -195,7 +196,7 @@ export const ResourceDetails = (props: ResourceDetailsProps) => {
|
|||
input={application.spec}
|
||||
onSave={async patch => {
|
||||
const spec = JSON.parse(JSON.stringify(application.spec));
|
||||
return services.applications.updateSpec(application.metadata.name, jsonMergePatch.apply(spec, JSON.parse(patch)));
|
||||
return services.applications.updateSpec(application.metadata.name, application.metadata.namespace, jsonMergePatch.apply(spec, JSON.parse(patch)));
|
||||
}}
|
||||
/>
|
||||
)
|
||||
|
|
@ -211,7 +212,7 @@ export const ResourceDetails = (props: ResourceDetailsProps) => {
|
|||
<DataLoader
|
||||
key='diff'
|
||||
load={async () =>
|
||||
await services.applications.managedResources(application.metadata.name, {
|
||||
await services.applications.managedResources(application.metadata.name, application.metadata.namespace, {
|
||||
fields: ['items.normalizedLiveState', 'items.predictedLiveState', 'items.group', 'items.kind', 'items.namespace', 'items.name']
|
||||
})
|
||||
}>
|
||||
|
|
@ -224,7 +225,7 @@ export const ResourceDetails = (props: ResourceDetailsProps) => {
|
|||
tabs.push({
|
||||
title: 'EVENTS',
|
||||
key: 'event',
|
||||
content: <ApplicationResourceEvents applicationName={application.metadata.name} />
|
||||
content: <ApplicationResourceEvents applicationName={application.metadata.name} applicationNamespace={application.metadata.namespace} />
|
||||
});
|
||||
|
||||
const extensionTabs = services.extensions.getResourceTabs('argoproj.io', 'Application').map((ext, i) => ({
|
||||
|
|
@ -246,7 +247,7 @@ export const ResourceDetails = (props: ResourceDetailsProps) => {
|
|||
noLoaderOnInputChange={true}
|
||||
input={selectedNode.resourceVersion}
|
||||
load={async () => {
|
||||
const managedResources = await services.applications.managedResources(application.metadata.name, {
|
||||
const managedResources = await services.applications.managedResources(application.metadata.name, application.metadata.namespace, {
|
||||
id: {
|
||||
name: selectedNode.name,
|
||||
namespace: selectedNode.namespace,
|
||||
|
|
@ -261,10 +262,10 @@ export const ResourceDetails = (props: ResourceDetailsProps) => {
|
|||
if (controlled && controlled.targetState) {
|
||||
resQuery.version = AppUtils.parseApiVersion(controlled.targetState.apiVersion).version;
|
||||
}
|
||||
const liveState = await services.applications.getResource(application.metadata.name, resQuery).catch(() => null);
|
||||
const liveState = await services.applications.getResource(application.metadata.name, application.metadata.namespace, resQuery).catch(() => null);
|
||||
const events =
|
||||
(liveState &&
|
||||
(await services.applications.resourceEvents(application.metadata.name, {
|
||||
(await services.applications.resourceEvents(application.metadata.name, application.metadata.namespace, {
|
||||
name: liveState.metadata.name,
|
||||
namespace: liveState.metadata.namespace,
|
||||
uid: liveState.metadata.uid
|
||||
|
|
@ -276,7 +277,7 @@ export const ResourceDetails = (props: ResourceDetailsProps) => {
|
|||
} else {
|
||||
const childPod = AppUtils.findChildPod(selectedNode, tree);
|
||||
if (childPod) {
|
||||
podState = await services.applications.getResource(application.metadata.name, childPod).catch(() => null);
|
||||
podState = await services.applications.getResource(application.metadata.name, application.metadata.namespace, childPod).catch(() => null);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ export function helpTip(text: string) {
|
|||
</Tooltip>
|
||||
);
|
||||
}
|
||||
export async function deleteApplication(appName: string, apis: ContextApis): Promise<boolean> {
|
||||
export async function deleteApplication(appName: string, appNamespace: string, apis: ContextApis): Promise<boolean> {
|
||||
let confirmed = false;
|
||||
const propagationPolicies: {name: string; message: string}[] = [
|
||||
{
|
||||
|
|
@ -100,7 +100,7 @@ export async function deleteApplication(appName: string, apis: ContextApis): Pro
|
|||
}),
|
||||
submit: async (vals, _, close) => {
|
||||
try {
|
||||
await services.applications.delete(appName, vals.propagationPolicy);
|
||||
await services.applications.delete(appName, appNamespace, vals.propagationPolicy);
|
||||
confirmed = true;
|
||||
close();
|
||||
} catch (e) {
|
||||
|
|
@ -288,7 +288,7 @@ export function findChildPod(node: appModels.ResourceNode, tree: appModels.Appli
|
|||
});
|
||||
}
|
||||
|
||||
export const deletePodAction = async (pod: appModels.Pod, appContext: AppContext, appName: string) => {
|
||||
export const deletePodAction = async (pod: appModels.Pod, appContext: AppContext, appName: string, appNamespace: string) => {
|
||||
appContext.apis.popup.prompt(
|
||||
'Delete pod',
|
||||
() => (
|
||||
|
|
@ -304,7 +304,7 @@ export const deletePodAction = async (pod: appModels.Pod, appContext: AppContext
|
|||
{
|
||||
submit: async (vals, _, close) => {
|
||||
try {
|
||||
await services.applications.deleteResource(appName, pod, !!vals.force, false);
|
||||
await services.applications.deleteResource(appName, appNamespace, pod, !!vals.force, false);
|
||||
close();
|
||||
} catch (e) {
|
||||
appContext.apis.notifications.show({
|
||||
|
|
@ -370,9 +370,9 @@ export const deletePopup = async (ctx: ContextApis, resource: ResourceTreeNode,
|
|||
const force = deleteOptions.option === 'force';
|
||||
const orphan = deleteOptions.option === 'orphan';
|
||||
try {
|
||||
await services.applications.deleteResource(application.metadata.name, resource, !!force, !!orphan);
|
||||
await services.applications.deleteResource(application.metadata.name, application.metadata.namespace, resource, !!force, !!orphan);
|
||||
if (appChanged) {
|
||||
appChanged.next(await services.applications.get(application.metadata.name));
|
||||
appChanged.next(await services.applications.get(application.metadata.name, application.metadata.namespace));
|
||||
}
|
||||
close();
|
||||
} catch (e) {
|
||||
|
|
@ -453,7 +453,7 @@ function getActionItems(
|
|||
.catch(() => items);
|
||||
|
||||
const resourceActions = services.applications
|
||||
.getResourceActions(application.metadata.name, resource)
|
||||
.getResourceActions(application.metadata.name, application.metadata.namespace, resource)
|
||||
.then(actions => {
|
||||
return items.concat(
|
||||
actions.map(action => ({
|
||||
|
|
@ -463,7 +463,7 @@ function getActionItems(
|
|||
try {
|
||||
const confirmed = await appContext.apis.popup.confirm(`Execute '${action.name}' action?`, `Are you sure you want to execute '${action.name}' action?`);
|
||||
if (confirmed) {
|
||||
await services.applications.runResourceAction(application.metadata.name, resource, action.name);
|
||||
await services.applications.runResourceAction(application.metadata.name, application.metadata.namespace, resource, action.name);
|
||||
}
|
||||
} catch (e) {
|
||||
appContext.apis.notifications.show({
|
||||
|
|
@ -1102,3 +1102,11 @@ export const urlPattern = new RegExp(
|
|||
'gi'
|
||||
)
|
||||
);
|
||||
|
||||
export function appQualifiedName(app: appModels.Application): string {
|
||||
return app.metadata.namespace + '/' + app.metadata.name;
|
||||
}
|
||||
|
||||
export function appInstanceName(app: appModels.Application): string {
|
||||
return app.metadata.namespace + '_' + app.metadata.name;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import * as React from 'react';
|
|||
import {FormFunctionProps} from 'react-form';
|
||||
import {CheckboxField} from '..';
|
||||
import * as models from '../../models';
|
||||
import {ComparisonStatusIcon, HealthStatusIcon, OperationPhaseIcon} from '../../../applications/components/utils';
|
||||
import {appInstanceName, appQualifiedName, ComparisonStatusIcon, HealthStatusIcon, OperationPhaseIcon} from '../../../applications/components/utils';
|
||||
|
||||
export const ApplicationSelector = ({apps, formApi}: {apps: models.Application[]; formApi: FormFunctionProps}) => {
|
||||
return (
|
||||
|
|
@ -15,10 +15,10 @@ export const ApplicationSelector = ({apps, formApi}: {apps: models.Application[]
|
|||
</label>
|
||||
<div style={{marginTop: '0.4em'}}>
|
||||
{apps.map((app, i) => (
|
||||
<label key={app.metadata.name} style={{marginTop: '0.5em', cursor: 'pointer'}}>
|
||||
<label key={appInstanceName(app)} style={{marginTop: '0.5em', cursor: 'pointer'}}>
|
||||
<CheckboxField field={`app/${i}`} />
|
||||
|
||||
{app.isAppOfAppsPattern ? `(App of Apps) ${app.metadata.name}` : app.metadata.name}
|
||||
{app.isAppOfAppsPattern ? `(App of Apps) ${appQualifiedName(app)}` : appQualifiedName(app)}
|
||||
|
||||
<ComparisonStatusIcon status={app.status.sync.status} />
|
||||
|
||||
|
|
|
|||
|
|
@ -9,11 +9,12 @@ interface QueryOptions {
|
|||
fields: string[];
|
||||
exclude?: boolean;
|
||||
selector?: string;
|
||||
appNamespace?: string;
|
||||
}
|
||||
|
||||
function optionsToSearch(options?: QueryOptions) {
|
||||
if (options) {
|
||||
return {fields: (options.exclude ? '-' : '') + options.fields.join(','), selector: options.selector || ''};
|
||||
return {fields: (options.exclude ? '-' : '') + options.fields.join(','), selector: options.selector || '', appNamespace: options.appNamespace || ''};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
|
@ -30,39 +31,51 @@ export class ApplicationsService {
|
|||
});
|
||||
}
|
||||
|
||||
public get(name: string, refresh?: 'normal' | 'hard'): Promise<models.Application> {
|
||||
public get(name: string, appNamespace: string, refresh?: 'normal' | 'hard'): Promise<models.Application> {
|
||||
const query: {[key: string]: string} = {};
|
||||
if (refresh) {
|
||||
query.refresh = refresh;
|
||||
}
|
||||
if (appNamespace) {
|
||||
query.appNamespace = appNamespace;
|
||||
}
|
||||
return requests
|
||||
.get(`/applications/${name}`)
|
||||
.query(query)
|
||||
.then(res => this.parseAppFields(res.body));
|
||||
}
|
||||
|
||||
public getApplicationSyncWindowState(name: string): Promise<models.ApplicationSyncWindowState> {
|
||||
public getApplicationSyncWindowState(name: string, appNamespace: string): Promise<models.ApplicationSyncWindowState> {
|
||||
return requests
|
||||
.get(`/applications/${name}/syncwindows`)
|
||||
.query({name})
|
||||
.query({name, appNamespace})
|
||||
.then(res => res.body as models.ApplicationSyncWindowState);
|
||||
}
|
||||
|
||||
public revisionMetadata(name: string, revision: string): Promise<models.RevisionMetadata> {
|
||||
return requests.get(`/applications/${name}/revisions/${revision || 'HEAD'}/metadata`).then(res => res.body as models.RevisionMetadata);
|
||||
public revisionMetadata(name: string, appNamespace: string, revision: string): Promise<models.RevisionMetadata> {
|
||||
return requests
|
||||
.get(`/applications/${name}/revisions/${revision || 'HEAD'}/metadata`)
|
||||
.query({appNamespace})
|
||||
.then(res => res.body as models.RevisionMetadata);
|
||||
}
|
||||
|
||||
public resourceTree(name: string): Promise<models.ApplicationTree> {
|
||||
return requests.get(`/applications/${name}/resource-tree`).then(res => res.body as models.ApplicationTree);
|
||||
public resourceTree(name: string, appNamespace: string): Promise<models.ApplicationTree> {
|
||||
return requests
|
||||
.get(`/applications/${name}/resource-tree`)
|
||||
.query({appNamespace})
|
||||
.then(res => res.body as models.ApplicationTree);
|
||||
}
|
||||
|
||||
public watchResourceTree(name: string): Observable<models.ApplicationTree> {
|
||||
return requests.loadEventSource(`/stream/applications/${name}/resource-tree`).pipe(map(data => JSON.parse(data).result as models.ApplicationTree));
|
||||
public watchResourceTree(name: string, appNamespace: string): Observable<models.ApplicationTree> {
|
||||
return requests
|
||||
.loadEventSource(`/stream/applications/${name}/resource-tree?appNamespace=${appNamespace}`)
|
||||
.pipe(map(data => JSON.parse(data).result as models.ApplicationTree));
|
||||
}
|
||||
|
||||
public managedResources(name: string, options: {id?: models.ResourceID; fields?: string[]} = {}): Promise<models.ResourceDiff[]> {
|
||||
public managedResources(name: string, appNamespace: string, options: {id?: models.ResourceID; fields?: string[]} = {}): Promise<models.ResourceDiff[]> {
|
||||
return requests
|
||||
.get(`/applications/${name}/managed-resources`)
|
||||
.query(`appNamespace=${appNamespace.toString()}`)
|
||||
.query({...options.id, fields: (options.fields || []).join(',')})
|
||||
.then(res => (res.body.items as any[]) || [])
|
||||
.then(items => {
|
||||
|
|
@ -84,14 +97,14 @@ export class ApplicationsService {
|
|||
});
|
||||
}
|
||||
|
||||
public getManifest(name: string, revision: string): Promise<models.ManifestResponse> {
|
||||
public getManifest(name: string, appNamespace: string, revision: string): Promise<models.ManifestResponse> {
|
||||
return requests
|
||||
.get(`/applications/${name}/manifests`)
|
||||
.query({name, revision})
|
||||
.then(res => res.body as models.ManifestResponse);
|
||||
}
|
||||
|
||||
public updateSpec(appName: string, spec: models.ApplicationSpec): Promise<models.ApplicationSpec> {
|
||||
public updateSpec(appName: string, appNamespace: string, spec: models.ApplicationSpec): Promise<models.ApplicationSpec> {
|
||||
return requests
|
||||
.put(`/applications/${appName}/spec`)
|
||||
.send(spec)
|
||||
|
|
@ -113,7 +126,7 @@ export class ApplicationsService {
|
|||
.then(res => this.parseAppFields(res.body));
|
||||
}
|
||||
|
||||
public delete(name: string, propagationPolicy: string): Promise<boolean> {
|
||||
public delete(name: string, appNamespace: string, propagationPolicy: string): Promise<boolean> {
|
||||
let cascade = true;
|
||||
if (propagationPolicy === 'non-cascading') {
|
||||
propagationPolicy = '';
|
||||
|
|
@ -123,13 +136,14 @@ export class ApplicationsService {
|
|||
.delete(`/applications/${name}`)
|
||||
.query({
|
||||
cascade,
|
||||
propagationPolicy
|
||||
propagationPolicy,
|
||||
appNamespace
|
||||
})
|
||||
.send({})
|
||||
.then(() => true);
|
||||
}
|
||||
|
||||
public watch(query?: {name?: string; resourceVersion?: string; projects?: string[]}, options?: QueryOptions): Observable<models.ApplicationWatchEvent> {
|
||||
public watch(query?: {name?: string; resourceVersion?: string; projects?: string[]; appNamespace?: string}, options?: QueryOptions): Observable<models.ApplicationWatchEvent> {
|
||||
const search = new URLSearchParams();
|
||||
if (query) {
|
||||
if (query.name) {
|
||||
|
|
@ -138,11 +152,15 @@ export class ApplicationsService {
|
|||
if (query.resourceVersion) {
|
||||
search.set('resourceVersion', query.resourceVersion);
|
||||
}
|
||||
if (query.appNamespace) {
|
||||
search.set('appNamespace', query.appNamespace);
|
||||
}
|
||||
}
|
||||
if (options) {
|
||||
const searchOptions = optionsToSearch(options);
|
||||
search.set('fields', searchOptions.fields);
|
||||
search.set('selector', searchOptions.selector);
|
||||
search.set('appNamespace', searchOptions.appNamespace);
|
||||
query?.projects?.forEach(project => search.append('projects', project));
|
||||
}
|
||||
const searchStr = search.toString();
|
||||
|
|
@ -162,6 +180,7 @@ export class ApplicationsService {
|
|||
|
||||
public sync(
|
||||
name: string,
|
||||
appNamespace: string,
|
||||
revision: string,
|
||||
prune: boolean,
|
||||
dryRun: boolean,
|
||||
|
|
@ -172,25 +191,42 @@ export class ApplicationsService {
|
|||
): Promise<boolean> {
|
||||
return requests
|
||||
.post(`/applications/${name}/sync`)
|
||||
.send({revision, prune: !!prune, dryRun: !!dryRun, strategy, resources, syncOptions: syncOptions ? {items: syncOptions} : null, retryStrategy})
|
||||
.send({
|
||||
appNamespace,
|
||||
revision,
|
||||
prune: !!prune,
|
||||
dryRun: !!dryRun,
|
||||
strategy,
|
||||
resources,
|
||||
syncOptions: syncOptions ? {items: syncOptions} : null,
|
||||
retryStrategy
|
||||
})
|
||||
.then(() => true);
|
||||
}
|
||||
|
||||
public rollback(name: string, id: number): Promise<boolean> {
|
||||
public rollback(name: string, appNamespace: string, id: number): Promise<boolean> {
|
||||
return requests
|
||||
.post(`/applications/${name}/rollback`)
|
||||
.send({id})
|
||||
.send({id, appNamespace})
|
||||
.then(() => true);
|
||||
}
|
||||
|
||||
public getDownloadLogsURL(applicationName: string, namespace: string, podName: string, resource: {group: string; kind: string; name: string}, containerName: string): string {
|
||||
const search = this.getLogsQuery(namespace, podName, resource, containerName, null, false);
|
||||
public getDownloadLogsURL(
|
||||
applicationName: string,
|
||||
appNamespace: string,
|
||||
namespace: string,
|
||||
podName: string,
|
||||
resource: {group: string; kind: string; name: string},
|
||||
containerName: string
|
||||
): string {
|
||||
const search = this.getLogsQuery(namespace, appNamespace, podName, resource, containerName, null, false);
|
||||
search.set('download', 'true');
|
||||
return `api/v1/applications/${applicationName}/logs?${search.toString()}`;
|
||||
}
|
||||
|
||||
public getContainerLogs(
|
||||
applicationName: string,
|
||||
appNamespace: string,
|
||||
namespace: string,
|
||||
podName: string,
|
||||
resource: {group: string; kind: string; name: string},
|
||||
|
|
@ -201,7 +237,7 @@ export class ApplicationsService {
|
|||
filter?: string,
|
||||
previous?: boolean
|
||||
): Observable<models.LogEntry> {
|
||||
const search = this.getLogsQuery(namespace, podName, resource, containerName, tail, follow, untilTime, filter, previous);
|
||||
const search = this.getLogsQuery(namespace, appNamespace, podName, resource, containerName, tail, follow, untilTime, filter, previous);
|
||||
const entries = requests.loadEventSource(`/applications/${applicationName}/logs?${search.toString()}`).pipe(map(data => JSON.parse(data).result as models.LogEntry));
|
||||
let first = true;
|
||||
return new Observable(observer => {
|
||||
|
|
@ -229,11 +265,12 @@ export class ApplicationsService {
|
|||
});
|
||||
}
|
||||
|
||||
public getResource(name: string, resource: models.ResourceNode): Promise<models.State> {
|
||||
public getResource(name: string, appNamespace: string, resource: models.ResourceNode): Promise<models.State> {
|
||||
return requests
|
||||
.get(`/applications/${name}/resource`)
|
||||
.query({
|
||||
name: resource.name,
|
||||
appNamespace,
|
||||
namespace: resource.namespace,
|
||||
resourceName: resource.name,
|
||||
version: resource.version,
|
||||
|
|
@ -244,7 +281,7 @@ export class ApplicationsService {
|
|||
.then(res => JSON.parse(res.manifest) as models.State);
|
||||
}
|
||||
|
||||
public getResourceActions(name: string, resource: models.ResourceNode): Promise<models.ResourceAction[]> {
|
||||
public getResourceActions(name: string, appNamspace: string, resource: models.ResourceNode): Promise<models.ResourceAction[]> {
|
||||
return requests
|
||||
.get(`/applications/${name}/resource/actions`)
|
||||
.query({
|
||||
|
|
@ -257,7 +294,7 @@ export class ApplicationsService {
|
|||
.then(res => (res.body.actions as models.ResourceAction[]) || []);
|
||||
}
|
||||
|
||||
public runResourceAction(name: string, resource: models.ResourceNode, action: string): Promise<models.ResourceAction[]> {
|
||||
public runResourceAction(name: string, appNamspace: string, resource: models.ResourceNode, action: string): Promise<models.ResourceAction[]> {
|
||||
return requests
|
||||
.post(`/applications/${name}/resource/actions`)
|
||||
.query({
|
||||
|
|
@ -271,7 +308,7 @@ export class ApplicationsService {
|
|||
.then(res => (res.body.actions as models.ResourceAction[]) || []);
|
||||
}
|
||||
|
||||
public patchResource(name: string, resource: models.ResourceNode, patch: string, patchType: string): Promise<models.State> {
|
||||
public patchResource(name: string, appNamspace: string, resource: models.ResourceNode, patch: string, patchType: string): Promise<models.State> {
|
||||
return requests
|
||||
.post(`/applications/${name}/resource`)
|
||||
.query({
|
||||
|
|
@ -288,11 +325,12 @@ export class ApplicationsService {
|
|||
.then(res => JSON.parse(res.manifest) as models.State);
|
||||
}
|
||||
|
||||
public deleteResource(applicationName: string, resource: models.ResourceNode, force: boolean, orphan: boolean): Promise<any> {
|
||||
public deleteResource(applicationName: string, appNamespace: string, resource: models.ResourceNode, force: boolean, orphan: boolean): Promise<any> {
|
||||
return requests
|
||||
.delete(`/applications/${applicationName}/resource`)
|
||||
.query({
|
||||
name: resource.name,
|
||||
appNamespace,
|
||||
namespace: resource.namespace,
|
||||
resourceName: resource.name,
|
||||
version: resource.version,
|
||||
|
|
@ -305,15 +343,17 @@ export class ApplicationsService {
|
|||
.then(() => true);
|
||||
}
|
||||
|
||||
public events(applicationName: string): Promise<models.Event[]> {
|
||||
public events(applicationName: string, appNamespace: string): Promise<models.Event[]> {
|
||||
return requests
|
||||
.get(`/applications/${applicationName}/events`)
|
||||
.query({appNamespace})
|
||||
.send()
|
||||
.then(res => (res.body as models.EventList).items || []);
|
||||
}
|
||||
|
||||
public resourceEvents(
|
||||
applicationName: string,
|
||||
appNamespace: string,
|
||||
resource: {
|
||||
namespace: string;
|
||||
name: string;
|
||||
|
|
@ -323,6 +363,7 @@ export class ApplicationsService {
|
|||
return requests
|
||||
.get(`/applications/${applicationName}/events`)
|
||||
.query({
|
||||
appNamespace,
|
||||
resourceUID: resource.uid,
|
||||
resourceNamespace: resource.namespace,
|
||||
resourceName: resource.name
|
||||
|
|
@ -331,7 +372,7 @@ export class ApplicationsService {
|
|||
.then(res => (res.body as models.EventList).items || []);
|
||||
}
|
||||
|
||||
public terminateOperation(applicationName: string): Promise<boolean> {
|
||||
public terminateOperation(applicationName: string, appNamespace: string): Promise<boolean> {
|
||||
return requests
|
||||
.delete(`/applications/${applicationName}/operation`)
|
||||
.send()
|
||||
|
|
@ -340,6 +381,7 @@ export class ApplicationsService {
|
|||
|
||||
private getLogsQuery(
|
||||
namespace: string,
|
||||
appNamespace: string,
|
||||
podName: string,
|
||||
resource: {group: string; kind: string; name: string},
|
||||
containerName: string,
|
||||
|
|
@ -353,6 +395,7 @@ export class ApplicationsService {
|
|||
follow = true;
|
||||
}
|
||||
const search = new URLSearchParams();
|
||||
search.set('appNamespace', appNamespace);
|
||||
search.set('container', containerName);
|
||||
search.set('namespace', namespace);
|
||||
search.set('follow', follow.toString());
|
||||
|
|
|
|||
|
|
@ -1,11 +0,0 @@
|
|||
package app
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
appv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
|
||||
)
|
||||
|
||||
// AppRBACName formats fully qualified application name for RBAC check
|
||||
func AppRBACName(app appv1.Application) string {
|
||||
return fmt.Sprintf("%s/%s", app.Spec.GetProject(), app.Name)
|
||||
}
|
||||
|
|
@ -412,9 +412,18 @@ func GetAppProjectByName(name string, projLister applicationsv1.AppProjectLister
|
|||
return GetAppVirtualProject(project, projLister, settingsManager)
|
||||
}
|
||||
|
||||
// GetAppProject returns a project from an application
|
||||
func GetAppProject(spec *argoappv1.ApplicationSpec, projLister applicationsv1.AppProjectLister, ns string, settingsManager *settings.SettingsManager, db db.ArgoDB, ctx context.Context) (*argoappv1.AppProject, error) {
|
||||
return GetAppProjectByName(spec.GetProject(), projLister, ns, settingsManager, db, ctx)
|
||||
// GetAppProject returns a project from an application. It will also ensure
|
||||
// that the application is allowed to use the project.
|
||||
func GetAppProject(app *argoappv1.Application, projLister applicationsv1.AppProjectLister, ns string, settingsManager *settings.SettingsManager, db db.ArgoDB, ctx context.Context) (*argoappv1.AppProject, error) {
|
||||
proj, err := GetAppProjectByName(app.Spec.GetProject(), projLister, ns, settingsManager, db, ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !proj.IsAppNamespacePermitted(app, ns) {
|
||||
return nil, fmt.Errorf("application '%s' in namespace '%s' is not allowed to use project '%s'",
|
||||
app.Name, app.Namespace, proj.Name)
|
||||
}
|
||||
return proj, nil
|
||||
}
|
||||
|
||||
// verifyGenerateManifests verifies a repo path can generate manifests
|
||||
|
|
@ -661,3 +670,55 @@ func GetDifferentPathsBetweenStructs(a, b interface{}) ([]string, error) {
|
|||
}
|
||||
return difference, nil
|
||||
}
|
||||
|
||||
// parseAppName will
|
||||
func parseAppName(appName string, defaultNs string, delim string) (string, string) {
|
||||
var ns string
|
||||
var name string
|
||||
t := strings.SplitN(appName, delim, 2)
|
||||
if len(t) == 2 {
|
||||
ns = t[0]
|
||||
name = t[1]
|
||||
} else {
|
||||
ns = defaultNs
|
||||
name = t[0]
|
||||
}
|
||||
return name, ns
|
||||
}
|
||||
|
||||
// ParseAppNamespacedName parses a namespaced name in the format namespace/name
|
||||
// and returns the components. If name wasn't namespaced, defaultNs will be
|
||||
// returned as namespace component.
|
||||
func ParseAppQualifiedName(appName string, defaultNs string) (string, string) {
|
||||
return parseAppName(appName, defaultNs, "/")
|
||||
}
|
||||
|
||||
// ParseAppInstanceName parses a namespaced name in the format namespace_name
|
||||
// and returns the components. If name wasn't namespaced, defaultNs will be
|
||||
// returned as namespace component.
|
||||
func ParseAppInstanceName(appName string, defaultNs string) (string, string) {
|
||||
return parseAppName(appName, defaultNs, "_")
|
||||
}
|
||||
|
||||
// AppInstanceName returns the value to be used for app instance labels from
|
||||
// the combination of appName, appNs and defaultNs.
|
||||
func AppInstanceName(appName, appNs, defaultNs string) string {
|
||||
if appNs == "" || appNs == defaultNs {
|
||||
return appName
|
||||
} else {
|
||||
return appNs + "_" + appName
|
||||
}
|
||||
}
|
||||
|
||||
// AppInstanceNameFromQualified returns the value to be used for app
|
||||
func AppInstanceNameFromQualified(name string, defaultNs string) string {
|
||||
appName, appNs := ParseAppQualifiedName(name, defaultNs)
|
||||
return AppInstanceName(appName, appNs, defaultNs)
|
||||
}
|
||||
|
||||
// ErrProjectNotPermitted returns an error to indicate that an application
|
||||
// identified by appName and appNamespace is not allowed to use the project
|
||||
// identified by projName.
|
||||
func ErrProjectNotPermitted(appName, appNamespace, projName string) error {
|
||||
return fmt.Errorf("application '%s' in namespace '%s' is not permitted to use project '%s'", appName, appNamespace, projName)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ func TestGetAppProjectWithNoProjDefined(t *testing.T) {
|
|||
kubeClient := fake.NewSimpleClientset(&cm)
|
||||
settingsMgr := settings.NewSettingsManager(context.Background(), kubeClient, test.FakeArgoCDNamespace)
|
||||
argoDB := db.NewDB("default", settingsMgr, kubeClient)
|
||||
proj, err := GetAppProject(&testApp.Spec, applisters.NewAppProjectLister(informer.GetIndexer()), namespace, settingsMgr, argoDB, ctx)
|
||||
proj, err := GetAppProject(&testApp, applisters.NewAppProjectLister(informer.GetIndexer()), namespace, settingsMgr, argoDB, ctx)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, proj.Name, projName)
|
||||
}
|
||||
|
|
@ -924,3 +924,95 @@ func Test_GenerateSpecIsDifferentErrorMessageWithDiff(t *testing.T) {
|
|||
assert.Equal(t, msg, "existing repo spec is different; use upsert flag to force update; difference in keys \"Name\"")
|
||||
|
||||
}
|
||||
|
||||
func Test_ParseAppQualifiedName(t *testing.T) {
|
||||
testcases := []struct {
|
||||
name string
|
||||
input string
|
||||
implicitNs string
|
||||
appName string
|
||||
appNs string
|
||||
}{
|
||||
{"Full qualified without implicit NS", "namespace/name", "", "name", "namespace"},
|
||||
{"Non qualified without implicit NS", "name", "", "name", ""},
|
||||
{"Full qualified with implicit NS", "namespace/name", "namespace2", "name", "namespace"},
|
||||
{"Non qualified with implicit NS", "name", "namespace2", "name", "namespace2"},
|
||||
{"Invalid without implicit NS", "namespace_name", "", "namespace_name", ""},
|
||||
}
|
||||
|
||||
for _, tt := range testcases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
appName, appNs := ParseAppQualifiedName(tt.input, tt.implicitNs)
|
||||
assert.Equal(t, tt.appName, appName)
|
||||
assert.Equal(t, tt.appNs, appNs)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_ParseAppInstanceName(t *testing.T) {
|
||||
testcases := []struct {
|
||||
name string
|
||||
input string
|
||||
implicitNs string
|
||||
appName string
|
||||
appNs string
|
||||
}{
|
||||
{"Full qualified without implicit NS", "namespace_name", "", "name", "namespace"},
|
||||
{"Non qualified without implicit NS", "name", "", "name", ""},
|
||||
{"Full qualified with implicit NS", "namespace_name", "namespace2", "name", "namespace"},
|
||||
{"Non qualified with implicit NS", "name", "namespace2", "name", "namespace2"},
|
||||
{"Invalid without implicit NS", "namespace/name", "", "namespace/name", ""},
|
||||
}
|
||||
|
||||
for _, tt := range testcases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
appName, appNs := ParseAppInstanceName(tt.input, tt.implicitNs)
|
||||
assert.Equal(t, tt.appName, appName)
|
||||
assert.Equal(t, tt.appNs, appNs)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_AppInstanceName(t *testing.T) {
|
||||
testcases := []struct {
|
||||
name string
|
||||
appName string
|
||||
appNamespace string
|
||||
defaultNs string
|
||||
result string
|
||||
}{
|
||||
{"defaultns different as appns", "appname", "appns", "defaultns", "appns_appname"},
|
||||
{"defaultns same as appns", "appname", "appns", "appns", "appname"},
|
||||
{"defaultns set and appns not given", "appname", "", "appns", "appname"},
|
||||
{"neither defaultns nor appns set", "appname", "", "appns", "appname"},
|
||||
}
|
||||
|
||||
for _, tt := range testcases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := AppInstanceName(tt.appName, tt.appNamespace, tt.defaultNs)
|
||||
assert.Equal(t, tt.result, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_AppInstanceNameFromQualified(t *testing.T) {
|
||||
testcases := []struct {
|
||||
name string
|
||||
appName string
|
||||
defaultNs string
|
||||
result string
|
||||
}{
|
||||
{"Qualified name with namespace not being defaultns", "appns/appname", "defaultns", "appns_appname"},
|
||||
{"Qualified name with namespace being defaultns", "defaultns/appname", "defaultns", "appname"},
|
||||
{"Qualified name without namespace", "appname", "defaultns", "appname"},
|
||||
{"Qualified name without namespace and defaultns", "appname", "", "appname"},
|
||||
}
|
||||
|
||||
for _, tt := range testcases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := AppInstanceNameFromQualified(tt.appName, tt.defaultNs)
|
||||
assert.Equal(t, tt.result, result)
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
57
util/glob/glob_test.go
Normal file
57
util/glob/glob_test.go
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
package glob
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_Match(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
pattern string
|
||||
result bool
|
||||
}{
|
||||
{"Exact match", "hello", "hello", true},
|
||||
{"Non-match exact", "hello", "hell", false},
|
||||
{"Long glob match", "hello", "hell*", true},
|
||||
{"Short glob match", "hello", "h*", true},
|
||||
{"Glob non-match", "hello", "e*", false},
|
||||
{"Invalid pattern", "e[[a*", "e[[a*", false},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
res := Match(tt.pattern, tt.input)
|
||||
assert.Equal(t, tt.result, res)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_MatchList(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
list []string
|
||||
exact bool
|
||||
result bool
|
||||
}{
|
||||
{"Exact name in list", "test", []string{"test"}, true, true},
|
||||
{"Exact name not in list", "test", []string{"other"}, true, false},
|
||||
{"Exact name not in list, multiple elements", "test", []string{"some", "other"}, true, false},
|
||||
{"Exact name not in list, list empty", "test", []string{}, true, false},
|
||||
{"Exact name not in list, empty element", "test", []string{""}, true, false},
|
||||
{"Glob name in list, but exact wanted", "test", []string{"*"}, true, false},
|
||||
{"Glob name in list with simple wildcard", "test", []string{"*"}, false, true},
|
||||
{"Glob name in list without wildcard", "test", []string{"test"}, false, true},
|
||||
{"Glob name in list, multiple elements", "test", []string{"other*", "te*"}, false, true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
res := MatchStringInList(tt.list, tt.input, tt.exact)
|
||||
assert.Equal(t, tt.result, res)
|
||||
})
|
||||
}
|
||||
}
|
||||
12
util/glob/list.go
Normal file
12
util/glob/list.go
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
package glob
|
||||
|
||||
// MatchStringInList will return true if item is contained in list. If
|
||||
// exactMatch is set to false, list may contain globs to be matched.
|
||||
func MatchStringInList(list []string, item string, exactMatch bool) bool {
|
||||
for _, ll := range list {
|
||||
if item == ll || (!exactMatch && Match(ll, item)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
@ -1883,3 +1883,7 @@ func (mgr *SettingsManager) GetGlobalProjectsSettings() ([]GlobalProjectSettings
|
|||
}
|
||||
return globalProjectSettings, nil
|
||||
}
|
||||
|
||||
func (mgr *SettingsManager) GetNamespace() string {
|
||||
return mgr.namespace
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue