Compare commits

...

37 Commits

Author SHA1 Message Date
Jesse Suen
ff87d8cb9e Fix issue where helm hooks were being deployed as part of sync (issue #605) 2018-09-17 11:39:10 -07:00
Jesse Suen
da1373e953 Support helm charts with dependencies and namespace sensitivity (issue #582) 2018-09-17 11:38:19 -07:00
Alexander Matyushentsev
53603b17c1 Issue #584 - ArgoCD fails to deploy resources list (#598) 2018-09-14 13:53:48 -07:00
Jesse Suen
13c15988cd Fix comparison failure when app contains unregistered custom resource (issue #583) (#596) 2018-09-13 14:03:30 -07:00
Jesse Suen
6375efe23e Fix race conditions in kube.GetResourcesWithLabel and DeleteResourceWithLabel (issue #587) (#593) 2018-09-13 13:59:52 -07:00
Conor Fennell
9a74698308 Issue #577 - Add rbac non resource url policy for argocd-manager-role (#578)
* Add rbac non resource url policy for argocd-manager-role
* allow all non resource urls to be added through rbac
2018-09-13 00:04:10 -07:00
Alexander Matyushentsev
3e374988ce Issue 499 - fileFiles path should be relative to app directory (#552) 2018-09-12 23:58:31 -07:00
Jesse Suen
e5eefa2b94 Fix app sync / wait panic in CLI 2018-09-12 01:27:25 -07:00
Jesse Suen
5293527a0c Downgrade ksonnet from v0.12.0 to v0.11.0 due to quote unescape regression 2018-09-12 01:27:25 -07:00
Jesse Suen
973f736b37 Update manifests to point to v0.8.1 2018-09-10 14:11:42 -07:00
Jesse Suen
8c91935575 Fix controller hot loop when app source contains bad manifests (issue #568) (#570) 2018-09-10 11:00:19 -07:00
Jesse Suen
f82bb53a86 Fix issue where branch checkout did not have accurate git tree state (issue #567) (#569) 2018-09-10 11:00:02 -07:00
Jesse Suen
d7c04ae24c Update manifests to use v0.8.0
Make manifests friendly to `kubectl apply` semantics by omitting `data:` field
RBAC docs improvements
2018-09-04 17:58:50 -07:00
Jesse Suen
5bcf8c40e0 Minor improvements to token CLI (#549) 2018-09-04 17:57:31 -07:00
dthomson25
b8e30ed953 Add documentation on project roles and JWT tokens (#533)
* Add documentation on project roles and JWT tokens
* Add AppProject CRD to architecture.md
2018-09-04 17:57:00 -07:00
Jesse Suen
e3adb30ca7 Run all containers as an unprivileged user (resolves #528) (#546) 2018-09-04 13:47:00 -07:00
Jesse Suen
1e8c570c8a Fix argocd app wait printing incorrect Sync output (resolves #542) (#543)
Timeout condition was not printing final status.
2018-08-31 11:25:15 -07:00
Jesse Suen
40f2220f1d Fix issue where argocd could not sync to a tag (#541) 2018-08-31 11:24:14 -07:00
dthomson25
4da779c44c Add PVC healthcheck to controller (#501) (#537) 2018-08-28 16:40:32 -07:00
Jesse Suen
b54a5a3e25 Refactor Makefile/build to use a single Dockerfile. Update kustomize to v1.0.7 (#538) 2018-08-28 16:00:14 -07:00
dthomson25
f572bcff58 Create default project on startup (#535)
Implements to solve issue #514
2018-08-28 10:06:01 -07:00
Andrew Merenbach
d47b7e6128 Use gRPC error codes instead of fmt.Errorf (#532) 2018-08-27 17:54:29 -07:00
Andrew Merenbach
8d9e4faae9 Add health check on API server (#522)
* Add app health endpoints

* Update generated files

* Revert "Update generated files"

This reverts commit 40f490797645ed0f30d05785748e3919dea31b7f.

* Revert "Add app health endpoints"

This reverts commit 650688dd2ee4a533e29b7df69e0bbb2436eead6b.

* Add dedicated health endpoint

* Update generated files

* Slim down basic server

* Update generated files

* Update health server creation

* Fix import, endpoint casing

* Flesh out basic health check

* Add additional endpoints, fix check, thanks @jessesuen

* Fix errors

* Update generated files

* Simplify health check, update endpoint

* Update generated files

* Factor out health check code

* Update generated files

* Rm health endpoint

* Add healthz utility

* Log error instead of printing it

* Update comment

* Add liveness, readiness probes to manifest for API server

* Add health check test

* Tweak timeouts, endpoints in probes, thanks @jessesuen

* Tweak probes, thanks @jessesuen
2018-08-23 09:24:21 -07:00
Jesse Suen
cf630055b0 API discovery becomes best effort when partial resource list is returned (resolves #524) (#526) 2018-08-21 13:53:42 -07:00
dthomson25
a5870c894f Fix typo in sso.md (#518) 2018-08-21 09:10:31 -07:00
Andrew Merenbach
c236ee99d4 Use named FIFO so we can exit with non-zero status (#516) 2018-08-16 13:22:29 -07:00
Jesse Suen
130e242aa9 Fix build breakage (#517) 2018-08-15 18:31:43 -07:00
Jesse Suen
39f0a17d0d Add ability to delete a single application resource (issue #262) (#511) 2018-08-15 15:01:29 -07:00
Jesse Suen
da0682afa7 Support for kustomize app directories (#510) 2018-08-15 14:54:56 -07:00
Andrew Merenbach
3c755a2002 Upgrade Ksonnet (#506) 2018-08-15 12:56:41 -07:00
dthomson25
66f64fbf15 Add Project JWT tokens (#498)
Implemented Project JWT Tokens (#472) using #228 as the overall design
2018-08-15 12:54:24 -07:00
Alexander Matyushentsev
4c0a0e09e2 Issue 435 - pump ci logs to s3 (#509) 2018-08-14 01:59:43 +03:00
Alexander Matyushentsev
f8de6084ed Issue #458 - Add api to load project events (#504) 2018-08-10 01:55:43 +03:00
Andrew Merenbach
36624f9d89 Enable code coverage (#500)
* Update Gopkg.toml

* Update Gopkg.lock

* Add new test-coverage command

* Update .gitignore to ignore coverage.out

* Test injection of COVERALLS_TOKEN variable

* Add draft of .travis.yml

* Rm recursive coveralls token

* Ensure that goveralls gets installed

* Rm second Go version

* Update workflow with coverage testing

* Change service from argo to argo-ci

* Rm .travis.yml

* Try setting coveralls token more explicitly

* Try file-based instead of env-based token

* Try both methods of providing token

* Go back to just env-based token

* Update with another printout test

* Try using container, thanks @alexmt

* Simplify for now, take 2

* Rm quotes

* Move env to ci-builder template

* Rm coveralls token

* Add coverage badge for current branch, take 2

* Add else statement for output in case of missing token

* Ensure we use the race detector

* Don't install goveralls with dep ensure

* Update generated files

* Try ignoring intermediate files

* Don't use race detector for now

* Try new pattern to ignore

* Try different pattern now

* Try different ignore path

* Try a different ignore style

* Ignore generated protobuf files properly now

* Rm standalone test since we have test-coverage
2018-08-09 15:54:15 -07:00
Alexander Matyushentsev
cbf1e3419b Issue #489 - Static assets are being browser cached between upgrades (#502) 2018-08-08 21:10:40 +03:00
Andrew Merenbach
7c8cc41d4c Support explicit deny (#497)
* Honor deny in RBAC model

* Add explicit allow for roles

* Update tests

* Test explicit deny

* Test deny,allow=>deny and allow,deny=>deny
2018-08-08 09:33:44 -07:00
Andrew Merenbach
5dbbd0a76f Support UI cluster creation (#469)
* Add kubeconfig string to ClusterCreateRequest

* Update generated files

* Copy and adapt cluster management logic into db

* Add service account deletion to db

* Return errors from new DB methods

* Adapt InstallClusterManagerRBAC for db

* Update errors in db

* Return error if it occurs from db

* Integrate code to (un)install cluster manager

* Use invalid argument instead of failed precondition

* Set bearer token if error is nil

* Rm cluster RBAC install from CLI

* Rm cluster mgmt install from e2e

* Rm common/install.go

* Move install components into server/cluster, thanks @jessesuen

* Rm unneeded ctx arg

* Restore common/installer.go

* Replace all quoted percent-s with percent-q

* Refactor common/installer.go with error returns

* Return errors rather than exiting fatally

* Return proper number of args

* Slim down cluster methods again

* Simplify, simplify, simplify

* Return gRPC error if RBAC could not be installed

* Issue log entries, not print statements

* Fix log import

* Update generated files

* Refactor

* Major cleanup

* Unmarshal context now

* Put claims check after bearer token insertion

* Initial work to use Kubernetes manifest to create a cluster

* Pass context name now

* Wire up prototype

* Add missing parameter for e2e test

* Just read file directly

* Change how we read cluster server

* Support more attributes from localconfig

* Update generated files

* Support incluster flag

* Comment out unused field for now

* Rm previous NewCluster function

* Unmarshal kube config successfully

* Handle insecure clusters, too

* Use existing logic to get config, thanks @jessesuen

* Revert cluster.go to master version

* Update invocations of RBAC installation

* Fix e2e invocation

* Don't remove management account, thanks @jessesuen

* Fix missing error check in e2e test

* Fix missing clientset arg in e2e fixture

* Create kubeclientset for kubeconfig, thanks @jessesuen
2018-08-06 11:27:48 -07:00
107 changed files with 7191 additions and 1476 deletions

View File

@@ -29,7 +29,13 @@ spec:
- name: cmd
value: "{{item}}"
withItems:
- dep ensure && make cli lint test
- dep ensure && make cli lint
- name: test-coverage
template: ci-builder
arguments:
parameters:
- name: cmd
value: "dep ensure && go get github.com/mattn/goveralls && make test-coverage"
- name: test-e2e
template: ci-builder
arguments:
@@ -50,12 +56,22 @@ spec:
container:
image: argoproj/argo-cd-ci-builder:latest
command: [sh, -c]
args: ["{{inputs.parameters.cmd}}"]
args: ["mkfifo pipe; tee /tmp/logs.txt < pipe & {{inputs.parameters.cmd}} > pipe"]
workingDir: /go/src/github.com/argoproj/argo-cd
env:
- name: COVERALLS_TOKEN
valueFrom:
secretKeyRef:
name: coverall-token
key: coverall-token
resources:
requests:
memory: 1024Mi
cpu: 200m
outputs:
artifacts:
- name: logs
path: /tmp/logs.txt
- name: ci-dind
inputs:
@@ -70,7 +86,7 @@ spec:
container:
image: argoproj/argo-cd-ci-builder:latest
command: [sh, -c]
args: ["until docker ps; do sleep 3; done && {{inputs.parameters.cmd}}"]
args: ["mkfifo pipe; tee /tmp/logs.txt < pipe & until docker ps; do sleep 3; done && {{inputs.parameters.cmd}} > pipe"]
workingDir: /go/src/github.com/argoproj/argo-cd
env:
- name: DOCKER_HOST
@@ -85,4 +101,7 @@ spec:
securityContext:
privileged: true
mirrorVolumeMounts: true
outputs:
artifacts:
- name: logs
path: /tmp/logs.txt

1
.gitignore vendored
View File

@@ -7,3 +7,4 @@ dist/
# delve debug binaries
cmd/**/debug
debug.test
coverage.out

View File

@@ -1,5 +1,53 @@
# Changelog
## v0.8.2 (2018-09-12)
- Downgrade ksonnet from v0.12.0 to v0.11.0 due to quote unescape regression
- Fix CLI panic when performing an initial `argocd sync/wait`
## v0.8.1 (2018-09-10)
+ [UI] Support selection of helm values files in App creation wizard (issue #499)
+ [UI] Support specifying source revision in App creation wizard allow (issue #503)
+ [UI] Improve resource diff rendering (issue #457)
+ [UI] Indicate number of ready containers in pod (issue #539)
+ [UI] Indicate when app is overriding parameters (issue #503)
+ [UI] Provide a YAML view of resources (issue #396)
- Fix issue where changes were not pulled when tracking a branch (issue #567)
- Fix controller hot loop when app source contains bad manifests (issue #568)
- [UI] Fix issue where projects filter does not work when application got changed
## v0.8.0 (2018-09-04)
### Notes about upgrading from v0.7
* The RBAC model has been improved to support explicit denies. What this means is that any previous
RBAC policy rules, need to be rewritten to include one extra column with the effect:
`allow` or `deny`. For example, if a rule was written like this:
```
p, my-org:my-team, applications, get, */*
```
It should be rewritten to look like this:
```
p, my-org:my-team, applications, get, */*, allow
```
### Changes since v0.7:
+ Support kustomize as an application source (issue #510)
+ Introduce project tokens for automation access (issue #498)
+ Add ability to delete a single application resource to support immutable updates (issue #262)
+ Update RBAC model to support explicit denies (issue #497)
+ Ability to view Kubernetes events related to application projects for auditing
+ Add PVC healthcheck to controller (issue #501)
+ Run all containers as an unprivileged user (issue #528)
* Upgrade ksonnet to v0.12.0
* Add readiness probes to API server (issue #522)
* Use gRPC error codes instead of fmt.Errorf (#532)
- API discovery becomes best effort when partial resource list is returned (issue #524)
- Fix `argocd app wait` printing incorrect Sync output (issue #542)
- Fix issue where argocd could not sync to a tag (#541)
- Fix issue where static assets were browser cached between upgrades (issue #489)
## v0.7.2 (2018-08-21)
- API discovery becomes best effort when partial resource list is returned (issue #524)
## v0.7.1 (2018-08-03)
+ Surface helm parameters to the application level (#485)
+ [UI] Improve application creation wizard (#459)

View File

@@ -6,6 +6,7 @@ Make sure you have following tools installed
* [protobuf](https://developers.google.com/protocol-buffers/)
* [ksonnet](https://github.com/ksonnet/ksonnet#install)
* [helm](https://github.com/helm/helm/releases)
* [kustomize](https://github.com/kubernetes-sigs/kustomize/releases)
* [go-swagger](https://github.com/go-swagger/go-swagger/blob/master/docs/install.md)
* [jq](https://stedolan.github.io/jq/)
* [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/).

131
Dockerfile Normal file
View File

@@ -0,0 +1,131 @@
####################################################################################################
# Builder image
# Initial stage which pulls prepares build dependencies and CLI tooling we need for our final image
# Also used as the image in CI jobs so needs all dependencies
####################################################################################################
FROM golang:1.10.3 as builder
RUN apt-get update && apt-get install -y \
git \
make \
wget \
gcc \
zip && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
WORKDIR /tmp
# Install docker
ENV DOCKER_VERSION=18.06.0
RUN curl -O https://download.docker.com/linux/static/stable/x86_64/docker-${DOCKER_VERSION}-ce.tgz && \
tar -xzf docker-${DOCKER_VERSION}-ce.tgz && \
mv docker/docker /usr/local/bin/docker && \
rm -rf ./docker
# Install dep
ENV DEP_VERSION=0.5.0
RUN wget https://github.com/golang/dep/releases/download/v${DEP_VERSION}/dep-linux-amd64 -O /usr/local/bin/dep && \
chmod +x /usr/local/bin/dep
# Install gometalinter
RUN curl -sLo- https://github.com/alecthomas/gometalinter/releases/download/v2.0.5/gometalinter-2.0.5-linux-amd64.tar.gz | \
tar -xzC "$GOPATH/bin" --exclude COPYING --exclude README.md --strip-components 1 -f- && \
ln -s $GOPATH/bin/gometalinter $GOPATH/bin/gometalinter.v2
# Install packr
ENV PACKR_VERSION=1.13.2
RUN wget https://github.com/gobuffalo/packr/releases/download/v${PACKR_VERSION}/packr_${PACKR_VERSION}_linux_amd64.tar.gz && \
tar -vxf packr*.tar.gz -C /tmp/ && \
mv /tmp/packr /usr/local/bin/packr
# Install kubectl
RUN curl -L -o /usr/local/bin/kubectl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl && \
chmod +x /usr/local/bin/kubectl
# Install ksonnet
# NOTE: we frequently switch between tip of master ksonnet vs. official builds. Comment/uncomment
# the corresponding section to switch between the two options:
# Option 1: build ksonnet ourselves
#RUN go get -v -u github.com/ksonnet/ksonnet && mv ${GOPATH}/bin/ksonnet /usr/local/bin/ks
# Option 2: use official tagged ksonnet release
ENV KSONNET_VERSION=0.11.0
RUN wget https://github.com/ksonnet/ksonnet/releases/download/v${KSONNET_VERSION}/ks_${KSONNET_VERSION}_linux_amd64.tar.gz && \
tar -C /tmp/ -xf ks_${KSONNET_VERSION}_linux_amd64.tar.gz && \
mv /tmp/ks_${KSONNET_VERSION}_linux_amd64/ks /usr/local/bin/ks
# Install helm
ENV HELM_VERSION=2.9.1
RUN wget https://storage.googleapis.com/kubernetes-helm/helm-v${HELM_VERSION}-linux-amd64.tar.gz && \
tar -C /tmp/ -xf helm-v${HELM_VERSION}-linux-amd64.tar.gz && \
mv /tmp/linux-amd64/helm /usr/local/bin/helm
# Install kustomize
ENV KUSTOMIZE_VERSION=1.0.7
RUN curl -L -o /usr/local/bin/kustomize https://github.com/kubernetes-sigs/kustomize/releases/download/v${KUSTOMIZE_VERSION}/kustomize_${KUSTOMIZE_VERSION}_linux_amd64 && \
chmod +x /usr/local/bin/kustomize
####################################################################################################
# ArgoCD Build stage which performs the actual build of ArgoCD binaries
####################################################################################################
FROM golang:1.10.3 as argocd-build
COPY --from=builder /usr/local/bin/dep /usr/local/bin/dep
COPY --from=builder /usr/local/bin/packr /usr/local/bin/packr
# A dummy directory is created under $GOPATH/src/dummy so we are able to use dep
# to install all the packages of our dep lock file
COPY Gopkg.toml ${GOPATH}/src/dummy/Gopkg.toml
COPY Gopkg.lock ${GOPATH}/src/dummy/Gopkg.lock
RUN cd ${GOPATH}/src/dummy && \
dep ensure -vendor-only && \
mv vendor/* ${GOPATH}/src/ && \
rmdir vendor
# Perform the build
WORKDIR /go/src/github.com/argoproj/argo-cd
COPY . .
ARG MAKE_TARGET="cli server controller repo-server argocd-util"
RUN make ${MAKE_TARGET}
####################################################################################################
# Final image
####################################################################################################
FROM debian:9.5-slim
RUN groupadd -g 999 argocd && \
useradd -r -u 999 -g argocd argocd && \
mkdir -p /home/argocd && \
chown argocd:argocd /home/argocd && \
apt-get update && \
apt-get install -y git && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
COPY --from=builder /usr/local/bin/ks /usr/local/bin/ks
COPY --from=builder /usr/local/bin/helm /usr/local/bin/helm
COPY --from=builder /usr/local/bin/kubectl /usr/local/bin/kubectl
COPY --from=builder /usr/local/bin/kustomize /usr/local/bin/kustomize
# workaround ksonnet issue https://github.com/ksonnet/ksonnet/issues/298
ENV USER=argocd
COPY --from=argocd-build /go/src/github.com/argoproj/argo-cd/dist/* /usr/local/bin/
# Symlink argocd binaries under root for backwards compatibility that expect it under /
RUN ln -s /usr/local/bin/argocd /argocd && \
ln -s /usr/local/bin/argocd-server /argocd-server && \
ln -s /usr/local/bin/argocd-util /argocd-util && \
ln -s /usr/local/bin/argocd-application-controller /argocd-application-controller && \
ln -s /usr/local/bin/argocd-repo-server /argocd-repo-server
USER argocd
RUN helm init --client-only
WORKDIR /home/argocd
ARG BINARY
CMD ${BINARY}

View File

@@ -1,88 +0,0 @@
FROM debian:9.4 as builder
RUN apt-get update && apt-get install -y \
git \
make \
wget \
gcc \
zip && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
# Install go
ENV GO_VERSION 1.10.3
ENV GO_ARCH amd64
ENV GOPATH /root/go
ENV PATH ${GOPATH}/bin:/usr/local/go/bin:${PATH}
RUN wget https://storage.googleapis.com/golang/go${GO_VERSION}.linux-${GO_ARCH}.tar.gz && \
tar -C /usr/local/ -xf /go${GO_VERSION}.linux-${GO_ARCH}.tar.gz && \
rm /go${GO_VERSION}.linux-${GO_ARCH}.tar.gz
# Install protoc, dep, packr
ENV PROTOBUF_VERSION 3.5.1
RUN cd /usr/local && \
wget https://github.com/google/protobuf/releases/download/v${PROTOBUF_VERSION}/protoc-${PROTOBUF_VERSION}-linux-x86_64.zip && \
unzip protoc-*.zip && \
wget https://github.com/golang/dep/releases/download/v0.4.1/dep-linux-amd64 -O /usr/local/bin/dep && \
chmod +x /usr/local/bin/dep && \
wget https://github.com/gobuffalo/packr/releases/download/v1.11.0/packr_1.11.0_linux_amd64.tar.gz && \
tar -vxf packr*.tar.gz -C /tmp/ && \
mv /tmp/packr /usr/local/bin/packr
# A dummy directory is created under $GOPATH/src/dummy so we are able to use dep
# to install all the packages of our dep lock file
COPY Gopkg.toml ${GOPATH}/src/dummy/Gopkg.toml
COPY Gopkg.lock ${GOPATH}/src/dummy/Gopkg.lock
RUN cd ${GOPATH}/src/dummy && \
dep ensure -vendor-only && \
mv vendor/* ${GOPATH}/src/ && \
rmdir vendor
# Perform the build
WORKDIR /root/go/src/github.com/argoproj/argo-cd
COPY . .
ARG MAKE_TARGET="cli server controller repo-server argocd-util"
RUN make ${MAKE_TARGET}
##############################################################
# This stage will pull in or build any CLI tooling we need for our final image
FROM golang:1.10 as cli-tooling
# NOTE: we frequently switch between tip of master ksonnet vs. official builds. Comment/uncomment
# the corresponding section to switch between the two options:
# Option 1: build ksonnet ourselves
#RUN go get -v -u github.com/ksonnet/ksonnet && mv ${GOPATH}/bin/ksonnet /ks
# Option 2: use official tagged ksonnet release
env KSONNET_VERSION=0.11.0
RUN wget https://github.com/ksonnet/ksonnet/releases/download/v${KSONNET_VERSION}/ks_${KSONNET_VERSION}_linux_amd64.tar.gz && \
tar -C /tmp/ -xf ks_${KSONNET_VERSION}_linux_amd64.tar.gz && \
mv /tmp/ks_${KSONNET_VERSION}_linux_amd64/ks /ks
RUN curl -o /kubectl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl && \
chmod +x /kubectl
env HELM_VERSION=2.9.1
RUN wget https://storage.googleapis.com/kubernetes-helm/helm-v${HELM_VERSION}-linux-amd64.tar.gz && \
tar -C /tmp/ -xf helm-v${HELM_VERSION}-linux-amd64.tar.gz && \
mv /tmp/linux-amd64/helm /helm
##############################################################
FROM debian:9.3
RUN apt-get update && apt-get install -y git && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
COPY --from=cli-tooling /ks /usr/local/bin/ks
COPY --from=cli-tooling /helm /usr/local/bin/helm
COPY --from=cli-tooling /kubectl /usr/local/bin/kubectl
# workaround ksonnet issue https://github.com/ksonnet/ksonnet/issues/298
ENV USER=root
COPY --from=builder /root/go/src/github.com/argoproj/argo-cd/dist/* /
ARG BINARY
CMD /${BINARY}

View File

@@ -1,28 +0,0 @@
FROM golang:1.10.3
WORKDIR /tmp
RUN curl -O https://get.docker.com/builds/Linux/x86_64/docker-1.13.1.tgz && \
tar -xzf docker-1.13.1.tgz && \
mv docker/docker /usr/local/bin/docker && \
rm -rf ./docker && \
go get -u github.com/golang/dep/cmd/dep && \
go get -u gopkg.in/alecthomas/gometalinter.v2 && \
gometalinter.v2 --install
# Install kubectl
RUN curl -o /kubectl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl && \
chmod +x /kubectl && mv /kubectl /usr/local/bin/kubectl
# Install ksonnet
env KSONNET_VERSION=0.11.0
RUN wget https://github.com/ksonnet/ksonnet/releases/download/v${KSONNET_VERSION}/ks_${KSONNET_VERSION}_linux_amd64.tar.gz && \
tar -C /tmp/ -xf ks_${KSONNET_VERSION}_linux_amd64.tar.gz && \
mv /tmp/ks_${KSONNET_VERSION}_linux_amd64/ks /usr/local/bin/ks && \
rm -rf /tmp/ks_${KSONNET_VERSION}
# Install helm
env HELM_VERSION=2.9.1
RUN wget https://storage.googleapis.com/kubernetes-helm/helm-v${HELM_VERSION}-linux-amd64.tar.gz && \
tar -C /tmp/ -xf helm-v${HELM_VERSION}-linux-amd64.tar.gz && \
mv /tmp/linux-amd64/helm /usr/local/bin/helm

400
Gopkg.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -6,6 +6,9 @@ required = [
"github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway",
"github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger",
"github.com/golang/protobuf/protoc-gen-go",
"golang.org/x/tools/cmd/cover",
"github.com/argoproj/pkg/time",
"github.com/dustin/go-humanize",
]
[[constraint]]
@@ -53,3 +56,7 @@ required = [
[[override]]
name = "github.com/sirupsen/logrus"
revision = "ea8897e79973357ba785ac2533559a6297e83c44"
[[constraint]]
branch = "master"
name = "github.com/argoproj/pkg"

View File

@@ -62,16 +62,16 @@ cli: clean-debug
.PHONY: cli-linux
cli-linux: clean-debug
docker build --iidfile /tmp/argocd-linux-id --target builder --build-arg MAKE_TARGET="cli IMAGE_TAG=$(IMAGE_TAG) IMAGE_NAMESPACE=$(IMAGE_NAMESPACE) CLI_NAME=argocd-linux-amd64" -f Dockerfile-argocd .
docker build --iidfile /tmp/argocd-linux-id --target argocd-build --build-arg MAKE_TARGET="cli IMAGE_TAG=$(IMAGE_TAG) IMAGE_NAMESPACE=$(IMAGE_NAMESPACE) CLI_NAME=argocd-linux-amd64" .
docker create --name tmp-argocd-linux `cat /tmp/argocd-linux-id`
docker cp tmp-argocd-linux:/root/go/src/github.com/argoproj/argo-cd/dist/argocd-linux-amd64 dist/
docker cp tmp-argocd-linux:/go/src/github.com/argoproj/argo-cd/dist/argocd-linux-amd64 dist/
docker rm tmp-argocd-linux
.PHONY: cli-darwin
cli-darwin: clean-debug
docker build --iidfile /tmp/argocd-darwin-id --target builder --build-arg MAKE_TARGET="cli GOOS=darwin IMAGE_TAG=$(IMAGE_TAG) IMAGE_NAMESPACE=$(IMAGE_NAMESPACE) CLI_NAME=argocd-darwin-amd64" -f Dockerfile-argocd .
docker build --iidfile /tmp/argocd-darwin-id --target argocd-build --build-arg MAKE_TARGET="cli GOOS=darwin IMAGE_TAG=$(IMAGE_TAG) IMAGE_NAMESPACE=$(IMAGE_NAMESPACE) CLI_NAME=argocd-darwin-amd64" .
docker create --name tmp-argocd-darwin `cat /tmp/argocd-darwin-id`
docker cp tmp-argocd-darwin:/root/go/src/github.com/argoproj/argo-cd/dist/argocd-darwin-amd64 dist/
docker cp tmp-argocd-darwin:/go/src/github.com/argoproj/argo-cd/dist/argocd-darwin-amd64 dist/
docker rm tmp-argocd-darwin
.PHONY: argocd-util
@@ -89,7 +89,7 @@ server: clean-debug
.PHONY: server-image
server-image:
docker build --build-arg BINARY=argocd-server -t $(IMAGE_PREFIX)argocd-server:$(IMAGE_TAG) -f Dockerfile-argocd .
docker build --build-arg BINARY=argocd-server -t $(IMAGE_PREFIX)argocd-server:$(IMAGE_TAG) .
@if [ "$(DOCKER_PUSH)" = "true" ] ; then docker push $(IMAGE_PREFIX)argocd-server:$(IMAGE_TAG) ; fi
.PHONY: repo-server
@@ -98,7 +98,7 @@ repo-server:
.PHONY: repo-server-image
repo-server-image:
docker build --build-arg BINARY=argocd-repo-server -t $(IMAGE_PREFIX)argocd-repo-server:$(IMAGE_TAG) -f Dockerfile-argocd .
docker build --build-arg BINARY=argocd-repo-server -t $(IMAGE_PREFIX)argocd-repo-server:$(IMAGE_TAG) .
@if [ "$(DOCKER_PUSH)" = "true" ] ; then docker push $(IMAGE_PREFIX)argocd-repo-server:$(IMAGE_TAG) ; fi
.PHONY: controller
@@ -107,17 +107,17 @@ controller:
.PHONY: controller-image
controller-image:
docker build --build-arg BINARY=argocd-application-controller -t $(IMAGE_PREFIX)argocd-application-controller:$(IMAGE_TAG) -f Dockerfile-argocd .
docker build --build-arg BINARY=argocd-application-controller -t $(IMAGE_PREFIX)argocd-application-controller:$(IMAGE_TAG) .
@if [ "$(DOCKER_PUSH)" = "true" ] ; then docker push $(IMAGE_PREFIX)argocd-application-controller:$(IMAGE_TAG) ; fi
.PHONY: cli-image
cli-image:
docker build --build-arg BINARY=argocd -t $(IMAGE_PREFIX)argocd-cli:$(IMAGE_TAG) -f Dockerfile-argocd .
docker build --build-arg BINARY=argocd -t $(IMAGE_PREFIX)argocd-cli:$(IMAGE_TAG) .
@if [ "$(DOCKER_PUSH)" = "true" ] ; then docker push $(IMAGE_PREFIX)argocd-cli:$(IMAGE_TAG) ; fi
.PHONY: builder-image
builder-image:
docker build -t $(IMAGE_PREFIX)argo-cd-ci-builder:$(IMAGE_TAG) -f Dockerfile-ci-builder .
docker build -t $(IMAGE_PREFIX)argo-cd-ci-builder:$(IMAGE_TAG) --target builder .
.PHONY: lint
lint:
@@ -127,6 +127,11 @@ lint:
test:
go test -v `go list ./... | grep -v "github.com/argoproj/argo-cd/test/e2e"`
.PHONY: test-coverage
test-coverage:
go test -v -covermode=count -coverprofile=coverage.out `go list ./... | grep -v "github.com/argoproj/argo-cd/test/e2e"`
@if [ "$(COVERALLS_TOKEN)" != "" ] ; then goveralls -ignore `find . -name '*.pb*.go' | grep -v vendor/ | sed 's!^./!!' | paste -d, -s -` -coverprofile=coverage.out -service=argo-ci -repotoken "$(COVERALLS_TOKEN)"; else echo 'No COVERALLS_TOKEN env var specified. Skipping submission to Coveralls.io'; fi
.PHONY: test-e2e
test-e2e:
go test -v -failfast -timeout 20m ./test/e2e

View File

@@ -1,3 +1,4 @@
[![Coverage Status](https://coveralls.io/repos/github/argoproj/argo-cd/badge.svg?branch=master)](https://coveralls.io/github/argoproj/argo-cd?branch=master)
# Argo CD - Declarative Continuous Delivery for Kubernetes

View File

@@ -1 +1 @@
0.7.1
0.8.2

View File

@@ -7,6 +7,7 @@ import (
"io"
"net/url"
"os"
"reflect"
"strconv"
"strings"
"text/tabwriter"
@@ -845,23 +846,22 @@ func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
// ResourceState tracks the state of a resource when waiting on an application status.
type resourceState struct {
Kind string
Name string
PrevState string
Fields map[string]string
Updated bool
Kind string
Name string
Status string
Health string
Hook string
Message string
}
func newResourceState(kind, name, status, healthStatus, resType, message string) *resourceState {
func newResourceState(kind, name, status, health, hook, message string) *resourceState {
return &resourceState{
Kind: kind,
Name: name,
Fields: map[string]string{
"status": status,
"healthStatus": healthStatus,
"type": resType,
"message": message,
},
Kind: kind,
Name: name,
Status: status,
Health: health,
Hook: hook,
Message: message,
}
}
@@ -870,47 +870,106 @@ func (rs *resourceState) Key() string {
return fmt.Sprintf("%s/%s", rs.Kind, rs.Name)
}
// Merge merges the new state into the previous state, returning whether the
// new state contains any additional keys or different values from the old state.
func (rs *resourceState) Merge() bool {
if out := rs.String(); out != rs.PrevState {
rs.PrevState = out
return true
}
return false
}
func (rs *resourceState) String() string {
return fmt.Sprintf("%s\t%s\t%s\t%s\t%s\t%s", rs.Kind, rs.Name, rs.Fields["status"], rs.Fields["healthStatus"], rs.Fields["type"], rs.Fields["message"])
return fmt.Sprintf("%s\t%s\t%s\t%s\t%s\t%s", rs.Kind, rs.Name, rs.Status, rs.Health, rs.Hook, rs.Message)
}
// Update a resourceState with any different contents from another resourceState.
// Merge merges the new state with any different contents from another resourceState.
// Blank fields in the receiver state will be updated to non-blank.
// Non-blank fields in the receiver state will never be updated to blank.
func (rs *resourceState) Update(newState *resourceState) {
for k, v := range newState.Fields {
if v != "" {
rs.Fields[k] = v
// Returns whether or not any keys were updated.
func (rs *resourceState) Merge(newState *resourceState) bool {
updated := false
for _, field := range []string{"Status", "Health", "Hook", "Message"} {
v := reflect.ValueOf(rs).Elem().FieldByName(field)
currVal := v.String()
newVal := reflect.ValueOf(newState).Elem().FieldByName(field).String()
if newVal != "" && currVal != newVal {
v.SetString(newVal)
updated = true
}
}
return updated
}
func waitOnApplicationStatus(appClient application.ApplicationServiceClient, appName string, timeout uint, watchSync, watchHealth, watchOperations bool) (*argoappv1.Application, error) {
func calculateResourceStates(app *argoappv1.Application) map[string]*resourceState {
resStates := make(map[string]*resourceState)
for _, res := range app.Status.ComparisonResult.Resources {
obj, err := argoappv1.UnmarshalToUnstructured(res.TargetState)
errors.CheckError(err)
if obj == nil {
obj, err = argoappv1.UnmarshalToUnstructured(res.LiveState)
errors.CheckError(err)
}
newState := newResourceState(obj.GetKind(), obj.GetName(), string(res.Status), res.Health.Status, "", "")
key := newState.Key()
if prev, ok := resStates[key]; ok {
prev.Merge(newState)
} else {
resStates[key] = newState
}
}
var opResult *argoappv1.SyncOperationResult
if app.Status.OperationState != nil {
if app.Status.OperationState.SyncResult != nil {
opResult = app.Status.OperationState.SyncResult
} else if app.Status.OperationState.RollbackResult != nil {
opResult = app.Status.OperationState.SyncResult
}
}
if opResult == nil {
return resStates
}
for _, hook := range opResult.Hooks {
newState := newResourceState(hook.Kind, hook.Name, string(hook.Status), "", string(hook.Type), hook.Message)
key := newState.Key()
if prev, ok := resStates[key]; ok {
prev.Merge(newState)
} else {
resStates[key] = newState
}
}
for _, res := range opResult.Resources {
newState := newResourceState(res.Kind, res.Name, "", "", "", res.Message)
key := newState.Key()
if prev, ok := resStates[key]; ok {
prev.Merge(newState)
} else {
resStates[key] = newState
}
}
return resStates
}
func waitOnApplicationStatus(appClient application.ApplicationServiceClient, appName string, timeout uint, watchSync, watchHealth, watchOperation bool) (*argoappv1.Application, error) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
printFinalStatus := func() {
// get refreshed app before printing to show accurate sync/health status
app, err := appClient.Get(ctx, &application.ApplicationQuery{Name: &appName, Refresh: true})
errors.CheckError(err)
// refresh controls whether or not we refresh the app before printing the final status.
// We only want to do this when an operation is in progress, since operations are the only
// time when the sync status lags behind when an operation completes
refresh := false
fmt.Printf(printOpFmtStr, "Application:", appName)
printOperationResult(app.Status.OperationState)
printFinalStatus := func(app *argoappv1.Application) {
var err error
if refresh {
app, err = appClient.Get(context.Background(), &application.ApplicationQuery{Name: &appName, Refresh: true})
errors.CheckError(err)
}
fmt.Println()
fmt.Printf(printOpFmtStr, "Application:", app.Name)
if watchOperation {
printOperationResult(app.Status.OperationState)
}
if len(app.Status.ComparisonResult.Resources) > 0 {
fmt.Println()
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
printAppResources(w, app, true)
w := tabwriter.NewWriter(os.Stdout, 5, 0, 2, ' ', 0)
printAppResources(w, app, watchOperation)
_ = w.Flush()
}
}
@@ -918,89 +977,47 @@ func waitOnApplicationStatus(appClient application.ApplicationServiceClient, app
if timeout != 0 {
time.AfterFunc(time.Duration(timeout)*time.Second, func() {
cancel()
printFinalStatus()
})
}
// print the initial components to format the tabwriter columns
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
w := tabwriter.NewWriter(os.Stdout, 5, 0, 2, ' ', 0)
fmt.Fprintln(w, "KIND\tNAME\tSTATUS\tHEALTH\tHOOK\tOPERATIONMSG")
_ = w.Flush()
prevStates := make(map[string]*resourceState)
conditionallyPrintOutput := func(w io.Writer, newState *resourceState) {
stateKey := newState.Key()
if prevState, found := prevStates[stateKey]; found {
prevState.Update(newState)
} else {
prevStates[stateKey] = newState
}
}
printCompResults := func(compResult *argoappv1.ComparisonResult) {
if compResult != nil {
for _, res := range compResult.Resources {
obj, err := argoappv1.UnmarshalToUnstructured(res.TargetState)
errors.CheckError(err)
if obj == nil {
obj, err = argoappv1.UnmarshalToUnstructured(res.LiveState)
errors.CheckError(err)
}
newState := newResourceState(obj.GetKind(), obj.GetName(), string(res.Status), res.Health.Status, "", "")
conditionallyPrintOutput(w, newState)
}
}
}
printOpResults := func(opResult *argoappv1.SyncOperationResult) {
if opResult != nil {
if opResult.Hooks != nil {
for _, hook := range opResult.Hooks {
newState := newResourceState(hook.Kind, hook.Name, string(hook.Status), "", string(hook.Type), hook.Message)
conditionallyPrintOutput(w, newState)
}
}
if opResult.Resources != nil {
for _, res := range opResult.Resources {
newState := newResourceState(res.Kind, res.Name, string(res.Status), "", "", res.Message)
conditionallyPrintOutput(w, newState)
}
}
}
}
appEventCh := watchApp(ctx, appClient, appName)
var app *argoappv1.Application
for appEvent := range appEventCh {
app := appEvent.Application
printCompResults(&app.Status.ComparisonResult)
if opState := app.Status.OperationState; opState != nil {
printOpResults(opState.SyncResult)
printOpResults(opState.RollbackResult)
app = &appEvent.Application
if app.Operation != nil {
refresh = true
}
for _, v := range prevStates {
if v.Merge() {
fmt.Fprintln(w, v)
}
}
_ = w.Flush()
// consider skipped checks successful
synced := !watchSync || app.Status.ComparisonResult.Status == argoappv1.ComparisonStatusSynced
healthy := !watchHealth || app.Status.Health.Status == argoappv1.HealthStatusHealthy
operational := !watchOperations || appEvent.Application.Operation == nil
operational := !watchOperation || appEvent.Application.Operation == nil
if len(app.Status.GetErrorConditions()) == 0 && synced && healthy && operational {
log.Printf("App %q matches desired state", appName)
printFinalStatus()
return &app, nil
printFinalStatus(app)
return app, nil
}
}
newStates := calculateResourceStates(app)
for _, newState := range newStates {
var doPrint bool
stateKey := newState.Key()
if prevState, found := prevStates[stateKey]; found {
doPrint = prevState.Merge(newState)
} else {
prevStates[stateKey] = newState
doPrint = true
}
if doPrint {
fmt.Fprintln(w, prevStates[stateKey])
}
}
_ = w.Flush()
}
printFinalStatus(app)
return nil, fmt.Errorf("Timed out (%ds) waiting for app %q match desired state", timeout, appName)
}

View File

@@ -18,6 +18,7 @@ import (
"github.com/ghodss/yaml"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
)
@@ -70,7 +71,10 @@ func NewClusterAddCommand(clientOpts *argocdclient.ClientOptions, pathOpts *clie
errors.CheckError(err)
// Install RBAC resources for managing the cluster
managerBearerToken := common.InstallClusterManagerRBAC(conf)
clientset, err := kubernetes.NewForConfig(conf)
errors.CheckError(err)
managerBearerToken, err := common.InstallClusterManagerRBAC(clientset)
errors.CheckError(err)
conn, clusterIf := argocdclient.NewClientOrDie(clientOpts).NewClusterClientOrDie()
defer util.Close(conn)
@@ -202,9 +206,14 @@ func NewClusterRemoveCommand(clientOpts *argocdclient.ClientOptions) *cobra.Comm
}
conn, clusterIf := argocdclient.NewClientOrDie(clientOpts).NewClusterClientOrDie()
defer util.Close(conn)
// clientset, err := kubernetes.NewForConfig(conf)
// errors.CheckError(err)
for _, clusterName := range args {
// TODO(jessesuen): find the right context and remove manager RBAC artifacts
// common.UninstallClusterManagerRBAC(conf)
// err := common.UninstallClusterManagerRBAC(clientset)
// errors.CheckError(err)
_, err := clusterIf.Delete(context.Background(), &cluster.ClusterQuery{Server: clusterName})
errors.CheckError(err)
}

View File

@@ -1,17 +1,20 @@
package commands
import (
"context"
"fmt"
"os"
"strconv"
"strings"
"text/tabwriter"
"time"
timeutil "github.com/argoproj/pkg/time"
"github.com/dustin/go-humanize"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"strings"
"context"
"fmt"
"text/tabwriter"
"github.com/spf13/pflag"
"k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/argoproj/argo-cd/errors"
argocdclient "github.com/argoproj/argo-cd/pkg/apiclient"
@@ -19,8 +22,11 @@ import (
"github.com/argoproj/argo-cd/server/project"
"github.com/argoproj/argo-cd/util"
"github.com/argoproj/argo-cd/util/git"
"github.com/spf13/pflag"
"k8s.io/apimachinery/pkg/apis/meta/v1"
projectutil "github.com/argoproj/argo-cd/util/project"
)
const (
policyTemplate = "p, proj:%s:%s, applications, %s, %s/%s, %s"
)
type projectOpts struct {
@@ -29,6 +35,12 @@ type projectOpts struct {
sources []string
}
type policyOpts struct {
action string
permission string
object string
}
func (opts *projectOpts) GetDestinations() []v1alpha1.ApplicationDestination {
destinations := make([]v1alpha1.ApplicationDestination, 0)
for _, destStr := range opts.destinations {
@@ -55,6 +67,7 @@ func NewProjectCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
os.Exit(1)
},
}
command.AddCommand(NewProjectRoleCommand(clientOpts))
command.AddCommand(NewProjectCreateCommand(clientOpts))
command.AddCommand(NewProjectDeleteCommand(clientOpts))
command.AddCommand(NewProjectListCommand(clientOpts))
@@ -67,10 +80,341 @@ func NewProjectCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
}
func addProjFlags(command *cobra.Command, opts *projectOpts) {
command.Flags().StringVarP(&opts.description, "description", "", "desc", "Project description")
command.Flags().StringVarP(&opts.description, "description", "", "", "Project description")
command.Flags().StringArrayVarP(&opts.destinations, "dest", "d", []string{},
"Allowed deployment destination. Includes comma separated server url and namespace (e.g. https://192.168.99.100:8443,default")
command.Flags().StringArrayVarP(&opts.sources, "src", "s", []string{}, "Allowed deployment source repository URL.")
"Permitted destination server and namespace (e.g. https://192.168.99.100:8443,default)")
command.Flags().StringArrayVarP(&opts.sources, "src", "s", []string{}, "Permitted git source repository URL")
}
func addPolicyFlags(command *cobra.Command, opts *policyOpts) {
command.Flags().StringVarP(&opts.action, "action", "a", "", "Action to grant/deny permission on (e.g. get, create, list, update, delete)")
command.Flags().StringVarP(&opts.permission, "permission", "p", "allow", "Whether to allow or deny access to object with the action. This can only be 'allow' or 'deny'")
command.Flags().StringVarP(&opts.object, "object", "o", "", "Object within the project to grant/deny access. Use '*' for a wildcard. Will want access to '<project>/<object>'")
}
// NewProjectRoleCommand returns a new instance of the `argocd proj role` command
func NewProjectRoleCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
roleCommand := &cobra.Command{
Use: "role",
Short: "Manage a project's roles",
Run: func(c *cobra.Command, args []string) {
c.HelpFunc()(c, args)
os.Exit(1)
},
}
roleCommand.AddCommand(NewProjectRoleListCommand(clientOpts))
roleCommand.AddCommand(NewProjectRoleGetCommand(clientOpts))
roleCommand.AddCommand(NewProjectRoleCreateCommand(clientOpts))
roleCommand.AddCommand(NewProjectRoleDeleteCommand(clientOpts))
roleCommand.AddCommand(NewProjectRoleCreateTokenCommand(clientOpts))
roleCommand.AddCommand(NewProjectRoleDeleteTokenCommand(clientOpts))
roleCommand.AddCommand(NewProjectRoleAddPolicyCommand(clientOpts))
roleCommand.AddCommand(NewProjectRoleRemovePolicyCommand(clientOpts))
return roleCommand
}
// NewProjectRoleAddPolicyCommand returns a new instance of an `argocd proj role add-policy` command
func NewProjectRoleAddPolicyCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
var (
opts policyOpts
)
var command = &cobra.Command{
Use: "add-policy PROJECT ROLE-NAME",
Short: "Add a policy to a project role",
Run: func(c *cobra.Command, args []string) {
if len(args) != 2 {
c.HelpFunc()(c, args)
os.Exit(1)
}
if len(opts.action) <= 0 {
log.Fatal("Action needs to longer than 0 characters")
}
if len(opts.object) <= 0 {
log.Fatal("Objects needs to longer than 0 characters")
}
projName := args[0]
roleName := args[1]
conn, projIf := argocdclient.NewClientOrDie(clientOpts).NewProjectClientOrDie()
defer util.Close(conn)
proj, err := projIf.Get(context.Background(), &project.ProjectQuery{Name: projName})
errors.CheckError(err)
roleIndex, err := projectutil.GetRoleIndexByName(proj, roleName)
if err != nil {
log.Fatal(err)
}
role := proj.Spec.Roles[roleIndex]
policy := fmt.Sprintf(policyTemplate, proj.Name, role.Name, opts.action, proj.Name, opts.object, opts.permission)
proj.Spec.Roles[roleIndex].Policies = append(role.Policies, policy)
_, err = projIf.Update(context.Background(), &project.ProjectUpdateRequest{Project: proj})
errors.CheckError(err)
},
}
addPolicyFlags(command, &opts)
return command
}
// NewProjectRoleRemovePolicyCommand returns a new instance of an `argocd proj role remove-policy` command
func NewProjectRoleRemovePolicyCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
var (
opts policyOpts
)
var command = &cobra.Command{
Use: "remove-policy PROJECT ROLE-NAME",
Short: "Remove a policy from a role within a project",
Run: func(c *cobra.Command, args []string) {
if len(args) != 2 {
c.HelpFunc()(c, args)
os.Exit(1)
}
if opts.permission != "allow" && opts.permission != "deny" {
log.Fatal("Permission flag can only have the values 'allow' or 'deny'")
}
if len(opts.action) <= 0 {
log.Fatal("Action needs to longer than 0 characters")
}
if len(opts.object) <= 0 {
log.Fatal("Objects needs to longer than 0 characters")
}
projName := args[0]
roleName := args[1]
conn, projIf := argocdclient.NewClientOrDie(clientOpts).NewProjectClientOrDie()
defer util.Close(conn)
proj, err := projIf.Get(context.Background(), &project.ProjectQuery{Name: projName})
errors.CheckError(err)
roleIndex, err := projectutil.GetRoleIndexByName(proj, roleName)
if err != nil {
log.Fatal(err)
}
role := proj.Spec.Roles[roleIndex]
policyToRemove := fmt.Sprintf(policyTemplate, proj.Name, role.Name, opts.action, proj.Name, opts.object, opts.permission)
duplicateIndex := -1
for i, policy := range role.Policies {
if policy == policyToRemove {
duplicateIndex = i
break
}
}
if duplicateIndex < 0 {
return
}
role.Policies[duplicateIndex] = role.Policies[len(role.Policies)-1]
proj.Spec.Roles[roleIndex].Policies = role.Policies[:len(role.Policies)-1]
_, err = projIf.Update(context.Background(), &project.ProjectUpdateRequest{Project: proj})
errors.CheckError(err)
},
}
addPolicyFlags(command, &opts)
return command
}
// NewProjectRoleCreateCommand returns a new instance of an `argocd proj role create` command
func NewProjectRoleCreateCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
var (
description string
)
var command = &cobra.Command{
Use: "create PROJECT ROLE-NAME",
Short: "Create a project role",
Run: func(c *cobra.Command, args []string) {
if len(args) != 2 {
c.HelpFunc()(c, args)
os.Exit(1)
}
projName := args[0]
roleName := args[1]
conn, projIf := argocdclient.NewClientOrDie(clientOpts).NewProjectClientOrDie()
defer util.Close(conn)
proj, err := projIf.Get(context.Background(), &project.ProjectQuery{Name: projName})
errors.CheckError(err)
_, err = projectutil.GetRoleIndexByName(proj, roleName)
if err == nil {
return
}
proj.Spec.Roles = append(proj.Spec.Roles, v1alpha1.ProjectRole{Name: roleName, Description: description})
_, err = projIf.Update(context.Background(), &project.ProjectUpdateRequest{Project: proj})
errors.CheckError(err)
},
}
command.Flags().StringVarP(&description, "description", "", "", "Project description")
return command
}
// NewProjectRoleDeleteCommand returns a new instance of an `argocd proj role delete` command
func NewProjectRoleDeleteCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
var command = &cobra.Command{
Use: "delete PROJECT ROLE-NAME",
Short: "Delete a project role",
Run: func(c *cobra.Command, args []string) {
if len(args) != 2 {
c.HelpFunc()(c, args)
os.Exit(1)
}
projName := args[0]
roleName := args[1]
conn, projIf := argocdclient.NewClientOrDie(clientOpts).NewProjectClientOrDie()
defer util.Close(conn)
proj, err := projIf.Get(context.Background(), &project.ProjectQuery{Name: projName})
errors.CheckError(err)
index, err := projectutil.GetRoleIndexByName(proj, roleName)
if err != nil {
return
}
proj.Spec.Roles[index] = proj.Spec.Roles[len(proj.Spec.Roles)-1]
proj.Spec.Roles = proj.Spec.Roles[:len(proj.Spec.Roles)-1]
_, err = projIf.Update(context.Background(), &project.ProjectUpdateRequest{Project: proj})
errors.CheckError(err)
},
}
return command
}
// NewProjectRoleCreateTokenCommand returns a new instance of an `argocd proj role create-token` command
func NewProjectRoleCreateTokenCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
var (
expiresIn string
)
var command = &cobra.Command{
Use: "create-token PROJECT ROLE-NAME",
Short: "Create a project token",
Run: func(c *cobra.Command, args []string) {
if len(args) != 2 {
c.HelpFunc()(c, args)
os.Exit(1)
}
projName := args[0]
roleName := args[1]
conn, projIf := argocdclient.NewClientOrDie(clientOpts).NewProjectClientOrDie()
defer util.Close(conn)
duration, err := timeutil.ParseDuration(expiresIn)
errors.CheckError(err)
token, err := projIf.CreateToken(context.Background(), &project.ProjectTokenCreateRequest{Project: projName, Role: roleName, ExpiresIn: int64(duration.Seconds())})
errors.CheckError(err)
fmt.Println(token.Token)
},
}
command.Flags().StringVarP(&expiresIn, "expires-in", "e", "0s", "Duration before the token will expire. (Default: No expiration)")
return command
}
// NewProjectRoleDeleteTokenCommand returns a new instance of an `argocd proj role delete-token` command
func NewProjectRoleDeleteTokenCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
var command = &cobra.Command{
Use: "delete-token PROJECT ROLE-NAME ISSUED-AT",
Short: "Delete a project token",
Run: func(c *cobra.Command, args []string) {
if len(args) != 3 {
c.HelpFunc()(c, args)
os.Exit(1)
}
projName := args[0]
roleName := args[1]
issuedAt, err := strconv.ParseInt(args[2], 10, 64)
if err != nil {
log.Fatal(err)
}
conn, projIf := argocdclient.NewClientOrDie(clientOpts).NewProjectClientOrDie()
defer util.Close(conn)
_, err = projIf.DeleteToken(context.Background(), &project.ProjectTokenDeleteRequest{Project: projName, Role: roleName, Iat: issuedAt})
errors.CheckError(err)
},
}
return command
}
// NewProjectRoleListCommand returns a new instance of an `argocd proj roles list` command
func NewProjectRoleListCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
var command = &cobra.Command{
Use: "list PROJECT",
Short: "List all the roles in a project",
Run: func(c *cobra.Command, args []string) {
if len(args) != 1 {
c.HelpFunc()(c, args)
os.Exit(1)
}
projName := args[0]
conn, projIf := argocdclient.NewClientOrDie(clientOpts).NewProjectClientOrDie()
defer util.Close(conn)
project, err := projIf.Get(context.Background(), &project.ProjectQuery{Name: projName})
errors.CheckError(err)
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
fmt.Fprintf(w, "ROLE-NAME\tDESCRIPTION\n")
for _, role := range project.Spec.Roles {
fmt.Fprintf(w, "%s\t%s\n", role.Name, role.Description)
}
_ = w.Flush()
},
}
return command
}
// NewProjectRoleGetCommand returns a new instance of an `argocd proj roles get` command
func NewProjectRoleGetCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
var command = &cobra.Command{
Use: "get PROJECT ROLE-NAME",
Short: "Get the details of a specific role",
Run: func(c *cobra.Command, args []string) {
if len(args) != 2 {
c.HelpFunc()(c, args)
os.Exit(1)
}
projName := args[0]
roleName := args[1]
conn, projIf := argocdclient.NewClientOrDie(clientOpts).NewProjectClientOrDie()
defer util.Close(conn)
project, err := projIf.Get(context.Background(), &project.ProjectQuery{Name: projName})
errors.CheckError(err)
index, err := projectutil.GetRoleIndexByName(project, roleName)
errors.CheckError(err)
role := project.Spec.Roles[index]
printRoleFmtStr := "%-15s%s\n"
fmt.Printf(printRoleFmtStr, "Role Name:", roleName)
fmt.Printf(printRoleFmtStr, "Description:", role.Description)
fmt.Printf("Policies:\n")
fmt.Printf("%s\n", project.ProjectPoliciesString())
fmt.Printf("JWT Tokens:\n")
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
fmt.Fprintf(w, "ID\tISSUED-AT\tEXPIRES-AT\n")
for _, token := range role.JWTTokens {
expiresAt := "<none>"
if token.ExpiresAt > 0 {
expiresAt = humanizeTimestamp(token.ExpiresAt)
}
fmt.Fprintf(w, "%d\t%s\t%s\n", token.IssuedAt, humanizeTimestamp(token.IssuedAt), expiresAt)
}
_ = w.Flush()
},
}
return command
}
func humanizeTimestamp(epoch int64) string {
ts := time.Unix(epoch, 0)
return fmt.Sprintf("%s (%s)", ts.Format(time.RFC3339), humanize.Time(ts))
}
// NewProjectCreateCommand returns a new instance of an `argocd proj create` command
@@ -242,8 +586,13 @@ func NewProjectAddSourceCommand(clientOpts *argocdclient.ClientOptions) *cobra.C
errors.CheckError(err)
for _, item := range proj.Spec.SourceRepos {
if item == "*" && item == url {
log.Info("Wildcard source repository is already defined in project")
return
}
if item == git.NormalizeGitURL(url) {
log.Fatal("Specified source repository is already defined in project")
log.Info("Specified source repository is already defined in project")
return
}
}
proj.Spec.SourceRepos = append(proj.Spec.SourceRepos, url)
@@ -274,13 +623,17 @@ func NewProjectRemoveSourceCommand(clientOpts *argocdclient.ClientOptions) *cobr
index := -1
for i, item := range proj.Spec.SourceRepos {
if item == "*" && item == url {
index = i
break
}
if item == git.NormalizeGitURL(url) {
index = i
break
}
}
if index == -1 {
log.Fatal("Specified source repository does not exist in project")
log.Info("Specified source repository does not exist in project")
} else {
proj.Spec.SourceRepos = append(proj.Spec.SourceRepos[:index], proj.Spec.SourceRepos[index+1:]...)
_, err = projIf.Update(context.Background(), &project.ProjectUpdateRequest{Project: proj})

View File

@@ -102,4 +102,8 @@ var ArgoCDManagerPolicyRules = []rbacv1.PolicyRule{
Resources: []string{"*"},
Verbs: []string{"*"},
},
{
NonResourceURLs: []string{"*"},
Verbs: []string{"*"},
},
}

View File

@@ -4,7 +4,6 @@ import (
"fmt"
"time"
"github.com/argoproj/argo-cd/errors"
log "github.com/sirupsen/logrus"
apiv1 "k8s.io/api/core/v1"
rbacv1 "k8s.io/api/rbac/v1"
@@ -12,7 +11,6 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
)
// CreateServiceAccount creates a service account
@@ -20,7 +18,7 @@ func CreateServiceAccount(
clientset kubernetes.Interface,
serviceAccountName string,
namespace string,
) {
) error {
serviceAccount := apiv1.ServiceAccount{
TypeMeta: metav1.TypeMeta{
APIVersion: "v1",
@@ -34,12 +32,13 @@ func CreateServiceAccount(
_, err := clientset.CoreV1().ServiceAccounts(namespace).Create(&serviceAccount)
if err != nil {
if !apierr.IsAlreadyExists(err) {
log.Fatalf("Failed to create service account '%s': %v\n", serviceAccountName, err)
return fmt.Errorf("Failed to create service account %q: %v", serviceAccountName, err)
}
fmt.Printf("ServiceAccount '%s' already exists\n", serviceAccountName)
return
log.Infof("ServiceAccount %q already exists", serviceAccountName)
return nil
}
fmt.Printf("ServiceAccount '%s' created\n", serviceAccountName)
log.Infof("ServiceAccount %q created", serviceAccountName)
return nil
}
// CreateClusterRole creates a cluster role
@@ -47,7 +46,7 @@ func CreateClusterRole(
clientset kubernetes.Interface,
clusterRoleName string,
rules []rbacv1.PolicyRule,
) {
) error {
clusterRole := rbacv1.ClusterRole{
TypeMeta: metav1.TypeMeta{
APIVersion: "rbac.authorization.k8s.io/v1",
@@ -62,16 +61,17 @@ func CreateClusterRole(
_, err := crclient.Create(&clusterRole)
if err != nil {
if !apierr.IsAlreadyExists(err) {
log.Fatalf("Failed to create ClusterRole '%s': %v\n", clusterRoleName, err)
return fmt.Errorf("Failed to create ClusterRole %q: %v", clusterRoleName, err)
}
_, err = crclient.Update(&clusterRole)
if err != nil {
log.Fatalf("Failed to update ClusterRole '%s': %v\n", clusterRoleName, err)
return fmt.Errorf("Failed to update ClusterRole %q: %v", clusterRoleName, err)
}
fmt.Printf("ClusterRole '%s' updated\n", clusterRoleName)
log.Infof("ClusterRole %q updated", clusterRoleName)
} else {
fmt.Printf("ClusterRole '%s' created\n", clusterRoleName)
log.Infof("ClusterRole %q created", clusterRoleName)
}
return nil
}
// CreateClusterRoleBinding create a ClusterRoleBinding
@@ -81,7 +81,7 @@ func CreateClusterRoleBinding(
serviceAccountName,
clusterRoleName string,
namespace string,
) {
) error {
roleBinding := rbacv1.ClusterRoleBinding{
TypeMeta: metav1.TypeMeta{
APIVersion: "rbac.authorization.k8s.io/v1",
@@ -106,22 +106,34 @@ func CreateClusterRoleBinding(
_, err := clientset.RbacV1().ClusterRoleBindings().Create(&roleBinding)
if err != nil {
if !apierr.IsAlreadyExists(err) {
log.Fatalf("Failed to create ClusterRoleBinding %s: %v\n", clusterBindingRoleName, err)
return fmt.Errorf("Failed to create ClusterRoleBinding %s: %v", clusterBindingRoleName, err)
}
fmt.Printf("ClusterRoleBinding '%s' already exists\n", clusterBindingRoleName)
return
log.Infof("ClusterRoleBinding %q already exists", clusterBindingRoleName)
return nil
}
fmt.Printf("ClusterRoleBinding '%s' created, bound '%s' to '%s'\n", clusterBindingRoleName, serviceAccountName, clusterRoleName)
log.Infof("ClusterRoleBinding %q created, bound %q to %q", clusterBindingRoleName, serviceAccountName, clusterRoleName)
return nil
}
// InstallClusterManagerRBAC installs RBAC resources for a cluster manager to operate a cluster. Returns a token
func InstallClusterManagerRBAC(conf *rest.Config) string {
func InstallClusterManagerRBAC(clientset kubernetes.Interface) (string, error) {
const ns = "kube-system"
clientset, err := kubernetes.NewForConfig(conf)
errors.CheckError(err)
CreateServiceAccount(clientset, ArgoCDManagerServiceAccount, ns)
CreateClusterRole(clientset, ArgoCDManagerClusterRole, ArgoCDManagerPolicyRules)
CreateClusterRoleBinding(clientset, ArgoCDManagerClusterRoleBinding, ArgoCDManagerServiceAccount, ArgoCDManagerClusterRole, ns)
var err error
err = CreateServiceAccount(clientset, ArgoCDManagerServiceAccount, ns)
if err != nil {
return "", err
}
err = CreateClusterRole(clientset, ArgoCDManagerClusterRole, ArgoCDManagerPolicyRules)
if err != nil {
return "", err
}
err = CreateClusterRoleBinding(clientset, ArgoCDManagerClusterRoleBinding, ArgoCDManagerServiceAccount, ArgoCDManagerClusterRole, ns)
if err != nil {
return "", err
}
var serviceAccount *apiv1.ServiceAccount
var secretName string
@@ -137,52 +149,51 @@ func InstallClusterManagerRBAC(conf *rest.Config) string {
return true, nil
})
if err != nil {
log.Fatalf("Failed to wait for service account secret: %v", err)
return "", fmt.Errorf("Failed to wait for service account secret: %v", err)
}
secret, err := clientset.CoreV1().Secrets(ns).Get(secretName, metav1.GetOptions{})
if err != nil {
log.Fatalf("Failed to retrieve secret '%s': %v", secretName, err)
return "", fmt.Errorf("Failed to retrieve secret %q: %v", secretName, err)
}
token, ok := secret.Data["token"]
if !ok {
log.Fatalf("Secret '%s' for service account '%s' did not have a token", secretName, serviceAccount)
return "", fmt.Errorf("Secret %q for service account %q did not have a token", secretName, serviceAccount)
}
return string(token)
return string(token), nil
}
// UninstallClusterManagerRBAC removes RBAC resources for a cluster manager to operate a cluster
func UninstallClusterManagerRBAC(conf *rest.Config) {
clientset, err := kubernetes.NewForConfig(conf)
errors.CheckError(err)
UninstallRBAC(clientset, "kube-system", ArgoCDManagerClusterRoleBinding, ArgoCDManagerClusterRole, ArgoCDManagerServiceAccount)
func UninstallClusterManagerRBAC(clientset kubernetes.Interface) error {
return UninstallRBAC(clientset, "kube-system", ArgoCDManagerClusterRoleBinding, ArgoCDManagerClusterRole, ArgoCDManagerServiceAccount)
}
// UninstallRBAC uninstalls RBAC related resources for a binding, role, and service account
func UninstallRBAC(clientset kubernetes.Interface, namespace, bindingName, roleName, serviceAccount string) {
func UninstallRBAC(clientset kubernetes.Interface, namespace, bindingName, roleName, serviceAccount string) error {
if err := clientset.RbacV1().ClusterRoleBindings().Delete(bindingName, &metav1.DeleteOptions{}); err != nil {
if !apierr.IsNotFound(err) {
log.Fatalf("Failed to delete ClusterRoleBinding: %v\n", err)
return fmt.Errorf("Failed to delete ClusterRoleBinding: %v", err)
}
fmt.Printf("ClusterRoleBinding '%s' not found\n", bindingName)
log.Infof("ClusterRoleBinding %q not found", bindingName)
} else {
fmt.Printf("ClusterRoleBinding '%s' deleted\n", bindingName)
log.Infof("ClusterRoleBinding %q deleted", bindingName)
}
if err := clientset.RbacV1().ClusterRoles().Delete(roleName, &metav1.DeleteOptions{}); err != nil {
if !apierr.IsNotFound(err) {
log.Fatalf("Failed to delete ClusterRole: %v\n", err)
return fmt.Errorf("Failed to delete ClusterRole: %v", err)
}
fmt.Printf("ClusterRole '%s' not found\n", roleName)
log.Infof("ClusterRole %q not found", roleName)
} else {
fmt.Printf("ClusterRole '%s' deleted\n", roleName)
log.Infof("ClusterRole %q deleted", roleName)
}
if err := clientset.CoreV1().ServiceAccounts(namespace).Delete(serviceAccount, &metav1.DeleteOptions{}); err != nil {
if !apierr.IsNotFound(err) {
log.Fatalf("Failed to delete ServiceAccount: %v\n", err)
return fmt.Errorf("Failed to delete ServiceAccount: %v", err)
}
fmt.Printf("ServiceAccount '%s' in namespace '%s' not found\n", serviceAccount, namespace)
log.Infof("ServiceAccount %q in namespace %q not found", serviceAccount, namespace)
} else {
fmt.Printf("ServiceAccount '%s' deleted\n", serviceAccount)
log.Infof("ServiceAccount %q deleted", serviceAccount)
}
return nil
}

View File

@@ -204,7 +204,7 @@ func retryUntilSucceed(action func() error, desc string, ctx context.Context, ti
log.Infof("Stop retrying %s", desc)
return
} else {
log.Warnf("Failed to %s: %v, retrying in %v", desc, err, timeout)
log.Warnf("Failed to %s: %+v, retrying in %v", desc, err, timeout)
time.Sleep(timeout)
}
}
@@ -487,13 +487,14 @@ func (ctrl *ApplicationController) processAppRefreshQueueItem() (processNext boo
// Returns true if application never been compared, has changed or comparison result has expired.
func (ctrl *ApplicationController) needRefreshAppStatus(app *appv1.Application, statusRefreshTimeout time.Duration) bool {
var reason string
expired := app.Status.ComparisonResult.ComparedAt.Add(statusRefreshTimeout).Before(time.Now().UTC())
if ctrl.isRefreshForced(app.Name) {
reason = "force refresh"
} else if app.Status.ComparisonResult.Status == appv1.ComparisonStatusUnknown {
} else if app.Status.ComparisonResult.Status == appv1.ComparisonStatusUnknown && expired {
reason = "comparison status unknown"
} else if !app.Spec.Source.Equals(app.Status.ComparisonResult.ComparedTo) {
reason = "spec.source differs"
} else if app.Status.ComparisonResult.ComparedAt.Add(statusRefreshTimeout).Before(time.Now().UTC()) {
} else if expired {
reason = fmt.Sprintf("comparison expired. comparedAt: %v, expiry: %v", app.Status.ComparisonResult.ComparedAt, statusRefreshTimeout)
}
if reason != "" {

View File

@@ -7,6 +7,7 @@ import (
"time"
log "github.com/sirupsen/logrus"
apierr "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/types"
@@ -121,6 +122,7 @@ func (s *ksonnetAppStateManager) getTargetObjs(app *v1alpha1.Application, revisi
ComponentParameterOverrides: mfReqOverrides,
AppLabel: app.Name,
ValueFiles: app.Spec.Source.ValuesFiles,
Namespace: app.Spec.Destination.Namespace,
})
if err != nil {
return nil, nil, err
@@ -188,11 +190,15 @@ func (s *ksonnetAppStateManager) getLiveObjs(app *v1alpha1.Application, targetOb
}
apiResource, err := kubeutil.ServerResourceForGroupVersionKind(disco, gvk)
if err != nil {
return nil, nil, err
}
liveObj, err = kubeutil.GetLiveResource(dclient, targetObj, apiResource, app.Spec.Destination.Namespace)
if err != nil {
return nil, nil, err
if !apierr.IsNotFound(err) {
return nil, nil, err
}
// If we get here, the app is comprised of a custom resource which has yet to be registered
} else {
liveObj, err = kubeutil.GetLiveResource(dclient, targetObj, apiResource, app.Spec.Destination.Namespace)
if err != nil {
return nil, nil, err
}
}
}
controlledLiveObj[i] = liveObj

52
controller/state_test.go Normal file
View File

@@ -0,0 +1,52 @@
package controller
import (
"testing"
"github.com/ghodss/yaml"
"github.com/stretchr/testify/assert"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
var podManifest = []byte(`
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- image: nginx:1.7.9
name: nginx
resources:
requests:
cpu: 0.2
`)
func newPod() *unstructured.Unstructured {
var un unstructured.Unstructured
err := yaml.Unmarshal(podManifest, &un)
if err != nil {
panic(err)
}
return &un
}
func TestIsHook(t *testing.T) {
pod := newPod()
assert.False(t, isHook(pod))
pod.SetAnnotations(map[string]string{"helm.sh/hook": "post-install"})
assert.True(t, isHook(pod))
pod = newPod()
pod.SetAnnotations(map[string]string{"argocd.argoproj.io/hook": "PreSync"})
assert.True(t, isHook(pod))
pod = newPod()
pod.SetAnnotations(map[string]string{"argocd.argoproj.io/hook": "Skip"})
assert.False(t, isHook(pod))
pod = newPod()
pod.SetAnnotations(map[string]string{"argocd.argoproj.io/hook": "Unknown"})
assert.False(t, isHook(pod))
}

View File

@@ -627,7 +627,7 @@ func isHelmHook(obj *unstructured.Unstructured) bool {
if annotations == nil {
return false
}
_, ok := annotations[common.AnnotationHook]
_, ok := annotations[common.AnnotationHelmHook]
return ok
}

View File

@@ -50,3 +50,29 @@ spec:
server: https://kubernetes.default.svc
namespace: default
```
### AppProject CRD (Custom Resource Definition)
The AppProject CRD is the Kubernetes resource object representing a grouping of applications. It is defined by three key pieces of information:
* `sourceRepos` reference to the reposities that applications within the project can pull manifests from.
* `destinations` reference to clusters and namespaces that applications within the project can deploy into.
* `roles` list of entities with defintions of their access to resources within the project.
An example spec is as follows:
```
spec:
description: Description of the project
destinations:
- namespace: default
server: https://kubernetes.default.svc
roles:
- description: Description of the role
jwtTokens:
- iat: 1535390316
name: role-name
policies:
- p, proj:proj-name:role-name, applications, get, proj-name/*, allow
- p, proj:proj-name:role-name, applications, sync, proj-name/*, deny
sourceRepos:
- https://github.com/argoproj/argocd-example-apps.git
```

View File

@@ -9,7 +9,7 @@ An example guestbook application is provided to demonstrate how ArgoCD works.
## 1. Install ArgoCD
```
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/v0.7.1/manifests/install.yaml
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/v0.7.2/manifests/install.yaml
```
This will create a new namespace, `argocd`, where ArgoCD services and application resources will live.
@@ -31,7 +31,7 @@ brew install argoproj/tap/argocd
On Linux:
```
curl -sSL -o /usr/local/bin/argocd https://github.com/argoproj/argo-cd/releases/download/v0.7.1/argocd-linux-amd64
curl -sSL -o /usr/local/bin/argocd https://github.com/argoproj/argo-cd/releases/download/v0.7.2/argocd-linux-amd64
chmod +x /usr/local/bin/argocd
```

View File

@@ -2,13 +2,17 @@
## Overview
The feature RBAC allows restricting access to ArgoCD resources. ArgoCD does not have own user management system and has only one built-in user `admin`. The `admin` user is a
superuser and it has full access. RBAC requires configuring [SSO](./sso.md) integration. Once [SSO](./sso.md) is connected you can define RBAC roles and map roles to groups.
The RBAC feature enables restriction of access to ArgoCD resources. ArgoCD does not have its own
user management system and has only one built-in user `admin`. The `admin` user is a superuser and
it has unrestricted access to the system. RBAC requires [SSO configuration](./sso.md). Once SSO is
configured, additional RBAC roles can be defined, and SSO groups can man be mapped to roles.
## Configure RBAC
RBAC configuration allows defining roles and groups. ArgoCD has two pre-defined roles: role `role:readonly` which provides read-only access to all resources and role `role:admin`
which provides full access. Role definitions are available in [builtin-policy.csv](../util/rbac/builtin-policy.csv) file.
RBAC configuration allows defining roles and groups. ArgoCD has two pre-defined roles:
* `role:readonly` - read-only access to all resources
* `role:admin` - unrestricted access to all resources
These role definitions can be seen in [builtin-policy.csv](../util/rbac/builtin-policy.csv)
Additional roles and groups can be configured in `argocd-rbac-cm` ConfigMap. The example below custom role `org-admin`. The role is assigned to any user which belongs to
`your-github-org:your-team` group. All other users get `role:readonly` and cannot modify ArgoCD settings.
@@ -20,16 +24,16 @@ apiVersion: v1
data:
policy.default: role:readonly
policy.csv: |
p, role:org-admin, applications, *, */*
p, role:org-admin, applications/*, *, */*
p, role:org-admin, applications, *, */*, allow
p, role:org-admin, applications/*, *, */*, allow
p, role:org-admin, clusters, get, *
p, role:org-admin, repositories, get, *
p, role:org-admin, repositories/apps, get, *
p, role:org-admin, clusters, get, *, allow
p, role:org-admin, repositories, get, *, allow
p, role:org-admin, repositories/apps, get, *, allow
p, role:org-admin, repositories, create, *
p, role:org-admin, repositories, update, *
p, role:org-admin, repositories, delete, *
p, role:org-admin, repositories, create, *, allow
p, role:org-admin, repositories, update, *, allow
p, role:org-admin, repositories, delete, *, allow
g, your-github-org:your-team, role:org-admin
kind: ConfigMap
@@ -79,19 +83,19 @@ apiVersion: v1
data:
policy.default: ""
policy.csv: |
p, role:team1-admin, applications, *, default/*
p, role:team1-admin, applications/*, *, default/*
p, role:team1-admin, applications, *, default/*, allow
p, role:team1-admin, applications/*, *, default/*, allow
p, role:team1-admin, applications, *, myproject/*
p, role:team1-admin, applications/*, *, myproject/*
p, role:team1-admin, applications, *, myproject/*, allow
p, role:team1-admin, applications/*, *, myproject/*, allow
p, role:org-admin, clusters, get, *
p, role:org-admin, repositories, get, *
p, role:org-admin, repositories/apps, get, *
p, role:org-admin, clusters, get, *, allow
p, role:org-admin, repositories, get, *, allow
p, role:org-admin, repositories/apps, get, *, allow
p, role:org-admin, repositories, create, *
p, role:org-admin, repositories, update, *
p, role:org-admin, repositories, delete, *
p, role:org-admin, repositories, create, *, allow
p, role:org-admin, repositories, update, *, allow
p, role:org-admin, repositories, delete, *, allow
g, role:team1-admin, org-admin
g, role:team2-admin, org-admin
@@ -101,3 +105,58 @@ kind: ConfigMap
metadata:
name: argocd-rbac-cm
```
## Project Roles
Projects include a feature called roles that allow users to define access to project's applications. A project can have multiple roles, and those roles can have different access granted to them. These permissions are called policies, and they are stored within the role as a list of casbin strings. A role's policy can only grant access to that role and are limited to applications within the role's project. However, the policies have an option for granting wildcard access to any application within a project.
In order to create roles in a project and add policies to a role, a user will need permission to update a project. The following commands can be used to manage a role.
```
argoproj proj role list
argoproj proj role get
argoproj proj role create
argoproj proj role delete
argoproj proj role add-policy
argoproj proj role remove-policy
```
Project roles can not be used unless a user creates a entity that is associated with that project role. ArgoCD supports creating JWT tokens with a role associated with it. Since the JWT token is associated with a role's policies, any changes to the role's policies will immediately take effect for that JWT token.
A user will need permission to update a project in order to create a JWT token for a role, and they can use the following commands to manage the JWT tokens.
```
argoproj proj role create-token
argoproj proj role delete-token
```
Since the JWT tokens aren't stored in ArgoCD, they can only be retrieved when they are created. A user can leverage them in the cli by either passing them in using the `--auth-token` flag or setting the ARGOCD_AUTH_TOKEN environment variable. The JWT tokens can be used until they expire or are revoked. The JWT tokens can created with or without an expiration, but the default on the cli is creates them without an expirations date. Even if a token has not expired, it can not be used if the token has been revoke.
Below is an example of leveraging a JWT token to access the guestbook application. It makes the assumption that the user already has a project named myproject and an application called guestbook-default.
```
PROJ=myproject
APP=guestbook-default
ROLE=get-role
argocd proj role create $PROJ $ROLE
argocd proj role create-token $PROJ $ROLE -e 10m
JWT=<value from command above>
argocd proj role list $PROJ
argocd proj role get $PROJ $ROLE
#This command will fail because the JWT Token associated with the project role does not have a policy to allow access to the application
argocd app get $APP --auth-token $JWT
# Adding a policy to grant access to the application for the new role
argocd proj role add-policy $PROJ $ROLE --action get --permission allow --object $APP
argocd app get $PROJ-$ROLE --auth-token $JWT
# Removing the policy we added and adding one with a wildcard.
argocd proj role remove-policy $PROJ $TOKEN -a get -o $PROJ-$TOKEN
argocd proj role remove-policy $PROJ $TOKEN -a get -o '*'
# The wildcard allows us to access the application due to the wildcard.
argocd app get $PROJ-$TOKEN --auth-token $JWT
argocd proj role get $PROJ
argocd proj role get $PROJ $ROLE
# Revoking the JWT token
argocd proj role delete-token $PROJ $ROLE <id field from the last command>
# This will fail since the JWT Token was deleted for the project role.
argocd app get $APP --auth-token $JWT
```

View File

@@ -35,7 +35,7 @@ kubectl edit configmap argocd-cm
[GitHub connector](https://github.com/coreos/dex/blob/master/Documentation/connectors/github.md)
documentation for explanation of the fields. A minimal config should populate the clientID,
clientSecret generated in Step 1.
* You will very likely want to restrict logins to one ore more GitHub organization. In the
* You will very likely want to restrict logins to one or more GitHub organization. In the
`connectors.config.orgs` list, add one or more GitHub organizations. Any member of the org will
then be able to login to ArgoCD to perform management tasks.

View File

@@ -117,6 +117,6 @@ clean_swagger() {
/usr/bin/find "${SWAGGER_ROOT}" -name '*.swagger.json' -delete
}
collect_swagger server 15
collect_swagger server 21
clean_swagger server
clean_swagger reposerver

View File

@@ -1,168 +0,0 @@
package main
import (
"context"
"fmt"
"hash/fnv"
"log"
"os"
"strings"
argocdclient "github.com/argoproj/argo-cd/pkg/apiclient"
"github.com/argoproj/argo-cd/server/repository"
"github.com/argoproj/argo-cd/util"
"github.com/argoproj/argo-cd/util/git"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
)
// origRepoURLToSecretName hashes repo URL to the secret name using a formula.
// Part of the original repo name is incorporated for debugging purposes
func origRepoURLToSecretName(repo string) string {
repo = git.NormalizeGitURL(repo)
h := fnv.New32a()
_, _ = h.Write([]byte(repo))
parts := strings.Split(strings.TrimSuffix(repo, ".git"), "/")
return fmt.Sprintf("repo-%s-%v", strings.ToLower(parts[len(parts)-1]), h.Sum32())
}
// repoURLToSecretName hashes repo URL to the secret name using a formula.
// Part of the original repo name is incorporated for debugging purposes
func repoURLToSecretName(repo string) string {
repo = strings.ToLower(git.NormalizeGitURL(repo))
h := fnv.New32a()
_, _ = h.Write([]byte(repo))
parts := strings.Split(strings.TrimSuffix(repo, ".git"), "/")
return fmt.Sprintf("repo-%s-%v", parts[len(parts)-1], h.Sum32())
}
// RenameSecret renames a Kubernetes secret in a given namespace.
func renameSecret(namespace, oldName, newName string) {
loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
loadingRules.DefaultClientConfig = &clientcmd.DefaultClientConfig
overrides := clientcmd.ConfigOverrides{}
clientConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, &overrides)
log.Printf("Renaming secret %q to %q in namespace %q\n", oldName, newName, namespace)
config, err := clientConfig.ClientConfig()
if err != nil {
log.Println("Could not retrieve client config: ", err)
return
}
kubeclientset := kubernetes.NewForConfigOrDie(config)
repoSecret, err := kubeclientset.CoreV1().Secrets(namespace).Get(oldName, metav1.GetOptions{})
if err != nil {
log.Println("Could not retrieve old secret: ", err)
return
}
repoSecret.ObjectMeta.Name = newName
repoSecret.ObjectMeta.ResourceVersion = ""
repoSecret, err = kubeclientset.CoreV1().Secrets(namespace).Create(repoSecret)
if err != nil {
log.Println("Could not create new secret: ", err)
return
}
err = kubeclientset.CoreV1().Secrets(namespace).Delete(oldName, &metav1.DeleteOptions{})
if err != nil {
log.Println("Could not remove old secret: ", err)
}
}
// RenameRepositorySecrets ensures that repository secrets use the new naming format.
func renameRepositorySecrets(clientOpts argocdclient.ClientOptions, namespace string) {
conn, repoIf := argocdclient.NewClientOrDie(&clientOpts).NewRepoClientOrDie()
defer util.Close(conn)
repos, err := repoIf.List(context.Background(), &repository.RepoQuery{})
if err != nil {
log.Println("An error occurred, so skipping secret renaming: ", err)
return
}
log.Println("Renaming repository secrets...")
for _, repo := range repos.Items {
oldSecretName := origRepoURLToSecretName(repo.Repo)
newSecretName := repoURLToSecretName(repo.Repo)
if oldSecretName != newSecretName {
log.Printf("Repo %q had its secret name change, so updating\n", repo.Repo)
renameSecret(namespace, oldSecretName, newSecretName)
}
}
}
/*
// PopulateAppDestinations ensures that apps have a Server and Namespace set explicitly.
func populateAppDestinations(clientOpts argocdclient.ClientOptions) {
conn, appIf := argocdclient.NewClientOrDie(&clientOpts).NewApplicationClientOrDie()
defer util.Close(conn)
apps, err := appIf.List(context.Background(), &application.ApplicationQuery{})
if err != nil {
log.Println("An error occurred, so skipping destination population: ", err)
return
}
log.Println("Populating app Destination fields")
for _, app := range apps.Items {
changed := false
log.Printf("Ensuring destination field is populated on app %q\n", app.ObjectMeta.Name)
if app.Spec.Destination.Server == "" {
if app.Status.ComparisonResult.Status == appv1.ComparisonStatusUnknown || app.Status.ComparisonResult.Status == appv1.ComparisonStatusError {
log.Printf("App %q was missing Destination.Server, but could not fill it in: %s", app.ObjectMeta.Name, app.Status.ComparisonResult.Status)
} else {
log.Printf("App %q was missing Destination.Server, so setting to %q\n", app.ObjectMeta.Name, app.Status.ComparisonResult.Server)
app.Spec.Destination.Server = app.Status.ComparisonResult.Server
changed = true
}
}
if app.Spec.Destination.Namespace == "" {
if app.Status.ComparisonResult.Status == appv1.ComparisonStatusUnknown || app.Status.ComparisonResult.Status == appv1.ComparisonStatusError {
log.Printf("App %q was missing Destination.Namespace, but could not fill it in: %s", app.ObjectMeta.Name, app.Status.ComparisonResult.Status)
} else {
log.Printf("App %q was missing Destination.Namespace, so setting to %q\n", app.ObjectMeta.Name, app.Status.ComparisonResult.Namespace)
app.Spec.Destination.Namespace = app.Status.ComparisonResult.Namespace
changed = true
}
}
if changed {
_, err = appIf.UpdateSpec(context.Background(), &application.ApplicationSpecRequest{
AppName: app.Name,
Spec: &app.Spec,
})
if err != nil {
log.Println("An error occurred (but continuing anyway): ", err)
}
}
}
}
*/
func main() {
if len(os.Args) < 3 {
log.Fatalf("USAGE: %s SERVER NAMESPACE\n", os.Args[0])
}
server, namespace := os.Args[1], os.Args[2]
log.Printf("Using argocd server %q and namespace %q\n", server, namespace)
isLocalhost := false
switch {
case strings.HasPrefix(server, "localhost:"):
isLocalhost = true
case strings.HasPrefix(server, "127.0.0.1:"):
isLocalhost = true
}
clientOpts := argocdclient.ClientOptions{
ServerAddr: server,
Insecure: true,
PlainText: isLocalhost,
}
renameRepositorySecrets(clientOpts, namespace)
//populateAppDestinations(clientOpts)
}

View File

@@ -3,12 +3,23 @@ apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-cm
data:
# See https://github.com/argoproj/argo-cd/blob/master/docs/sso.md#2-configure-argocd-for-sso
# for more details about how to setup data config needed for sso
#data:
# ArgoCD's externally facing URL
# url: https://argo-cd-demo.argoproj.io
# URL is the external URL of ArgoCD
#url:
# A dex connector configuration
#dex.config:
# A dex connector configuration.
# Visit https://github.com/argoproj/argo-cd/blob/master/docs/sso.md#2-configure-argocd-for-sso
# for instructions on configuring SSO.
# dex.config: |
# connectors:
# # GitHub example
# - type: github
# id: github
# name: GitHub
# config:
# clientID: aabbccddeeff00112233
# clientSecret: $dex.github.clientSecret
# orgs:
# - name: your-github-org
# teams:
# - red-team

View File

@@ -1,24 +1,26 @@
---
# NOTE: the values in this secret will be populated by the initial startup of the API
# NOTE: some values in this secret will be populated by the initial startup of the API server
apiVersion: v1
kind: Secret
metadata:
name: argocd-secret
type: Opaque
# bcrypt hash of the admin password
#admin.password:
# random server signature key for session validation
#server.secretkey:
#data:
# TLS certificate and private key for API server
#server.crt:
#server.key:
# server.crt:
# server.key:
# The following keys hold the shared secret for authenticating GitHub/GitLab/BitBucket webhook
# events. To enable webhooks, configure one or more of the following keys with the shared git
# provider webhook secret. The payload URL configured in the git provider should use the
# /api/webhook endpoint of your ArgoCD instance (e.g. https://argocd.example.com/api/webhook)
#github.webhook.secret:
#gitlab.webhook.secret:
#bitbucket.webhook.uuid:
# github.webhook.secret:
# gitlab.webhook.secret:
# bitbucket.webhook.uuid:
# bcrypt hash of the admin password (autogenerated on initial startup).
# To reset a forgotten password, delete this key and restart the argocd-server
# admin.password:
# random server signature key for session validation (autogenerated on initial startup)
# server.secretkey:

View File

@@ -3,24 +3,14 @@ apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-rbac-cm
data:
# policy.csv holds the CSV file policy file which contains additional policy and role definitions.
# ArgoCD defines two built-in roles:
# * role:readonly - readonly access to all objects
# * role:admin - admin access to all objects
# The built-in policy can be seen under util/rbac/builtin-policy.csv
#policy.csv: ""
#data:
# An RBAC policy .csv file containing additional policy and role definitions.
# See https://github.com/argoproj/argo-cd/blob/master/docs/rbac.md on how to write RBAC policies.
# policy.csv: |
# # Give all members of "my-org:team-alpha" the ability to sync apps in "my-project"
# p, my-org:team-alpha, applications, sync, my-project/*, allow
# # Make all members of "my-org:team-beta" admins
# g, my-org:team-beta, role:admin
# There are two policy formats:
# 1. Applications (which belong to a project):
# p, <user/group>, <resource>, <action>, <project>/<object>
# 2. All other resources:
# p, <user/group>, <resource>, <action>, <object>
# For example, the following rule gives all members of 'my-org:team1' the ability to sync
# applications in the project named: my-project
# p, my-org:team1, applications, sync, my-project/*
# policy.default holds the default policy which will ArgoCD will fall back to, when authorizing
# a user for API requests
policy.default: role:readonly
# The default role ArgoCD will fall back to, when authorizing API requests
# policy.default: role:readonly

View File

@@ -14,6 +14,6 @@ spec:
spec:
containers:
- command: [/argocd-application-controller, --repo-server, 'argocd-repo-server:8081']
image: argoproj/argocd-application-controller:v0.7.1
image: argoproj/argocd-application-controller:v0.8.2
name: application-controller
serviceAccountName: application-controller

View File

@@ -15,24 +15,30 @@ spec:
serviceAccountName: argocd-server
initContainers:
- name: copyutil
image: argoproj/argocd-server:v0.7.1
image: argoproj/argocd-server:v0.8.2
command: [cp, /argocd-util, /shared]
volumeMounts:
- mountPath: /shared
name: static-files
- name: ui
image: argoproj/argocd-ui:v0.7.1
image: argoproj/argocd-ui:v0.8.2
command: [cp, -r, /app, /shared]
volumeMounts:
- mountPath: /shared
name: static-files
containers:
- name: argocd-server
image: argoproj/argocd-server:v0.7.1
image: argoproj/argocd-server:v0.8.2
command: [/argocd-server, --staticassets, /shared/app, --repo-server, 'argocd-repo-server:8081']
volumeMounts:
- mountPath: /shared
name: static-files
readinessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 3
periodSeconds: 30
- name: dex
image: quay.io/coreos/dex:v2.10.0
command: [/shared/argocd-util, rundex]

View File

@@ -12,9 +12,15 @@ spec:
labels:
app: argocd-repo-server
spec:
automountServiceAccountToken: false
containers:
- name: argocd-repo-server
image: argoproj/argocd-repo-server:v0.7.1
image: argoproj/argocd-repo-server:v0.8.2
command: [/argocd-repo-server]
ports:
- containerPort: 8081
- containerPort: 8081
readinessProbe:
tcpSocket:
port: 8081
initialDelaySeconds: 5
periodSeconds: 10

View File

@@ -33,65 +33,68 @@ apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-cm
data:
# See https://github.com/argoproj/argo-cd/blob/master/docs/sso.md#2-configure-argocd-for-sso
# for more details about how to setup data config needed for sso
#data:
# ArgoCD's externally facing URL
# url: https://argo-cd-demo.argoproj.io
# URL is the external URL of ArgoCD
#url:
# A dex connector configuration
#dex.config:
# A dex connector configuration.
# Visit https://github.com/argoproj/argo-cd/blob/master/docs/sso.md#2-configure-argocd-for-sso
# for instructions on configuring SSO.
# dex.config: |
# connectors:
# # GitHub example
# - type: github
# id: github
# name: GitHub
# config:
# clientID: aabbccddeeff00112233
# clientSecret: $dex.github.clientSecret
# orgs:
# - name: your-github-org
# teams:
# - red-team
---
# NOTE: the values in this secret will be populated by the initial startup of the API
# NOTE: some values in this secret will be populated by the initial startup of the API server
apiVersion: v1
kind: Secret
metadata:
name: argocd-secret
type: Opaque
# bcrypt hash of the admin password
#admin.password:
# random server signature key for session validation
#server.secretkey:
#data:
# TLS certificate and private key for API server
#server.crt:
#server.key:
# server.crt:
# server.key:
# The following keys hold the shared secret for authenticating GitHub/GitLab/BitBucket webhook
# events. To enable webhooks, configure one or more of the following keys with the shared git
# provider webhook secret. The payload URL configured in the git provider should use the
# /api/webhook endpoint of your ArgoCD instance (e.g. https://argocd.example.com/api/webhook)
#github.webhook.secret:
#gitlab.webhook.secret:
#bitbucket.webhook.uuid:
# github.webhook.secret:
# gitlab.webhook.secret:
# bitbucket.webhook.uuid:
# bcrypt hash of the admin password (autogenerated on initial startup).
# To reset a forgotten password, delete this key and restart the argocd-server
# admin.password:
# random server signature key for session validation (autogenerated on initial startup)
# server.secretkey:
---
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-rbac-cm
data:
# policy.csv holds the CSV file policy file which contains additional policy and role definitions.
# ArgoCD defines two built-in roles:
# * role:readonly - readonly access to all objects
# * role:admin - admin access to all objects
# The built-in policy can be seen under util/rbac/builtin-policy.csv
#policy.csv: ""
#data:
# An RBAC policy .csv file containing additional policy and role definitions.
# See https://github.com/argoproj/argo-cd/blob/master/docs/rbac.md on how to write RBAC policies.
# policy.csv: |
# # Give all members of "my-org:team-alpha" the ability to sync apps in "my-project"
# p, my-org:team-alpha, applications, sync, my-project/*, allow
# # Make all members of "my-org:team-beta" admins
# g, my-org:team-beta, role:admin
# There are two policy formats:
# 1. Applications (which belong to a project):
# p, <user/group>, <resource>, <action>, <project>/<object>
# 2. All other resources:
# p, <user/group>, <resource>, <action>, <object>
# For example, the following rule gives all members of 'my-org:team1' the ability to sync
# applications in the project named: my-project
# p, my-org:team1, applications, sync, my-project/*
# policy.default holds the default policy which will ArgoCD will fall back to, when authorizing
# a user for API requests
policy.default: role:readonly
# The default role ArgoCD will fall back to, when authorizing API requests
# policy.default: role:readonly
---
apiVersion: v1
kind: ServiceAccount
@@ -162,7 +165,7 @@ spec:
spec:
containers:
- command: [/argocd-application-controller, --repo-server, 'argocd-repo-server:8081']
image: argoproj/argocd-application-controller:v0.7.1
image: argoproj/argocd-application-controller:v0.8.2
name: application-controller
serviceAccountName: application-controller
---
@@ -238,24 +241,30 @@ spec:
serviceAccountName: argocd-server
initContainers:
- name: copyutil
image: argoproj/argocd-server:v0.7.1
image: argoproj/argocd-server:v0.8.2
command: [cp, /argocd-util, /shared]
volumeMounts:
- mountPath: /shared
name: static-files
- name: ui
image: argoproj/argocd-ui:v0.7.1
image: argoproj/argocd-ui:v0.8.2
command: [cp, -r, /app, /shared]
volumeMounts:
- mountPath: /shared
name: static-files
containers:
- name: argocd-server
image: argoproj/argocd-server:v0.7.1
image: argoproj/argocd-server:v0.8.2
command: [/argocd-server, --staticassets, /shared/app, --repo-server, 'argocd-repo-server:8081']
volumeMounts:
- mountPath: /shared
name: static-files
readinessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 3
periodSeconds: 30
- name: dex
image: quay.io/coreos/dex:v2.10.0
command: [/shared/argocd-util, rundex]
@@ -298,7 +307,7 @@ spec:
spec:
containers:
- name: argocd-repo-server
image: argoproj/argocd-repo-server:v0.7.1
image: argoproj/argocd-repo-server:v0.8.2
command: [/argocd-repo-server]
ports:
- containerPort: 8081

View File

@@ -28,8 +28,10 @@
DeploymentInfo
HealthStatus
HookStatus
JWTToken
Operation
OperationState
ProjectRole
Repository
RepositoryList
ResourceDetails
@@ -149,61 +151,69 @@ func (m *HookStatus) Reset() { *m = HookStatus{} }
func (*HookStatus) ProtoMessage() {}
func (*HookStatus) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{19} }
func (m *JWTToken) Reset() { *m = JWTToken{} }
func (*JWTToken) ProtoMessage() {}
func (*JWTToken) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{20} }
func (m *Operation) Reset() { *m = Operation{} }
func (*Operation) ProtoMessage() {}
func (*Operation) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{20} }
func (*Operation) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{21} }
func (m *OperationState) Reset() { *m = OperationState{} }
func (*OperationState) ProtoMessage() {}
func (*OperationState) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{21} }
func (*OperationState) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{22} }
func (m *ProjectRole) Reset() { *m = ProjectRole{} }
func (*ProjectRole) ProtoMessage() {}
func (*ProjectRole) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{23} }
func (m *Repository) Reset() { *m = Repository{} }
func (*Repository) ProtoMessage() {}
func (*Repository) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{22} }
func (*Repository) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{24} }
func (m *RepositoryList) Reset() { *m = RepositoryList{} }
func (*RepositoryList) ProtoMessage() {}
func (*RepositoryList) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{23} }
func (*RepositoryList) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{25} }
func (m *ResourceDetails) Reset() { *m = ResourceDetails{} }
func (*ResourceDetails) ProtoMessage() {}
func (*ResourceDetails) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{24} }
func (*ResourceDetails) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{26} }
func (m *ResourceNode) Reset() { *m = ResourceNode{} }
func (*ResourceNode) ProtoMessage() {}
func (*ResourceNode) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{25} }
func (*ResourceNode) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{27} }
func (m *ResourceState) Reset() { *m = ResourceState{} }
func (*ResourceState) ProtoMessage() {}
func (*ResourceState) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{26} }
func (*ResourceState) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{28} }
func (m *RollbackOperation) Reset() { *m = RollbackOperation{} }
func (*RollbackOperation) ProtoMessage() {}
func (*RollbackOperation) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{27} }
func (*RollbackOperation) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{29} }
func (m *SyncOperation) Reset() { *m = SyncOperation{} }
func (*SyncOperation) ProtoMessage() {}
func (*SyncOperation) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{28} }
func (*SyncOperation) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{30} }
func (m *SyncOperationResult) Reset() { *m = SyncOperationResult{} }
func (*SyncOperationResult) ProtoMessage() {}
func (*SyncOperationResult) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{29} }
func (*SyncOperationResult) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{31} }
func (m *SyncStrategy) Reset() { *m = SyncStrategy{} }
func (*SyncStrategy) ProtoMessage() {}
func (*SyncStrategy) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{30} }
func (*SyncStrategy) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{32} }
func (m *SyncStrategyApply) Reset() { *m = SyncStrategyApply{} }
func (*SyncStrategyApply) ProtoMessage() {}
func (*SyncStrategyApply) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{31} }
func (*SyncStrategyApply) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{33} }
func (m *SyncStrategyHook) Reset() { *m = SyncStrategyHook{} }
func (*SyncStrategyHook) ProtoMessage() {}
func (*SyncStrategyHook) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{32} }
func (*SyncStrategyHook) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{34} }
func (m *TLSClientConfig) Reset() { *m = TLSClientConfig{} }
func (*TLSClientConfig) ProtoMessage() {}
func (*TLSClientConfig) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{33} }
func (*TLSClientConfig) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{35} }
func init() {
proto.RegisterType((*AppProject)(nil), "github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.AppProject")
@@ -226,8 +236,10 @@ func init() {
proto.RegisterType((*DeploymentInfo)(nil), "github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.DeploymentInfo")
proto.RegisterType((*HealthStatus)(nil), "github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.HealthStatus")
proto.RegisterType((*HookStatus)(nil), "github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.HookStatus")
proto.RegisterType((*JWTToken)(nil), "github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.JWTToken")
proto.RegisterType((*Operation)(nil), "github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.Operation")
proto.RegisterType((*OperationState)(nil), "github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.OperationState")
proto.RegisterType((*ProjectRole)(nil), "github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.ProjectRole")
proto.RegisterType((*Repository)(nil), "github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.Repository")
proto.RegisterType((*RepositoryList)(nil), "github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.RepositoryList")
proto.RegisterType((*ResourceDetails)(nil), "github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.ResourceDetails")
@@ -359,6 +371,18 @@ func (m *AppProjectSpec) MarshalTo(dAtA []byte) (int, error) {
i++
i = encodeVarintGenerated(dAtA, i, uint64(len(m.Description)))
i += copy(dAtA[i:], m.Description)
if len(m.Roles) > 0 {
for _, msg := range m.Roles {
dAtA[i] = 0x22
i++
i = encodeVarintGenerated(dAtA, i, uint64(msg.Size()))
n, err := msg.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
i += n
}
}
return i, nil
}
@@ -1072,6 +1096,30 @@ func (m *HookStatus) MarshalTo(dAtA []byte) (int, error) {
return i, nil
}
func (m *JWTToken) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalTo(dAtA)
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *JWTToken) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
dAtA[i] = 0x8
i++
i = encodeVarintGenerated(dAtA, i, uint64(m.IssuedAt))
dAtA[i] = 0x10
i++
i = encodeVarintGenerated(dAtA, i, uint64(m.ExpiresAt))
return i, nil
}
func (m *Operation) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
@@ -1182,6 +1230,59 @@ func (m *OperationState) MarshalTo(dAtA []byte) (int, error) {
return i, nil
}
func (m *ProjectRole) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalTo(dAtA)
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *ProjectRole) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
dAtA[i] = 0xa
i++
i = encodeVarintGenerated(dAtA, i, uint64(len(m.Name)))
i += copy(dAtA[i:], m.Name)
dAtA[i] = 0x12
i++
i = encodeVarintGenerated(dAtA, i, uint64(len(m.Description)))
i += copy(dAtA[i:], m.Description)
if len(m.Policies) > 0 {
for _, s := range m.Policies {
dAtA[i] = 0x1a
i++
l = len(s)
for l >= 1<<7 {
dAtA[i] = uint8(uint64(l)&0x7f | 0x80)
l >>= 7
i++
}
dAtA[i] = uint8(l)
i++
i += copy(dAtA[i:], s)
}
}
if len(m.JWTTokens) > 0 {
for _, msg := range m.JWTTokens {
dAtA[i] = 0x22
i++
i = encodeVarintGenerated(dAtA, i, uint64(msg.Size()))
n, err := msg.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
i += n
}
}
return i, nil
}
func (m *Repository) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
@@ -1703,6 +1804,12 @@ func (m *AppProjectSpec) Size() (n int) {
}
l = len(m.Description)
n += 1 + l + sovGenerated(uint64(l))
if len(m.Roles) > 0 {
for _, e := range m.Roles {
l = e.Size()
n += 1 + l + sovGenerated(uint64(l))
}
}
return n
}
@@ -1973,6 +2080,14 @@ func (m *HookStatus) Size() (n int) {
return n
}
func (m *JWTToken) Size() (n int) {
var l int
_ = l
n += 1 + sovGenerated(uint64(m.IssuedAt))
n += 1 + sovGenerated(uint64(m.ExpiresAt))
return n
}
func (m *Operation) Size() (n int) {
var l int
_ = l
@@ -2013,6 +2128,28 @@ func (m *OperationState) Size() (n int) {
return n
}
func (m *ProjectRole) Size() (n int) {
var l int
_ = l
l = len(m.Name)
n += 1 + l + sovGenerated(uint64(l))
l = len(m.Description)
n += 1 + l + sovGenerated(uint64(l))
if len(m.Policies) > 0 {
for _, s := range m.Policies {
l = len(s)
n += 1 + l + sovGenerated(uint64(l))
}
}
if len(m.JWTTokens) > 0 {
for _, e := range m.JWTTokens {
l = e.Size()
n += 1 + l + sovGenerated(uint64(l))
}
}
return n
}
func (m *Repository) Size() (n int) {
var l int
_ = l
@@ -2229,6 +2366,7 @@ func (this *AppProjectSpec) String() string {
`SourceRepos:` + fmt.Sprintf("%v", this.SourceRepos) + `,`,
`Destinations:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.Destinations), "ApplicationDestination", "ApplicationDestination", 1), `&`, ``, 1) + `,`,
`Description:` + fmt.Sprintf("%v", this.Description) + `,`,
`Roles:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.Roles), "ProjectRole", "ProjectRole", 1), `&`, ``, 1) + `,`,
`}`,
}, "")
return s
@@ -2446,6 +2584,17 @@ func (this *HookStatus) String() string {
}, "")
return s
}
func (this *JWTToken) String() string {
if this == nil {
return "nil"
}
s := strings.Join([]string{`&JWTToken{`,
`IssuedAt:` + fmt.Sprintf("%v", this.IssuedAt) + `,`,
`ExpiresAt:` + fmt.Sprintf("%v", this.ExpiresAt) + `,`,
`}`,
}, "")
return s
}
func (this *Operation) String() string {
if this == nil {
return "nil"
@@ -2473,6 +2622,19 @@ func (this *OperationState) String() string {
}, "")
return s
}
func (this *ProjectRole) String() string {
if this == nil {
return "nil"
}
s := strings.Join([]string{`&ProjectRole{`,
`Name:` + fmt.Sprintf("%v", this.Name) + `,`,
`Description:` + fmt.Sprintf("%v", this.Description) + `,`,
`Policies:` + fmt.Sprintf("%v", this.Policies) + `,`,
`JWTTokens:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.JWTTokens), "JWTToken", "JWTToken", 1), `&`, ``, 1) + `,`,
`}`,
}, "")
return s
}
func (this *Repository) String() string {
if this == nil {
return "nil"
@@ -2966,6 +3128,37 @@ func (m *AppProjectSpec) Unmarshal(dAtA []byte) error {
}
m.Description = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 4:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Roles", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenerated
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthGenerated
}
postIndex := iNdEx + msglen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Roles = append(m.Roles, ProjectRole{})
if err := m.Roles[len(m.Roles)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipGenerated(dAtA[iNdEx:])
@@ -5613,6 +5806,94 @@ func (m *HookStatus) Unmarshal(dAtA []byte) error {
}
return nil
}
func (m *JWTToken) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenerated
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: JWTToken: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: JWTToken: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field IssuedAt", wireType)
}
m.IssuedAt = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenerated
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.IssuedAt |= (int64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 2:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field ExpiresAt", wireType)
}
m.ExpiresAt = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenerated
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.ExpiresAt |= (int64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
default:
iNdEx = preIndex
skippy, err := skipGenerated(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthGenerated
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *Operation) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
@@ -5996,6 +6277,174 @@ func (m *OperationState) Unmarshal(dAtA []byte) error {
}
return nil
}
func (m *ProjectRole) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenerated
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: ProjectRole: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: ProjectRole: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Name", 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 > l {
return io.ErrUnexpectedEOF
}
m.Name = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Description", 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 > l {
return io.ErrUnexpectedEOF
}
m.Description = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 3:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Policies", 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 > l {
return io.ErrUnexpectedEOF
}
m.Policies = append(m.Policies, string(dAtA[iNdEx:postIndex]))
iNdEx = postIndex
case 4:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field JWTTokens", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenerated
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthGenerated
}
postIndex := iNdEx + msglen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.JWTTokens = append(m.JWTTokens, JWTToken{})
if err := m.JWTTokens[len(m.JWTTokens)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipGenerated(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthGenerated
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *Repository) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
@@ -7776,158 +8225,167 @@ func init() {
}
var fileDescriptorGenerated = []byte{
// 2446 bytes of a gzipped FileDescriptorProto
// 2577 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x59, 0x4b, 0x8c, 0x1c, 0x47,
0x19, 0x76, 0xcf, 0x6b, 0x67, 0xfe, 0xd9, 0x87, 0x5d, 0x79, 0x30, 0x38, 0xd2, 0xee, 0xaa, 0xc3,
0xc3, 0xa0, 0x64, 0x06, 0x1b, 0x02, 0xe6, 0x21, 0x24, 0xcf, 0xae, 0x1d, 0x6f, 0xd6, 0x8f, 0xa5,
0x66, 0x13, 0xa4, 0x10, 0x05, 0xda, 0x3d, 0xb5, 0x33, 0xed, 0x99, 0xe9, 0xee, 0x74, 0xd5, 0x8c,
0x35, 0x12, 0x41, 0x41, 0x08, 0x29, 0xbc, 0x24, 0x10, 0x42, 0x5c, 0x39, 0x70, 0x42, 0x48, 0x48,
0x88, 0x13, 0x12, 0x07, 0x38, 0x20, 0x1f, 0x73, 0x00, 0x11, 0x05, 0xb4, 0xc2, 0x9b, 0x4b, 0x24,
0x0e, 0xdc, 0x73, 0x42, 0xf5, 0xe8, 0xae, 0xea, 0x9e, 0x5d, 0x76, 0xed, 0x69, 0x1b, 0x72, 0xeb,
0xfe, 0xff, 0xbf, 0xff, 0xef, 0xaf, 0xbf, 0xfe, 0xfa, 0x1f, 0xd5, 0xb0, 0xd5, 0xf3, 0x58, 0x7f,
0x7c, 0xab, 0xe9, 0x06, 0xa3, 0x96, 0x13, 0xf5, 0x82, 0x30, 0x0a, 0x6e, 0x8b, 0x87, 0x67, 0xdd,
0x6e, 0x2b, 0x1c, 0xf4, 0x5a, 0x4e, 0xe8, 0xd1, 0x96, 0x13, 0x86, 0x43, 0xcf, 0x75, 0x98, 0x17,
0xf8, 0xad, 0xc9, 0x79, 0x67, 0x18, 0xf6, 0x9d, 0xf3, 0xad, 0x1e, 0xf1, 0x49, 0xe4, 0x30, 0xd2,
0x6d, 0x86, 0x51, 0xc0, 0x02, 0xf4, 0x79, 0xad, 0xaa, 0x19, 0xab, 0x12, 0x0f, 0x5f, 0x77, 0xbb,
0xcd, 0x70, 0xd0, 0x6b, 0x72, 0x55, 0x4d, 0x43, 0x55, 0x33, 0x56, 0x75, 0xf6, 0x59, 0xc3, 0x8a,
0x5e, 0xd0, 0x0b, 0x5a, 0x42, 0xe3, 0xad, 0xf1, 0x9e, 0x78, 0x13, 0x2f, 0xe2, 0x49, 0x22, 0x9d,
0xfd, 0xcc, 0xe0, 0x22, 0x6d, 0x7a, 0x01, 0xb7, 0x6d, 0xe4, 0xb8, 0x7d, 0xcf, 0x27, 0xd1, 0x54,
0x1b, 0x3b, 0x22, 0xcc, 0x69, 0x4d, 0x66, 0xec, 0x3b, 0xdb, 0x3a, 0xea, 0xab, 0x68, 0xec, 0x33,
0x6f, 0x44, 0x66, 0x3e, 0xf8, 0xec, 0x71, 0x1f, 0x50, 0xb7, 0x4f, 0x46, 0xce, 0xcc, 0x77, 0x9f,
0x3e, 0xea, 0xbb, 0x31, 0xf3, 0x86, 0x2d, 0xcf, 0x67, 0x94, 0x45, 0xd9, 0x8f, 0xec, 0xbf, 0x5b,
0x00, 0x97, 0xc2, 0x70, 0x27, 0x0a, 0x6e, 0x13, 0x97, 0xa1, 0x6f, 0x40, 0x95, 0xaf, 0xa3, 0xeb,
0x30, 0xa7, 0x61, 0xad, 0x5b, 0xe7, 0xea, 0x17, 0x3e, 0xd5, 0x94, 0x6a, 0x9b, 0xa6, 0x5a, 0xed,
0x57, 0x2e, 0xdd, 0x9c, 0x9c, 0x6f, 0xde, 0xbc, 0xc5, 0xbf, 0xbf, 0x4e, 0x98, 0xd3, 0x46, 0x77,
0xf7, 0xd7, 0x4e, 0x1d, 0xec, 0xaf, 0x81, 0xa6, 0xe1, 0x44, 0x2b, 0x1a, 0x40, 0x89, 0x86, 0xc4,
0x6d, 0x14, 0x84, 0xf6, 0xad, 0xe6, 0x03, 0xef, 0x5e, 0x53, 0x9b, 0xdd, 0x09, 0x89, 0xdb, 0x5e,
0x54, 0xb0, 0x25, 0xfe, 0x86, 0x05, 0x88, 0xfd, 0x8e, 0x05, 0xcb, 0x5a, 0xec, 0x9a, 0x47, 0x19,
0x7a, 0x65, 0x66, 0x85, 0xcd, 0x93, 0xad, 0x90, 0x7f, 0x2d, 0xd6, 0x77, 0x5a, 0x01, 0x55, 0x63,
0x8a, 0xb1, 0xba, 0xdb, 0x50, 0xf6, 0x18, 0x19, 0xd1, 0x46, 0x61, 0xbd, 0x78, 0xae, 0x7e, 0xe1,
0x72, 0x2e, 0xcb, 0x6b, 0x2f, 0x29, 0xc4, 0xf2, 0x16, 0xd7, 0x8d, 0x25, 0x84, 0xfd, 0x66, 0xc1,
0x5c, 0x1c, 0x5f, 0x35, 0x3a, 0x0f, 0x75, 0x1a, 0x8c, 0x23, 0x97, 0x60, 0x12, 0x06, 0xb4, 0x61,
0xad, 0x17, 0xcf, 0xd5, 0xda, 0x2b, 0x07, 0xfb, 0x6b, 0xf5, 0x8e, 0x26, 0x63, 0x53, 0x06, 0xfd,
0xc0, 0x82, 0xc5, 0x2e, 0xa1, 0xcc, 0xf3, 0x05, 0x7e, 0x6c, 0xf9, 0x57, 0xe6, 0xb3, 0x3c, 0x26,
0x6e, 0x6a, 0xcd, 0xed, 0xc7, 0xd5, 0x2a, 0x16, 0x0d, 0x22, 0xc5, 0x29, 0x70, 0xf4, 0x1c, 0xd4,
0xbb, 0x84, 0xba, 0x91, 0x17, 0xf2, 0xf7, 0x46, 0x71, 0xdd, 0x3a, 0x57, 0x6b, 0x3f, 0xa6, 0x3e,
0xac, 0x6f, 0x6a, 0x16, 0x36, 0xe5, 0xec, 0x3f, 0x17, 0xa1, 0x6e, 0xa0, 0x3e, 0x82, 0x30, 0x1e,
0xa6, 0xc2, 0xf8, 0x85, 0x7c, 0xbc, 0x75, 0x54, 0x1c, 0x23, 0x06, 0x15, 0xca, 0x1c, 0x36, 0xa6,
0xc2, 0x23, 0xf5, 0x0b, 0xd7, 0x72, 0xc2, 0x13, 0x3a, 0xdb, 0xcb, 0x0a, 0xb1, 0x22, 0xdf, 0xb1,
0xc2, 0x42, 0xaf, 0x41, 0x2d, 0x08, 0x79, 0xb6, 0xe0, 0x5b, 0x51, 0x12, 0xc0, 0x9b, 0x73, 0x00,
0xdf, 0x8c, 0x75, 0xb5, 0x97, 0x0e, 0xf6, 0xd7, 0x6a, 0xc9, 0x2b, 0xd6, 0x28, 0xb6, 0x0b, 0x8f,
0x1b, 0xf6, 0x6d, 0x04, 0x7e, 0xd7, 0x13, 0x1b, 0xba, 0x0e, 0x25, 0x36, 0x0d, 0x89, 0xd8, 0xcc,
0x9a, 0x76, 0xd1, 0xee, 0x34, 0x24, 0x58, 0x70, 0xd0, 0x27, 0x60, 0x61, 0x44, 0x28, 0x75, 0x7a,
0x44, 0xec, 0x49, 0xad, 0xbd, 0xa2, 0x84, 0x16, 0xae, 0x4b, 0x32, 0x8e, 0xf9, 0xf6, 0x6b, 0xf0,
0xe4, 0xe1, 0x21, 0x8a, 0x3e, 0x06, 0x15, 0x4a, 0xa2, 0x09, 0x89, 0x14, 0x90, 0xf6, 0x8c, 0xa0,
0x62, 0xc5, 0x45, 0x2d, 0xa8, 0xf9, 0xce, 0x88, 0xd0, 0xd0, 0x71, 0x63, 0xb8, 0x33, 0x4a, 0xb4,
0x76, 0x23, 0x66, 0x60, 0x2d, 0x63, 0xff, 0xc3, 0x82, 0x15, 0x03, 0xf3, 0x11, 0x64, 0xa2, 0x41,
0x3a, 0x13, 0x5d, 0xc9, 0x27, 0x62, 0x8e, 0x48, 0x45, 0x7f, 0x2c, 0xc2, 0x19, 0x33, 0xae, 0x44,
0x7e, 0xe1, 0x5b, 0x12, 0x91, 0x30, 0x78, 0x11, 0x5f, 0x53, 0xee, 0x4c, 0xb6, 0x04, 0x4b, 0x32,
0x8e, 0xf9, 0x7c, 0x7f, 0x43, 0x87, 0xf5, 0x95, 0x2f, 0x93, 0xfd, 0xdd, 0x71, 0x58, 0x1f, 0x0b,
0x0e, 0xcf, 0x0c, 0xc4, 0x9f, 0x78, 0x51, 0xe0, 0x8f, 0x88, 0xcf, 0xb2, 0x99, 0xe1, 0xb2, 0x66,
0x61, 0x53, 0x0e, 0x7d, 0x19, 0x96, 0x99, 0x13, 0xf5, 0x08, 0xc3, 0x64, 0xe2, 0xd1, 0x38, 0x90,
0x6b, 0xed, 0x27, 0xd5, 0x97, 0xcb, 0xbb, 0x29, 0x2e, 0xce, 0x48, 0xa3, 0xdf, 0x59, 0xf0, 0x94,
0x1b, 0x8c, 0xc2, 0xc0, 0x27, 0x3e, 0xdb, 0x71, 0x22, 0x67, 0x44, 0x18, 0x89, 0x6e, 0x4e, 0x48,
0x14, 0x79, 0x5d, 0x42, 0x1b, 0x65, 0xe1, 0xdd, 0xeb, 0x73, 0x78, 0x77, 0x63, 0x46, 0x7b, 0xfb,
0x69, 0x65, 0xdc, 0x53, 0x1b, 0x47, 0x23, 0xe3, 0xff, 0x66, 0x16, 0x2f, 0x04, 0x13, 0x67, 0x38,
0x26, 0xf4, 0x8a, 0x37, 0x24, 0xb4, 0x51, 0xd1, 0x85, 0xe0, 0x25, 0x4d, 0xc6, 0xa6, 0x8c, 0xfd,
0x87, 0x42, 0x2a, 0x44, 0x3b, 0x71, 0xde, 0x11, 0x7b, 0xa9, 0x02, 0x34, 0xaf, 0xbc, 0x23, 0x74,
0x1a, 0xa7, 0x4b, 0xd6, 0x23, 0x85, 0x85, 0xde, 0xb4, 0x44, 0x15, 0x88, 0x4f, 0xa5, 0xca, 0xb1,
0x0f, 0xa1, 0x22, 0x99, 0x85, 0x25, 0x26, 0x62, 0x13, 0x9a, 0x87, 0x70, 0x28, 0xeb, 0xab, 0x8a,
0xb8, 0x24, 0x84, 0x55, 0xd9, 0xc5, 0x31, 0xdf, 0xfe, 0x45, 0x25, 0x7d, 0x06, 0x64, 0x0e, 0xfd,
0x89, 0x05, 0xa7, 0xf9, 0x46, 0x39, 0x91, 0x47, 0x03, 0x1f, 0x13, 0x3a, 0x1e, 0x32, 0xe5, 0xcc,
0xed, 0x39, 0x83, 0xc6, 0x54, 0xd9, 0x6e, 0x28, 0xbb, 0x4e, 0x67, 0x39, 0x78, 0x06, 0x1e, 0x31,
0x58, 0xe8, 0x7b, 0x94, 0x05, 0xd1, 0x54, 0x25, 0x87, 0x79, 0xba, 0xb0, 0x4d, 0x12, 0x0e, 0x83,
0x29, 0x3f, 0x6b, 0x5b, 0xfe, 0x5e, 0xa0, 0xfd, 0x73, 0x55, 0x22, 0xe0, 0x18, 0x0a, 0x7d, 0xdb,
0x02, 0x08, 0xe3, 0x48, 0xe5, 0x85, 0xec, 0x21, 0x1c, 0x9c, 0xa4, 0x66, 0x27, 0x24, 0x8a, 0x0d,
0x50, 0x14, 0x40, 0xa5, 0x4f, 0x9c, 0x21, 0xeb, 0xab, 0x72, 0xf6, 0xfc, 0x1c, 0xf0, 0x57, 0x85,
0xa2, 0x6c, 0x09, 0x95, 0x54, 0xac, 0x60, 0xd0, 0x77, 0x2d, 0x58, 0x4e, 0xaa, 0x1b, 0x97, 0x25,
0x8d, 0xf2, 0xdc, 0x8d, 0xef, 0xcd, 0x94, 0xc2, 0x36, 0xe2, 0x69, 0x2c, 0x4d, 0xc3, 0x19, 0x50,
0xf4, 0x1d, 0x0b, 0xc0, 0x8d, 0xab, 0xa9, 0xcc, 0x07, 0xf5, 0x0b, 0x37, 0xf3, 0x39, 0x51, 0x49,
0x95, 0xd6, 0xee, 0x4f, 0x48, 0x14, 0x1b, 0xb0, 0xf6, 0xbb, 0x16, 0x3c, 0x61, 0x7c, 0xf8, 0x55,
0x87, 0xb9, 0xfd, 0xcb, 0x13, 0x9e, 0xa6, 0xb7, 0x53, 0xf5, 0xfd, 0x73, 0x66, 0x7d, 0x7f, 0x7f,
0x7f, 0xed, 0xe3, 0x47, 0x4d, 0x36, 0x77, 0xb8, 0x86, 0xa6, 0x50, 0x61, 0xb4, 0x02, 0xaf, 0x43,
0xdd, 0xb0, 0x59, 0xa5, 0x8f, 0xbc, 0x0a, 0x60, 0x92, 0x33, 0x0c, 0x22, 0x36, 0xf1, 0xec, 0xbf,
0x16, 0x60, 0x61, 0x63, 0x38, 0xa6, 0x8c, 0x44, 0x27, 0x6e, 0x28, 0xd6, 0xa1, 0xc4, 0x9b, 0x85,
0x6c, 0xfd, 0xe3, 0xbd, 0x04, 0x16, 0x1c, 0x14, 0x42, 0xc5, 0x0d, 0xfc, 0x3d, 0xaf, 0xa7, 0x5a,
0xc0, 0xab, 0xf3, 0x9c, 0x1c, 0x69, 0xdd, 0x86, 0xd0, 0xa7, 0x6d, 0x92, 0xef, 0x58, 0xe1, 0xa0,
0x1f, 0x59, 0xb0, 0xe2, 0x06, 0xbe, 0x4f, 0x5c, 0x1d, 0xbc, 0xa5, 0xb9, 0xdb, 0xdd, 0x8d, 0xb4,
0xc6, 0xf6, 0x87, 0x14, 0xfa, 0x4a, 0x86, 0x81, 0xb3, 0xd8, 0xf6, 0x6f, 0x0b, 0xb0, 0x94, 0xb2,
0x1c, 0x3d, 0x03, 0xd5, 0x31, 0x25, 0x91, 0xf0, 0x9c, 0xf4, 0x6f, 0xd2, 0x11, 0xbd, 0xa8, 0xe8,
0x38, 0x91, 0xe0, 0xd2, 0xa1, 0x43, 0xe9, 0x9d, 0x20, 0xea, 0x2a, 0x3f, 0x27, 0xd2, 0x3b, 0x8a,
0x8e, 0x13, 0x09, 0xde, 0x6f, 0xdc, 0x22, 0x4e, 0x44, 0xa2, 0xdd, 0x60, 0x40, 0x66, 0x26, 0x91,
0xb6, 0x66, 0x61, 0x53, 0x4e, 0x38, 0x8d, 0x0d, 0xe9, 0xc6, 0xd0, 0x23, 0x3e, 0x93, 0x66, 0xe6,
0xe0, 0xb4, 0xdd, 0x6b, 0x1d, 0x53, 0xa3, 0x76, 0x5a, 0x86, 0x81, 0xb3, 0xd8, 0xf6, 0x5f, 0x2c,
0xa8, 0x2b, 0xa7, 0x3d, 0x82, 0xa6, 0xb3, 0x97, 0x6e, 0x3a, 0xdb, 0xf3, 0xc7, 0xe8, 0x11, 0x0d,
0xe7, 0xaf, 0x8b, 0x30, 0x53, 0xe9, 0xd0, 0xab, 0x3c, 0xc7, 0x71, 0x1a, 0xe9, 0x5e, 0x8a, 0x8b,
0xec, 0x27, 0x4f, 0xb6, 0xba, 0x5d, 0x6f, 0x44, 0xcc, 0xf4, 0x15, 0x6b, 0xc1, 0x86, 0x46, 0xf4,
0x86, 0xa5, 0x01, 0x76, 0x03, 0x95, 0x57, 0xf2, 0x6d, 0x89, 0x66, 0x4c, 0xd8, 0x0d, 0xb0, 0x81,
0x89, 0xbe, 0x90, 0x0c, 0x82, 0x65, 0x11, 0x90, 0x76, 0x7a, 0x74, 0x7b, 0x3f, 0xd5, 0x00, 0x64,
0xc6, 0xb9, 0x29, 0xd4, 0x22, 0x22, 0x5b, 0xac, 0xb8, 0x02, 0xcc, 0x93, 0x44, 0xb0, 0xd2, 0x25,
0x8f, 0x71, 0x32, 0xfe, 0xc4, 0x64, 0x8a, 0x35, 0x9a, 0xfd, 0x43, 0x0b, 0xd0, 0x6c, 0xb9, 0xe6,
0x63, 0x54, 0xd2, 0xc4, 0xaa, 0x03, 0x9c, 0xe8, 0x49, 0xc4, 0xb1, 0x96, 0x39, 0x41, 0x9a, 0x7c,
0x1a, 0xca, 0xa2, 0xa9, 0x55, 0x07, 0x36, 0x89, 0x1e, 0xd1, 0xf6, 0x62, 0xc9, 0xb3, 0xff, 0x64,
0x41, 0x36, 0xdd, 0x88, 0x4c, 0x2d, 0x3d, 0x9b, 0xcd, 0xd4, 0x69, 0x2f, 0x9e, 0x7c, 0xce, 0x44,
0xaf, 0x40, 0xdd, 0x61, 0x8c, 0x8c, 0x42, 0x26, 0x02, 0xb2, 0x78, 0xdf, 0x01, 0xb9, 0xcc, 0x23,
0xe1, 0x7a, 0xd0, 0xf5, 0xf6, 0x3c, 0x11, 0x8c, 0xa6, 0x3a, 0xfb, 0xbd, 0x22, 0x2c, 0xa7, 0x9b,
0x2f, 0x34, 0x86, 0x8a, 0x68, 0x76, 0xe4, 0xcd, 0x4f, 0xee, 0xdd, 0x55, 0xe2, 0x12, 0x41, 0xa2,
0x58, 0x81, 0xf1, 0xc4, 0x1a, 0xc5, 0xd3, 0x55, 0x26, 0xb1, 0x26, 0x73, 0x55, 0x22, 0x71, 0xec,
0x44, 0x55, 0xfc, 0xff, 0x9c, 0xa8, 0x5e, 0x05, 0xe8, 0x0a, 0x6f, 0x8b, 0xbd, 0x2c, 0x3d, 0x78,
0x72, 0xd9, 0x4c, 0xb4, 0x60, 0x43, 0x23, 0x3a, 0x0b, 0x05, 0xaf, 0x2b, 0x4e, 0x75, 0xb1, 0x0d,
0x4a, 0xb6, 0xb0, 0xb5, 0x89, 0x0b, 0x5e, 0xd7, 0xa6, 0xb0, 0x68, 0x76, 0x9b, 0x27, 0x8e, 0xd5,
0x2f, 0xc2, 0x92, 0x7c, 0xda, 0x24, 0xcc, 0xf1, 0x86, 0x54, 0xed, 0xce, 0x13, 0x4a, 0x7c, 0xa9,
0x63, 0x32, 0x71, 0x5a, 0xd6, 0xfe, 0x79, 0x01, 0xe0, 0x6a, 0x10, 0x0c, 0x14, 0x66, 0x7c, 0xf4,
0xac, 0x23, 0x8f, 0xde, 0x3a, 0x94, 0x06, 0x9e, 0xdf, 0xcd, 0x1e, 0xce, 0x6d, 0xcf, 0xef, 0x62,
0xc1, 0x41, 0x17, 0x00, 0x9c, 0xd0, 0x7b, 0x89, 0x44, 0x54, 0x5f, 0xee, 0x25, 0x7e, 0xb9, 0xb4,
0xb3, 0xa5, 0x38, 0xd8, 0x90, 0x42, 0xcf, 0xa8, 0xce, 0x50, 0x8e, 0xed, 0x8d, 0x4c, 0x67, 0x58,
0xe5, 0x16, 0x1a, 0xad, 0xdf, 0xc5, 0x4c, 0x7e, 0x5c, 0x9f, 0xc9, 0x8f, 0xba, 0x53, 0xde, 0xe9,
0x3b, 0x94, 0x1c, 0x76, 0xae, 0x2b, 0xc7, 0xdc, 0x1f, 0xfd, 0xcb, 0x02, 0x7d, 0x7b, 0x85, 0xf6,
0xa0, 0x44, 0xa7, 0xbe, 0xab, 0xea, 0xcd, 0x3c, 0x19, 0xb5, 0x33, 0xf5, 0x5d, 0x7d, 0x49, 0x56,
0x15, 0x77, 0x80, 0x53, 0xdf, 0xc5, 0x42, 0x3f, 0x9a, 0x40, 0x35, 0x0a, 0x86, 0xc3, 0x5b, 0x8e,
0x3b, 0xc8, 0xa1, 0xf4, 0x60, 0xa5, 0x4a, 0xe3, 0x2d, 0x8a, 0xf3, 0xaa, 0xc8, 0x38, 0xc1, 0xb2,
0x7f, 0x53, 0x86, 0xcc, 0x74, 0x81, 0xc6, 0xe6, 0xc5, 0xa0, 0x95, 0xe3, 0xc5, 0x60, 0x92, 0xfd,
0x0f, 0xbb, 0x1c, 0x44, 0xcf, 0x41, 0x39, 0xe4, 0x7b, 0xa6, 0x22, 0x6c, 0x2d, 0xce, 0xed, 0x62,
0x23, 0x0f, 0xd9, 0x5a, 0x29, 0x6d, 0xee, 0x6c, 0xf1, 0x98, 0x8c, 0xfd, 0x2d, 0x00, 0xee, 0x6b,
0x35, 0xa6, 0xcb, 0x43, 0x7e, 0x23, 0xaf, 0x1d, 0x55, 0x93, 0xba, 0x48, 0xea, 0x9d, 0x04, 0x05,
0x1b, 0x88, 0xe8, 0xfb, 0x16, 0x2c, 0xc7, 0x8e, 0x57, 0x46, 0x94, 0x1f, 0x8a, 0x11, 0x62, 0x66,
0xc4, 0x29, 0x24, 0x9c, 0x41, 0x46, 0x5f, 0x83, 0x1a, 0x65, 0x4e, 0x24, 0x8b, 0x57, 0xe5, 0xbe,
0x13, 0x5e, 0xb2, 0x97, 0x9d, 0x58, 0x09, 0xd6, 0xfa, 0xd0, 0xcb, 0x00, 0x7b, 0x9e, 0xef, 0xd1,
0xbe, 0xd0, 0xbe, 0xf0, 0x60, 0xa5, 0xf1, 0x4a, 0xa2, 0x01, 0x1b, 0xda, 0xec, 0xbf, 0x15, 0x00,
0xc4, 0xcf, 0x0d, 0x4f, 0x5c, 0x3c, 0xac, 0x43, 0x29, 0x22, 0x61, 0x90, 0xcd, 0x5c, 0x5c, 0x02,
0x0b, 0x4e, 0x6a, 0x8e, 0x28, 0xdc, 0xd7, 0x1c, 0x51, 0x3c, 0x76, 0x8e, 0xe0, 0x39, 0x98, 0xf6,
0x77, 0x22, 0x6f, 0xe2, 0x30, 0xb2, 0x4d, 0xa6, 0x2a, 0x91, 0xe9, 0x1c, 0xdc, 0xb9, 0xaa, 0x99,
0x38, 0x2d, 0x7b, 0xe8, 0x08, 0x56, 0xfe, 0x1f, 0x8e, 0x60, 0xef, 0x58, 0xb0, 0xac, 0x3d, 0xfb,
0xc1, 0xfa, 0x9f, 0xa6, 0xed, 0x3e, 0x62, 0xa6, 0xf8, 0xb7, 0x05, 0x2b, 0x71, 0xf7, 0xaa, 0x8a,
0x60, 0x2e, 0x55, 0x2f, 0xf5, 0xb3, 0xa0, 0x78, 0xfc, 0xcf, 0x02, 0x33, 0x61, 0x95, 0x8e, 0x49,
0x58, 0x5f, 0xca, 0xd4, 0xbb, 0x8f, 0xcc, 0xd4, 0x3b, 0x94, 0xf4, 0xe9, 0x53, 0xdf, 0x4d, 0xf7,
0x07, 0xf6, 0xaf, 0x2c, 0x58, 0x8c, 0xd9, 0x37, 0x82, 0xae, 0xe8, 0x9e, 0xa9, 0x08, 0x32, 0x2b,
0xdd, 0x3d, 0xcb, 0x70, 0x90, 0x3c, 0x34, 0x86, 0xaa, 0xdb, 0xf7, 0x86, 0xdd, 0x88, 0xf8, 0x6a,
0x5b, 0x9e, 0xcf, 0x61, 0x8c, 0xe0, 0xf8, 0x3a, 0x14, 0x36, 0x14, 0x00, 0x4e, 0xa0, 0xec, 0xdf,
0x17, 0x61, 0x29, 0x35, 0x73, 0xf0, 0x11, 0x5d, 0xde, 0xd6, 0x77, 0x0c, 0x9b, 0x93, 0x11, 0x7d,
0x57, 0xb3, 0xb0, 0x29, 0xc7, 0xf7, 0x63, 0xe8, 0x4d, 0xa4, 0x8e, 0xec, 0xcf, 0x9b, 0x6b, 0x31,
0x03, 0x6b, 0x19, 0x63, 0xe8, 0x2a, 0xde, 0xf7, 0xd0, 0xf5, 0x53, 0x0b, 0x90, 0x58, 0x02, 0xd7,
0x9c, 0xcc, 0x46, 0x8d, 0x52, 0xbe, 0x7e, 0x3b, 0xab, 0x2c, 0x42, 0x1b, 0x33, 0x50, 0xf8, 0x10,
0x78, 0xe3, 0x1e, 0xb4, 0xfc, 0x48, 0xee, 0x41, 0xed, 0x6f, 0xc2, 0x99, 0x99, 0x8e, 0x43, 0xb5,
0xbc, 0xd6, 0x61, 0x2d, 0x2f, 0x8f, 0xc4, 0x30, 0x1a, 0xfb, 0x72, 0x83, 0xaa, 0x3a, 0x12, 0x77,
0x38, 0x11, 0x4b, 0x1e, 0xef, 0x83, 0xbb, 0xd1, 0x14, 0x8f, 0x65, 0x2f, 0x59, 0xd5, 0xe8, 0x9b,
0x82, 0x8a, 0x15, 0xd7, 0xfe, 0x5e, 0x01, 0x96, 0x52, 0x55, 0x30, 0x35, 0xb2, 0x58, 0xc7, 0x8e,
0x2c, 0x79, 0x1a, 0x83, 0x5e, 0x87, 0x45, 0x2a, 0x8e, 0x62, 0xe4, 0x30, 0xd2, 0x9b, 0xe6, 0x70,
0x13, 0xdd, 0x31, 0xd4, 0xb5, 0x4f, 0x1f, 0xec, 0xaf, 0x2d, 0x9a, 0x14, 0x9c, 0x82, 0xb3, 0x7f,
0x59, 0x80, 0xc7, 0x0e, 0xe9, 0x08, 0xd0, 0x1d, 0xf3, 0x76, 0x40, 0x8e, 0x8f, 0x2f, 0xe4, 0x10,
0x9e, 0x2a, 0x91, 0xca, 0x5f, 0xbe, 0x87, 0xdd, 0x0d, 0xdc, 0xe7, 0xf4, 0xb8, 0x07, 0xe5, 0x7e,
0x10, 0x0c, 0xe2, 0x31, 0x71, 0x9e, 0x82, 0xa0, 0x87, 0x9b, 0x76, 0x8d, 0xef, 0x26, 0x7f, 0xa7,
0x58, 0xaa, 0xb7, 0xdf, 0xb3, 0x20, 0xe5, 0x45, 0x34, 0x82, 0x32, 0xd7, 0x32, 0xcd, 0xe1, 0x4f,
0x98, 0xa9, 0xf7, 0x12, 0xd7, 0x29, 0xf1, 0xc5, 0x23, 0x96, 0x28, 0xc8, 0x83, 0x12, 0x37, 0x44,
0x75, 0xfa, 0xdb, 0x39, 0xa1, 0xf1, 0x25, 0xca, 0xc1, 0x82, 0x3f, 0x61, 0x01, 0x61, 0x5f, 0x84,
0x33, 0x33, 0x16, 0xf1, 0x90, 0xdf, 0x0b, 0xe2, 0x1f, 0x7f, 0x46, 0xc8, 0x5f, 0xe1, 0x44, 0x2c,
0x79, 0xbc, 0x7e, 0x9c, 0xce, 0xaa, 0x47, 0x3f, 0xb3, 0xe0, 0x0c, 0xcd, 0xea, 0x7b, 0x28, 0x5e,
0xfb, 0xb0, 0x32, 0x6a, 0xd6, 0x7c, 0x3c, 0x6b, 0x01, 0xdf, 0xd1, 0xec, 0x75, 0x29, 0x8f, 0x3d,
0xcf, 0xa7, 0xc4, 0x1d, 0x47, 0xf1, 0x42, 0x93, 0xd8, 0xdb, 0x52, 0x74, 0x9c, 0x48, 0xf0, 0xf1,
0x55, 0x5e, 0xd7, 0xdf, 0xd0, 0x8d, 0x62, 0x32, 0xbe, 0x76, 0x12, 0x0e, 0x36, 0xa4, 0xd0, 0x39,
0xa8, 0xba, 0x24, 0x62, 0x9b, 0xbc, 0x3d, 0xe2, 0x79, 0x61, 0x51, 0xce, 0x59, 0x1b, 0x8a, 0x86,
0x13, 0x2e, 0xfa, 0x28, 0x2c, 0x0c, 0xc8, 0x54, 0x08, 0x96, 0x84, 0x60, 0x9d, 0x57, 0xfc, 0x6d,
0x49, 0xc2, 0x31, 0x0f, 0xd9, 0x50, 0x71, 0x1d, 0x21, 0x55, 0x16, 0x52, 0x20, 0x6e, 0xee, 0x2f,
0x09, 0x21, 0xc5, 0x69, 0x37, 0xef, 0xde, 0x5b, 0x3d, 0xf5, 0xd6, 0xbd, 0xd5, 0x53, 0x6f, 0xdf,
0x5b, 0x3d, 0xf5, 0xc6, 0xc1, 0xaa, 0x75, 0xf7, 0x60, 0xd5, 0x7a, 0xeb, 0x60, 0xd5, 0x7a, 0xfb,
0x60, 0xd5, 0xfa, 0xe7, 0xc1, 0xaa, 0xf5, 0xe3, 0x77, 0x57, 0x4f, 0xbd, 0x5c, 0x8d, 0x5d, 0xfb,
0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xf5, 0xd2, 0xa5, 0x7e, 0x8e, 0x27, 0x00, 0x00,
0xf9, 0x77, 0xcf, 0x6b, 0x67, 0xbe, 0xd9, 0x87, 0x5d, 0x79, 0xfc, 0xf7, 0xef, 0x48, 0xbb, 0xab,
0x36, 0x0f, 0x83, 0x92, 0x19, 0xbc, 0x10, 0x30, 0x0f, 0x21, 0x79, 0x66, 0xed, 0x78, 0xbd, 0x7e,
0x2c, 0x35, 0x9b, 0x44, 0x0a, 0x51, 0xa0, 0xdd, 0x53, 0x3b, 0xd3, 0x9e, 0x99, 0xee, 0x4e, 0x57,
0xcd, 0xd8, 0x23, 0x11, 0x14, 0x84, 0x40, 0x3c, 0x25, 0x10, 0x42, 0x5c, 0x39, 0x70, 0x42, 0x48,
0x48, 0x88, 0x13, 0x12, 0x07, 0x38, 0x20, 0x1f, 0x73, 0x00, 0x11, 0x05, 0xb4, 0xc2, 0x9b, 0x4b,
0x24, 0x0e, 0x9c, 0xb8, 0xe4, 0x84, 0xea, 0xd1, 0x5d, 0xd5, 0x3d, 0xbb, 0xec, 0xae, 0x67, 0x6c,
0xe0, 0xd6, 0xfd, 0x7d, 0x5f, 0x7f, 0xbf, 0xaf, 0xbf, 0xfa, 0xea, 0x7b, 0x54, 0xc1, 0x66, 0xc7,
0x63, 0xdd, 0xe1, 0xed, 0x9a, 0x1b, 0x0c, 0xea, 0x4e, 0xd4, 0x09, 0xc2, 0x28, 0xb8, 0x23, 0x1e,
0x9e, 0x73, 0xdb, 0xf5, 0xb0, 0xd7, 0xa9, 0x3b, 0xa1, 0x47, 0xeb, 0x4e, 0x18, 0xf6, 0x3d, 0xd7,
0x61, 0x5e, 0xe0, 0xd7, 0x47, 0x17, 0x9c, 0x7e, 0xd8, 0x75, 0x2e, 0xd4, 0x3b, 0xc4, 0x27, 0x91,
0xc3, 0x48, 0xbb, 0x16, 0x46, 0x01, 0x0b, 0xd0, 0xa7, 0xb5, 0xaa, 0x5a, 0xac, 0x4a, 0x3c, 0x7c,
0xc9, 0x6d, 0xd7, 0xc2, 0x5e, 0xa7, 0xc6, 0x55, 0xd5, 0x0c, 0x55, 0xb5, 0x58, 0xd5, 0xd9, 0xe7,
0x0c, 0x2b, 0x3a, 0x41, 0x27, 0xa8, 0x0b, 0x8d, 0xb7, 0x87, 0xbb, 0xe2, 0x4d, 0xbc, 0x88, 0x27,
0x89, 0x74, 0xf6, 0x13, 0xbd, 0x8b, 0xb4, 0xe6, 0x05, 0xdc, 0xb6, 0x81, 0xe3, 0x76, 0x3d, 0x9f,
0x44, 0x63, 0x6d, 0xec, 0x80, 0x30, 0xa7, 0x3e, 0x9a, 0xb0, 0xef, 0x6c, 0xfd, 0xb0, 0xaf, 0xa2,
0xa1, 0xcf, 0xbc, 0x01, 0x99, 0xf8, 0xe0, 0x93, 0x47, 0x7d, 0x40, 0xdd, 0x2e, 0x19, 0x38, 0x13,
0xdf, 0x7d, 0xfc, 0xb0, 0xef, 0x86, 0xcc, 0xeb, 0xd7, 0x3d, 0x9f, 0x51, 0x16, 0x65, 0x3f, 0xb2,
0xff, 0x62, 0x01, 0x5c, 0x0a, 0xc3, 0xed, 0x28, 0xb8, 0x43, 0x5c, 0x86, 0xbe, 0x0c, 0x65, 0xfe,
0x1f, 0x6d, 0x87, 0x39, 0xcb, 0xd6, 0x9a, 0x75, 0xbe, 0xba, 0xfe, 0xb1, 0x9a, 0x54, 0x5b, 0x33,
0xd5, 0x6a, 0xbf, 0x72, 0xe9, 0xda, 0xe8, 0x42, 0xed, 0xd6, 0x6d, 0xfe, 0xfd, 0x0d, 0xc2, 0x9c,
0x06, 0xba, 0xbf, 0xb7, 0x7a, 0x6a, 0x7f, 0x6f, 0x15, 0x34, 0x0d, 0x27, 0x5a, 0x51, 0x0f, 0x0a,
0x34, 0x24, 0xee, 0x72, 0x4e, 0x68, 0xdf, 0xac, 0x3d, 0xf4, 0xea, 0xd5, 0xb4, 0xd9, 0xad, 0x90,
0xb8, 0x8d, 0x79, 0x05, 0x5b, 0xe0, 0x6f, 0x58, 0x80, 0xd8, 0xef, 0x58, 0xb0, 0xa8, 0xc5, 0xae,
0x7b, 0x94, 0xa1, 0x57, 0x27, 0xfe, 0xb0, 0x76, 0xbc, 0x3f, 0xe4, 0x5f, 0x8b, 0xff, 0x3b, 0xad,
0x80, 0xca, 0x31, 0xc5, 0xf8, 0xbb, 0x3b, 0x50, 0xf4, 0x18, 0x19, 0xd0, 0xe5, 0xdc, 0x5a, 0xfe,
0x7c, 0x75, 0xfd, 0xf2, 0x4c, 0x7e, 0xaf, 0xb1, 0xa0, 0x10, 0x8b, 0x9b, 0x5c, 0x37, 0x96, 0x10,
0xf6, 0x3f, 0x73, 0xe6, 0xcf, 0xf1, 0xbf, 0x46, 0x17, 0xa0, 0x4a, 0x83, 0x61, 0xe4, 0x12, 0x4c,
0xc2, 0x80, 0x2e, 0x5b, 0x6b, 0xf9, 0xf3, 0x95, 0xc6, 0xd2, 0xfe, 0xde, 0x6a, 0xb5, 0xa5, 0xc9,
0xd8, 0x94, 0x41, 0xdf, 0xb5, 0x60, 0xbe, 0x4d, 0x28, 0xf3, 0x7c, 0x81, 0x1f, 0x5b, 0xfe, 0x85,
0xe9, 0x2c, 0x8f, 0x89, 0x1b, 0x5a, 0x73, 0xe3, 0x49, 0xf5, 0x17, 0xf3, 0x06, 0x91, 0xe2, 0x14,
0x38, 0x7a, 0x1e, 0xaa, 0x6d, 0x42, 0xdd, 0xc8, 0x0b, 0xf9, 0xfb, 0x72, 0x7e, 0xcd, 0x3a, 0x5f,
0x69, 0x3c, 0xa1, 0x3e, 0xac, 0x6e, 0x68, 0x16, 0x36, 0xe5, 0x50, 0x0f, 0x8a, 0x51, 0xd0, 0x27,
0x74, 0xb9, 0x20, 0x8c, 0xbf, 0x32, 0x85, 0xf1, 0xca, 0x9d, 0x38, 0xe8, 0x13, 0xed, 0x77, 0xfe,
0x46, 0xb1, 0xc4, 0xb0, 0xff, 0x90, 0x87, 0xaa, 0xf1, 0x8b, 0x8f, 0x61, 0xcf, 0xf4, 0x53, 0x7b,
0xe6, 0xda, 0x6c, 0x96, 0xe6, 0xb0, 0x4d, 0x83, 0x18, 0x94, 0x28, 0x73, 0xd8, 0x90, 0x0a, 0xf7,
0x57, 0xd7, 0xaf, 0xcf, 0x08, 0x4f, 0xe8, 0x6c, 0x2c, 0x2a, 0xc4, 0x92, 0x7c, 0xc7, 0x0a, 0x0b,
0xbd, 0x0e, 0x95, 0x20, 0xe4, 0xa9, 0x89, 0xaf, 0x7b, 0x41, 0x00, 0x6f, 0x4c, 0x01, 0x7c, 0x2b,
0xd6, 0xd5, 0x58, 0xd8, 0xdf, 0x5b, 0xad, 0x24, 0xaf, 0x58, 0xa3, 0xd8, 0x2e, 0x3c, 0x69, 0xd8,
0xd7, 0x0c, 0xfc, 0xb6, 0x27, 0x16, 0x74, 0x0d, 0x0a, 0x6c, 0x1c, 0x12, 0xb1, 0x98, 0x15, 0xed,
0xa2, 0x9d, 0x71, 0x48, 0xb0, 0xe0, 0xa0, 0x8f, 0xc0, 0xdc, 0x80, 0x50, 0xea, 0x74, 0x88, 0x58,
0x93, 0x4a, 0x63, 0x49, 0x09, 0xcd, 0xdd, 0x90, 0x64, 0x1c, 0xf3, 0xed, 0xd7, 0xe1, 0xe9, 0x83,
0xf7, 0x03, 0xfa, 0x10, 0x94, 0x28, 0x89, 0x46, 0x24, 0x52, 0x40, 0xda, 0x33, 0x82, 0x8a, 0x15,
0x17, 0xd5, 0xa1, 0xe2, 0x3b, 0x03, 0x42, 0x43, 0xc7, 0x8d, 0xe1, 0xce, 0x28, 0xd1, 0xca, 0xcd,
0x98, 0x81, 0xb5, 0x8c, 0xfd, 0x57, 0x0b, 0x96, 0x0c, 0xcc, 0xc7, 0x90, 0xf6, 0x7a, 0xe9, 0xb4,
0x77, 0x65, 0x36, 0x11, 0x73, 0x48, 0xde, 0xfb, 0x5d, 0x1e, 0xce, 0x98, 0x71, 0x25, 0x92, 0x19,
0x5f, 0x92, 0x88, 0x84, 0xc1, 0x8b, 0xf8, 0xba, 0x72, 0x67, 0xb2, 0x24, 0x58, 0x92, 0x71, 0xcc,
0xe7, 0xeb, 0x1b, 0x3a, 0xac, 0xab, 0x7c, 0x99, 0xac, 0xef, 0xb6, 0xc3, 0xba, 0x58, 0x70, 0x78,
0x1a, 0x22, 0xfe, 0xc8, 0x8b, 0x02, 0x7f, 0x40, 0x7c, 0x96, 0x4d, 0x43, 0x97, 0x35, 0x0b, 0x9b,
0x72, 0xe8, 0xf3, 0xb0, 0xc8, 0x9c, 0xa8, 0x43, 0x18, 0x26, 0x23, 0x8f, 0xc6, 0x81, 0x5c, 0x69,
0x3c, 0xad, 0xbe, 0x5c, 0xdc, 0x49, 0x71, 0x71, 0x46, 0x1a, 0xfd, 0xda, 0x82, 0x67, 0xdc, 0x60,
0x10, 0x06, 0x3e, 0xf1, 0xd9, 0xb6, 0x13, 0x39, 0x03, 0xc2, 0x48, 0x74, 0x6b, 0x44, 0xa2, 0xc8,
0x6b, 0x13, 0xba, 0x5c, 0x14, 0xde, 0xbd, 0x31, 0x85, 0x77, 0x9b, 0x13, 0xda, 0x1b, 0xe7, 0x94,
0x71, 0xcf, 0x34, 0x0f, 0x47, 0xc6, 0xff, 0xce, 0x2c, 0x5e, 0x75, 0x46, 0x4e, 0x7f, 0x48, 0xe8,
0x15, 0x8f, 0xe7, 0xe0, 0x92, 0xae, 0x3a, 0x2f, 0x69, 0x32, 0x36, 0x65, 0xec, 0xdf, 0xe6, 0x52,
0x21, 0xda, 0x8a, 0xf3, 0x8e, 0x58, 0x4b, 0x15, 0xa0, 0xb3, 0xca, 0x3b, 0x42, 0xa7, 0xb1, 0xbb,
0x64, 0xf1, 0x53, 0x58, 0xe8, 0x5b, 0x96, 0x28, 0x39, 0xf1, 0xae, 0x54, 0x39, 0xf6, 0x11, 0x94,
0x3f, 0xb3, 0x8a, 0xc5, 0x44, 0x6c, 0x42, 0xf3, 0x10, 0x0e, 0x65, 0xf5, 0x51, 0x11, 0x97, 0x84,
0x70, 0x5c, 0x94, 0x62, 0xbe, 0xfd, 0xd3, 0x52, 0x7a, 0x0f, 0xc8, 0x1c, 0xfa, 0x43, 0x0b, 0x4e,
0xf3, 0x85, 0x72, 0x22, 0x8f, 0x06, 0x3e, 0x26, 0x74, 0xd8, 0x67, 0xca, 0x99, 0x5b, 0x53, 0x06,
0x8d, 0xa9, 0xb2, 0xb1, 0xac, 0xec, 0x3a, 0x9d, 0xe5, 0xe0, 0x09, 0x78, 0xc4, 0x60, 0xae, 0xeb,
0x51, 0x16, 0x44, 0x63, 0x95, 0x1c, 0xa6, 0x69, 0xf9, 0x36, 0x48, 0xd8, 0x0f, 0xc6, 0x7c, 0xaf,
0x6d, 0xfa, 0xbb, 0x81, 0xf6, 0xcf, 0x55, 0x89, 0x80, 0x63, 0x28, 0xf4, 0x35, 0x0b, 0x20, 0x8c,
0x23, 0x95, 0x17, 0xb2, 0x47, 0xb0, 0x71, 0x92, 0x9a, 0x9d, 0x90, 0x28, 0x36, 0x40, 0x51, 0x00,
0xa5, 0x2e, 0x71, 0xfa, 0xac, 0xab, 0xca, 0xd9, 0x0b, 0x53, 0xc0, 0x5f, 0x15, 0x8a, 0xb2, 0x25,
0x54, 0x52, 0xb1, 0x82, 0x41, 0xdf, 0xb0, 0x60, 0x31, 0xa9, 0x6e, 0x5c, 0x96, 0x2c, 0x17, 0xa7,
0xee, 0xb2, 0x6f, 0xa5, 0x14, 0x36, 0x10, 0x4f, 0x63, 0x69, 0x1a, 0xce, 0x80, 0xa2, 0xaf, 0x5b,
0x00, 0x6e, 0x5c, 0x4d, 0x65, 0x3e, 0xa8, 0xae, 0xdf, 0x9a, 0xcd, 0x8e, 0x4a, 0xaa, 0xb4, 0x76,
0x7f, 0x42, 0xa2, 0xd8, 0x80, 0xb5, 0xdf, 0xb5, 0xe0, 0x29, 0xe3, 0xc3, 0x97, 0x1d, 0xe6, 0x76,
0x2f, 0x8f, 0x78, 0x9a, 0xde, 0x4a, 0xd5, 0xf7, 0x4f, 0x99, 0xf5, 0xfd, 0xfd, 0xbd, 0xd5, 0x0f,
0x1f, 0x36, 0x46, 0xdd, 0xe5, 0x1a, 0x6a, 0x42, 0x85, 0xd1, 0x0a, 0xbc, 0x01, 0x55, 0xc3, 0x66,
0x95, 0x3e, 0x66, 0x55, 0x00, 0x93, 0x9c, 0x61, 0x10, 0xb1, 0x89, 0x67, 0xff, 0x29, 0x07, 0x73,
0xcd, 0xfe, 0x90, 0x32, 0x12, 0x1d, 0xbb, 0xa1, 0x58, 0x83, 0x02, 0x6f, 0x16, 0xb2, 0xf5, 0x8f,
0xf7, 0x12, 0x58, 0x70, 0x50, 0x08, 0x25, 0x37, 0xf0, 0x77, 0xbd, 0x8e, 0x6a, 0x01, 0xaf, 0x4e,
0xb3, 0x73, 0xa4, 0x75, 0x4d, 0xa1, 0x4f, 0xdb, 0x24, 0xdf, 0xb1, 0xc2, 0x41, 0xdf, 0xb7, 0x60,
0xc9, 0x0d, 0x7c, 0x9f, 0xb8, 0x3a, 0x78, 0x0b, 0x53, 0xb7, 0xbb, 0xcd, 0xb4, 0xc6, 0xc6, 0xff,
0x29, 0xf4, 0xa5, 0x0c, 0x03, 0x67, 0xb1, 0xed, 0x5f, 0xe5, 0x60, 0x21, 0x65, 0x39, 0x7a, 0x16,
0xca, 0x43, 0x4a, 0x22, 0xe1, 0x39, 0xe9, 0xdf, 0xa4, 0x23, 0x7a, 0x51, 0xd1, 0x71, 0x22, 0xc1,
0xa5, 0x43, 0x87, 0xd2, 0xbb, 0x41, 0xd4, 0x56, 0x7e, 0x4e, 0xa4, 0xb7, 0x15, 0x1d, 0x27, 0x12,
0xbc, 0xdf, 0xb8, 0x4d, 0x9c, 0x88, 0x44, 0x3b, 0x41, 0x8f, 0x4c, 0x8c, 0x3d, 0x0d, 0xcd, 0xc2,
0xa6, 0x9c, 0x70, 0x1a, 0xeb, 0xd3, 0x66, 0xdf, 0x23, 0x3e, 0x93, 0x66, 0xce, 0xc0, 0x69, 0x3b,
0xd7, 0x5b, 0xa6, 0x46, 0xed, 0xb4, 0x0c, 0x03, 0x67, 0xb1, 0xed, 0x3f, 0x5a, 0x50, 0x55, 0x4e,
0x7b, 0x0c, 0x4d, 0x67, 0x27, 0xdd, 0x74, 0x36, 0xa6, 0x8f, 0xd1, 0x43, 0x1a, 0xce, 0x5f, 0xe4,
0x61, 0xa2, 0xd2, 0xa1, 0xd7, 0x78, 0x8e, 0xe3, 0x34, 0xd2, 0xbe, 0x14, 0x17, 0xd9, 0x8f, 0x1e,
0xef, 0xef, 0x76, 0xbc, 0x01, 0x31, 0xd3, 0x57, 0xac, 0x05, 0x1b, 0x1a, 0xd1, 0x9b, 0x96, 0x06,
0xd8, 0x09, 0x54, 0x5e, 0x99, 0x6d, 0x4b, 0x34, 0x61, 0xc2, 0x4e, 0x80, 0x0d, 0x4c, 0xf4, 0x99,
0x64, 0x10, 0x2c, 0x8a, 0x80, 0xb4, 0xd3, 0xa3, 0xdb, 0xfb, 0xa9, 0x06, 0x20, 0x33, 0xce, 0x8d,
0xa1, 0x12, 0x11, 0xd9, 0x62, 0xc5, 0x15, 0x60, 0x9a, 0x24, 0x82, 0x95, 0x2e, 0xb9, 0x8d, 0x93,
0xf1, 0x27, 0x26, 0x53, 0xac, 0xd1, 0xec, 0xef, 0x59, 0x80, 0x26, 0xcb, 0x35, 0x1f, 0xa3, 0x92,
0x26, 0x56, 0x6d, 0xe0, 0x44, 0x4f, 0x22, 0x8e, 0xb5, 0xcc, 0x31, 0xd2, 0xe4, 0x39, 0x28, 0x8a,
0xa6, 0x56, 0x6d, 0xd8, 0x24, 0x7a, 0x44, 0xdb, 0x8b, 0x25, 0xcf, 0xfe, 0xbd, 0x05, 0xd9, 0x74,
0x23, 0x32, 0xb5, 0xf4, 0x6c, 0x36, 0x53, 0xa7, 0xbd, 0x78, 0xfc, 0x39, 0x13, 0xbd, 0x0a, 0x55,
0x87, 0x31, 0x32, 0x08, 0x99, 0x08, 0xc8, 0xfc, 0x89, 0x03, 0x72, 0x91, 0x47, 0xc2, 0x8d, 0xa0,
0xed, 0xed, 0x7a, 0x22, 0x18, 0x4d, 0x75, 0xf6, 0x7b, 0x79, 0x58, 0x4c, 0x37, 0x5f, 0x68, 0x08,
0x25, 0xd1, 0xec, 0xc8, 0x63, 0xa6, 0x99, 0x77, 0x57, 0x89, 0x4b, 0x04, 0x89, 0x62, 0x05, 0xc6,
0x13, 0x6b, 0x14, 0x4f, 0x57, 0x99, 0xc4, 0x9a, 0xcc, 0x55, 0x89, 0xc4, 0x91, 0x13, 0x55, 0xfe,
0xbf, 0x73, 0xa2, 0x7a, 0x0d, 0xa0, 0x2d, 0xbc, 0x2d, 0xd6, 0xb2, 0xf0, 0xf0, 0xc9, 0x65, 0x23,
0xd1, 0x82, 0x0d, 0x8d, 0xe8, 0x2c, 0xe4, 0xbc, 0xb6, 0xd8, 0xd5, 0xf9, 0x06, 0x28, 0xd9, 0xdc,
0xe6, 0x06, 0xce, 0x79, 0x6d, 0x9b, 0xc2, 0xbc, 0xd9, 0x6d, 0x1e, 0x3b, 0x56, 0x3f, 0x0b, 0x0b,
0xf2, 0x69, 0x83, 0x30, 0xc7, 0xeb, 0x53, 0xb5, 0x3a, 0x4f, 0x29, 0xf1, 0x85, 0x96, 0xc9, 0xc4,
0x69, 0x59, 0xfb, 0x27, 0x39, 0x80, 0xab, 0x41, 0xd0, 0x53, 0x98, 0xf1, 0xd6, 0xb3, 0x0e, 0xdd,
0x7a, 0x6b, 0x50, 0xe8, 0x79, 0x7e, 0x3b, 0xbb, 0x39, 0xb7, 0x3c, 0xbf, 0x8d, 0x05, 0x07, 0xad,
0x03, 0x38, 0xa1, 0xf7, 0x12, 0x89, 0xa8, 0x3e, 0x49, 0x4c, 0xfc, 0x72, 0x69, 0x7b, 0x53, 0x71,
0xb0, 0x21, 0x85, 0x9e, 0x55, 0x9d, 0xa1, 0x1c, 0xdb, 0x97, 0x33, 0x9d, 0x61, 0x99, 0x5b, 0x68,
0xb4, 0x7e, 0x17, 0x33, 0xf9, 0x71, 0x6d, 0x22, 0x3f, 0xea, 0x4e, 0x79, 0xbb, 0xeb, 0x50, 0x72,
0xd0, 0xbe, 0x2e, 0x1d, 0x71, 0x7e, 0xd4, 0x82, 0xf2, 0xb5, 0x97, 0x77, 0x64, 0xbd, 0xb7, 0x21,
0xef, 0x39, 0x32, 0x79, 0xe5, 0x75, 0xd8, 0x6f, 0x52, 0x3a, 0x14, 0x2b, 0xcc, 0x99, 0xe8, 0x1c,
0xe4, 0xc9, 0xbd, 0x50, 0xf8, 0x25, 0xaf, 0x13, 0xdc, 0xe5, 0x7b, 0xa1, 0x17, 0x11, 0xca, 0x85,
0xc8, 0xbd, 0xd0, 0xfe, 0xbb, 0x05, 0xfa, 0x48, 0x0c, 0xed, 0x42, 0x81, 0x8e, 0x7d, 0x57, 0x15,
0xb1, 0x69, 0xd2, 0x74, 0x6b, 0xec, 0xbb, 0xfa, 0xe4, 0xad, 0x2c, 0x0e, 0x16, 0xc7, 0xbe, 0x8b,
0x85, 0x7e, 0x34, 0x82, 0x72, 0x14, 0xf4, 0xfb, 0xb7, 0x1d, 0xb7, 0x37, 0x83, 0x7a, 0x86, 0x95,
0x2a, 0x8d, 0x37, 0x2f, 0x92, 0x80, 0x22, 0xe3, 0x04, 0xcb, 0xfe, 0x65, 0x11, 0x32, 0x23, 0x0b,
0x1a, 0x9a, 0xa7, 0x8d, 0xd6, 0x0c, 0x4f, 0x1b, 0x13, 0x8f, 0x1f, 0x74, 0xe2, 0x88, 0x9e, 0x87,
0x62, 0xc8, 0x03, 0x41, 0x85, 0xed, 0x6a, 0x5c, 0x30, 0x44, 0x74, 0x1c, 0x10, 0x2f, 0x52, 0xda,
0x0c, 0x97, 0xfc, 0x11, 0x65, 0xe0, 0xab, 0x00, 0xdc, 0xd7, 0x6a, 0xf6, 0x97, 0x99, 0xe3, 0xe6,
0xac, 0x56, 0x54, 0x8d, 0xff, 0xa2, 0x52, 0xb4, 0x12, 0x14, 0x6c, 0x20, 0xa2, 0xef, 0x58, 0xb0,
0x18, 0x3b, 0x5e, 0x19, 0x51, 0x7c, 0x24, 0x46, 0x88, 0x41, 0x14, 0xa7, 0x90, 0x70, 0x06, 0x19,
0x7d, 0x11, 0x2a, 0x94, 0x39, 0x91, 0xac, 0x88, 0xa5, 0x13, 0x67, 0xd1, 0x64, 0x2d, 0x5b, 0xb1,
0x12, 0xac, 0xf5, 0xa1, 0x57, 0x00, 0x76, 0x3d, 0xdf, 0xa3, 0x5d, 0xa1, 0x7d, 0xee, 0xe1, 0xea,
0xed, 0x95, 0x44, 0x03, 0x36, 0xb4, 0xd9, 0xdf, 0xcc, 0x41, 0xd5, 0xb8, 0x88, 0x38, 0x46, 0x3e,
0xcc, 0x5c, 0x9c, 0xe4, 0x8e, 0x79, 0x71, 0x72, 0x1e, 0xca, 0x61, 0xd0, 0xf7, 0x5c, 0x4f, 0xd5,
0xc2, 0x8a, 0xdc, 0x44, 0xdb, 0x8a, 0x86, 0x13, 0x2e, 0x62, 0x50, 0xb9, 0x73, 0x97, 0x89, 0x3c,
0x14, 0x5f, 0xb3, 0x34, 0xa7, 0x58, 0xd2, 0x38, 0xa7, 0x69, 0x27, 0xc7, 0x14, 0x8a, 0x35, 0x90,
0xfd, 0xe7, 0x1c, 0x80, 0xb8, 0xa7, 0xf2, 0xc4, 0xb1, 0xce, 0x1a, 0x14, 0x22, 0x12, 0x06, 0x59,
0x3f, 0x70, 0x09, 0x2c, 0x38, 0xa9, 0x29, 0x2d, 0x77, 0xa2, 0x29, 0x2d, 0x7f, 0xe4, 0x94, 0xc6,
0x2b, 0x1c, 0xed, 0x6e, 0x47, 0xde, 0xc8, 0x61, 0x64, 0x8b, 0x8c, 0x55, 0x99, 0xd0, 0x15, 0xae,
0x75, 0x55, 0x33, 0x71, 0x5a, 0xf6, 0xc0, 0x01, 0xb7, 0xf8, 0x1f, 0x1c, 0x70, 0xdf, 0xb1, 0x60,
0x51, 0x7b, 0xf6, 0x7f, 0xeb, 0x6a, 0x54, 0xdb, 0x7d, 0xc8, 0xc4, 0xf6, 0x0f, 0x0b, 0x96, 0xe2,
0xd9, 0x40, 0xb5, 0x18, 0x33, 0xe9, 0x29, 0x52, 0x57, 0x31, 0xf9, 0xa3, 0xaf, 0x62, 0xcc, 0xcc,
0x5d, 0x38, 0x22, 0x73, 0x7f, 0x2e, 0xd3, 0x4d, 0x7c, 0x60, 0xa2, 0x9b, 0x40, 0xc9, 0x14, 0x34,
0xf6, 0xdd, 0x74, 0xf7, 0x65, 0xff, 0xdc, 0x82, 0xf9, 0x98, 0x7d, 0x33, 0x68, 0x8b, 0xd9, 0x84,
0x8a, 0x20, 0xb3, 0xd2, 0xb3, 0x89, 0x0c, 0x07, 0xc9, 0x43, 0x43, 0x28, 0xbb, 0x5d, 0xaf, 0xdf,
0x8e, 0x88, 0xaf, 0x96, 0xe5, 0x85, 0x19, 0x0c, 0x69, 0x1c, 0x5f, 0x87, 0x42, 0x53, 0x01, 0xe0,
0x04, 0xca, 0xfe, 0x4d, 0x1e, 0x16, 0x52, 0x13, 0x1d, 0x4f, 0x5f, 0xf2, 0x2e, 0xa4, 0x65, 0xd8,
0x9c, 0xa4, 0xaf, 0x1d, 0xcd, 0xc2, 0xa6, 0x1c, 0x5f, 0x8f, 0xbe, 0x37, 0x92, 0x3a, 0xb2, 0x57,
0x63, 0xd7, 0x63, 0x06, 0xd6, 0x32, 0xc6, 0x48, 0x9b, 0x3f, 0xf1, 0x48, 0xfb, 0x23, 0x0b, 0x90,
0xf8, 0x05, 0xae, 0x39, 0x99, 0x3c, 0x55, 0x2e, 0x9c, 0x99, 0xdf, 0xce, 0x2a, 0x8b, 0x50, 0x73,
0x02, 0x0a, 0x1f, 0x00, 0x6f, 0x9c, 0x32, 0x17, 0x1f, 0xcb, 0x29, 0xb3, 0xfd, 0x15, 0x38, 0x33,
0xd1, 0x7a, 0xa9, 0x81, 0xc2, 0x3a, 0x68, 0xa0, 0xe0, 0x91, 0x18, 0x46, 0x43, 0x5f, 0x2e, 0x50,
0x59, 0x47, 0xe2, 0x36, 0x27, 0x62, 0xc9, 0xe3, 0x53, 0x46, 0x3b, 0x1a, 0xe3, 0xa1, 0xec, 0xd4,
0xcb, 0x1a, 0x7d, 0x43, 0x50, 0xb1, 0xe2, 0xda, 0xdf, 0xce, 0xc1, 0x42, 0xaa, 0x1d, 0x48, 0x0d,
0x84, 0xd6, 0x91, 0x03, 0xe1, 0x2c, 0x8d, 0x41, 0x6f, 0xc0, 0x3c, 0x15, 0x5b, 0x31, 0x72, 0x18,
0xe9, 0x8c, 0x67, 0x70, 0xce, 0xdf, 0x32, 0xd4, 0x35, 0x4e, 0xef, 0xef, 0xad, 0xce, 0x9b, 0x14,
0x9c, 0x82, 0xb3, 0x7f, 0x96, 0x83, 0x27, 0x0e, 0x68, 0x8d, 0xd0, 0x5d, 0xf3, 0xec, 0x45, 0x0e,
0xe7, 0xd7, 0x66, 0x10, 0x9e, 0x2a, 0x91, 0xca, 0x0b, 0xf5, 0x83, 0x4e, 0x5e, 0x4e, 0x38, 0x9b,
0xef, 0x42, 0xb1, 0x1b, 0x04, 0xbd, 0x78, 0x08, 0x9f, 0xa6, 0x20, 0xe8, 0xd1, 0xb1, 0x51, 0xe1,
0xab, 0xc9, 0xdf, 0x29, 0x96, 0xea, 0xed, 0xf7, 0x2c, 0x48, 0x79, 0x11, 0x0d, 0xa0, 0xc8, 0xb5,
0x8c, 0x67, 0x70, 0xcf, 0x68, 0xea, 0xbd, 0xc4, 0x75, 0x4a, 0x7c, 0xf1, 0x88, 0x25, 0x0a, 0xf2,
0xa0, 0xc0, 0x0d, 0x51, 0x23, 0xcf, 0xd6, 0x8c, 0xd0, 0xf8, 0x2f, 0xca, 0x09, 0x8b, 0x3f, 0x61,
0x01, 0x61, 0x5f, 0x84, 0x33, 0x13, 0x16, 0xf1, 0x90, 0xdf, 0x0d, 0xe2, 0x6b, 0x55, 0x23, 0xe4,
0xaf, 0x70, 0x22, 0x96, 0x3c, 0x5e, 0x3f, 0x4e, 0x67, 0xd5, 0xa3, 0x1f, 0x5b, 0x70, 0x86, 0x66,
0xf5, 0x3d, 0x12, 0xaf, 0xfd, 0xbf, 0x32, 0x6a, 0xd2, 0x7c, 0x3c, 0x69, 0x01, 0x5f, 0xd1, 0xec,
0x61, 0x34, 0x8f, 0x3d, 0xcf, 0xa7, 0xc4, 0x1d, 0x46, 0xf1, 0x8f, 0xea, 0x01, 0x59, 0xd1, 0x71,
0x22, 0x81, 0xd6, 0x01, 0xe4, 0x65, 0xc8, 0x4d, 0xdd, 0x28, 0x26, 0x87, 0x03, 0xad, 0x84, 0x83,
0x0d, 0x29, 0xde, 0x2b, 0xbb, 0x24, 0x62, 0x1b, 0xbc, 0x3d, 0xe2, 0x79, 0x61, 0x5e, 0xf6, 0xca,
0x4d, 0x45, 0xc3, 0x09, 0x17, 0x7d, 0x10, 0xe6, 0x7a, 0x64, 0x2c, 0x04, 0x0b, 0x42, 0xb0, 0xca,
0x2b, 0xfe, 0x96, 0x24, 0xe1, 0x98, 0x87, 0x6c, 0x28, 0xb9, 0x8e, 0x90, 0x2a, 0x0a, 0x29, 0x10,
0xf7, 0x22, 0x97, 0x84, 0x90, 0xe2, 0x34, 0x6a, 0xf7, 0x1f, 0xac, 0x9c, 0x7a, 0xeb, 0xc1, 0xca,
0xa9, 0xb7, 0x1f, 0xac, 0x9c, 0x7a, 0x73, 0x7f, 0xc5, 0xba, 0xbf, 0xbf, 0x62, 0xbd, 0xb5, 0xbf,
0x62, 0xbd, 0xbd, 0xbf, 0x62, 0xfd, 0x6d, 0x7f, 0xc5, 0xfa, 0xc1, 0xbb, 0x2b, 0xa7, 0x5e, 0x29,
0xc7, 0xae, 0xfd, 0x57, 0x00, 0x00, 0x00, 0xff, 0xff, 0x38, 0x84, 0xaf, 0x0d, 0x59, 0x29, 0x00,
0x00,
}

View File

@@ -41,6 +41,8 @@ message AppProjectSpec {
// Description contains optional project description
optional string description = 3;
repeated ProjectRole roles = 4;
}
// Application is a definition of Application resource.
@@ -252,6 +254,13 @@ message HookStatus {
optional string message = 6;
}
// JWTToken holds the issuedAt and expiresAt values of a token
message JWTToken {
optional int64 iat = 1;
optional int64 exp = 2;
}
// Operation contains requested operation parameters.
message Operation {
optional SyncOperation sync = 1;
@@ -283,6 +292,18 @@ message OperationState {
optional k8s.io.apimachinery.pkg.apis.meta.v1.Time finishedAt = 7;
}
// ProjectRole represents a role that has access to a project
message ProjectRole {
optional string name = 1;
optional string description = 2;
// Policies Stores a list of casbin formated strings that define access policies for the role in the project.
repeated string policies = 3;
repeated JWTToken jwtTokens = 4;
}
// Repository is a Git repository holding application configurations
message Repository {
optional string repo = 1;

View File

@@ -443,6 +443,15 @@ type AppProject struct {
Spec AppProjectSpec `json:"spec" protobuf:"bytes,2,opt,name=spec"`
}
// ProjectPoliciesString returns Casbin formated string of a project's polcies for each role
func (proj *AppProject) ProjectPoliciesString() string {
var policies []string
for _, role := range proj.Spec.Roles {
policies = append(policies, role.Policies...)
}
return strings.Join(policies, "\n")
}
// AppProjectSpec represents
type AppProjectSpec struct {
// SourceRepos contains list of git repository URLs which can be used for deployment
@@ -453,15 +462,23 @@ type AppProjectSpec struct {
// Description contains optional project description
Description string `json:"description,omitempty" protobuf:"bytes,3,opt,name=description"`
Roles []ProjectRole `json:"roles,omitempty" protobuf:"bytes,4,rep,name=roles"`
}
func GetDefaultProject(namespace string) AppProject {
return AppProject{
ObjectMeta: metav1.ObjectMeta{
Name: common.DefaultAppProjectName,
Namespace: namespace,
},
}
// ProjectRole represents a role that has access to a project
type ProjectRole struct {
Name string `json:"name" protobuf:"bytes,1,opt,name=name"`
Description string `json:"description" protobuf:"bytes,2,opt,name=description"`
// Policies Stores a list of casbin formated strings that define access policies for the role in the project.
Policies []string `json:"policies" protobuf:"bytes,3,rep,name=policies"`
JWTTokens []JWTToken `json:"jwtTokens" protobuf:"bytes,4,rep,name=jwtTokens"`
}
// JWTToken holds the issuedAt and expiresAt values of a token
type JWTToken struct {
IssuedAt int64 `json:"iat,omitempty" protobuf:"int64,1,opt,name=iat"`
ExpiresAt int64 `json:"exp,omitempty" protobuf:"int64,2,opt,name=exp"`
}
func (app *Application) getFinalizerIndex(name string) int {
@@ -524,16 +541,14 @@ func (spec ApplicationSpec) GetProject() string {
return spec.Project
}
func (proj AppProject) IsDefault() bool {
return proj.Name == "" || proj.Name == common.DefaultAppProjectName
}
// IsSourcePermitted validiates if the provided application's source is a one of the allowed sources for the project.
func (proj AppProject) IsSourcePermitted(src ApplicationSource) bool {
if proj.IsDefault() {
return true
}
normalizedURL := git.NormalizeGitURL(src.RepoURL)
for _, repoURL := range proj.Spec.SourceRepos {
if repoURL == "*" {
return true
}
if git.NormalizeGitURL(repoURL) == normalizedURL {
return true
}
@@ -541,13 +556,14 @@ func (proj AppProject) IsSourcePermitted(src ApplicationSource) bool {
return false
}
// IsDestinationPermitted validiates if the provided application's destination is one of the allowed destinations for the project
func (proj AppProject) IsDestinationPermitted(dst ApplicationDestination) bool {
if proj.IsDefault() {
return true
}
for _, item := range proj.Spec.Destinations {
if item.Server == dst.Server && item.Namespace == dst.Namespace {
return true
if item.Server == dst.Server || item.Server == "*" {
if item.Namespace == dst.Namespace || item.Namespace == "*" {
return true
}
}
}
return false

View File

@@ -82,6 +82,13 @@ func (in *AppProjectSpec) DeepCopyInto(out *AppProjectSpec) {
*out = make([]ApplicationDestination, len(*in))
copy(*out, *in)
}
if in.Roles != nil {
in, out := &in.Roles, &out.Roles
*out = make([]ProjectRole, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
@@ -486,6 +493,22 @@ func (in *HookStatus) DeepCopy() *HookStatus {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *JWTToken) DeepCopyInto(out *JWTToken) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JWTToken.
func (in *JWTToken) DeepCopy() *JWTToken {
if in == nil {
return nil
}
out := new(JWTToken)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Operation) DeepCopyInto(out *Operation) {
*out = *in
@@ -565,6 +588,32 @@ func (in *OperationState) DeepCopy() *OperationState {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ProjectRole) DeepCopyInto(out *ProjectRole) {
*out = *in
if in.Policies != nil {
in, out := &in.Policies, &out.Policies
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.JWTTokens != nil {
in, out := &in.JWTTokens, &out.JWTTokens
*out = make([]JWTToken, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProjectRole.
func (in *ProjectRole) DeepCopy() *ProjectRole {
if in == nil {
return nil
}
out := new(ProjectRole)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Repository) DeepCopyInto(out *Repository) {
*out = *in

View File

@@ -13,7 +13,10 @@ import (
"github.com/ksonnet/ksonnet/pkg/app"
log "github.com/sirupsen/logrus"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"github.com/argoproj/argo-cd/common"
"github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
@@ -21,8 +24,9 @@ import (
"github.com/argoproj/argo-cd/util/cache"
"github.com/argoproj/argo-cd/util/git"
"github.com/argoproj/argo-cd/util/helm"
ksutil "github.com/argoproj/argo-cd/util/ksonnet"
"github.com/argoproj/argo-cd/util/ksonnet"
"github.com/argoproj/argo-cd/util/kube"
"github.com/argoproj/argo-cd/util/kustomize"
)
const (
@@ -35,6 +39,7 @@ type AppSourceType string
const (
AppSourceKsonnet AppSourceType = "ksonnet"
AppSourceHelm AppSourceType = "helm"
AppSourceKustomize AppSourceType = "kustomize"
AppSourceDirectory AppSourceType = "directory"
)
@@ -78,7 +83,7 @@ func (s *Service) ListDir(ctx context.Context, q *ListDirRequest) (*FileList, er
return &res, nil
}
err = checkoutRevision(gitClient, q.Revision)
err = checkoutRevision(gitClient, commitSHA)
if err != nil {
return nil, err
}
@@ -112,7 +117,11 @@ func (s *Service) GetFile(ctx context.Context, q *GetFileRequest) (*GetFileRespo
if err != nil {
return nil, err
}
err = checkoutRevision(gitClient, q.Revision)
commitSHA, err := gitClient.LsRemote(q.Revision)
if err != nil {
return nil, err
}
err = checkoutRevision(gitClient, commitSHA)
if err != nil {
return nil, err
}
@@ -161,7 +170,7 @@ func (s *Service) GenerateManifest(c context.Context, q *ManifestRequest) (*Mani
log.Infof("manifest cache miss: %s", cacheKey)
}
err = checkoutRevision(gitClient, q.Revision)
err = checkoutRevision(gitClient, commitSHA)
if err != nil {
return nil, err
}
@@ -197,7 +206,11 @@ func generateManifests(appPath string, q *ManifestRequest) (*ManifestResponse, e
targetObjs, params, env, err = ksShow(appPath, q.Environment, q.ComponentParameterOverrides)
case AppSourceHelm:
h := helm.NewHelmApp(appPath)
targetObjs, err = h.Template(q.AppLabel, q.ValueFiles, q.ComponentParameterOverrides)
err = h.DependencyBuild()
if err != nil {
return nil, err
}
targetObjs, err = h.Template(q.AppLabel, q.Namespace, q.ValueFiles, q.ComponentParameterOverrides)
if err != nil {
return nil, err
}
@@ -205,27 +218,49 @@ func generateManifests(appPath string, q *ManifestRequest) (*ManifestResponse, e
if err != nil {
return nil, err
}
case AppSourceKustomize:
k := kustomize.NewKustomizeApp(appPath)
targetObjs, err = k.Build()
case AppSourceDirectory:
targetObjs, err = findManifests(appPath)
}
if err != nil {
return nil, err
}
// TODO(jessesuen): we need to sort objects based on their dependency order of creation
manifests := make([]string, len(targetObjs))
for i, target := range targetObjs {
if q.AppLabel != "" {
err = kube.SetLabel(target, common.LabelApplicationName, q.AppLabel)
manifests := make([]string, 0)
for _, obj := range targetObjs {
var targets []*unstructured.Unstructured
if obj.IsList() {
err = obj.EachListItem(func(object runtime.Object) error {
unstructuredObj, ok := object.(*unstructured.Unstructured)
if ok {
targets = append(targets, unstructuredObj)
return nil
} else {
return fmt.Errorf("resource list item has unexpected type")
}
})
if err != nil {
return nil, err
}
} else {
targets = []*unstructured.Unstructured{obj}
}
manifestStr, err := json.Marshal(target.Object)
if err != nil {
return nil, err
for _, target := range targets {
if q.AppLabel != "" {
err = kube.SetLabel(target, common.LabelApplicationName, q.AppLabel)
if err != nil {
return nil, err
}
}
manifestStr, err := json.Marshal(target.Object)
if err != nil {
return nil, err
}
manifests = append(manifests, string(manifestStr))
}
manifests[i] = string(manifestStr)
}
res := ManifestResponse{
@@ -252,6 +287,9 @@ func IdentifyAppSourceTypeByAppDir(appDirPath string) AppSourceType {
if pathExists(path.Join(appDirPath, "Chart.yaml")) {
return AppSourceHelm
}
if pathExists(path.Join(appDirPath, "kustomization.yaml")) {
return AppSourceKustomize
}
return AppSourceDirectory
}
@@ -263,20 +301,19 @@ func IdentifyAppSourceTypeByAppPath(appFilePath string) AppSourceType {
if strings.HasSuffix(appFilePath, "Chart.yaml") {
return AppSourceHelm
}
if strings.HasSuffix(appFilePath, "kustomization.yaml") {
return AppSourceKustomize
}
return AppSourceDirectory
}
// checkoutRevision is a convenience function to initialize a repo, fetch, and checkout a revision
func checkoutRevision(gitClient git.Client, revision string) error {
func checkoutRevision(gitClient git.Client, commitSHA string) error {
err := gitClient.Fetch()
if err != nil {
return err
}
err = gitClient.Reset()
if err != nil {
log.Warn(err)
}
err = gitClient.Checkout(revision)
err = gitClient.Checkout(commitSHA)
if err != nil {
return err
}
@@ -286,7 +323,7 @@ func checkoutRevision(gitClient git.Client, revision string) error {
func manifestCacheKey(commitSHA string, q *ManifestRequest) string {
pStr, _ := json.Marshal(q.ComponentParameterOverrides)
valuesFiles := strings.Join(q.ValueFiles, ",")
return fmt.Sprintf("mfst|%s|%s|%s|%s|%s|%s", q.AppLabel, q.Path, q.Environment, commitSHA, string(pStr), valuesFiles)
return fmt.Sprintf("mfst|%s|%s|%s|%s|%s|%s|%s", q.AppLabel, q.Path, q.Environment, commitSHA, string(pStr), valuesFiles, q.Namespace)
}
func listDirCacheKey(commitSHA string, q *ListDirRequest) string {
@@ -295,13 +332,13 @@ func listDirCacheKey(commitSHA string, q *ListDirRequest) string {
// ksShow runs `ks show` in an app directory after setting any component parameter overrides
func ksShow(appPath, envName string, overrides []*v1alpha1.ComponentParameter) ([]*unstructured.Unstructured, []*v1alpha1.ComponentParameter, *app.EnvironmentSpec, error) {
ksApp, err := ksutil.NewKsonnetApp(appPath)
ksApp, err := ksonnet.NewKsonnetApp(appPath)
if err != nil {
return nil, nil, nil, fmt.Errorf("unable to load application from %s: %v", appPath, err)
return nil, nil, nil, status.Errorf(codes.FailedPrecondition, "unable to load application from %s: %v", appPath, err)
}
params, err := ksApp.ListEnvParams(envName)
if err != nil {
return nil, nil, nil, fmt.Errorf("Failed to list ksonnet app params: %v", err)
return nil, nil, nil, status.Errorf(codes.InvalidArgument, "Failed to list ksonnet app params: %v", err)
}
if overrides != nil {
for _, override := range overrides {
@@ -314,7 +351,7 @@ func ksShow(appPath, envName string, overrides []*v1alpha1.ComponentParameter) (
appSpec := ksApp.App()
env, err := appSpec.Environment(envName)
if err != nil {
return nil, nil, nil, fmt.Errorf("environment '%s' does not exist in ksonnet app", envName)
return nil, nil, nil, status.Errorf(codes.NotFound, "environment %q does not exist in ksonnet app", envName)
}
targetObjs, err := ksApp.Show(envName)
if err != nil {
@@ -329,7 +366,7 @@ var manifestFile = regexp.MustCompile(`^.*\.(yaml|yml|json)$`)
func findManifests(appPath string) ([]*unstructured.Unstructured, error) {
files, err := ioutil.ReadDir(appPath)
if err != nil {
return nil, fmt.Errorf("Failed to read dir %s: %v", appPath, err)
return nil, status.Errorf(codes.FailedPrecondition, "Failed to read dir %s: %v", appPath, err)
}
var objs []*unstructured.Unstructured
for _, f := range files {
@@ -344,7 +381,7 @@ func findManifests(appPath string) ([]*unstructured.Unstructured, error) {
var obj unstructured.Unstructured
err = json.Unmarshal(out, &obj)
if err != nil {
return nil, fmt.Errorf("Failed to unmarshal '%s': %v", f.Name(), err)
return nil, status.Errorf(codes.FailedPrecondition, "Failed to unmarshal %q: %v", f.Name(), err)
}
objs = append(objs, &obj)
} else {
@@ -354,7 +391,7 @@ func findManifests(appPath string) ([]*unstructured.Unstructured, error) {
// If we get here, we had a multiple objects in a single YAML file which had some
// valid k8s objects, but errors parsing others (within the same file). It's very
// likely the user messed up a portion of the YAML, so report on that.
return nil, fmt.Errorf("Failed to unmarshal '%s': %v", f.Name(), err)
return nil, status.Errorf(codes.FailedPrecondition, "Failed to unmarshal %q: %v", f.Name(), err)
}
// Otherwise, it might be a unrelated YAML file which we will ignore
continue

View File

@@ -50,6 +50,7 @@ type ManifestRequest struct {
AppLabel string `protobuf:"bytes,5,opt,name=appLabel,proto3" json:"appLabel,omitempty"`
ComponentParameterOverrides []*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.ComponentParameter `protobuf:"bytes,6,rep,name=componentParameterOverrides" json:"componentParameterOverrides,omitempty"`
ValueFiles []string `protobuf:"bytes,7,rep,name=valueFiles" json:"valueFiles,omitempty"`
Namespace string `protobuf:"bytes,8,opt,name=namespace,proto3" json:"namespace,omitempty"`
}
func (m *ManifestRequest) Reset() { *m = ManifestRequest{} }
@@ -106,6 +107,13 @@ func (m *ManifestRequest) GetValueFiles() []string {
return nil
}
func (m *ManifestRequest) GetNamespace() string {
if m != nil {
return m.Namespace
}
return ""
}
type ManifestResponse struct {
Manifests []string `protobuf:"bytes,1,rep,name=manifests" json:"manifests,omitempty"`
Namespace string `protobuf:"bytes,2,opt,name=namespace,proto3" json:"namespace,omitempty"`
@@ -483,6 +491,12 @@ func (m *ManifestRequest) MarshalTo(dAtA []byte) (int, error) {
i += copy(dAtA[i:], s)
}
}
if len(m.Namespace) > 0 {
dAtA[i] = 0x42
i++
i = encodeVarintRepository(dAtA, i, uint64(len(m.Namespace)))
i += copy(dAtA[i:], m.Namespace)
}
return i, nil
}
@@ -730,6 +744,10 @@ func (m *ManifestRequest) Size() (n int) {
n += 1 + l + sovRepository(uint64(l))
}
}
l = len(m.Namespace)
if l > 0 {
n += 1 + l + sovRepository(uint64(l))
}
return n
}
@@ -1072,6 +1090,35 @@ func (m *ManifestRequest) Unmarshal(dAtA []byte) error {
}
m.ValueFiles = append(m.ValueFiles, string(dAtA[iNdEx:postIndex]))
iNdEx = postIndex
case 8:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Namespace", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowRepository
}
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 ErrInvalidLengthRepository
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Namespace = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipRepository(dAtA[iNdEx:])
@@ -1840,41 +1887,42 @@ var (
func init() { proto.RegisterFile("reposerver/repository/repository.proto", fileDescriptorRepository) }
var fileDescriptorRepository = []byte{
// 576 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x54, 0xcd, 0x6e, 0xd3, 0x40,
0x10, 0xae, 0xc9, 0x5f, 0xb3, 0x41, 0xb4, 0xac, 0x22, 0x64, 0x39, 0x51, 0x64, 0x59, 0x02, 0xe5,
0x82, 0xad, 0x84, 0x0b, 0x17, 0x84, 0x04, 0x85, 0x0a, 0xa9, 0x55, 0x91, 0x39, 0xc1, 0x05, 0x6d,
0x9c, 0xc1, 0x59, 0x62, 0xef, 0x2e, 0xbb, 0x1b, 0x4b, 0xbc, 0x03, 0x12, 0x0f, 0xc0, 0x0b, 0x71,
0xe4, 0x11, 0x50, 0x6e, 0x7d, 0x0b, 0xe4, 0x8d, 0x1d, 0x3b, 0x6d, 0xd4, 0x0b, 0xaa, 0xd4, 0xdb,
0xcc, 0x37, 0xb3, 0xf3, 0xcd, 0x7e, 0x33, 0x1a, 0xf4, 0x44, 0x82, 0xe0, 0x0a, 0x64, 0x06, 0x32,
0x30, 0x26, 0xd5, 0x5c, 0x7e, 0xaf, 0x99, 0xbe, 0x90, 0x5c, 0x73, 0x8c, 0x2a, 0xc4, 0xe9, 0xc7,
0x3c, 0xe6, 0x06, 0x0e, 0x72, 0x6b, 0x93, 0xe1, 0x0c, 0x63, 0xce, 0xe3, 0x04, 0x02, 0x22, 0x68,
0x40, 0x18, 0xe3, 0x9a, 0x68, 0xca, 0x99, 0x2a, 0xa2, 0xde, 0xf2, 0xb9, 0xf2, 0x29, 0x37, 0xd1,
0x88, 0x4b, 0x08, 0xb2, 0x49, 0x10, 0x03, 0x03, 0x49, 0x34, 0xcc, 0x8b, 0x9c, 0x77, 0x31, 0xd5,
0x8b, 0xd5, 0xcc, 0x8f, 0x78, 0x1a, 0x10, 0x69, 0x28, 0xbe, 0x1a, 0xe3, 0x69, 0x34, 0x0f, 0xc4,
0x32, 0xce, 0x1f, 0xab, 0x80, 0x08, 0x91, 0xd0, 0xc8, 0x14, 0x0f, 0xb2, 0x09, 0x49, 0xc4, 0x82,
0x5c, 0x2b, 0xe5, 0xfd, 0x68, 0xa0, 0xa3, 0x73, 0xc2, 0xe8, 0x17, 0x50, 0x3a, 0x84, 0x6f, 0x2b,
0x50, 0x1a, 0x7f, 0x44, 0xcd, 0xfc, 0x13, 0xb6, 0xe5, 0x5a, 0xe3, 0xde, 0xf4, 0x8d, 0x5f, 0xb1,
0xf9, 0x25, 0x9b, 0x31, 0x3e, 0x47, 0x73, 0x5f, 0x2c, 0x63, 0x3f, 0x67, 0xf3, 0x6b, 0x6c, 0x7e,
0xc9, 0xe6, 0x87, 0x5b, 0x2d, 0x42, 0x53, 0x12, 0x3b, 0xe8, 0x50, 0x42, 0x46, 0x15, 0xe5, 0xcc,
0xbe, 0xe7, 0x5a, 0xe3, 0x6e, 0xb8, 0xf5, 0x31, 0x46, 0x4d, 0x41, 0xf4, 0xc2, 0x6e, 0x18, 0xdc,
0xd8, 0xd8, 0x45, 0x3d, 0x60, 0x19, 0x95, 0x9c, 0xa5, 0xc0, 0xb4, 0xdd, 0x34, 0xa1, 0x3a, 0x94,
0x57, 0x24, 0x42, 0x9c, 0x91, 0x19, 0x24, 0x76, 0x6b, 0x53, 0xb1, 0xf4, 0xf1, 0x4f, 0x0b, 0x0d,
0x22, 0x9e, 0x0a, 0xce, 0x80, 0xe9, 0xf7, 0x44, 0x92, 0x14, 0x34, 0xc8, 0x8b, 0x0c, 0xa4, 0xa4,
0x73, 0x50, 0x76, 0xdb, 0x6d, 0x8c, 0x7b, 0xd3, 0xf3, 0xff, 0xf8, 0xe0, 0xeb, 0x6b, 0xd5, 0xc3,
0x9b, 0x18, 0xf1, 0x08, 0xa1, 0x8c, 0x24, 0x2b, 0x78, 0x4b, 0x13, 0x50, 0x76, 0xc7, 0x6d, 0x8c,
0xbb, 0x61, 0x0d, 0xf1, 0x2e, 0x2d, 0x74, 0x5c, 0x8d, 0x43, 0x09, 0xce, 0x14, 0xe0, 0x21, 0xea,
0xa6, 0x05, 0xa6, 0x6c, 0xcb, 0xbc, 0xa9, 0x80, 0x3c, 0xca, 0x48, 0x0a, 0x4a, 0x90, 0x08, 0x0a,
0x4d, 0x2b, 0x00, 0x3f, 0x42, 0xed, 0xcd, 0xd2, 0x16, 0xb2, 0x16, 0xde, 0xce, 0x20, 0x9a, 0x57,
0x06, 0x01, 0xa8, 0x2d, 0xf2, 0xd6, 0x95, 0xdd, 0xba, 0x0d, 0x81, 0x8a, 0xe2, 0xde, 0x2f, 0x0b,
0x3d, 0x38, 0xa3, 0x4a, 0x9f, 0x50, 0x79, 0xf7, 0x36, 0xcf, 0x73, 0xd1, 0x61, 0x3e, 0x92, 0xbc,
0x41, 0xdc, 0x47, 0x2d, 0xaa, 0x21, 0x2d, 0xc5, 0xdf, 0x38, 0xa6, 0xff, 0x53, 0xd0, 0x79, 0xd6,
0x1d, 0xec, 0xff, 0x31, 0x3a, 0xda, 0x36, 0x57, 0xec, 0x11, 0x46, 0xcd, 0x39, 0xd1, 0xc4, 0x74,
0x77, 0x3f, 0x34, 0xf6, 0xf4, 0xd2, 0x42, 0x0f, 0x2b, 0xae, 0x0f, 0x20, 0x33, 0x1a, 0x01, 0xbe,
0x40, 0xc7, 0xa7, 0xc5, 0xa1, 0x28, 0xb7, 0x11, 0x0f, 0xfc, 0xda, 0xad, 0xbb, 0x72, 0x32, 0x9c,
0xe1, 0xfe, 0xe0, 0x86, 0xd8, 0x3b, 0xc0, 0x2f, 0x50, 0xa7, 0x18, 0x35, 0x76, 0xea, 0xa9, 0xbb,
0xf3, 0x77, 0xfa, 0xf5, 0x58, 0x29, 0xbf, 0x77, 0x80, 0x4f, 0x50, 0xa7, 0xf8, 0xcc, 0xee, 0xf3,
0x5d, 0xf9, 0x9d, 0xc1, 0xde, 0x58, 0xd9, 0xc4, 0xab, 0x97, 0xbf, 0xd7, 0x23, 0xeb, 0xcf, 0x7a,
0x64, 0xfd, 0x5d, 0x8f, 0xac, 0x4f, 0x93, 0x9b, 0x8e, 0xe8, 0xde, 0x63, 0x3f, 0x6b, 0x9b, 0x9b,
0xf9, 0xec, 0x5f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x12, 0x81, 0x49, 0x46, 0x0c, 0x06, 0x00, 0x00,
// 584 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x55, 0xdd, 0x8a, 0xd3, 0x40,
0x14, 0xde, 0x6c, 0xbb, 0xdd, 0x76, 0x2a, 0xee, 0x3a, 0x14, 0x09, 0x69, 0x29, 0x21, 0xa0, 0xf4,
0xc6, 0x84, 0xd6, 0x1b, 0x6f, 0x44, 0xd0, 0xd5, 0x45, 0xd8, 0x65, 0x25, 0x5e, 0xe9, 0x8d, 0x4c,
0xd3, 0x63, 0x3a, 0x36, 0x99, 0x19, 0x67, 0xa6, 0x01, 0x9f, 0xc2, 0x07, 0xf0, 0x0d, 0x7c, 0x12,
0x2f, 0x7d, 0x04, 0xe9, 0xdd, 0xbe, 0x85, 0x64, 0x9a, 0x34, 0x69, 0xb7, 0xec, 0x8d, 0x08, 0x7b,
0x77, 0xe6, 0x3b, 0x27, 0xdf, 0x77, 0xfe, 0x38, 0x41, 0x8f, 0x25, 0x08, 0xae, 0x40, 0x66, 0x20,
0x03, 0x63, 0x52, 0xcd, 0xe5, 0xb7, 0x9a, 0xe9, 0x0b, 0xc9, 0x35, 0xc7, 0xa8, 0x42, 0x9c, 0x5e,
0xcc, 0x63, 0x6e, 0xe0, 0x20, 0xb7, 0xd6, 0x11, 0xce, 0x20, 0xe6, 0x3c, 0x4e, 0x20, 0x20, 0x82,
0x06, 0x84, 0x31, 0xae, 0x89, 0xa6, 0x9c, 0xa9, 0xc2, 0xeb, 0x2d, 0x9e, 0x29, 0x9f, 0x72, 0xe3,
0x8d, 0xb8, 0x84, 0x20, 0x1b, 0x07, 0x31, 0x30, 0x90, 0x44, 0xc3, 0xac, 0x88, 0x79, 0x1b, 0x53,
0x3d, 0x5f, 0x4e, 0xfd, 0x88, 0xa7, 0x01, 0x91, 0x46, 0xe2, 0x8b, 0x31, 0x9e, 0x44, 0xb3, 0x40,
0x2c, 0xe2, 0xfc, 0x63, 0x15, 0x10, 0x21, 0x12, 0x1a, 0x19, 0xf2, 0x20, 0x1b, 0x93, 0x44, 0xcc,
0xc9, 0x0d, 0x2a, 0xef, 0x67, 0x03, 0x9d, 0x5c, 0x12, 0x46, 0x3f, 0x83, 0xd2, 0x21, 0x7c, 0x5d,
0x82, 0xd2, 0xf8, 0x03, 0x6a, 0xe6, 0x45, 0xd8, 0x96, 0x6b, 0x8d, 0xba, 0x93, 0xd7, 0x7e, 0xa5,
0xe6, 0x97, 0x6a, 0xc6, 0xf8, 0x14, 0xcd, 0x7c, 0xb1, 0x88, 0xfd, 0x5c, 0xcd, 0xaf, 0xa9, 0xf9,
0xa5, 0x9a, 0x1f, 0x6e, 0x7a, 0x11, 0x1a, 0x4a, 0xec, 0xa0, 0xb6, 0x84, 0x8c, 0x2a, 0xca, 0x99,
0x7d, 0xe8, 0x5a, 0xa3, 0x4e, 0xb8, 0x79, 0x63, 0x8c, 0x9a, 0x82, 0xe8, 0xb9, 0xdd, 0x30, 0xb8,
0xb1, 0xb1, 0x8b, 0xba, 0xc0, 0x32, 0x2a, 0x39, 0x4b, 0x81, 0x69, 0xbb, 0x69, 0x5c, 0x75, 0x28,
0x67, 0x24, 0x42, 0x5c, 0x90, 0x29, 0x24, 0xf6, 0xd1, 0x9a, 0xb1, 0x7c, 0xe3, 0xef, 0x16, 0xea,
0x47, 0x3c, 0x15, 0x9c, 0x01, 0xd3, 0xef, 0x88, 0x24, 0x29, 0x68, 0x90, 0x57, 0x19, 0x48, 0x49,
0x67, 0xa0, 0xec, 0x96, 0xdb, 0x18, 0x75, 0x27, 0x97, 0xff, 0x50, 0xe0, 0xab, 0x1b, 0xec, 0xe1,
0x6d, 0x8a, 0x78, 0x88, 0x50, 0x46, 0x92, 0x25, 0xbc, 0xa1, 0x09, 0x28, 0xfb, 0xd8, 0x6d, 0x8c,
0x3a, 0x61, 0x0d, 0xc1, 0x03, 0xd4, 0x61, 0x24, 0x05, 0x25, 0x48, 0x04, 0x76, 0xdb, 0x94, 0x53,
0x01, 0xde, 0xb5, 0x85, 0x4e, 0xab, 0x61, 0x29, 0xc1, 0x99, 0x82, 0xfc, 0x93, 0xb4, 0xc0, 0x94,
0x6d, 0x19, 0xc6, 0x0a, 0xd8, 0x26, 0x3c, 0xdc, 0x21, 0xc4, 0x0f, 0x51, 0x6b, 0xbd, 0xd2, 0x45,
0xd3, 0x8b, 0xd7, 0xd6, 0x98, 0x9a, 0x3b, 0x63, 0x02, 0xd4, 0x12, 0x79, 0x61, 0xca, 0x3e, 0xfa,
0x1f, 0xed, 0x2b, 0xc8, 0xbd, 0x1f, 0x16, 0xba, 0x7f, 0x41, 0x95, 0x3e, 0xa3, 0xf2, 0xee, 0xed,
0xa5, 0xe7, 0xa2, 0x76, 0x3e, 0xb0, 0x3c, 0x41, 0xdc, 0x43, 0x47, 0x54, 0x43, 0x5a, 0x36, 0x7f,
0xfd, 0x30, 0xf9, 0x9f, 0x83, 0xce, 0xa3, 0xee, 0x60, 0xfe, 0x8f, 0xd0, 0xc9, 0x26, 0xb9, 0x62,
0x8f, 0x30, 0x6a, 0xce, 0x88, 0x26, 0x26, 0xbb, 0x7b, 0xa1, 0xb1, 0x27, 0xd7, 0x16, 0x7a, 0x50,
0x69, 0xbd, 0x07, 0x99, 0xd1, 0x08, 0xf0, 0x15, 0x3a, 0x3d, 0x2f, 0xce, 0x48, 0xb9, 0x8d, 0xb8,
0xef, 0xd7, 0x2e, 0xe1, 0xce, 0x41, 0x71, 0x06, 0xfb, 0x9d, 0x6b, 0x61, 0xef, 0x00, 0x3f, 0x47,
0xc7, 0xc5, 0xa8, 0xb1, 0x53, 0x0f, 0xdd, 0x9e, 0xbf, 0xd3, 0xab, 0xfb, 0xca, 0xf6, 0x7b, 0x07,
0xf8, 0x0c, 0x1d, 0x17, 0xc5, 0x6c, 0x7f, 0xbe, 0xdd, 0x7e, 0xa7, 0xbf, 0xd7, 0x57, 0x26, 0xf1,
0xf2, 0xc5, 0xaf, 0xd5, 0xd0, 0xfa, 0xbd, 0x1a, 0x5a, 0x7f, 0x56, 0x43, 0xeb, 0xe3, 0xf8, 0xb6,
0x13, 0xbb, 0xf7, 0x57, 0x30, 0x6d, 0x99, 0x8b, 0xfa, 0xf4, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff,
0x22, 0x8e, 0xa1, 0x51, 0x2a, 0x06, 0x00, 0x00,
}

View File

@@ -17,6 +17,7 @@ message ManifestRequest {
string appLabel = 5;
repeated github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.ComponentParameter componentParameterOverrides = 6;
repeated string valueFiles = 7;
string namespace = 8;
}
message ManifestResponse {

View File

@@ -15,6 +15,7 @@ import (
"k8s.io/api/core/v1"
apierr "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/kubernetes"
@@ -31,6 +32,7 @@ import (
argoutil "github.com/argoproj/argo-cd/util/argo"
"github.com/argoproj/argo-cd/util/db"
"github.com/argoproj/argo-cd/util/grpc"
"github.com/argoproj/argo-cd/util/kube"
"github.com/argoproj/argo-cd/util/rbac"
"github.com/argoproj/argo-cd/util/session"
)
@@ -100,10 +102,8 @@ func (s *Server) Create(ctx context.Context, q *ApplicationCreateRequest) (*appv
return nil, grpc.ErrPermissionDenied
}
if !q.Application.Spec.BelongsToDefaultProject() {
s.projectLock.Lock(q.Application.Spec.Project)
defer s.projectLock.Unlock(q.Application.Spec.Project)
}
s.projectLock.Lock(q.Application.Spec.Project)
defer s.projectLock.Unlock(q.Application.Spec.Project)
a := q.Application
err := s.validateApp(ctx, &a.Spec)
@@ -174,6 +174,7 @@ func (s *Server) GetManifests(ctx context.Context, q *ApplicationManifestQuery)
ComponentParameterOverrides: overrides,
AppLabel: a.Name,
ValueFiles: a.Spec.Source.ValuesFiles,
Namespace: a.Spec.Destination.Namespace,
})
if err != nil {
return nil, err
@@ -258,10 +259,8 @@ func (s *Server) Update(ctx context.Context, q *ApplicationUpdateRequest) (*appv
return nil, grpc.ErrPermissionDenied
}
if !q.Application.Spec.BelongsToDefaultProject() {
s.projectLock.Lock(q.Application.Spec.Project)
defer s.projectLock.Unlock(q.Application.Spec.Project)
}
s.projectLock.Lock(q.Application.Spec.Project)
defer s.projectLock.Unlock(q.Application.Spec.Project)
a := q.Application
err := s.validateApp(ctx, &a.Spec)
@@ -302,10 +301,8 @@ func (s *Server) removeInvalidOverrides(a *appv1.Application, q *ApplicationUpda
// UpdateSpec updates an application spec and filters out any invalid parameter overrides
func (s *Server) UpdateSpec(ctx context.Context, q *ApplicationUpdateSpecRequest) (*appv1.ApplicationSpec, error) {
if !q.Spec.BelongsToDefaultProject() {
s.projectLock.Lock(q.Spec.Project)
defer s.projectLock.Unlock(q.Spec.Project)
}
s.projectLock.Lock(q.Spec.Project)
defer s.projectLock.Unlock(q.Spec.Project)
a, err := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Get(*q.Name, metav1.GetOptions{})
if err != nil {
@@ -348,10 +345,8 @@ func (s *Server) Delete(ctx context.Context, q *ApplicationDeleteRequest) (*Appl
return nil, err
}
if !a.Spec.BelongsToDefaultProject() {
s.projectLock.Lock(a.Spec.Project)
defer s.projectLock.Unlock(a.Spec.Project)
}
s.projectLock.Lock(a.Spec.Project)
defer s.projectLock.Unlock(a.Spec.Project)
if !s.enf.EnforceClaims(ctx.Value("claims"), "applications", "delete", appRBACName(*a)) {
return nil, grpc.ErrPermissionDenied
@@ -481,35 +476,69 @@ func (s *Server) ensurePodBelongsToApp(applicationName string, podName, namespac
return nil
}
func (s *Server) DeletePod(ctx context.Context, q *ApplicationDeletePodRequest) (*ApplicationResponse, error) {
func (s *Server) DeleteResource(ctx context.Context, q *ApplicationDeleteResourceRequest) (*ApplicationResponse, error) {
a, err := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Get(*q.Name, metav1.GetOptions{})
if err != nil {
return nil, err
}
if !s.enf.EnforceClaims(ctx.Value("claims"), "applications/pods", "delete", appRBACName(*a)) {
if !s.enf.EnforceClaims(ctx.Value("claims"), "applications/resources", "delete", appRBACName(*a)) {
return nil, grpc.ErrPermissionDenied
}
found := findResource(a, q)
if found == nil {
return nil, status.Errorf(codes.InvalidArgument, "%s %s %s not found as part of application %s", q.Kind, q.APIVersion, q.ResourceName, *q.Name)
}
config, namespace, err := s.getApplicationClusterConfig(*q.Name)
if err != nil {
return nil, err
}
kubeClientset, err := kubernetes.NewForConfig(config)
if err != nil {
return nil, err
}
err = s.ensurePodBelongsToApp(*q.Name, *q.PodName, namespace, kubeClientset)
if err != nil {
return nil, err
}
err = kubeClientset.CoreV1().Pods(namespace).Delete(*q.PodName, &metav1.DeleteOptions{})
err = kube.DeleteResource(config, found, namespace)
if err != nil {
return nil, err
}
return &ApplicationResponse{}, nil
}
func findResource(a *appv1.Application, q *ApplicationDeleteResourceRequest) *unstructured.Unstructured {
for _, res := range a.Status.ComparisonResult.Resources {
liveObj, err := res.LiveObject()
if err != nil {
log.Warnf("Failed to unmarshal live object: %v", err)
continue
}
if liveObj == nil {
continue
}
if q.ResourceName == liveObj.GetName() && q.APIVersion == liveObj.GetAPIVersion() && q.Kind == liveObj.GetKind() {
return liveObj
}
liveObj = recurseResourceNode(q.ResourceName, q.APIVersion, q.Kind, res.ChildLiveResources)
if liveObj != nil {
return liveObj
}
}
return nil
}
func recurseResourceNode(name, apiVersion, kind string, nodes []appv1.ResourceNode) *unstructured.Unstructured {
for _, node := range nodes {
var childObj unstructured.Unstructured
err := json.Unmarshal([]byte(node.State), &childObj)
if err != nil {
log.Warnf("Failed to unmarshal child live object: %v", err)
continue
}
if name == childObj.GetName() && apiVersion == childObj.GetAPIVersion() && kind == childObj.GetKind() {
return &childObj
}
recurseChildObj := recurseResourceNode(name, apiVersion, kind, node.Children)
if recurseChildObj != nil {
return recurseChildObj
}
}
return nil
}
func (s *Server) PodLogs(q *ApplicationPodLogsQuery, ws ApplicationService_PodLogsServer) error {
a, err := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Get(*q.Name, metav1.GetOptions{})
if err != nil {

View File

@@ -22,7 +22,7 @@
ApplicationSyncRequest
ApplicationUpdateSpecRequest
ApplicationRollbackRequest
ApplicationDeletePodRequest
ApplicationDeleteResourceRequest
ApplicationPodLogsQuery
LogEntry
OperationTerminateRequest
@@ -359,29 +359,45 @@ func (m *ApplicationRollbackRequest) GetPrune() bool {
return false
}
type ApplicationDeletePodRequest struct {
type ApplicationDeleteResourceRequest struct {
Name *string `protobuf:"bytes,1,req,name=name" json:"name,omitempty"`
PodName *string `protobuf:"bytes,2,req,name=podName" json:"podName,omitempty"`
ResourceName string `protobuf:"bytes,2,req,name=resourceName" json:"resourceName"`
APIVersion string `protobuf:"bytes,3,req,name=apiVersion" json:"apiVersion"`
Kind string `protobuf:"bytes,4,req,name=kind" json:"kind"`
XXX_unrecognized []byte `json:"-"`
}
func (m *ApplicationDeletePodRequest) Reset() { *m = ApplicationDeletePodRequest{} }
func (m *ApplicationDeletePodRequest) String() string { return proto.CompactTextString(m) }
func (*ApplicationDeletePodRequest) ProtoMessage() {}
func (*ApplicationDeletePodRequest) Descriptor() ([]byte, []int) {
func (m *ApplicationDeleteResourceRequest) Reset() { *m = ApplicationDeleteResourceRequest{} }
func (m *ApplicationDeleteResourceRequest) String() string { return proto.CompactTextString(m) }
func (*ApplicationDeleteResourceRequest) ProtoMessage() {}
func (*ApplicationDeleteResourceRequest) Descriptor() ([]byte, []int) {
return fileDescriptorApplication, []int{10}
}
func (m *ApplicationDeletePodRequest) GetName() string {
func (m *ApplicationDeleteResourceRequest) GetName() string {
if m != nil && m.Name != nil {
return *m.Name
}
return ""
}
func (m *ApplicationDeletePodRequest) GetPodName() string {
if m != nil && m.PodName != nil {
return *m.PodName
func (m *ApplicationDeleteResourceRequest) GetResourceName() string {
if m != nil {
return m.ResourceName
}
return ""
}
func (m *ApplicationDeleteResourceRequest) GetAPIVersion() string {
if m != nil {
return m.APIVersion
}
return ""
}
func (m *ApplicationDeleteResourceRequest) GetKind() string {
if m != nil {
return m.Kind
}
return ""
}
@@ -519,7 +535,7 @@ func init() {
proto.RegisterType((*ApplicationSyncRequest)(nil), "application.ApplicationSyncRequest")
proto.RegisterType((*ApplicationUpdateSpecRequest)(nil), "application.ApplicationUpdateSpecRequest")
proto.RegisterType((*ApplicationRollbackRequest)(nil), "application.ApplicationRollbackRequest")
proto.RegisterType((*ApplicationDeletePodRequest)(nil), "application.ApplicationDeletePodRequest")
proto.RegisterType((*ApplicationDeleteResourceRequest)(nil), "application.ApplicationDeleteResourceRequest")
proto.RegisterType((*ApplicationPodLogsQuery)(nil), "application.ApplicationPodLogsQuery")
proto.RegisterType((*LogEntry)(nil), "application.LogEntry")
proto.RegisterType((*OperationTerminateRequest)(nil), "application.OperationTerminateRequest")
@@ -561,8 +577,8 @@ type ApplicationServiceClient interface {
Rollback(ctx context.Context, in *ApplicationRollbackRequest, opts ...grpc.CallOption) (*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Application, error)
// TerminateOperation terminates the currently running operation
TerminateOperation(ctx context.Context, in *OperationTerminateRequest, opts ...grpc.CallOption) (*OperationTerminateResponse, error)
// DeletePod returns stream of log entries for the specified pod. Pod
DeletePod(ctx context.Context, in *ApplicationDeletePodRequest, opts ...grpc.CallOption) (*ApplicationResponse, error)
// DeleteResource deletes a single application resource
DeleteResource(ctx context.Context, in *ApplicationDeleteResourceRequest, opts ...grpc.CallOption) (*ApplicationResponse, error)
// PodLogs returns stream of log entries for the specified pod. Pod
PodLogs(ctx context.Context, in *ApplicationPodLogsQuery, opts ...grpc.CallOption) (ApplicationService_PodLogsClient, error)
}
@@ -706,9 +722,9 @@ func (c *applicationServiceClient) TerminateOperation(ctx context.Context, in *O
return out, nil
}
func (c *applicationServiceClient) DeletePod(ctx context.Context, in *ApplicationDeletePodRequest, opts ...grpc.CallOption) (*ApplicationResponse, error) {
func (c *applicationServiceClient) DeleteResource(ctx context.Context, in *ApplicationDeleteResourceRequest, opts ...grpc.CallOption) (*ApplicationResponse, error) {
out := new(ApplicationResponse)
err := grpc.Invoke(ctx, "/application.ApplicationService/DeletePod", in, out, c.cc, opts...)
err := grpc.Invoke(ctx, "/application.ApplicationService/DeleteResource", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
@@ -774,8 +790,8 @@ type ApplicationServiceServer interface {
Rollback(context.Context, *ApplicationRollbackRequest) (*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Application, error)
// TerminateOperation terminates the currently running operation
TerminateOperation(context.Context, *OperationTerminateRequest) (*OperationTerminateResponse, error)
// DeletePod returns stream of log entries for the specified pod. Pod
DeletePod(context.Context, *ApplicationDeletePodRequest) (*ApplicationResponse, error)
// DeleteResource deletes a single application resource
DeleteResource(context.Context, *ApplicationDeleteResourceRequest) (*ApplicationResponse, error)
// PodLogs returns stream of log entries for the specified pod. Pod
PodLogs(*ApplicationPodLogsQuery, ApplicationService_PodLogsServer) error
}
@@ -1003,20 +1019,20 @@ func _ApplicationService_TerminateOperation_Handler(srv interface{}, ctx context
return interceptor(ctx, in, info, handler)
}
func _ApplicationService_DeletePod_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ApplicationDeletePodRequest)
func _ApplicationService_DeleteResource_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ApplicationDeleteResourceRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ApplicationServiceServer).DeletePod(ctx, in)
return srv.(ApplicationServiceServer).DeleteResource(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/application.ApplicationService/DeletePod",
FullMethod: "/application.ApplicationService/DeleteResource",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ApplicationServiceServer).DeletePod(ctx, req.(*ApplicationDeletePodRequest))
return srv.(ApplicationServiceServer).DeleteResource(ctx, req.(*ApplicationDeleteResourceRequest))
}
return interceptor(ctx, in, info, handler)
}
@@ -1091,8 +1107,8 @@ var _ApplicationService_serviceDesc = grpc.ServiceDesc{
Handler: _ApplicationService_TerminateOperation_Handler,
},
{
MethodName: "DeletePod",
Handler: _ApplicationService_DeletePod_Handler,
MethodName: "DeleteResource",
Handler: _ApplicationService_DeleteResource_Handler,
},
},
Streams: []grpc.StreamDesc{
@@ -1506,7 +1522,7 @@ func (m *ApplicationRollbackRequest) MarshalTo(dAtA []byte) (int, error) {
return i, nil
}
func (m *ApplicationDeletePodRequest) Marshal() (dAtA []byte, err error) {
func (m *ApplicationDeleteResourceRequest) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalTo(dAtA)
@@ -1516,7 +1532,7 @@ func (m *ApplicationDeletePodRequest) Marshal() (dAtA []byte, err error) {
return dAtA[:n], nil
}
func (m *ApplicationDeletePodRequest) MarshalTo(dAtA []byte) (int, error) {
func (m *ApplicationDeleteResourceRequest) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
@@ -1529,14 +1545,18 @@ func (m *ApplicationDeletePodRequest) MarshalTo(dAtA []byte) (int, error) {
i = encodeVarintApplication(dAtA, i, uint64(len(*m.Name)))
i += copy(dAtA[i:], *m.Name)
}
if m.PodName == nil {
return 0, proto.NewRequiredNotSetError("podName")
} else {
dAtA[i] = 0x12
i++
i = encodeVarintApplication(dAtA, i, uint64(len(*m.PodName)))
i += copy(dAtA[i:], *m.PodName)
}
dAtA[i] = 0x12
i++
i = encodeVarintApplication(dAtA, i, uint64(len(m.ResourceName)))
i += copy(dAtA[i:], m.ResourceName)
dAtA[i] = 0x1a
i++
i = encodeVarintApplication(dAtA, i, uint64(len(m.APIVersion)))
i += copy(dAtA[i:], m.APIVersion)
dAtA[i] = 0x22
i++
i = encodeVarintApplication(dAtA, i, uint64(len(m.Kind)))
i += copy(dAtA[i:], m.Kind)
if m.XXX_unrecognized != nil {
i += copy(dAtA[i:], m.XXX_unrecognized)
}
@@ -1856,17 +1876,19 @@ func (m *ApplicationRollbackRequest) Size() (n int) {
return n
}
func (m *ApplicationDeletePodRequest) Size() (n int) {
func (m *ApplicationDeleteResourceRequest) Size() (n int) {
var l int
_ = l
if m.Name != nil {
l = len(*m.Name)
n += 1 + l + sovApplication(uint64(l))
}
if m.PodName != nil {
l = len(*m.PodName)
n += 1 + l + sovApplication(uint64(l))
}
l = len(m.ResourceName)
n += 1 + l + sovApplication(uint64(l))
l = len(m.APIVersion)
n += 1 + l + sovApplication(uint64(l))
l = len(m.Kind)
n += 1 + l + sovApplication(uint64(l))
if m.XXX_unrecognized != nil {
n += len(m.XXX_unrecognized)
}
@@ -3155,7 +3177,7 @@ func (m *ApplicationRollbackRequest) Unmarshal(dAtA []byte) error {
}
return nil
}
func (m *ApplicationDeletePodRequest) Unmarshal(dAtA []byte) error {
func (m *ApplicationDeleteResourceRequest) Unmarshal(dAtA []byte) error {
var hasFields [1]uint64
l := len(dAtA)
iNdEx := 0
@@ -3179,10 +3201,10 @@ func (m *ApplicationDeletePodRequest) Unmarshal(dAtA []byte) error {
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: ApplicationDeletePodRequest: wiretype end group for non-group")
return fmt.Errorf("proto: ApplicationDeleteResourceRequest: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: ApplicationDeletePodRequest: illegal tag %d (wire type %d)", fieldNum, wire)
return fmt.Errorf("proto: ApplicationDeleteResourceRequest: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
@@ -3218,7 +3240,7 @@ func (m *ApplicationDeletePodRequest) Unmarshal(dAtA []byte) error {
hasFields[0] |= uint64(0x00000001)
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field PodName", wireType)
return fmt.Errorf("proto: wrong wireType = %d for field ResourceName", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
@@ -3243,10 +3265,69 @@ func (m *ApplicationDeletePodRequest) Unmarshal(dAtA []byte) error {
if postIndex > l {
return io.ErrUnexpectedEOF
}
s := string(dAtA[iNdEx:postIndex])
m.PodName = &s
m.ResourceName = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
hasFields[0] |= uint64(0x00000002)
case 3:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field APIVersion", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowApplication
}
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 ErrInvalidLengthApplication
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.APIVersion = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
hasFields[0] |= uint64(0x00000004)
case 4:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Kind", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowApplication
}
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 ErrInvalidLengthApplication
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Kind = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
hasFields[0] |= uint64(0x00000008)
default:
iNdEx = preIndex
skippy, err := skipApplication(dAtA[iNdEx:])
@@ -3267,7 +3348,13 @@ func (m *ApplicationDeletePodRequest) Unmarshal(dAtA []byte) error {
return proto.NewRequiredNotSetError("name")
}
if hasFields[0]&uint64(0x00000002) == 0 {
return proto.NewRequiredNotSetError("podName")
return proto.NewRequiredNotSetError("resourceName")
}
if hasFields[0]&uint64(0x00000004) == 0 {
return proto.NewRequiredNotSetError("apiVersion")
}
if hasFields[0]&uint64(0x00000008) == 0 {
return proto.NewRequiredNotSetError("kind")
}
if iNdEx > l {
@@ -3895,86 +3982,88 @@ var (
func init() { proto.RegisterFile("server/application/application.proto", fileDescriptorApplication) }
var fileDescriptorApplication = []byte{
// 1288 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x58, 0x41, 0x8f, 0x1b, 0x35,
0x14, 0xc6, 0xd9, 0x74, 0x77, 0xe3, 0xed, 0xa1, 0x32, 0x6d, 0x19, 0xa6, 0xe9, 0x36, 0x72, 0xb7,
0x6d, 0x9a, 0xd2, 0x99, 0xee, 0x0a, 0x09, 0x54, 0x21, 0x21, 0x96, 0x96, 0xb6, 0xb0, 0x94, 0x25,
0xdb, 0x0a, 0x89, 0x0b, 0x72, 0x67, 0xdc, 0xc9, 0xb0, 0x89, 0x3d, 0xd8, 0x4e, 0x50, 0xa8, 0x7a,
0xa0, 0x42, 0x5c, 0x40, 0x42, 0x08, 0x0e, 0xdc, 0x80, 0x9e, 0xb9, 0x71, 0xe7, 0xdc, 0x23, 0x12,
0xf7, 0x0a, 0xad, 0xb8, 0xf2, 0x1b, 0x40, 0xf6, 0xcc, 0x64, 0x3c, 0xdd, 0x64, 0xb6, 0x40, 0xb8,
0x79, 0x9e, 0xed, 0xf7, 0x7d, 0x7e, 0xef, 0xd9, 0xdf, 0x4b, 0xe0, 0x9a, 0xa4, 0x62, 0x44, 0x85,
0x4f, 0x92, 0xa4, 0x1f, 0x07, 0x44, 0xc5, 0x9c, 0xd9, 0x63, 0x2f, 0x11, 0x5c, 0x71, 0xb4, 0x62,
0x99, 0xdc, 0xa3, 0x11, 0x8f, 0xb8, 0xb1, 0xfb, 0x7a, 0x94, 0x2e, 0x71, 0x9b, 0x11, 0xe7, 0x51,
0x9f, 0xfa, 0x24, 0x89, 0x7d, 0xc2, 0x18, 0x57, 0x66, 0xb1, 0xcc, 0x66, 0xf1, 0xee, 0xcb, 0xd2,
0x8b, 0xb9, 0x99, 0x0d, 0xb8, 0xa0, 0xfe, 0x68, 0xdd, 0x8f, 0x28, 0xa3, 0x82, 0x28, 0x1a, 0x66,
0x6b, 0x5e, 0x2c, 0xd6, 0x0c, 0x48, 0xd0, 0x8b, 0x19, 0x15, 0x63, 0x3f, 0xd9, 0x8d, 0xb4, 0x41,
0xfa, 0x03, 0xaa, 0xc8, 0xb4, 0x5d, 0x37, 0xa2, 0x58, 0xf5, 0x86, 0x77, 0xbc, 0x80, 0x0f, 0x7c,
0x22, 0x0c, 0xb1, 0x0f, 0xcd, 0xe0, 0x62, 0x10, 0x16, 0xbb, 0xed, 0xe3, 0x8d, 0xd6, 0x49, 0x3f,
0xe9, 0x91, 0xfd, 0xae, 0x36, 0xab, 0x5c, 0x09, 0x9a, 0xf0, 0x2c, 0x56, 0x66, 0x18, 0x2b, 0x2e,
0xc6, 0xd6, 0x30, 0xf5, 0x81, 0x19, 0x3c, 0xf2, 0x5a, 0x81, 0xf5, 0xee, 0x90, 0x8a, 0x31, 0x42,
0xb0, 0xce, 0xc8, 0x80, 0x3a, 0xa0, 0x05, 0xda, 0x8d, 0xae, 0x19, 0xa3, 0x55, 0xb8, 0x24, 0xe8,
0x5d, 0x41, 0x65, 0xcf, 0xa9, 0xb5, 0x40, 0x7b, 0x79, 0xb3, 0xfe, 0xe8, 0xf1, 0xa9, 0x67, 0xba,
0xb9, 0x11, 0x9d, 0x85, 0x4b, 0x1a, 0x9e, 0x06, 0xca, 0x59, 0x68, 0x2d, 0xb4, 0x1b, 0x9b, 0x87,
0xf7, 0x1e, 0x9f, 0x5a, 0xde, 0x4e, 0x4d, 0xb2, 0x9b, 0x4f, 0xe2, 0xcf, 0x01, 0x5c, 0xb5, 0x00,
0xbb, 0x54, 0xf2, 0xa1, 0x08, 0xe8, 0xd5, 0x11, 0x65, 0x4a, 0x3e, 0x09, 0x5f, 0x9b, 0xc0, 0xb7,
0xe1, 0x61, 0x91, 0x2d, 0xbd, 0xa9, 0xe7, 0x6a, 0x7a, 0x2e, 0xe3, 0x50, 0x9a, 0x41, 0x67, 0xe1,
0x4a, 0xfe, 0x7d, 0xfb, 0xc6, 0x15, 0x67, 0xc1, 0x5a, 0x68, 0x4f, 0xe0, 0x6d, 0xe8, 0x58, 0x3c,
0xde, 0x26, 0x2c, 0xbe, 0x4b, 0xa5, 0x9a, 0xcd, 0xa0, 0x05, 0x97, 0x05, 0x1d, 0xc5, 0x32, 0xe6,
0xcc, 0x44, 0x20, 0x77, 0x3a, 0xb1, 0xe2, 0x63, 0xf0, 0xd9, 0xf2, 0xc9, 0x12, 0xce, 0x24, 0xc5,
0x0f, 0x41, 0x09, 0xe9, 0x75, 0x41, 0x89, 0xa2, 0x5d, 0xfa, 0xd1, 0x90, 0x4a, 0x85, 0x18, 0xb4,
0x4b, 0xd5, 0x00, 0xae, 0x6c, 0xbc, 0xe1, 0x15, 0x89, 0xf5, 0xf2, 0xc4, 0x9a, 0xc1, 0x07, 0x41,
0xe8, 0x25, 0xbb, 0x91, 0xa7, 0x6b, 0xc4, 0xb3, 0xcb, 0x3e, 0xaf, 0x11, 0xcf, 0x42, 0xca, 0x4f,
0x6d, 0xad, 0x43, 0xc7, 0xe1, 0xe2, 0x30, 0x91, 0x54, 0xa8, 0x34, 0x8b, 0xdd, 0xec, 0x0b, 0x7f,
0x56, 0x26, 0x79, 0x3b, 0x09, 0x2d, 0x92, 0xbd, 0xff, 0x91, 0x64, 0x89, 0x1e, 0xbe, 0x5e, 0x62,
0x71, 0x85, 0xf6, 0x69, 0xc1, 0x62, 0x5a, 0x52, 0x1c, 0xb8, 0x14, 0x10, 0x19, 0x90, 0x90, 0x66,
0xe7, 0xc9, 0x3f, 0xf1, 0x9f, 0x00, 0x1e, 0xb7, 0x5c, 0xed, 0x8c, 0x59, 0x50, 0xe5, 0xe8, 0xc0,
0xec, 0xa2, 0x26, 0x5c, 0x0c, 0xc5, 0xb8, 0x3b, 0x64, 0xce, 0x82, 0x55, 0xff, 0x99, 0x0d, 0xb9,
0xf0, 0x50, 0x22, 0x86, 0x8c, 0x3a, 0x75, 0x6b, 0x32, 0x35, 0xa1, 0x00, 0x2e, 0x4b, 0xa5, 0xef,
0x6d, 0x34, 0x76, 0x0e, 0xb5, 0x40, 0x7b, 0x65, 0xe3, 0xda, 0x7f, 0x88, 0x9d, 0x3e, 0xc9, 0x4e,
0xe6, 0xae, 0x3b, 0x71, 0x8c, 0xbf, 0x03, 0xb0, 0xb9, 0x2f, 0x81, 0x3b, 0x09, 0xad, 0x3c, 0x75,
0x08, 0xeb, 0x32, 0xa1, 0x81, 0xb9, 0x4d, 0x2b, 0x1b, 0x6f, 0xce, 0x27, 0xa3, 0x1a, 0x34, 0x0b,
0x80, 0xf1, 0xae, 0xaf, 0xbc, 0x6b, 0x67, 0x9c, 0xf7, 0xfb, 0x77, 0x48, 0xb0, 0x5b, 0x45, 0xcc,
0x85, 0xb5, 0x38, 0x34, 0xb4, 0x16, 0x36, 0xa1, 0x76, 0xb5, 0xf7, 0xf8, 0x54, 0xed, 0xc6, 0x95,
0x6e, 0x2d, 0x0e, 0xff, 0x7d, 0x22, 0xf0, 0x5b, 0xf0, 0xc4, 0xbe, 0xea, 0xda, 0xe6, 0xe1, 0x01,
0x05, 0x96, 0xf0, 0xb0, 0x78, 0x72, 0xba, 0xf9, 0x27, 0xfe, 0xb1, 0x06, 0x9f, 0xb3, 0xbc, 0x6d,
0xf3, 0x70, 0x8b, 0x47, 0x15, 0x2f, 0xd8, 0x4c, 0x4f, 0x08, 0xc3, 0x46, 0xc0, 0x99, 0x22, 0x5a,
0x40, 0x4a, 0xef, 0x55, 0x61, 0xd6, 0xef, 0x9f, 0x8c, 0x59, 0x40, 0x77, 0x68, 0xc0, 0x59, 0x28,
0x9d, 0xba, 0x09, 0x4d, 0xf6, 0xfe, 0xd9, 0x33, 0xe8, 0x3a, 0x6c, 0x98, 0xef, 0x5b, 0xf1, 0x80,
0x66, 0xe5, 0xd6, 0xf1, 0x52, 0xa5, 0xf2, 0x6c, 0xa5, 0x2a, 0x12, 0xaa, 0x95, 0xca, 0x1b, 0xad,
0x7b, 0x7a, 0x47, 0xb7, 0xd8, 0xac, 0x79, 0x29, 0x12, 0xf7, 0xb7, 0x62, 0x46, 0xa5, 0xb3, 0x68,
0x01, 0x16, 0x66, 0x9d, 0x8c, 0xbb, 0xbc, 0xdf, 0xe7, 0x1f, 0x3b, 0x4b, 0xad, 0x5a, 0x91, 0x8c,
0xd4, 0x86, 0x3f, 0x81, 0xcb, 0x5b, 0x3c, 0xba, 0xca, 0x94, 0x18, 0x6b, 0x01, 0xd1, 0xc7, 0xa1,
0x4c, 0xa5, 0x61, 0xc9, 0x05, 0x24, 0x33, 0xa2, 0x9b, 0xb0, 0xa1, 0xe2, 0x01, 0xdd, 0x51, 0x64,
0x90, 0x64, 0x05, 0xf9, 0x0f, 0x78, 0x4f, 0x98, 0xe5, 0x2e, 0xb0, 0x0f, 0x9f, 0x7f, 0x27, 0xd1,
0x72, 0x19, 0x73, 0x76, 0x8b, 0x8a, 0x41, 0xcc, 0x48, 0xe5, 0x5b, 0x82, 0x9b, 0xd0, 0x9d, 0xb6,
0x21, 0x7d, 0xc5, 0x37, 0xfe, 0x3a, 0x02, 0x91, 0x5d, 0xe4, 0x54, 0x8c, 0xe2, 0x80, 0xa2, 0xaf,
0x00, 0xac, 0x6f, 0xc5, 0x52, 0xa1, 0x93, 0xa5, 0x7b, 0xf1, 0xa4, 0xa4, 0xba, 0x73, 0xba, 0x5b,
0x1a, 0x0a, 0x37, 0x1f, 0xfc, 0xf6, 0xc7, 0x37, 0xb5, 0xe3, 0xe8, 0xa8, 0xe9, 0x4e, 0x46, 0xeb,
0x76, 0xb3, 0x20, 0xd1, 0x97, 0x00, 0x22, 0xbd, 0xac, 0xac, 0xac, 0xe8, 0xc2, 0x2c, 0x7e, 0x53,
0x14, 0xd8, 0x3d, 0x69, 0x05, 0xde, 0xd3, 0xed, 0x8f, 0x0e, 0xb3, 0x59, 0x60, 0x08, 0x74, 0x0c,
0x81, 0x35, 0x84, 0xa7, 0x11, 0xf0, 0xef, 0xe9, 0x68, 0xde, 0xf7, 0x69, 0x8a, 0xfb, 0x3d, 0x80,
0x87, 0xde, 0x23, 0x2a, 0xe8, 0x1d, 0x14, 0xa1, 0xed, 0xf9, 0x44, 0xc8, 0x60, 0x19, 0xaa, 0xf8,
0xb4, 0xa1, 0x79, 0x12, 0x9d, 0xc8, 0x69, 0x4a, 0x25, 0x28, 0x19, 0x94, 0xd8, 0x5e, 0x02, 0xe8,
0x21, 0x80, 0x8b, 0xa9, 0x28, 0xa3, 0x33, 0xb3, 0x28, 0x96, 0x44, 0xdb, 0x9d, 0x93, 0xf4, 0xe1,
0xf3, 0x86, 0xe0, 0x69, 0x3c, 0x35, 0x91, 0x97, 0x4b, 0xba, 0xfd, 0x35, 0x80, 0x0b, 0xd7, 0xe8,
0x81, 0x65, 0x36, 0x2f, 0x66, 0xfb, 0x42, 0x37, 0x25, 0xc3, 0xe8, 0x01, 0x80, 0x87, 0xaf, 0x51,
0x95, 0xb7, 0x4e, 0x72, 0x76, 0xf8, 0x4a, 0xdd, 0x95, 0xdb, 0xf4, 0xac, 0x2e, 0x34, 0x9f, 0x9a,
0xb4, 0x4b, 0x17, 0x0d, 0xf4, 0x39, 0x74, 0xa6, 0xaa, 0xb8, 0x06, 0x13, 0xcc, 0x5f, 0x00, 0x5c,
0x4c, 0xc5, 0x6e, 0x36, 0x7c, 0xa9, 0x9b, 0x99, 0x5b, 0x8c, 0xae, 0x1a, 0xa2, 0xaf, 0xba, 0x97,
0xa6, 0x13, 0xb5, 0xf7, 0xeb, 0x97, 0x2a, 0x24, 0x8a, 0x78, 0x86, 0x7d, 0x39, 0xb3, 0x3f, 0x03,
0x08, 0x0b, 0xb5, 0x46, 0xe7, 0xab, 0x0f, 0x61, 0x29, 0xba, 0x3b, 0x47, 0xbd, 0xc6, 0x9e, 0x39,
0x4c, 0xdb, 0x6d, 0x55, 0x45, 0x5d, 0xab, 0xf9, 0x65, 0xa3, 0xe9, 0x68, 0x04, 0x17, 0x53, 0xfd,
0x9c, 0x1d, 0xf5, 0x52, 0xf7, 0xe6, 0xb6, 0x2a, 0xde, 0x9f, 0x34, 0xf1, 0x59, 0xcd, 0x75, 0x2a,
0x6b, 0xee, 0x07, 0x00, 0xeb, 0xba, 0x03, 0x42, 0xa7, 0x67, 0xf9, 0xb3, 0x3a, 0xbd, 0xb9, 0xa5,
0xfa, 0x82, 0xa1, 0x76, 0x06, 0x57, 0x47, 0x67, 0xcc, 0x82, 0xcb, 0xa0, 0x83, 0x7e, 0x02, 0x70,
0x39, 0xef, 0x71, 0xd0, 0xb9, 0x99, 0xc7, 0x2e, 0x77, 0x41, 0x73, 0xa3, 0xea, 0x1b, 0xaa, 0xe7,
0xf1, 0x5a, 0x15, 0x55, 0x91, 0x81, 0x6b, 0xba, 0xdf, 0x02, 0x88, 0x26, 0x72, 0x37, 0x11, 0x40,
0x74, 0xb6, 0x04, 0x35, 0x53, 0x49, 0xdd, 0x73, 0x07, 0xae, 0x2b, 0xdf, 0xeb, 0x4e, 0xe5, 0xbd,
0xe6, 0x13, 0xfc, 0x2f, 0x00, 0x6c, 0x4c, 0x3a, 0x34, 0xd4, 0xae, 0x2e, 0xb2, 0xa2, 0x89, 0x7b,
0x8a, 0x3a, 0xdb, 0x30, 0x44, 0x5e, 0xe8, 0x74, 0xaa, 0x88, 0x24, 0x3c, 0x94, 0xfe, 0xbd, 0xac,
0x43, 0xbb, 0x8f, 0x3e, 0x05, 0x70, 0x29, 0xeb, 0xf0, 0xd0, 0xda, 0x2c, 0x04, 0xbb, 0x05, 0x74,
0x8f, 0x95, 0x56, 0xe5, 0x5d, 0x10, 0x7e, 0xc9, 0x80, 0xaf, 0x23, 0xff, 0xe9, 0xc1, 0xfd, 0x3e,
0x8f, 0xe4, 0x25, 0xb0, 0xf9, 0xca, 0xa3, 0xbd, 0x55, 0xf0, 0xeb, 0xde, 0x2a, 0xf8, 0x7d, 0x6f,
0x15, 0xbc, 0xef, 0x55, 0xfd, 0xf6, 0xdf, 0xff, 0x1f, 0xc9, 0xdf, 0x01, 0x00, 0x00, 0xff, 0xff,
0x6a, 0x89, 0x9d, 0x9f, 0x38, 0x11, 0x00, 0x00,
// 1323 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x58, 0xcd, 0x6f, 0xdc, 0x44,
0x14, 0x67, 0x76, 0xb7, 0xf9, 0x78, 0xa9, 0x10, 0x0c, 0x6d, 0x31, 0x26, 0x4d, 0x57, 0x6e, 0x9a,
0xa6, 0x29, 0xb5, 0x9b, 0x08, 0x09, 0x54, 0x21, 0xa1, 0x86, 0x96, 0x36, 0x28, 0x94, 0xb0, 0x69,
0x41, 0xe2, 0x82, 0xa6, 0xf6, 0x74, 0x63, 0xb2, 0x3b, 0x63, 0x66, 0x66, 0x17, 0x2d, 0x55, 0x0f,
0x14, 0xc4, 0x09, 0xa9, 0x42, 0x70, 0xe0, 0x06, 0xf4, 0x8c, 0xb8, 0x70, 0xe7, 0xdc, 0x23, 0x12,
0xf7, 0x08, 0x45, 0x5c, 0xf9, 0x1f, 0xd0, 0x8c, 0xed, 0xf5, 0xb8, 0xd9, 0x75, 0x0a, 0x2c, 0xb7,
0xf1, 0x9b, 0x37, 0xef, 0xfd, 0xde, 0xc7, 0xcc, 0xfb, 0xc9, 0xb0, 0x28, 0xa9, 0xe8, 0x53, 0x11,
0x90, 0x24, 0xe9, 0xc4, 0x21, 0x51, 0x31, 0x67, 0xf6, 0xda, 0x4f, 0x04, 0x57, 0x1c, 0xcf, 0x59,
0x22, 0xf7, 0x58, 0x9b, 0xb7, 0xb9, 0x91, 0x07, 0x7a, 0x95, 0xaa, 0xb8, 0xf3, 0x6d, 0xce, 0xdb,
0x1d, 0x1a, 0x90, 0x24, 0x0e, 0x08, 0x63, 0x5c, 0x19, 0x65, 0x99, 0xed, 0x7a, 0xbb, 0xaf, 0x4a,
0x3f, 0xe6, 0x66, 0x37, 0xe4, 0x82, 0x06, 0xfd, 0xd5, 0xa0, 0x4d, 0x19, 0x15, 0x44, 0xd1, 0x28,
0xd3, 0x79, 0xb9, 0xd0, 0xe9, 0x92, 0x70, 0x27, 0x66, 0x54, 0x0c, 0x82, 0x64, 0xb7, 0xad, 0x05,
0x32, 0xe8, 0x52, 0x45, 0x46, 0x9d, 0xda, 0x68, 0xc7, 0x6a, 0xa7, 0x77, 0xdb, 0x0f, 0x79, 0x37,
0x20, 0xc2, 0x00, 0xfb, 0xc8, 0x2c, 0x2e, 0x84, 0x51, 0x71, 0xda, 0x0e, 0xaf, 0xbf, 0x4a, 0x3a,
0xc9, 0x0e, 0x39, 0x68, 0x6a, 0xbd, 0xca, 0x94, 0xa0, 0x09, 0xcf, 0x72, 0x65, 0x96, 0xb1, 0xe2,
0x62, 0x60, 0x2d, 0x53, 0x1b, 0x1e, 0x83, 0x67, 0x2e, 0x17, 0xbe, 0xde, 0xed, 0x51, 0x31, 0xc0,
0x18, 0x1a, 0x8c, 0x74, 0xa9, 0x83, 0x9a, 0x68, 0x79, 0xb6, 0x65, 0xd6, 0x78, 0x01, 0xa6, 0x05,
0xbd, 0x23, 0xa8, 0xdc, 0x71, 0x6a, 0x4d, 0xb4, 0x3c, 0xb3, 0xde, 0x78, 0xb4, 0x77, 0xea, 0xa9,
0x56, 0x2e, 0xc4, 0x4b, 0x30, 0xad, 0xdd, 0xd3, 0x50, 0x39, 0xf5, 0x66, 0x7d, 0x79, 0x76, 0xfd,
0xe8, 0xfe, 0xde, 0xa9, 0x99, 0xad, 0x54, 0x24, 0x5b, 0xf9, 0xa6, 0xf7, 0x25, 0x82, 0x05, 0xcb,
0x61, 0x8b, 0x4a, 0xde, 0x13, 0x21, 0xbd, 0xda, 0xa7, 0x4c, 0xc9, 0xc7, 0xdd, 0xd7, 0x86, 0xee,
0x97, 0xe1, 0xa8, 0xc8, 0x54, 0x6f, 0xe8, 0xbd, 0x9a, 0xde, 0xcb, 0x30, 0x94, 0x76, 0xf0, 0x12,
0xcc, 0xe5, 0xdf, 0xb7, 0x36, 0xae, 0x38, 0x75, 0x4b, 0xd1, 0xde, 0xf0, 0xb6, 0xc0, 0xb1, 0x70,
0xbc, 0x4d, 0x58, 0x7c, 0x87, 0x4a, 0x35, 0x1e, 0x41, 0x13, 0x66, 0x04, 0xed, 0xc7, 0x32, 0xe6,
0xcc, 0x64, 0x20, 0x37, 0x3a, 0x94, 0x7a, 0xc7, 0xe1, 0xb9, 0x72, 0x64, 0x09, 0x67, 0x92, 0x7a,
0x0f, 0x51, 0xc9, 0xd3, 0x1b, 0x82, 0x12, 0x45, 0x5b, 0xf4, 0xe3, 0x1e, 0x95, 0x0a, 0x33, 0xb0,
0x5b, 0xd5, 0x38, 0x9c, 0x5b, 0x7b, 0xd3, 0x2f, 0x0a, 0xeb, 0xe7, 0x85, 0x35, 0x8b, 0x0f, 0xc3,
0xc8, 0x4f, 0x76, 0xdb, 0xbe, 0xee, 0x11, 0xdf, 0x6e, 0xfb, 0xbc, 0x47, 0x7c, 0xcb, 0x53, 0x1e,
0xb5, 0xa5, 0x87, 0x4f, 0xc0, 0x54, 0x2f, 0x91, 0x54, 0xa8, 0xb4, 0x8a, 0xad, 0xec, 0xcb, 0xfb,
0xa2, 0x0c, 0xf2, 0x56, 0x12, 0x59, 0x20, 0x77, 0xfe, 0x47, 0x90, 0x25, 0x78, 0xde, 0xf5, 0x12,
0x8a, 0x2b, 0xb4, 0x43, 0x0b, 0x14, 0xa3, 0x8a, 0xe2, 0xc0, 0x74, 0x48, 0x64, 0x48, 0x22, 0x9a,
0xc5, 0x93, 0x7f, 0x7a, 0x7f, 0x21, 0x38, 0x61, 0x99, 0xda, 0x1e, 0xb0, 0xb0, 0xca, 0xd0, 0xa1,
0xd5, 0xc5, 0xf3, 0x30, 0x15, 0x89, 0x41, 0xab, 0xc7, 0x9c, 0xba, 0xd5, 0xff, 0x99, 0x0c, 0xbb,
0x70, 0x24, 0x11, 0x3d, 0x46, 0x9d, 0x86, 0xb5, 0x99, 0x8a, 0x70, 0x08, 0x33, 0x52, 0xe9, 0x7b,
0xdb, 0x1e, 0x38, 0x47, 0x9a, 0x68, 0x79, 0x6e, 0xed, 0xda, 0x7f, 0xc8, 0x9d, 0x8e, 0x64, 0x3b,
0x33, 0xd7, 0x1a, 0x1a, 0xf6, 0xbe, 0x43, 0x30, 0x7f, 0xa0, 0x80, 0xdb, 0x09, 0xad, 0x8c, 0x3a,
0x82, 0x86, 0x4c, 0x68, 0x68, 0x6e, 0xd3, 0xdc, 0xda, 0x5b, 0x93, 0xa9, 0xa8, 0x76, 0x9a, 0x25,
0xc0, 0x58, 0xd7, 0x57, 0xde, 0xb5, 0x2b, 0xce, 0x3b, 0x9d, 0xdb, 0x24, 0xdc, 0xad, 0x02, 0xe6,
0x42, 0x2d, 0x8e, 0x0c, 0xac, 0xfa, 0x3a, 0x68, 0x53, 0xfb, 0x7b, 0xa7, 0x6a, 0x1b, 0x57, 0x5a,
0xb5, 0x38, 0xfa, 0xf7, 0x85, 0xf0, 0x7e, 0x46, 0xd0, 0x1c, 0xd1, 0x5e, 0xe9, 0x9b, 0x50, 0x05,
0xe7, 0xc9, 0x5f, 0x9f, 0x35, 0x00, 0x92, 0xc4, 0xef, 0x51, 0x61, 0x3a, 0x29, 0x7d, 0x7c, 0x70,
0x16, 0x00, 0x5c, 0xde, 0xda, 0xc8, 0x76, 0x5a, 0x96, 0x16, 0x76, 0xa0, 0xb1, 0x1b, 0xb3, 0xc8,
0x69, 0x58, 0x56, 0x8d, 0xc4, 0xfb, 0xb1, 0x06, 0xcf, 0x5b, 0x80, 0xb7, 0x78, 0xb4, 0xc9, 0xdb,
0x15, 0xaf, 0xa4, 0x03, 0xd3, 0x09, 0x8f, 0x0a, 0x88, 0xad, 0xfc, 0x13, 0x7b, 0x30, 0x1b, 0x72,
0xa6, 0x88, 0x1e, 0x52, 0xa5, 0x37, 0xb1, 0x10, 0xeb, 0x28, 0x65, 0xcc, 0x42, 0xba, 0x4d, 0x43,
0xce, 0x22, 0x69, 0xf0, 0xd4, 0xf3, 0x28, 0xed, 0x1d, 0x7c, 0x1d, 0x66, 0xcd, 0xf7, 0xcd, 0xb8,
0x4b, 0xb3, 0x96, 0x5e, 0xf1, 0xd3, 0x69, 0xe8, 0xdb, 0xd3, 0xb0, 0x68, 0x1a, 0x3d, 0x0d, 0xfd,
0xfe, 0xaa, 0xaf, 0x4f, 0xb4, 0x8a, 0xc3, 0x1a, 0x97, 0x22, 0x71, 0x67, 0x33, 0x66, 0x54, 0x3a,
0x53, 0x96, 0xc3, 0x42, 0xac, 0x0b, 0x7e, 0x87, 0x77, 0x3a, 0xfc, 0x13, 0x67, 0xba, 0x59, 0x2b,
0x0a, 0x9e, 0xca, 0xbc, 0x4f, 0x61, 0x66, 0x93, 0xb7, 0xaf, 0x32, 0x25, 0x06, 0x7a, 0x48, 0xe9,
0x70, 0x28, 0x53, 0x69, 0x5a, 0xf2, 0x21, 0x95, 0x09, 0xf1, 0x0d, 0x98, 0x55, 0x71, 0x97, 0x6e,
0x2b, 0xd2, 0x4d, 0xb2, 0xa6, 0xff, 0x07, 0xb8, 0x87, 0xc8, 0x72, 0x13, 0x5e, 0x00, 0x2f, 0xbc,
0x93, 0xe8, 0x91, 0x1c, 0x73, 0x76, 0x93, 0x8a, 0x6e, 0xcc, 0x48, 0xe5, 0x7b, 0xe5, 0xcd, 0x83,
0x3b, 0xea, 0x40, 0x3a, 0x29, 0xd6, 0x3e, 0x7f, 0x16, 0xb0, 0x7d, 0x91, 0xa8, 0xe8, 0xc7, 0x21,
0xc5, 0x0f, 0x10, 0x34, 0x36, 0x63, 0xa9, 0xf0, 0xc9, 0xd2, 0xdd, 0x7b, 0x7c, 0x6c, 0xbb, 0x13,
0xba, 0xbf, 0xda, 0x95, 0x37, 0x7f, 0xff, 0xf7, 0x3f, 0xbf, 0xa9, 0x9d, 0xc0, 0xc7, 0x0c, 0x03,
0xea, 0xaf, 0xda, 0x84, 0x44, 0xe2, 0xaf, 0x10, 0x60, 0xad, 0x56, 0x9e, 0xde, 0xf8, 0xfc, 0x38,
0x7c, 0x23, 0xa6, 0xbc, 0x7b, 0xd2, 0x4a, 0xbc, 0xaf, 0x29, 0x96, 0x4e, 0xb3, 0x51, 0x30, 0x00,
0x56, 0x0c, 0x80, 0x45, 0xec, 0x8d, 0x02, 0x10, 0xdc, 0xd5, 0xd9, 0xbc, 0x17, 0xd0, 0xd4, 0xef,
0xf7, 0x08, 0x8e, 0xbc, 0x4f, 0x54, 0xb8, 0x73, 0x58, 0x86, 0xb6, 0x26, 0x93, 0x21, 0xe3, 0xcb,
0x40, 0xf5, 0x4e, 0x1b, 0x98, 0x27, 0xf1, 0x8b, 0x39, 0x4c, 0xa9, 0x04, 0x25, 0xdd, 0x12, 0xda,
0x8b, 0x08, 0x3f, 0x44, 0x30, 0x95, 0x0e, 0x7e, 0x7c, 0x66, 0x1c, 0xc4, 0x12, 0x31, 0x70, 0x27,
0x34, 0x5e, 0xbd, 0x73, 0x06, 0xe0, 0x69, 0x6f, 0x64, 0x21, 0x2f, 0x95, 0xb8, 0xc1, 0xd7, 0x08,
0xea, 0xd7, 0xe8, 0xa1, 0x6d, 0x36, 0x29, 0x64, 0x07, 0x52, 0x37, 0xa2, 0xc2, 0xf8, 0x3e, 0x82,
0xa3, 0xd7, 0xa8, 0xca, 0xe9, 0x99, 0x1c, 0x9f, 0xbe, 0x12, 0x83, 0x73, 0xe7, 0x7d, 0x8b, 0xe9,
0xe6, 0x5b, 0x43, 0x4a, 0x76, 0xc1, 0xb8, 0x3e, 0x8b, 0xcf, 0x54, 0x35, 0x57, 0x77, 0xe8, 0xf3,
0x57, 0x04, 0x53, 0xe9, 0x40, 0x1d, 0xef, 0xbe, 0xc4, 0x98, 0x26, 0x96, 0xa3, 0xab, 0x06, 0xe8,
0xeb, 0xee, 0xc5, 0xd1, 0x40, 0xed, 0xf3, 0xfa, 0xa5, 0x8a, 0x88, 0x22, 0xbe, 0x41, 0x5f, 0xae,
0xec, 0x2f, 0x08, 0xa0, 0x60, 0x04, 0xf8, 0x5c, 0x75, 0x10, 0x16, 0x6b, 0x70, 0x27, 0xc8, 0x09,
0x3c, 0xdf, 0x04, 0xb3, 0xec, 0x36, 0xab, 0xb2, 0xae, 0x19, 0xc3, 0x25, 0xc3, 0x1b, 0x70, 0x1f,
0xa6, 0xd2, 0x11, 0x3d, 0x3e, 0xeb, 0x25, 0x86, 0xe8, 0x36, 0x2b, 0xde, 0x9f, 0xb4, 0xf0, 0x59,
0xcf, 0xad, 0x54, 0xf6, 0xdc, 0x0f, 0x08, 0x1a, 0x9a, 0x65, 0xe1, 0xd3, 0xe3, 0xec, 0x59, 0x6c,
0x72, 0x62, 0xa5, 0x3e, 0x6f, 0xa0, 0x9d, 0xf1, 0xaa, 0xb3, 0x33, 0x60, 0xe1, 0x25, 0xb4, 0x82,
0x7f, 0x42, 0x30, 0x93, 0xf3, 0x28, 0x7c, 0x76, 0x6c, 0xd8, 0x65, 0xa6, 0x35, 0x31, 0xa8, 0x81,
0x81, 0x7a, 0xce, 0x5b, 0xac, 0x82, 0x2a, 0x32, 0xe7, 0x1a, 0xee, 0xb7, 0x08, 0xf0, 0x70, 0xdc,
0x0d, 0x07, 0x20, 0x5e, 0x2a, 0xb9, 0x1a, 0x3b, 0x49, 0xdd, 0xb3, 0x87, 0xea, 0x95, 0xef, 0xf5,
0x4a, 0xe5, 0xbd, 0xe6, 0x43, 0xff, 0x0f, 0x10, 0x3c, 0x5d, 0x26, 0x81, 0xf8, 0xc2, 0x61, 0x9d,
0x56, 0x22, 0x8b, 0x4f, 0xd0, 0x71, 0x2f, 0x19, 0x48, 0x4b, 0x2b, 0xd5, 0xb9, 0xca, 0xdd, 0x7f,
0x86, 0x60, 0x3a, 0x63, 0x79, 0x78, 0x71, 0x9c, 0x6d, 0x9b, 0x06, 0xba, 0xc7, 0x4b, 0x5a, 0x39,
0x13, 0xf2, 0x5e, 0x31, 0x6e, 0x57, 0x71, 0x50, 0xe5, 0x36, 0xe1, 0x91, 0x0c, 0xee, 0x66, 0x14,
0xf1, 0x5e, 0xd0, 0xe1, 0x6d, 0x79, 0x11, 0xad, 0xbf, 0xf6, 0x68, 0x7f, 0x01, 0xfd, 0xb6, 0xbf,
0x80, 0xfe, 0xd8, 0x5f, 0x40, 0x1f, 0xf8, 0x55, 0xff, 0x18, 0x0e, 0xfe, 0x8b, 0xf9, 0x3b, 0x00,
0x00, 0xff, 0xff, 0x23, 0x18, 0x5a, 0x1f, 0xa0, 0x11, 0x00, 0x00,
}

View File

@@ -382,8 +382,12 @@ func request_ApplicationService_TerminateOperation_0(ctx context.Context, marsha
}
func request_ApplicationService_DeletePod_0(ctx context.Context, marshaler runtime.Marshaler, client ApplicationServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ApplicationDeletePodRequest
var (
filter_ApplicationService_DeleteResource_0 = &utilities.DoubleArray{Encoding: map[string]int{"name": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}}
)
func request_ApplicationService_DeleteResource_0(ctx context.Context, marshaler runtime.Marshaler, client ApplicationServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ApplicationDeleteResourceRequest
var metadata runtime.ServerMetadata
var (
@@ -404,18 +408,11 @@ func request_ApplicationService_DeletePod_0(ctx context.Context, marshaler runti
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err)
}
val, ok = pathParams["podName"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "podName")
if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_ApplicationService_DeleteResource_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
protoReq.PodName, err = runtime.StringP(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "podName", err)
}
msg, err := client.DeletePod(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
msg, err := client.DeleteResource(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
@@ -860,7 +857,7 @@ func RegisterApplicationServiceHandlerClient(ctx context.Context, mux *runtime.S
})
mux.Handle("DELETE", pattern_ApplicationService_DeletePod_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
mux.Handle("DELETE", pattern_ApplicationService_DeleteResource_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
if cn, ok := w.(http.CloseNotifier); ok {
@@ -878,14 +875,14 @@ func RegisterApplicationServiceHandlerClient(ctx context.Context, mux *runtime.S
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ApplicationService_DeletePod_0(rctx, inboundMarshaler, client, req, pathParams)
resp, md, err := request_ApplicationService_DeleteResource_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ApplicationService_DeletePod_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
forward_ApplicationService_DeleteResource_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
@@ -946,7 +943,7 @@ var (
pattern_ApplicationService_TerminateOperation_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"api", "v1", "applications", "name", "operation"}, ""))
pattern_ApplicationService_DeletePod_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"api", "v1", "applications", "name", "pods", "podName"}, ""))
pattern_ApplicationService_DeleteResource_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"api", "v1", "applications", "name", "resource"}, ""))
pattern_ApplicationService_PodLogs_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6}, []string{"api", "v1", "applications", "name", "pods", "podName", "logs"}, ""))
)
@@ -976,7 +973,7 @@ var (
forward_ApplicationService_TerminateOperation_0 = runtime.ForwardResponseMessage
forward_ApplicationService_DeletePod_0 = runtime.ForwardResponseMessage
forward_ApplicationService_DeleteResource_0 = runtime.ForwardResponseMessage
forward_ApplicationService_PodLogs_0 = runtime.ForwardResponseStream
)

View File

@@ -72,9 +72,11 @@ message ApplicationRollbackRequest {
optional bool prune = 4 [(gogoproto.nullable) = false];
}
message ApplicationDeletePodRequest {
message ApplicationDeleteResourceRequest {
required string name = 1;
required string podName = 2;
required string resourceName = 2 [(gogoproto.nullable) = false];
required string apiVersion = 3 [(gogoproto.customname) = "APIVersion", (gogoproto.nullable) = false];
required string kind = 4 [(gogoproto.nullable) = false];
}
message ApplicationPodLogsQuery {
@@ -179,9 +181,9 @@ service ApplicationService {
};
}
// DeletePod returns stream of log entries for the specified pod. Pod
rpc DeletePod(ApplicationDeletePodRequest) returns (ApplicationResponse) {
option (google.api.http).delete = "/api/v1/applications/{name}/pods/{podName}";
// DeleteResource deletes a single application resource
rpc DeleteResource(ApplicationDeleteResourceRequest) returns (ApplicationResponse) {
option (google.api.http).delete = "/api/v1/applications/{name}/resource";
}
// PodLogs returns stream of log entries for the specified pod. Pod

View File

@@ -6,6 +6,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"golang.org/x/net/context"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes/fake"
"github.com/argoproj/argo-cd/common"
@@ -78,7 +79,9 @@ func newTestAppServer() ApplicationServiceServer {
enforcer := rbac.NewEnforcer(kubeclientset, testNamespace, common.ArgoCDRBACConfigMapName, nil)
enforcer.SetBuiltinPolicy(test.BuiltinPolicy)
enforcer.SetDefaultRole("role:admin")
enforcer.SetClaimsEnforcerFunc(func(rvals ...interface{}) bool {
return true
})
db := db.NewDB(testNamespace, kubeclientset)
ctx := context.Background()
_, err := db.CreateRepository(ctx, fakeRepo())
@@ -93,10 +96,18 @@ func newTestAppServer() ApplicationServiceServer {
mockRepoClient := &mockrepo.Clientset{}
mockRepoClient.On("NewRepositoryClient").Return(&fakeCloser{}, &mockRepoServiceClient, nil)
defaultProj := &appsv1.AppProject{
ObjectMeta: metav1.ObjectMeta{Name: "default", Namespace: "default"},
Spec: appsv1.AppProjectSpec{
SourceRepos: []string{"*"},
Destinations: []appsv1.ApplicationDestination{{Server: "*", Namespace: "*"}},
},
}
return NewServer(
testNamespace,
kubeclientset,
apps.NewSimpleClientset(),
apps.NewSimpleClientset(defaultProj),
mockRepoClient,
db,
enforcer,

View File

@@ -6,7 +6,10 @@ import (
"golang.org/x/net/context"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
"github.com/argoproj/argo-cd/common"
appv1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
"github.com/argoproj/argo-cd/util/db"
"github.com/argoproj/argo-cd/util/grpc"
@@ -76,6 +79,53 @@ func (s *Server) Create(ctx context.Context, q *ClusterCreateRequest) (*appv1.Cl
return redact(clust), err
}
// Create creates a cluster
func (s *Server) CreateFromKubeConfig(ctx context.Context, q *ClusterCreateFromKubeConfigRequest) (*appv1.Cluster, error) {
kubeconfig, err := clientcmd.Load([]byte(q.Kubeconfig))
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not unmarshal kubeconfig: %v", err)
}
var clusterServer string
var clusterInsecure bool
if q.InCluster {
clusterServer = common.KubernetesInternalAPIServerAddr
} else if cluster, ok := kubeconfig.Clusters[q.Context]; ok {
clusterServer = cluster.Server
clusterInsecure = cluster.InsecureSkipTLSVerify
} else {
return nil, status.Errorf(codes.Internal, "Context %s does not exist in kubeconfig", q.Context)
}
c := &appv1.Cluster{
Server: clusterServer,
Name: q.Context,
Config: appv1.ClusterConfig{
TLSClientConfig: appv1.TLSClientConfig{
Insecure: clusterInsecure,
},
},
}
// Temporarily install RBAC resources for managing the cluster
clientset, err := kubernetes.NewForConfig(c.RESTConfig())
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not create Kubernetes clientset: %v", err)
}
bearerToken, err := common.InstallClusterManagerRBAC(clientset)
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not install cluster manager RBAC: %v", err)
}
c.Config.BearerToken = bearerToken
return s.Create(ctx, &ClusterCreateRequest{
Cluster: c,
Upsert: q.Upsert,
})
}
// Get returns a cluster from a query
func (s *Server) Get(ctx context.Context, q *ClusterQuery) (*appv1.Cluster, error) {
if !s.enf.EnforceClaims(ctx.Value("claims"), "clusters", "get", q.Server) {

View File

@@ -15,6 +15,7 @@
ClusterQuery
ClusterResponse
ClusterCreateRequest
ClusterCreateFromKubeConfigRequest
ClusterUpdateRequest
*/
package cluster
@@ -92,6 +93,48 @@ func (m *ClusterCreateRequest) GetUpsert() bool {
return false
}
type ClusterCreateFromKubeConfigRequest struct {
Kubeconfig string `protobuf:"bytes,1,opt,name=kubeconfig,proto3" json:"kubeconfig,omitempty"`
Context string `protobuf:"bytes,2,opt,name=context,proto3" json:"context,omitempty"`
Upsert bool `protobuf:"varint,3,opt,name=upsert,proto3" json:"upsert,omitempty"`
InCluster bool `protobuf:"varint,4,opt,name=inCluster,proto3" json:"inCluster,omitempty"`
}
func (m *ClusterCreateFromKubeConfigRequest) Reset() { *m = ClusterCreateFromKubeConfigRequest{} }
func (m *ClusterCreateFromKubeConfigRequest) String() string { return proto.CompactTextString(m) }
func (*ClusterCreateFromKubeConfigRequest) ProtoMessage() {}
func (*ClusterCreateFromKubeConfigRequest) Descriptor() ([]byte, []int) {
return fileDescriptorCluster, []int{3}
}
func (m *ClusterCreateFromKubeConfigRequest) GetKubeconfig() string {
if m != nil {
return m.Kubeconfig
}
return ""
}
func (m *ClusterCreateFromKubeConfigRequest) GetContext() string {
if m != nil {
return m.Context
}
return ""
}
func (m *ClusterCreateFromKubeConfigRequest) GetUpsert() bool {
if m != nil {
return m.Upsert
}
return false
}
func (m *ClusterCreateFromKubeConfigRequest) GetInCluster() bool {
if m != nil {
return m.InCluster
}
return false
}
type ClusterUpdateRequest struct {
Cluster *github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Cluster `protobuf:"bytes,1,opt,name=cluster" json:"cluster,omitempty"`
}
@@ -99,7 +142,7 @@ type ClusterUpdateRequest struct {
func (m *ClusterUpdateRequest) Reset() { *m = ClusterUpdateRequest{} }
func (m *ClusterUpdateRequest) String() string { return proto.CompactTextString(m) }
func (*ClusterUpdateRequest) ProtoMessage() {}
func (*ClusterUpdateRequest) Descriptor() ([]byte, []int) { return fileDescriptorCluster, []int{3} }
func (*ClusterUpdateRequest) Descriptor() ([]byte, []int) { return fileDescriptorCluster, []int{4} }
func (m *ClusterUpdateRequest) GetCluster() *github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Cluster {
if m != nil {
@@ -112,6 +155,7 @@ func init() {
proto.RegisterType((*ClusterQuery)(nil), "cluster.ClusterQuery")
proto.RegisterType((*ClusterResponse)(nil), "cluster.ClusterResponse")
proto.RegisterType((*ClusterCreateRequest)(nil), "cluster.ClusterCreateRequest")
proto.RegisterType((*ClusterCreateFromKubeConfigRequest)(nil), "cluster.ClusterCreateFromKubeConfigRequest")
proto.RegisterType((*ClusterUpdateRequest)(nil), "cluster.ClusterUpdateRequest")
}
@@ -130,6 +174,8 @@ type ClusterServiceClient interface {
List(ctx context.Context, in *ClusterQuery, opts ...grpc.CallOption) (*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.ClusterList, error)
// Create creates a cluster
Create(ctx context.Context, in *ClusterCreateRequest, opts ...grpc.CallOption) (*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Cluster, error)
// CreateFromKubeConfig installs the argocd-manager service account into the cluster specified in the given kubeconfig and context
CreateFromKubeConfig(ctx context.Context, in *ClusterCreateFromKubeConfigRequest, opts ...grpc.CallOption) (*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Cluster, error)
// Get returns a cluster by server address
Get(ctx context.Context, in *ClusterQuery, opts ...grpc.CallOption) (*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Cluster, error)
// Update updates a cluster
@@ -164,6 +210,15 @@ func (c *clusterServiceClient) Create(ctx context.Context, in *ClusterCreateRequ
return out, nil
}
func (c *clusterServiceClient) CreateFromKubeConfig(ctx context.Context, in *ClusterCreateFromKubeConfigRequest, opts ...grpc.CallOption) (*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Cluster, error) {
out := new(github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Cluster)
err := grpc.Invoke(ctx, "/cluster.ClusterService/CreateFromKubeConfig", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *clusterServiceClient) Get(ctx context.Context, in *ClusterQuery, opts ...grpc.CallOption) (*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Cluster, error) {
out := new(github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Cluster)
err := grpc.Invoke(ctx, "/cluster.ClusterService/Get", in, out, c.cc, opts...)
@@ -198,6 +253,8 @@ type ClusterServiceServer interface {
List(context.Context, *ClusterQuery) (*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.ClusterList, error)
// Create creates a cluster
Create(context.Context, *ClusterCreateRequest) (*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Cluster, error)
// CreateFromKubeConfig installs the argocd-manager service account into the cluster specified in the given kubeconfig and context
CreateFromKubeConfig(context.Context, *ClusterCreateFromKubeConfigRequest) (*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Cluster, error)
// Get returns a cluster by server address
Get(context.Context, *ClusterQuery) (*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Cluster, error)
// Update updates a cluster
@@ -246,6 +303,24 @@ func _ClusterService_Create_Handler(srv interface{}, ctx context.Context, dec fu
return interceptor(ctx, in, info, handler)
}
func _ClusterService_CreateFromKubeConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ClusterCreateFromKubeConfigRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ClusterServiceServer).CreateFromKubeConfig(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/cluster.ClusterService/CreateFromKubeConfig",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ClusterServiceServer).CreateFromKubeConfig(ctx, req.(*ClusterCreateFromKubeConfigRequest))
}
return interceptor(ctx, in, info, handler)
}
func _ClusterService_Get_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ClusterQuery)
if err := dec(in); err != nil {
@@ -312,6 +387,10 @@ var _ClusterService_serviceDesc = grpc.ServiceDesc{
MethodName: "Create",
Handler: _ClusterService_Create_Handler,
},
{
MethodName: "CreateFromKubeConfig",
Handler: _ClusterService_CreateFromKubeConfig_Handler,
},
{
MethodName: "Get",
Handler: _ClusterService_Get_Handler,
@@ -409,6 +488,56 @@ func (m *ClusterCreateRequest) MarshalTo(dAtA []byte) (int, error) {
return i, nil
}
func (m *ClusterCreateFromKubeConfigRequest) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalTo(dAtA)
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *ClusterCreateFromKubeConfigRequest) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
if len(m.Kubeconfig) > 0 {
dAtA[i] = 0xa
i++
i = encodeVarintCluster(dAtA, i, uint64(len(m.Kubeconfig)))
i += copy(dAtA[i:], m.Kubeconfig)
}
if len(m.Context) > 0 {
dAtA[i] = 0x12
i++
i = encodeVarintCluster(dAtA, i, uint64(len(m.Context)))
i += copy(dAtA[i:], m.Context)
}
if m.Upsert {
dAtA[i] = 0x18
i++
if m.Upsert {
dAtA[i] = 1
} else {
dAtA[i] = 0
}
i++
}
if m.InCluster {
dAtA[i] = 0x20
i++
if m.InCluster {
dAtA[i] = 1
} else {
dAtA[i] = 0
}
i++
}
return i, nil
}
func (m *ClusterUpdateRequest) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
@@ -475,6 +604,26 @@ func (m *ClusterCreateRequest) Size() (n int) {
return n
}
func (m *ClusterCreateFromKubeConfigRequest) Size() (n int) {
var l int
_ = l
l = len(m.Kubeconfig)
if l > 0 {
n += 1 + l + sovCluster(uint64(l))
}
l = len(m.Context)
if l > 0 {
n += 1 + l + sovCluster(uint64(l))
}
if m.Upsert {
n += 2
}
if m.InCluster {
n += 2
}
return n
}
func (m *ClusterUpdateRequest) Size() (n int) {
var l int
_ = l
@@ -730,6 +879,154 @@ func (m *ClusterCreateRequest) Unmarshal(dAtA []byte) error {
}
return nil
}
func (m *ClusterCreateFromKubeConfigRequest) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowCluster
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: ClusterCreateFromKubeConfigRequest: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: ClusterCreateFromKubeConfigRequest: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Kubeconfig", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowCluster
}
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 ErrInvalidLengthCluster
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Kubeconfig = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Context", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowCluster
}
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 ErrInvalidLengthCluster
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Context = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 3:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Upsert", wireType)
}
var v int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowCluster
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
v |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
m.Upsert = bool(v != 0)
case 4:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field InCluster", wireType)
}
var v int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowCluster
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
v |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
m.InCluster = bool(v != 0)
default:
iNdEx = preIndex
skippy, err := skipCluster(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthCluster
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *ClusterUpdateRequest) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
@@ -921,35 +1218,41 @@ var (
func init() { proto.RegisterFile("server/cluster/cluster.proto", fileDescriptorCluster) }
var fileDescriptorCluster = []byte{
// 472 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x94, 0xcf, 0x8b, 0x13, 0x31,
0x14, 0xc7, 0xc9, 0xaa, 0xa3, 0x46, 0xf1, 0x47, 0x58, 0xa5, 0x8e, 0x6b, 0xd9, 0xcd, 0x41, 0x96,
0x45, 0x13, 0x5a, 0x2f, 0x8b, 0xc7, 0x5d, 0x51, 0x04, 0x2f, 0x56, 0xbc, 0xc8, 0x82, 0x64, 0xa7,
0x8f, 0xec, 0xd8, 0x71, 0x12, 0x93, 0xcc, 0x80, 0x88, 0x08, 0x7a, 0x15, 0x2f, 0xfe, 0x01, 0x5e,
0xfd, 0x53, 0x3c, 0x0a, 0xfe, 0x03, 0x52, 0xfc, 0x43, 0x64, 0x32, 0x49, 0xbb, 0x6d, 0xa9, 0x17,
0xcb, 0x9e, 0x9a, 0xbc, 0xa4, 0xef, 0x7d, 0xf2, 0x7d, 0xdf, 0x79, 0x78, 0xc3, 0x82, 0xa9, 0xc1,
0xf0, 0xac, 0xa8, 0xac, 0x9b, 0xfe, 0x32, 0x6d, 0x94, 0x53, 0xe4, 0x6c, 0xd8, 0xa6, 0xeb, 0x52,
0x49, 0xe5, 0x63, 0xbc, 0x59, 0xb5, 0xc7, 0xe9, 0x86, 0x54, 0x4a, 0x16, 0xc0, 0x85, 0xce, 0xb9,
0x28, 0x4b, 0xe5, 0x84, 0xcb, 0x55, 0x69, 0xc3, 0x29, 0x1d, 0xed, 0x5a, 0x96, 0x2b, 0x7f, 0x9a,
0x29, 0x03, 0xbc, 0xee, 0x71, 0x09, 0x25, 0x18, 0xe1, 0x60, 0x18, 0xee, 0x3c, 0x96, 0xb9, 0x3b,
0xaa, 0x0e, 0x59, 0xa6, 0x5e, 0x73, 0x61, 0x7c, 0x89, 0x57, 0x7e, 0x71, 0x37, 0x1b, 0x72, 0x3d,
0x92, 0xcd, 0x9f, 0x2d, 0x17, 0x5a, 0x17, 0x79, 0xe6, 0x93, 0xf3, 0xba, 0x27, 0x0a, 0x7d, 0x24,
0x16, 0x52, 0xd1, 0xdb, 0xf8, 0xe2, 0x7e, 0x4b, 0xfb, 0xb4, 0x02, 0xf3, 0x96, 0x5c, 0xc7, 0x49,
0xfb, 0xb6, 0x0e, 0xda, 0x44, 0xdb, 0xe7, 0x07, 0x61, 0x47, 0xaf, 0xe2, 0xcb, 0xe1, 0xde, 0x00,
0xac, 0x56, 0xa5, 0x05, 0xfa, 0x19, 0xe1, 0xf5, 0x10, 0xdb, 0x37, 0x20, 0x1c, 0x0c, 0xe0, 0x4d,
0x05, 0xd6, 0x91, 0x03, 0x1c, 0x15, 0xf0, 0x49, 0x2e, 0xf4, 0xf7, 0xd8, 0x14, 0x98, 0x45, 0x60,
0xbf, 0x78, 0x99, 0x0d, 0x99, 0x1e, 0x49, 0xd6, 0x00, 0xb3, 0x63, 0xc0, 0x2c, 0x02, 0xb3, 0x58,
0x35, 0xa6, 0x6c, 0x08, 0x2b, 0x6d, 0xc1, 0xb8, 0xce, 0xda, 0x26, 0xda, 0x3e, 0x37, 0x08, 0x3b,
0xea, 0x26, 0x34, 0xcf, 0xf5, 0xf0, 0xa4, 0x68, 0xfa, 0xdf, 0xcf, 0xe0, 0x4b, 0x21, 0xf8, 0x0c,
0x4c, 0x9d, 0x67, 0x40, 0x3e, 0xe0, 0xd3, 0x4f, 0x72, 0xeb, 0xc8, 0x35, 0x16, 0x6d, 0x71, 0x5c,
0xe1, 0xf4, 0xe1, 0xff, 0x97, 0x6f, 0xd2, 0xd3, 0xce, 0xc7, 0x5f, 0x7f, 0xbe, 0xae, 0x11, 0x72,
0xc5, 0x5b, 0xa5, 0xee, 0x45, 0x13, 0x5a, 0xf2, 0x05, 0xe1, 0xa4, 0xed, 0x08, 0xb9, 0x35, 0xcf,
0x30, 0xd3, 0xa9, 0x74, 0x05, 0x52, 0xd0, 0x2d, 0xcf, 0x71, 0x93, 0x2e, 0x70, 0xdc, 0x9f, 0xb4,
0xec, 0x13, 0xc2, 0xa7, 0x1e, 0xc1, 0x52, 0x45, 0x56, 0x48, 0x41, 0x6e, 0xcc, 0x53, 0xf0, 0x77,
0xad, 0x83, 0xdf, 0x93, 0x6f, 0x08, 0x27, 0xad, 0x35, 0x16, 0x65, 0x99, 0xb1, 0xcc, 0x4a, 0x80,
0xfa, 0x1e, 0xe8, 0x4e, 0xba, 0xb5, 0x08, 0x14, 0x6b, 0x07, 0xb0, 0xa9, 0x4e, 0x07, 0x38, 0x79,
0x00, 0x05, 0x38, 0x58, 0xa6, 0x54, 0x67, 0x3e, 0x3c, 0xf9, 0x18, 0xc3, 0xfb, 0x77, 0x96, 0xbf,
0x7f, 0x6f, 0xf7, 0xc7, 0xb8, 0x8b, 0x7e, 0x8e, 0xbb, 0xe8, 0xf7, 0xb8, 0x8b, 0x5e, 0xec, 0xfc,
0x6b, 0x86, 0xcc, 0x8e, 0xb7, 0xc3, 0xc4, 0xcf, 0x8a, 0x7b, 0x7f, 0x03, 0x00, 0x00, 0xff, 0xff,
0x2c, 0xae, 0x46, 0x1e, 0xf7, 0x04, 0x00, 0x00,
// 564 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x95, 0xcd, 0x6e, 0x13, 0x31,
0x10, 0xc7, 0xe5, 0xb6, 0xda, 0x12, 0x83, 0xf8, 0xb0, 0x0a, 0x5a, 0xd2, 0x10, 0xa5, 0x3e, 0x54,
0x55, 0xa0, 0xb6, 0x12, 0x2e, 0x55, 0x8f, 0x0d, 0x2a, 0x42, 0x70, 0x21, 0x88, 0x0b, 0xaa, 0x84,
0x36, 0x9b, 0x61, 0xbb, 0x24, 0x5d, 0x2f, 0xb6, 0x37, 0x02, 0x21, 0x84, 0x04, 0x57, 0xc4, 0x05,
0xee, 0x3c, 0x02, 0xaf, 0xc1, 0x11, 0x89, 0x1b, 0x27, 0x14, 0xf1, 0x20, 0x68, 0xbd, 0x76, 0xbe,
0xc3, 0x85, 0x88, 0x53, 0xec, 0x19, 0x67, 0xe6, 0x37, 0x33, 0xff, 0x4c, 0x70, 0x45, 0x81, 0x1c,
0x80, 0xe4, 0x61, 0x3f, 0x53, 0x7a, 0xfc, 0xc9, 0x52, 0x29, 0xb4, 0x20, 0x9b, 0xf6, 0x5a, 0xde,
0x8a, 0x44, 0x24, 0x8c, 0x8d, 0xe7, 0xa7, 0xc2, 0x5d, 0xae, 0x44, 0x42, 0x44, 0x7d, 0xe0, 0x41,
0x1a, 0xf3, 0x20, 0x49, 0x84, 0x0e, 0x74, 0x2c, 0x12, 0x65, 0xbd, 0xb4, 0x77, 0xa0, 0x58, 0x2c,
0x8c, 0x37, 0x14, 0x12, 0xf8, 0xa0, 0xc1, 0x23, 0x48, 0x40, 0x06, 0x1a, 0xba, 0xf6, 0xcd, 0xbd,
0x28, 0xd6, 0xa7, 0x59, 0x87, 0x85, 0xe2, 0x8c, 0x07, 0xd2, 0xa4, 0x78, 0x6e, 0x0e, 0xfb, 0x61,
0x97, 0xa7, 0xbd, 0x28, 0xff, 0xb2, 0xe2, 0x41, 0x9a, 0xf6, 0xe3, 0xd0, 0x04, 0xe7, 0x83, 0x46,
0xd0, 0x4f, 0x4f, 0x83, 0xb9, 0x50, 0x74, 0x17, 0x5f, 0x68, 0x15, 0xb4, 0x0f, 0x33, 0x90, 0xaf,
0xc8, 0x35, 0xec, 0x15, 0xb5, 0xf9, 0xa8, 0x86, 0xf6, 0x4a, 0x6d, 0x7b, 0xa3, 0x57, 0xf0, 0x25,
0xfb, 0xae, 0x0d, 0x2a, 0x15, 0x89, 0x02, 0xfa, 0x01, 0xe1, 0x2d, 0x6b, 0x6b, 0x49, 0x08, 0x34,
0xb4, 0xe1, 0x45, 0x06, 0x4a, 0x93, 0x13, 0xec, 0x3a, 0x60, 0x82, 0x9c, 0x6f, 0x1e, 0xb1, 0x31,
0x30, 0x73, 0xc0, 0xe6, 0xf0, 0x34, 0xec, 0xb2, 0xb4, 0x17, 0xb1, 0x1c, 0x98, 0x4d, 0x00, 0x33,
0x07, 0xcc, 0x5c, 0x56, 0x17, 0x32, 0x27, 0xcc, 0x52, 0x05, 0x52, 0xfb, 0x6b, 0x35, 0xb4, 0x77,
0xae, 0x6d, 0x6f, 0xf4, 0x33, 0xc2, 0x74, 0x0a, 0xe7, 0x58, 0x8a, 0xb3, 0xfb, 0x59, 0x07, 0x5a,
0x22, 0x79, 0x16, 0x47, 0x0e, 0xae, 0x8a, 0x71, 0x2f, 0xeb, 0x40, 0x68, 0x8c, 0xb6, 0xc8, 0x09,
0x0b, 0xf1, 0xf1, 0x66, 0x28, 0x12, 0x0d, 0x2f, 0x8b, 0xf8, 0xa5, 0xb6, 0xbb, 0x4e, 0x24, 0x5e,
0x9f, 0x4c, 0x4c, 0x2a, 0xb8, 0x14, 0x27, 0x36, 0xb3, 0xbf, 0x61, 0x5c, 0x63, 0x03, 0xd5, 0xa3,
0x26, 0x3d, 0x4e, 0xbb, 0xff, 0xab, 0x49, 0xcd, 0x9f, 0x1e, 0xbe, 0x68, 0x8d, 0x8f, 0x40, 0x0e,
0xe2, 0x10, 0xc8, 0x5b, 0xbc, 0xf1, 0x20, 0x56, 0x9a, 0x5c, 0x65, 0x4e, 0xad, 0x93, 0x83, 0x2f,
0x1f, 0xff, 0x7b, 0xfa, 0x3c, 0x3c, 0xf5, 0xdf, 0xfd, 0xf8, 0xfd, 0x69, 0x8d, 0x90, 0xcb, 0x46,
0xc1, 0x83, 0x86, 0xfb, 0x6d, 0x28, 0xf2, 0x11, 0x61, 0xaf, 0x98, 0x0c, 0xb9, 0x31, 0xcb, 0x30,
0x25, 0xa0, 0xf2, 0x0a, 0x5a, 0x41, 0x77, 0x0c, 0xc7, 0x36, 0x9d, 0xe3, 0x38, 0x1c, 0x29, 0xe9,
0x6b, 0x2e, 0xe0, 0x05, 0x52, 0x21, 0x37, 0x17, 0xe3, 0x2d, 0x14, 0xd4, 0x4a, 0x60, 0x77, 0x0d,
0x6c, 0x8d, 0x6e, 0xcf, 0xc2, 0xee, 0x8f, 0x95, 0x79, 0x88, 0xea, 0xe4, 0x3d, 0xc2, 0xeb, 0x77,
0x61, 0xe9, 0x0c, 0x57, 0xd8, 0x37, 0x72, 0x7d, 0x16, 0x85, 0xbf, 0x2e, 0x56, 0xc1, 0x1b, 0xf2,
0x05, 0x61, 0xaf, 0x10, 0xf3, 0xfc, 0x20, 0xa7, 0x44, 0xbe, 0x12, 0xa0, 0xa6, 0x01, 0xba, 0x55,
0xde, 0x99, 0x07, 0x72, 0xb9, 0x2d, 0xd8, 0x78, 0xb2, 0x27, 0xd8, 0xbb, 0x03, 0x7d, 0xd0, 0xb0,
0xac, 0x53, 0xfe, 0xac, 0x79, 0xb4, 0xd5, 0x6c, 0xfd, 0xf5, 0xe5, 0xf5, 0x1f, 0x1d, 0x7c, 0x1b,
0x56, 0xd1, 0xf7, 0x61, 0x15, 0xfd, 0x1a, 0x56, 0xd1, 0x93, 0xfa, 0xdf, 0x96, 0xf1, 0xf4, 0xff,
0x44, 0xc7, 0x33, 0x4b, 0xf7, 0xf6, 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x23, 0xc4, 0x8d, 0xa4,
0x40, 0x06, 0x00, 0x00,
}

View File

@@ -66,6 +66,19 @@ func request_ClusterService_Create_0(ctx context.Context, marshaler runtime.Mars
}
func request_ClusterService_CreateFromKubeConfig_0(ctx context.Context, marshaler runtime.Marshaler, client ClusterServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ClusterCreateFromKubeConfigRequest
var metadata runtime.ServerMetadata
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.CreateFromKubeConfig(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func request_ClusterService_Get_0(ctx context.Context, marshaler runtime.Marshaler, client ClusterServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ClusterQuery
var metadata runtime.ServerMetadata
@@ -247,6 +260,35 @@ func RegisterClusterServiceHandlerClient(ctx context.Context, mux *runtime.Serve
})
mux.Handle("POST", pattern_ClusterService_CreateFromKubeConfig_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
if cn, ok := w.(http.CloseNotifier); ok {
go func(done <-chan struct{}, closed <-chan bool) {
select {
case <-done:
case <-closed:
cancel()
}
}(ctx.Done(), cn.CloseNotify())
}
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ClusterService_CreateFromKubeConfig_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ClusterService_CreateFromKubeConfig_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_ClusterService_Get_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
@@ -342,6 +384,8 @@ var (
pattern_ClusterService_Create_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "clusters"}, ""))
pattern_ClusterService_CreateFromKubeConfig_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "clusters-kubeconfig"}, ""))
pattern_ClusterService_Get_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v1", "clusters", "server"}, ""))
pattern_ClusterService_Update_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v1", "clusters", "cluster.server"}, ""))
@@ -354,6 +398,8 @@ var (
forward_ClusterService_Create_0 = runtime.ForwardResponseMessage
forward_ClusterService_CreateFromKubeConfig_0 = runtime.ForwardResponseMessage
forward_ClusterService_Get_0 = runtime.ForwardResponseMessage
forward_ClusterService_Update_0 = runtime.ForwardResponseMessage

View File

@@ -24,6 +24,13 @@ message ClusterCreateRequest {
bool upsert = 2;
}
message ClusterCreateFromKubeConfigRequest {
string kubeconfig = 1;
string context = 2;
bool upsert = 3;
bool inCluster = 4;
}
message ClusterUpdateRequest {
github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.Cluster cluster = 1;
}
@@ -43,6 +50,14 @@ service ClusterService {
body: "cluster"
};
}
// CreateFromKubeConfig installs the argocd-manager service account into the cluster specified in the given kubeconfig and context
rpc CreateFromKubeConfig(ClusterCreateFromKubeConfigRequest) returns (github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.Cluster) {
option (google.api.http) = {
post: "/api/v1/clusters-kubeconfig"
body: "*"
};
}
// Get returns a cluster by server address
rpc Get(ClusterQuery) returns (github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.Cluster) {

View File

@@ -3,9 +3,15 @@ package project
import (
"context"
"fmt"
"strings"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/client-go/kubernetes"
"github.com/argoproj/argo-cd/common"
"github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
appclientset "github.com/argoproj/argo-cd/pkg/client/clientset/versioned"
@@ -13,28 +19,118 @@ import (
"github.com/argoproj/argo-cd/util/argo"
"github.com/argoproj/argo-cd/util/git"
"github.com/argoproj/argo-cd/util/grpc"
projectutil "github.com/argoproj/argo-cd/util/project"
"github.com/argoproj/argo-cd/util/rbac"
"github.com/argoproj/argo-cd/util/session"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
jwt "github.com/dgrijalva/jwt-go"
)
const (
// JWTTokenSubFormat format of the JWT token subject that ArgoCD vends out.
JWTTokenSubFormat = "proj:%s:%s"
)
// Server provides a Project service
type Server struct {
ns string
enf *rbac.Enforcer
appclientset appclientset.Interface
auditLogger *argo.AuditLogger
projectLock *util.KeyLock
ns string
enf *rbac.Enforcer
appclientset appclientset.Interface
kubeclientset kubernetes.Interface
auditLogger *argo.AuditLogger
projectLock *util.KeyLock
sessionMgr *session.SessionManager
}
// NewServer returns a new instance of the Project service
func NewServer(ns string, kubeclientset kubernetes.Interface, appclientset appclientset.Interface, enf *rbac.Enforcer, projectLock *util.KeyLock) *Server {
func NewServer(ns string, kubeclientset kubernetes.Interface, appclientset appclientset.Interface, enf *rbac.Enforcer, projectLock *util.KeyLock, sessionMgr *session.SessionManager) *Server {
auditLogger := argo.NewAuditLogger(ns, kubeclientset, "argocd-server")
return &Server{enf: enf, appclientset: appclientset, ns: ns, projectLock: projectLock, auditLogger: auditLogger}
return &Server{enf: enf, appclientset: appclientset, kubeclientset: kubeclientset, ns: ns, projectLock: projectLock, auditLogger: auditLogger, sessionMgr: sessionMgr}
}
// CreateToken creates a new token to access a project
func (s *Server) CreateToken(ctx context.Context, q *ProjectTokenCreateRequest) (*ProjectTokenResponse, error) {
if !s.enf.EnforceClaims(ctx.Value("claims"), "projects", "update", q.Project) {
return nil, grpc.ErrPermissionDenied
}
project, err := s.appclientset.ArgoprojV1alpha1().AppProjects(s.ns).Get(q.Project, metav1.GetOptions{})
if err != nil {
return nil, err
}
err = validateProject(project)
if err != nil {
return nil, err
}
s.projectLock.Lock(q.Project)
defer s.projectLock.Unlock(q.Project)
index, err := projectutil.GetRoleIndexByName(project, q.Role)
if err != nil {
return nil, status.Errorf(codes.NotFound, "project '%s' does not have role '%s'", q.Project, q.Role)
}
tokenName := fmt.Sprintf(JWTTokenSubFormat, q.Project, q.Role)
jwtToken, err := s.sessionMgr.Create(tokenName, q.ExpiresIn)
if err != nil {
return nil, status.Error(codes.InvalidArgument, err.Error())
}
parser := &jwt.Parser{
SkipClaimsValidation: true,
}
claims := jwt.StandardClaims{}
_, _, err = parser.ParseUnverified(jwtToken, &claims)
if err != nil {
return nil, status.Error(codes.InvalidArgument, err.Error())
}
issuedAt := claims.IssuedAt
expiresAt := claims.ExpiresAt
project.Spec.Roles[index].JWTTokens = append(project.Spec.Roles[index].JWTTokens, v1alpha1.JWTToken{IssuedAt: issuedAt, ExpiresAt: expiresAt})
_, err = s.appclientset.ArgoprojV1alpha1().AppProjects(s.ns).Update(project)
if err != nil {
return nil, err
}
s.logEvent(project, ctx, argo.EventReasonResourceCreated, "create token")
return &ProjectTokenResponse{Token: jwtToken}, nil
}
// DeleteToken deletes a token in a project
func (s *Server) DeleteToken(ctx context.Context, q *ProjectTokenDeleteRequest) (*EmptyResponse, error) {
if !s.enf.EnforceClaims(ctx.Value("claims"), "projects", "delete", q.Project) {
return nil, grpc.ErrPermissionDenied
}
project, err := s.appclientset.ArgoprojV1alpha1().AppProjects(s.ns).Get(q.Project, metav1.GetOptions{})
if err != nil {
return nil, err
}
err = validateProject(project)
if err != nil {
return nil, err
}
s.projectLock.Lock(q.Project)
defer s.projectLock.Unlock(q.Project)
roleIndex, err := projectutil.GetRoleIndexByName(project, q.Role)
if err != nil {
return &EmptyResponse{}, nil
}
if project.Spec.Roles[roleIndex].JWTTokens == nil {
return &EmptyResponse{}, nil
}
jwtTokenIndex, err := projectutil.GetJWTTokenIndexByIssuedAt(project, roleIndex, q.Iat)
if err != nil {
return &EmptyResponse{}, nil
}
project.Spec.Roles[roleIndex].JWTTokens[jwtTokenIndex] = project.Spec.Roles[roleIndex].JWTTokens[len(project.Spec.Roles[roleIndex].JWTTokens)-1]
project.Spec.Roles[roleIndex].JWTTokens = project.Spec.Roles[roleIndex].JWTTokens[:len(project.Spec.Roles[roleIndex].JWTTokens)-1]
_, err = s.appclientset.ArgoprojV1alpha1().AppProjects(s.ns).Update(project)
if err != nil {
return nil, err
}
s.logEvent(project, ctx, argo.EventReasonResourceDeleted, "deleted token")
return &EmptyResponse{}, nil
}
// Create a new project.
@@ -42,9 +138,7 @@ func (s *Server) Create(ctx context.Context, q *ProjectCreateRequest) (*v1alpha1
if !s.enf.EnforceClaims(ctx.Value("claims"), "projects", "create", q.Project.Name) {
return nil, grpc.ErrPermissionDenied
}
if q.Project.Name == common.DefaultAppProjectName {
return nil, status.Errorf(codes.InvalidArgument, "name '%s' is reserved and cannot be used as a project name", q.Project.Name)
}
err := validateProject(q.Project)
if err != nil {
return nil, err
@@ -59,7 +153,6 @@ func (s *Server) Create(ctx context.Context, q *ProjectCreateRequest) (*v1alpha1
// List returns list of projects
func (s *Server) List(ctx context.Context, q *ProjectQuery) (*v1alpha1.AppProjectList, error) {
list, err := s.appclientset.ArgoprojV1alpha1().AppProjects(s.ns).List(metav1.ListOptions{})
list.Items = append(list.Items, v1alpha1.GetDefaultProject(s.ns))
if list != nil {
newItems := make([]v1alpha1.AppProject, 0)
for i := range list.Items {
@@ -121,6 +214,58 @@ func getRemovedSources(oldProj, newProj *v1alpha1.AppProject) map[string]bool {
return removed
}
func validateJWTToken(proj string, token string, policy string) error {
err := validatePolicy(proj, policy)
if err != nil {
return err
}
policyComponents := strings.Split(policy, ",")
if strings.Trim(policyComponents[2], " ") != "applications" {
return status.Errorf(codes.InvalidArgument, "incorrect format for '%s' as JWT tokens can only access applications", policy)
}
roleComponents := strings.Split(strings.Trim(policyComponents[1], " "), ":")
if len(roleComponents) != 3 {
return status.Errorf(codes.InvalidArgument, "incorrect number of role arguments for '%s' policy", policy)
}
if roleComponents[0] != "proj" {
return status.Errorf(codes.InvalidArgument, "incorrect policy format for '%s' as role should start with 'proj:'", policy)
}
if roleComponents[1] != proj {
return status.Errorf(codes.InvalidArgument, "incorrect policy format for '%s' as policy can't grant access to other projects", policy)
}
if roleComponents[2] != token {
return status.Errorf(codes.InvalidArgument, "incorrect policy format for '%s' as policy can't grant access to other roles", policy)
}
return nil
}
func validatePolicy(proj string, policy string) error {
policyComponents := strings.Split(policy, ",")
if len(policyComponents) != 6 {
return status.Errorf(codes.InvalidArgument, "incorrect number of policy arguments for '%s'", policy)
}
if strings.Trim(policyComponents[0], " ") != "p" {
return status.Errorf(codes.InvalidArgument, "policies can only use the policy format: '%s'", policy)
}
if len(strings.Trim(policyComponents[1], " ")) <= 0 {
return status.Errorf(codes.InvalidArgument, "incorrect policy format for '%s' as subject must be longer than 0 characters:", policy)
}
if len(strings.Trim(policyComponents[2], " ")) <= 0 {
return status.Errorf(codes.InvalidArgument, "incorrect policy format for '%s' as object must be longer than 0 characters:", policy)
}
if len(strings.Trim(policyComponents[3], " ")) <= 0 {
return status.Errorf(codes.InvalidArgument, "incorrect policy format for '%s' as action must be longer than 0 characters:", policy)
}
if !strings.HasPrefix(strings.Trim(policyComponents[4], " "), proj) {
return status.Errorf(codes.InvalidArgument, "incorrect policy format for '%s' as policies can't grant access to other projects", policy)
}
effect := strings.Trim(policyComponents[5], " ")
if effect != "allow" && effect != "deny" {
return status.Errorf(codes.InvalidArgument, "incorrect policy format for '%s' as effect can only have value 'allow' or 'deny'", policy)
}
return nil
}
func validateProject(p *v1alpha1.AppProject) error {
destKeys := make(map[string]bool)
for _, dest := range p.Spec.Destinations {
@@ -133,7 +278,9 @@ func validateProject(p *v1alpha1.AppProject) error {
}
srcRepos := make(map[string]bool)
for i, src := range p.Spec.SourceRepos {
src = git.NormalizeGitURL(src)
if src != "*" {
src = git.NormalizeGitURL(src)
}
p.Spec.SourceRepos[i] = src
if _, ok := srcRepos[src]; !ok {
srcRepos[src] = true
@@ -141,14 +288,39 @@ func validateProject(p *v1alpha1.AppProject) error {
return status.Errorf(codes.InvalidArgument, "source repository %s should not be listed more than once.", src)
}
}
roleNames := make(map[string]bool)
for _, role := range p.Spec.Roles {
existingPolicies := make(map[string]bool)
for _, policy := range role.Policies {
var err error
if role.JWTTokens != nil {
err = validateJWTToken(p.Name, role.Name, policy)
} else {
err = validatePolicy(p.Name, policy)
}
if err != nil {
return err
}
if _, ok := existingPolicies[policy]; !ok {
existingPolicies[policy] = true
} else {
return status.Errorf(codes.AlreadyExists, "policy '%s' already exists for role '%s'", policy, role.Name)
}
}
if _, ok := roleNames[role.Name]; !ok {
roleNames[role.Name] = true
} else {
return status.Errorf(codes.AlreadyExists, "can't have duplicate roles: role '%s' already exists", role.Name)
}
}
return nil
}
// Update updates a project
func (s *Server) Update(ctx context.Context, q *ProjectUpdateRequest) (*v1alpha1.AppProject, error) {
if q.Project.Name == common.DefaultAppProjectName {
return nil, grpc.ErrPermissionDenied
}
if !s.enf.EnforceClaims(ctx.Value("claims"), "projects", "update", q.Project.Name) {
return nil, grpc.ErrPermissionDenied
}
@@ -205,6 +377,9 @@ func (s *Server) Update(ctx context.Context, q *ProjectUpdateRequest) (*v1alpha1
// Delete deletes a project
func (s *Server) Delete(ctx context.Context, q *ProjectQuery) (*EmptyResponse, error) {
if q.Name == common.DefaultAppProjectName {
return nil, status.Errorf(codes.InvalidArgument, "name '%s' is reserved and cannot be deleted", q.Name)
}
if !s.enf.EnforceClaims(ctx.Value("claims"), "projects", "delete", q.Name) {
return nil, grpc.ErrPermissionDenied
}
@@ -232,6 +407,22 @@ func (s *Server) Delete(ctx context.Context, q *ProjectQuery) (*EmptyResponse, e
return &EmptyResponse{}, err
}
func (s *Server) ListEvents(ctx context.Context, q *ProjectQuery) (*v1.EventList, error) {
if !s.enf.EnforceClaims(ctx.Value("claims"), "projects/events", "get", q.Name) {
return nil, grpc.ErrPermissionDenied
}
proj, err := s.appclientset.ArgoprojV1alpha1().AppProjects(s.ns).Get(q.Name, metav1.GetOptions{})
if err != nil {
return nil, err
}
fieldSelector := fields.SelectorFromSet(map[string]string{
"involvedObject.name": proj.Name,
"involvedObject.uid": string(proj.UID),
"involvedObject.namespace": proj.Namespace,
}).String()
return s.kubeclientset.CoreV1().Events(s.ns).List(metav1.ListOptions{FieldSelector: fieldSelector})
}
func (s *Server) logEvent(p *v1alpha1.AppProject, ctx context.Context, reason string, action string) {
s.auditLogger.LogAppProjEvent(p, argo.EventInfo{Reason: reason, Action: action, Username: session.Username(ctx)}, v1.EventTypeNormal)
}

View File

@@ -13,6 +13,9 @@
It has these top-level messages:
ProjectCreateRequest
ProjectTokenDeleteRequest
ProjectTokenCreateRequest
ProjectTokenResponse
ProjectQuery
ProjectUpdateRequest
EmptyResponse
@@ -24,7 +27,7 @@ import fmt "fmt"
import math "math"
import _ "github.com/gogo/protobuf/gogoproto"
import _ "google.golang.org/genproto/googleapis/api/annotations"
import _ "k8s.io/api/core/v1"
import k8s_io_api_core_v1 "k8s.io/api/core/v1"
import _ "k8s.io/apimachinery/pkg/apis/meta/v1"
import github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
@@ -61,6 +64,98 @@ func (m *ProjectCreateRequest) GetProject() *github_com_argoproj_argo_cd_pkg_api
return nil
}
// ProjectTokenCreateRequest defines project token deletion parameters.
type ProjectTokenDeleteRequest struct {
Project string `protobuf:"bytes,1,opt,name=project,proto3" json:"project,omitempty"`
Role string `protobuf:"bytes,2,opt,name=role,proto3" json:"role,omitempty"`
Iat int64 `protobuf:"varint,3,opt,name=iat,proto3" json:"iat,omitempty"`
}
func (m *ProjectTokenDeleteRequest) Reset() { *m = ProjectTokenDeleteRequest{} }
func (m *ProjectTokenDeleteRequest) String() string { return proto.CompactTextString(m) }
func (*ProjectTokenDeleteRequest) ProtoMessage() {}
func (*ProjectTokenDeleteRequest) Descriptor() ([]byte, []int) { return fileDescriptorProject, []int{1} }
func (m *ProjectTokenDeleteRequest) GetProject() string {
if m != nil {
return m.Project
}
return ""
}
func (m *ProjectTokenDeleteRequest) GetRole() string {
if m != nil {
return m.Role
}
return ""
}
func (m *ProjectTokenDeleteRequest) GetIat() int64 {
if m != nil {
return m.Iat
}
return 0
}
// ProjectTokenCreateRequest defines project token creation parameters.
type ProjectTokenCreateRequest struct {
Project string `protobuf:"bytes,1,opt,name=project,proto3" json:"project,omitempty"`
Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"`
Role string `protobuf:"bytes,3,opt,name=role,proto3" json:"role,omitempty"`
// expiresIn represents a duration in seconds
ExpiresIn int64 `protobuf:"varint,4,opt,name=expiresIn,proto3" json:"expiresIn,omitempty"`
}
func (m *ProjectTokenCreateRequest) Reset() { *m = ProjectTokenCreateRequest{} }
func (m *ProjectTokenCreateRequest) String() string { return proto.CompactTextString(m) }
func (*ProjectTokenCreateRequest) ProtoMessage() {}
func (*ProjectTokenCreateRequest) Descriptor() ([]byte, []int) { return fileDescriptorProject, []int{2} }
func (m *ProjectTokenCreateRequest) GetProject() string {
if m != nil {
return m.Project
}
return ""
}
func (m *ProjectTokenCreateRequest) GetDescription() string {
if m != nil {
return m.Description
}
return ""
}
func (m *ProjectTokenCreateRequest) GetRole() string {
if m != nil {
return m.Role
}
return ""
}
func (m *ProjectTokenCreateRequest) GetExpiresIn() int64 {
if m != nil {
return m.ExpiresIn
}
return 0
}
// ProjectTokenResponse wraps the created token or returns an empty string if deleted.
type ProjectTokenResponse struct {
Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"`
}
func (m *ProjectTokenResponse) Reset() { *m = ProjectTokenResponse{} }
func (m *ProjectTokenResponse) String() string { return proto.CompactTextString(m) }
func (*ProjectTokenResponse) ProtoMessage() {}
func (*ProjectTokenResponse) Descriptor() ([]byte, []int) { return fileDescriptorProject, []int{3} }
func (m *ProjectTokenResponse) GetToken() string {
if m != nil {
return m.Token
}
return ""
}
// ProjectQuery is a query for Project resources
type ProjectQuery struct {
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
@@ -69,7 +164,7 @@ type ProjectQuery struct {
func (m *ProjectQuery) Reset() { *m = ProjectQuery{} }
func (m *ProjectQuery) String() string { return proto.CompactTextString(m) }
func (*ProjectQuery) ProtoMessage() {}
func (*ProjectQuery) Descriptor() ([]byte, []int) { return fileDescriptorProject, []int{1} }
func (*ProjectQuery) Descriptor() ([]byte, []int) { return fileDescriptorProject, []int{4} }
func (m *ProjectQuery) GetName() string {
if m != nil {
@@ -85,7 +180,7 @@ type ProjectUpdateRequest struct {
func (m *ProjectUpdateRequest) Reset() { *m = ProjectUpdateRequest{} }
func (m *ProjectUpdateRequest) String() string { return proto.CompactTextString(m) }
func (*ProjectUpdateRequest) ProtoMessage() {}
func (*ProjectUpdateRequest) Descriptor() ([]byte, []int) { return fileDescriptorProject, []int{2} }
func (*ProjectUpdateRequest) Descriptor() ([]byte, []int) { return fileDescriptorProject, []int{5} }
func (m *ProjectUpdateRequest) GetProject() *github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.AppProject {
if m != nil {
@@ -100,10 +195,13 @@ type EmptyResponse struct {
func (m *EmptyResponse) Reset() { *m = EmptyResponse{} }
func (m *EmptyResponse) String() string { return proto.CompactTextString(m) }
func (*EmptyResponse) ProtoMessage() {}
func (*EmptyResponse) Descriptor() ([]byte, []int) { return fileDescriptorProject, []int{3} }
func (*EmptyResponse) Descriptor() ([]byte, []int) { return fileDescriptorProject, []int{6} }
func init() {
proto.RegisterType((*ProjectCreateRequest)(nil), "project.ProjectCreateRequest")
proto.RegisterType((*ProjectTokenDeleteRequest)(nil), "project.ProjectTokenDeleteRequest")
proto.RegisterType((*ProjectTokenCreateRequest)(nil), "project.ProjectTokenCreateRequest")
proto.RegisterType((*ProjectTokenResponse)(nil), "project.ProjectTokenResponse")
proto.RegisterType((*ProjectQuery)(nil), "project.ProjectQuery")
proto.RegisterType((*ProjectUpdateRequest)(nil), "project.ProjectUpdateRequest")
proto.RegisterType((*EmptyResponse)(nil), "project.EmptyResponse")
@@ -120,6 +218,10 @@ const _ = grpc.SupportPackageIsVersion4
// Client API for ProjectService service
type ProjectServiceClient interface {
// Create a new project token.
CreateToken(ctx context.Context, in *ProjectTokenCreateRequest, opts ...grpc.CallOption) (*ProjectTokenResponse, error)
// Delete a new project token.
DeleteToken(ctx context.Context, in *ProjectTokenDeleteRequest, opts ...grpc.CallOption) (*EmptyResponse, error)
// Create a new project.
Create(ctx context.Context, in *ProjectCreateRequest, opts ...grpc.CallOption) (*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.AppProject, error)
// List returns list of projects
@@ -130,6 +232,8 @@ type ProjectServiceClient interface {
Update(ctx context.Context, in *ProjectUpdateRequest, opts ...grpc.CallOption) (*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.AppProject, error)
// Delete deletes a project
Delete(ctx context.Context, in *ProjectQuery, opts ...grpc.CallOption) (*EmptyResponse, error)
// ListEvents returns a list of project events
ListEvents(ctx context.Context, in *ProjectQuery, opts ...grpc.CallOption) (*k8s_io_api_core_v1.EventList, error)
}
type projectServiceClient struct {
@@ -140,6 +244,24 @@ func NewProjectServiceClient(cc *grpc.ClientConn) ProjectServiceClient {
return &projectServiceClient{cc}
}
func (c *projectServiceClient) CreateToken(ctx context.Context, in *ProjectTokenCreateRequest, opts ...grpc.CallOption) (*ProjectTokenResponse, error) {
out := new(ProjectTokenResponse)
err := grpc.Invoke(ctx, "/project.ProjectService/CreateToken", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *projectServiceClient) DeleteToken(ctx context.Context, in *ProjectTokenDeleteRequest, opts ...grpc.CallOption) (*EmptyResponse, error) {
out := new(EmptyResponse)
err := grpc.Invoke(ctx, "/project.ProjectService/DeleteToken", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *projectServiceClient) Create(ctx context.Context, in *ProjectCreateRequest, opts ...grpc.CallOption) (*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.AppProject, error) {
out := new(github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.AppProject)
err := grpc.Invoke(ctx, "/project.ProjectService/Create", in, out, c.cc, opts...)
@@ -185,9 +307,22 @@ func (c *projectServiceClient) Delete(ctx context.Context, in *ProjectQuery, opt
return out, nil
}
func (c *projectServiceClient) ListEvents(ctx context.Context, in *ProjectQuery, opts ...grpc.CallOption) (*k8s_io_api_core_v1.EventList, error) {
out := new(k8s_io_api_core_v1.EventList)
err := grpc.Invoke(ctx, "/project.ProjectService/ListEvents", in, out, c.cc, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// Server API for ProjectService service
type ProjectServiceServer interface {
// Create a new project token.
CreateToken(context.Context, *ProjectTokenCreateRequest) (*ProjectTokenResponse, error)
// Delete a new project token.
DeleteToken(context.Context, *ProjectTokenDeleteRequest) (*EmptyResponse, error)
// Create a new project.
Create(context.Context, *ProjectCreateRequest) (*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.AppProject, error)
// List returns list of projects
@@ -198,12 +333,50 @@ type ProjectServiceServer interface {
Update(context.Context, *ProjectUpdateRequest) (*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.AppProject, error)
// Delete deletes a project
Delete(context.Context, *ProjectQuery) (*EmptyResponse, error)
// ListEvents returns a list of project events
ListEvents(context.Context, *ProjectQuery) (*k8s_io_api_core_v1.EventList, error)
}
func RegisterProjectServiceServer(s *grpc.Server, srv ProjectServiceServer) {
s.RegisterService(&_ProjectService_serviceDesc, srv)
}
func _ProjectService_CreateToken_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ProjectTokenCreateRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ProjectServiceServer).CreateToken(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/project.ProjectService/CreateToken",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ProjectServiceServer).CreateToken(ctx, req.(*ProjectTokenCreateRequest))
}
return interceptor(ctx, in, info, handler)
}
func _ProjectService_DeleteToken_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ProjectTokenDeleteRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ProjectServiceServer).DeleteToken(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/project.ProjectService/DeleteToken",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ProjectServiceServer).DeleteToken(ctx, req.(*ProjectTokenDeleteRequest))
}
return interceptor(ctx, in, info, handler)
}
func _ProjectService_Create_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ProjectCreateRequest)
if err := dec(in); err != nil {
@@ -294,10 +467,36 @@ func _ProjectService_Delete_Handler(srv interface{}, ctx context.Context, dec fu
return interceptor(ctx, in, info, handler)
}
func _ProjectService_ListEvents_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ProjectQuery)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ProjectServiceServer).ListEvents(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/project.ProjectService/ListEvents",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ProjectServiceServer).ListEvents(ctx, req.(*ProjectQuery))
}
return interceptor(ctx, in, info, handler)
}
var _ProjectService_serviceDesc = grpc.ServiceDesc{
ServiceName: "project.ProjectService",
HandlerType: (*ProjectServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "CreateToken",
Handler: _ProjectService_CreateToken_Handler,
},
{
MethodName: "DeleteToken",
Handler: _ProjectService_DeleteToken_Handler,
},
{
MethodName: "Create",
Handler: _ProjectService_Create_Handler,
@@ -318,6 +517,10 @@ var _ProjectService_serviceDesc = grpc.ServiceDesc{
MethodName: "Delete",
Handler: _ProjectService_Delete_Handler,
},
{
MethodName: "ListEvents",
Handler: _ProjectService_ListEvents_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "server/project/project.proto",
@@ -351,6 +554,106 @@ func (m *ProjectCreateRequest) MarshalTo(dAtA []byte) (int, error) {
return i, nil
}
func (m *ProjectTokenDeleteRequest) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalTo(dAtA)
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *ProjectTokenDeleteRequest) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
if len(m.Project) > 0 {
dAtA[i] = 0xa
i++
i = encodeVarintProject(dAtA, i, uint64(len(m.Project)))
i += copy(dAtA[i:], m.Project)
}
if len(m.Role) > 0 {
dAtA[i] = 0x12
i++
i = encodeVarintProject(dAtA, i, uint64(len(m.Role)))
i += copy(dAtA[i:], m.Role)
}
if m.Iat != 0 {
dAtA[i] = 0x18
i++
i = encodeVarintProject(dAtA, i, uint64(m.Iat))
}
return i, nil
}
func (m *ProjectTokenCreateRequest) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalTo(dAtA)
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *ProjectTokenCreateRequest) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
if len(m.Project) > 0 {
dAtA[i] = 0xa
i++
i = encodeVarintProject(dAtA, i, uint64(len(m.Project)))
i += copy(dAtA[i:], m.Project)
}
if len(m.Description) > 0 {
dAtA[i] = 0x12
i++
i = encodeVarintProject(dAtA, i, uint64(len(m.Description)))
i += copy(dAtA[i:], m.Description)
}
if len(m.Role) > 0 {
dAtA[i] = 0x1a
i++
i = encodeVarintProject(dAtA, i, uint64(len(m.Role)))
i += copy(dAtA[i:], m.Role)
}
if m.ExpiresIn != 0 {
dAtA[i] = 0x20
i++
i = encodeVarintProject(dAtA, i, uint64(m.ExpiresIn))
}
return i, nil
}
func (m *ProjectTokenResponse) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalTo(dAtA)
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *ProjectTokenResponse) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
if len(m.Token) > 0 {
dAtA[i] = 0xa
i++
i = encodeVarintProject(dAtA, i, uint64(len(m.Token)))
i += copy(dAtA[i:], m.Token)
}
return i, nil
}
func (m *ProjectQuery) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
@@ -440,6 +743,54 @@ func (m *ProjectCreateRequest) Size() (n int) {
return n
}
func (m *ProjectTokenDeleteRequest) Size() (n int) {
var l int
_ = l
l = len(m.Project)
if l > 0 {
n += 1 + l + sovProject(uint64(l))
}
l = len(m.Role)
if l > 0 {
n += 1 + l + sovProject(uint64(l))
}
if m.Iat != 0 {
n += 1 + sovProject(uint64(m.Iat))
}
return n
}
func (m *ProjectTokenCreateRequest) Size() (n int) {
var l int
_ = l
l = len(m.Project)
if l > 0 {
n += 1 + l + sovProject(uint64(l))
}
l = len(m.Description)
if l > 0 {
n += 1 + l + sovProject(uint64(l))
}
l = len(m.Role)
if l > 0 {
n += 1 + l + sovProject(uint64(l))
}
if m.ExpiresIn != 0 {
n += 1 + sovProject(uint64(m.ExpiresIn))
}
return n
}
func (m *ProjectTokenResponse) Size() (n int) {
var l int
_ = l
l = len(m.Token)
if l > 0 {
n += 1 + l + sovProject(uint64(l))
}
return n
}
func (m *ProjectQuery) Size() (n int) {
var l int
_ = l
@@ -562,6 +913,368 @@ func (m *ProjectCreateRequest) Unmarshal(dAtA []byte) error {
}
return nil
}
func (m *ProjectTokenDeleteRequest) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowProject
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: ProjectTokenDeleteRequest: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: ProjectTokenDeleteRequest: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Project", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowProject
}
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 ErrInvalidLengthProject
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Project = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Role", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowProject
}
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 ErrInvalidLengthProject
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Role = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 3:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Iat", wireType)
}
m.Iat = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowProject
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.Iat |= (int64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
default:
iNdEx = preIndex
skippy, err := skipProject(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthProject
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *ProjectTokenCreateRequest) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowProject
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: ProjectTokenCreateRequest: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: ProjectTokenCreateRequest: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Project", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowProject
}
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 ErrInvalidLengthProject
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Project = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowProject
}
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 ErrInvalidLengthProject
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Description = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 3:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Role", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowProject
}
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 ErrInvalidLengthProject
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Role = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 4:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field ExpiresIn", wireType)
}
m.ExpiresIn = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowProject
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.ExpiresIn |= (int64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
default:
iNdEx = preIndex
skippy, err := skipProject(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthProject
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *ProjectTokenResponse) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowProject
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: ProjectTokenResponse: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: ProjectTokenResponse: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Token", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowProject
}
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 ErrInvalidLengthProject
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Token = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipProject(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthProject
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *ProjectQuery) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
@@ -882,36 +1595,49 @@ var (
func init() { proto.RegisterFile("server/project/project.proto", fileDescriptorProject) }
var fileDescriptorProject = []byte{
// 487 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x94, 0xcd, 0x6e, 0x13, 0x31,
0x10, 0xc7, 0x65, 0x28, 0x41, 0x98, 0x4f, 0x59, 0x2d, 0x94, 0xa5, 0x04, 0xb4, 0xa7, 0x2a, 0x52,
0x6d, 0xa5, 0xe5, 0x50, 0x71, 0xe3, 0xa3, 0x42, 0x95, 0x38, 0x40, 0x10, 0x12, 0xe2, 0x52, 0xb9,
0xde, 0x91, 0xe3, 0x26, 0xbb, 0x36, 0xb6, 0xb3, 0x28, 0x42, 0x5c, 0x2a, 0x6e, 0x1c, 0x79, 0x04,
0x6e, 0x3c, 0x09, 0x47, 0x24, 0x5e, 0x00, 0x45, 0x3c, 0x08, 0x5a, 0x67, 0x4d, 0x9a, 0xa6, 0xe1,
0xb4, 0xe2, 0x94, 0xc9, 0xf8, 0xe3, 0xff, 0x9b, 0xf1, 0x7f, 0x07, 0x6f, 0x38, 0xb0, 0x25, 0x58,
0x66, 0xac, 0x3e, 0x02, 0xe1, 0xe3, 0x2f, 0x35, 0x56, 0x7b, 0x4d, 0x2e, 0xd6, 0x7f, 0x93, 0x55,
0xa9, 0xa5, 0x0e, 0x39, 0x56, 0x45, 0xd3, 0xe5, 0x64, 0x43, 0x6a, 0x2d, 0x87, 0xc0, 0xb8, 0x51,
0x8c, 0x17, 0x85, 0xf6, 0xdc, 0x2b, 0x5d, 0xb8, 0x7a, 0x35, 0x1d, 0xec, 0x3a, 0xaa, 0x74, 0x58,
0x15, 0xda, 0x02, 0x2b, 0xbb, 0x4c, 0x42, 0x01, 0x96, 0x7b, 0xc8, 0xea, 0x3d, 0x0f, 0x66, 0x7b,
0x72, 0x2e, 0xfa, 0xaa, 0x00, 0x3b, 0x66, 0x66, 0x20, 0xab, 0x84, 0x63, 0x39, 0x78, 0x7e, 0xd6,
0xa9, 0x7d, 0xa9, 0x7c, 0x7f, 0x74, 0x48, 0x85, 0xce, 0x19, 0xb7, 0x01, 0xec, 0x28, 0x04, 0x5b,
0x22, 0x9b, 0x9d, 0xe6, 0xc6, 0x0c, 0x95, 0x08, 0x48, 0xac, 0xec, 0xf2, 0xa1, 0xe9, 0xf3, 0x85,
0xab, 0xd2, 0xf7, 0x78, 0xf5, 0xc5, 0xb4, 0xc6, 0x27, 0x16, 0xb8, 0x87, 0x1e, 0xbc, 0x1b, 0x81,
0xf3, 0xe4, 0x00, 0xc7, 0xda, 0xd7, 0xd1, 0x7d, 0xb4, 0x79, 0x79, 0x7b, 0x8f, 0xce, 0x44, 0x69,
0x14, 0x0d, 0xc1, 0x81, 0xc8, 0xa8, 0x19, 0x48, 0x5a, 0x89, 0xd2, 0x13, 0xa2, 0x34, 0x8a, 0xd2,
0x47, 0xc6, 0xd4, 0x22, 0xbd, 0x78, 0x6b, 0x9a, 0xe2, 0x2b, 0x75, 0xee, 0xe5, 0x08, 0xec, 0x98,
0x10, 0xbc, 0x52, 0xf0, 0x1c, 0x82, 0xda, 0xa5, 0x5e, 0x88, 0x4f, 0xc0, 0xbd, 0x36, 0xd9, 0xff,
0x84, 0xbb, 0x8e, 0xaf, 0xee, 0xe5, 0xc6, 0x8f, 0x7b, 0xe0, 0x8c, 0x2e, 0x1c, 0x6c, 0x7f, 0xbb,
0x80, 0xaf, 0xd5, 0xbb, 0x5e, 0x81, 0x2d, 0x95, 0x00, 0xf2, 0x19, 0xe1, 0xd6, 0xb4, 0x67, 0xe4,
0x2e, 0x8d, 0xb6, 0x39, 0xab, 0x97, 0x49, 0x33, 0x74, 0xe9, 0x9d, 0xe3, 0x9f, 0xbf, 0xbf, 0x9c,
0x5b, 0x4b, 0x6f, 0x04, 0x47, 0x95, 0xdd, 0xe8, 0x55, 0xf7, 0x10, 0x75, 0xc8, 0x31, 0xc2, 0x2b,
0xcf, 0x95, 0xf3, 0x64, 0xed, 0x34, 0x4b, 0x68, 0x6f, 0xb2, 0xdf, 0x08, 0x43, 0xa5, 0x90, 0xae,
0x07, 0x0e, 0x42, 0x16, 0x38, 0xc8, 0x27, 0x84, 0xcf, 0x3f, 0x83, 0xa5, 0x0c, 0x0d, 0xf5, 0xe1,
0x5e, 0xd0, 0xbf, 0x4d, 0x6e, 0x9d, 0xd6, 0x67, 0x1f, 0x2a, 0xd7, 0x7c, 0x24, 0x5f, 0x11, 0x6e,
0x4d, 0x0d, 0xb3, 0xf8, 0x32, 0x73, 0x46, 0x6a, 0x8a, 0x68, 0x27, 0x10, 0x6d, 0x25, 0x9b, 0x8b,
0x44, 0x51, 0xbe, 0xfa, 0x94, 0x33, 0xee, 0x39, 0x0d, 0x88, 0xd5, 0x8b, 0xbd, 0xc1, 0xad, 0xa7,
0x30, 0x04, 0x0f, 0xcb, 0xda, 0x75, 0xf3, 0x6f, 0x7a, 0xce, 0x8b, 0xb1, 0xfe, 0xce, 0xb2, 0xfa,
0x1f, 0xef, 0x7e, 0x9f, 0xb4, 0xd1, 0x8f, 0x49, 0x1b, 0xfd, 0x9a, 0xb4, 0xd1, 0xdb, 0xce, 0xbf,
0x86, 0xc5, 0xfc, 0xf4, 0x3b, 0x6c, 0x85, 0xa1, 0xb0, 0xf3, 0x27, 0x00, 0x00, 0xff, 0xff, 0x59,
0x47, 0x12, 0x67, 0x16, 0x05, 0x00, 0x00,
// 689 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x55, 0x5d, 0x6b, 0x13, 0x4d,
0x14, 0x66, 0x9a, 0xbe, 0x79, 0xed, 0xc4, 0x8f, 0x32, 0xb4, 0x9a, 0xc6, 0x36, 0x86, 0xb9, 0x90,
0x12, 0xec, 0x0c, 0x69, 0x15, 0x8a, 0x77, 0x7e, 0x14, 0x29, 0x78, 0xa1, 0x51, 0x41, 0xf4, 0xa2,
0x4c, 0x37, 0x87, 0xed, 0x36, 0xc9, 0xce, 0x38, 0x3b, 0x5d, 0x2d, 0xa5, 0x20, 0xc5, 0x1b, 0xf5,
0xd2, 0x9f, 0x20, 0xf8, 0x5b, 0xbc, 0x14, 0xfc, 0x03, 0x12, 0xfc, 0x21, 0x32, 0xb3, 0xbb, 0x49,
0xb6, 0xe9, 0x16, 0x84, 0xe0, 0x55, 0xce, 0x9e, 0x39, 0x73, 0x9e, 0xe7, 0x39, 0x1f, 0x19, 0xbc,
0x1c, 0x81, 0x8e, 0x41, 0x73, 0xa5, 0xe5, 0x3e, 0x78, 0x26, 0xfb, 0x65, 0x4a, 0x4b, 0x23, 0xc9,
0xff, 0xe9, 0x67, 0x6d, 0xc1, 0x97, 0xbe, 0x74, 0x3e, 0x6e, 0xad, 0xe4, 0xb8, 0xb6, 0xec, 0x4b,
0xe9, 0xf7, 0x80, 0x0b, 0x15, 0x70, 0x11, 0x86, 0xd2, 0x08, 0x13, 0xc8, 0x30, 0x4a, 0x4f, 0x69,
0x77, 0x33, 0x62, 0x81, 0x74, 0xa7, 0x9e, 0xd4, 0xc0, 0xe3, 0x16, 0xf7, 0x21, 0x04, 0x2d, 0x0c,
0x74, 0xd2, 0x98, 0xdb, 0xa3, 0x98, 0xbe, 0xf0, 0xf6, 0x82, 0x10, 0xf4, 0x21, 0x57, 0x5d, 0xdf,
0x3a, 0x22, 0xde, 0x07, 0x23, 0xce, 0xba, 0xb5, 0xed, 0x07, 0x66, 0xef, 0x60, 0x97, 0x79, 0xb2,
0xcf, 0x85, 0x76, 0xc4, 0xf6, 0x9d, 0xb1, 0xe6, 0x75, 0x46, 0xb7, 0x85, 0x52, 0xbd, 0xc0, 0x73,
0x94, 0x78, 0xdc, 0x12, 0x3d, 0xb5, 0x27, 0x26, 0x52, 0xd1, 0xb7, 0x78, 0xe1, 0x49, 0xa2, 0xf1,
0x81, 0x06, 0x61, 0xa0, 0x0d, 0x6f, 0x0e, 0x20, 0x32, 0x64, 0x07, 0x67, 0xda, 0xab, 0xa8, 0x81,
0x56, 0x2b, 0xeb, 0x5b, 0x6c, 0x04, 0xca, 0x32, 0x50, 0x67, 0xec, 0x78, 0x1d, 0xa6, 0xba, 0x3e,
0xb3, 0xa0, 0x6c, 0x0c, 0x94, 0x65, 0xa0, 0xec, 0x9e, 0x52, 0x29, 0x48, 0x3b, 0xcb, 0x4a, 0x5f,
0xe3, 0xa5, 0xd4, 0xf7, 0x5c, 0x76, 0x21, 0x7c, 0x08, 0x3d, 0x18, 0xa1, 0x57, 0xf3, 0xe8, 0x73,
0xc3, 0x6b, 0x84, 0xe0, 0x59, 0x2d, 0x7b, 0x50, 0x9d, 0x71, 0x6e, 0x67, 0x93, 0x79, 0x5c, 0x0a,
0x84, 0xa9, 0x96, 0x1a, 0x68, 0xb5, 0xd4, 0xb6, 0x26, 0xfd, 0x88, 0xf2, 0xd9, 0xf3, 0xda, 0x8a,
0xb3, 0x37, 0x70, 0xa5, 0x03, 0x91, 0xa7, 0x03, 0x65, 0x05, 0xa4, 0x20, 0xe3, 0xae, 0x21, 0x7e,
0x69, 0x0c, 0x7f, 0x19, 0xcf, 0xc1, 0x3b, 0x15, 0x68, 0x88, 0xb6, 0xc3, 0xea, 0xac, 0x63, 0x31,
0x72, 0xd0, 0x5b, 0xc3, 0x0a, 0x3b, 0x2a, 0x6d, 0x88, 0x94, 0x0c, 0x23, 0x20, 0x0b, 0xf8, 0x3f,
0x63, 0x1d, 0x29, 0x87, 0xe4, 0x83, 0x52, 0x7c, 0x31, 0x8d, 0x7e, 0x7a, 0x00, 0xfa, 0xd0, 0xe2,
0x85, 0xa2, 0x0f, 0x69, 0x90, 0xb3, 0xc7, 0x7a, 0xf6, 0x42, 0x75, 0xfe, 0x65, 0xcf, 0xae, 0xe0,
0x4b, 0x5b, 0x7d, 0x65, 0x0e, 0x33, 0x0d, 0xeb, 0xdf, 0x2e, 0xe0, 0xcb, 0x69, 0xd4, 0x33, 0xd0,
0x71, 0xe0, 0x01, 0xf9, 0x84, 0x70, 0x25, 0x29, 0xb7, 0x93, 0x4b, 0x28, 0xcb, 0x56, 0xaa, 0xb0,
0x21, 0xb5, 0x95, 0x33, 0x63, 0x32, 0x14, 0xba, 0x79, 0xf2, 0xf3, 0xf7, 0x97, 0x99, 0x75, 0xba,
0xe6, 0x56, 0x29, 0x6e, 0x65, 0x4b, 0x1a, 0xf1, 0xa3, 0xd4, 0x3a, 0xe6, 0xb6, 0x11, 0x11, 0x3f,
0xb2, 0x3f, 0xc7, 0xdc, 0x95, 0xf2, 0x2e, 0x6a, 0x92, 0xf7, 0x08, 0x57, 0x92, 0xc9, 0x3a, 0x8f,
0x4c, 0x6e, 0xf6, 0x6a, 0x57, 0x87, 0x31, 0x39, 0xad, 0xf4, 0x8e, 0x63, 0xc1, 0x9b, 0x7f, 0xc7,
0x82, 0x7c, 0x46, 0xb8, 0x9c, 0xa8, 0x25, 0x13, 0x32, 0xf3, 0x55, 0x98, 0x4e, 0xb7, 0xe8, 0x75,
0xc7, 0x73, 0x91, 0xce, 0x9f, 0xe6, 0x69, 0x0b, 0x72, 0x82, 0xf0, 0xec, 0xe3, 0x20, 0x32, 0x64,
0xf1, 0x34, 0x17, 0x37, 0x6e, 0xb5, 0xed, 0xa9, 0x70, 0xb0, 0x08, 0xb4, 0xea, 0x78, 0x10, 0x32,
0xc1, 0x83, 0x7c, 0x40, 0xb8, 0xf4, 0x08, 0x0a, 0x39, 0x4c, 0xa9, 0x0e, 0x37, 0x1c, 0xfe, 0x12,
0xb9, 0x36, 0xd9, 0x2f, 0xbb, 0x45, 0xc7, 0xe4, 0x2b, 0xc2, 0xe5, 0x64, 0x81, 0x26, 0x3b, 0x93,
0x5b, 0xac, 0x69, 0x31, 0xda, 0x70, 0x8c, 0xd6, 0x6a, 0xab, 0x85, 0x13, 0xc4, 0xec, 0x3f, 0x7e,
0x47, 0x18, 0xc1, 0x1c, 0x45, 0xdb, 0xb1, 0x97, 0xb8, 0x9c, 0xcc, 0x67, 0x51, 0xb9, 0x8a, 0xe6,
0x35, 0xd5, 0xdf, 0x2c, 0xd4, 0xbf, 0x8f, 0xb1, 0x6d, 0xd4, 0x56, 0x0c, 0xa1, 0x89, 0x8a, 0xb2,
0xaf, 0xb0, 0xe4, 0x85, 0xb2, 0x0a, 0x99, 0x7d, 0xc5, 0x58, 0xdc, 0x62, 0xee, 0x8a, 0x6b, 0xf2,
0x4d, 0x07, 0xd2, 0x20, 0xf5, 0x02, 0x10, 0x0e, 0x2e, 0xfb, 0xfd, 0xcd, 0xef, 0x83, 0x3a, 0xfa,
0x31, 0xa8, 0xa3, 0x5f, 0x83, 0x3a, 0x7a, 0xd5, 0x3c, 0xef, 0xfd, 0xca, 0x3f, 0xc8, 0xbb, 0x65,
0xf7, 0x4e, 0x6d, 0xfc, 0x09, 0x00, 0x00, 0xff, 0xff, 0x53, 0xd4, 0xec, 0x49, 0xa9, 0x07, 0x00,
0x00,
}

View File

@@ -28,6 +28,94 @@ var _ status.Status
var _ = runtime.String
var _ = utilities.NewDoubleArray
func request_ProjectService_CreateToken_0(ctx context.Context, marshaler runtime.Marshaler, client ProjectServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ProjectTokenCreateRequest
var metadata runtime.ServerMetadata
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["project"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "project")
}
protoReq.Project, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "project", err)
}
val, ok = pathParams["role"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "role")
}
protoReq.Role, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "role", err)
}
msg, err := client.CreateToken(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
var (
filter_ProjectService_DeleteToken_0 = &utilities.DoubleArray{Encoding: map[string]int{"project": 0, "role": 1}, Base: []int{1, 1, 2, 0, 0}, Check: []int{0, 1, 1, 2, 3}}
)
func request_ProjectService_DeleteToken_0(ctx context.Context, marshaler runtime.Marshaler, client ProjectServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ProjectTokenDeleteRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["project"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "project")
}
protoReq.Project, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "project", err)
}
val, ok = pathParams["role"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "role")
}
protoReq.Role, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "role", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_ProjectService_DeleteToken_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.DeleteToken(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func request_ProjectService_Create_0(ctx context.Context, marshaler runtime.Marshaler, client ProjectServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ProjectCreateRequest
var metadata runtime.ServerMetadata
@@ -143,6 +231,33 @@ func request_ProjectService_Delete_0(ctx context.Context, marshaler runtime.Mars
}
func request_ProjectService_ListEvents_0(ctx context.Context, marshaler runtime.Marshaler, client ProjectServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ProjectQuery
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["name"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "name")
}
protoReq.Name, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err)
}
msg, err := client.ListEvents(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
// RegisterProjectServiceHandlerFromEndpoint is same as RegisterProjectServiceHandler but
// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
func RegisterProjectServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
@@ -181,6 +296,64 @@ func RegisterProjectServiceHandler(ctx context.Context, mux *runtime.ServeMux, c
// "ProjectServiceClient" to call the correct interceptors.
func RegisterProjectServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client ProjectServiceClient) error {
mux.Handle("POST", pattern_ProjectService_CreateToken_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
if cn, ok := w.(http.CloseNotifier); ok {
go func(done <-chan struct{}, closed <-chan bool) {
select {
case <-done:
case <-closed:
cancel()
}
}(ctx.Done(), cn.CloseNotify())
}
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ProjectService_CreateToken_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProjectService_CreateToken_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("DELETE", pattern_ProjectService_DeleteToken_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
if cn, ok := w.(http.CloseNotifier); ok {
go func(done <-chan struct{}, closed <-chan bool) {
select {
case <-done:
case <-closed:
cancel()
}
}(ctx.Done(), cn.CloseNotify())
}
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ProjectService_DeleteToken_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProjectService_DeleteToken_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ProjectService_Create_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
@@ -326,10 +499,43 @@ func RegisterProjectServiceHandlerClient(ctx context.Context, mux *runtime.Serve
})
mux.Handle("GET", pattern_ProjectService_ListEvents_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
if cn, ok := w.(http.CloseNotifier); ok {
go func(done <-chan struct{}, closed <-chan bool) {
select {
case <-done:
case <-closed:
cancel()
}
}(ctx.Done(), cn.CloseNotify())
}
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ProjectService_ListEvents_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ProjectService_ListEvents_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
var (
pattern_ProjectService_CreateToken_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6}, []string{"api", "v1", "projects", "project", "roles", "role", "token"}, ""))
pattern_ProjectService_DeleteToken_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6}, []string{"api", "v1", "projects", "project", "roles", "role", "token"}, ""))
pattern_ProjectService_Create_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "projects"}, ""))
pattern_ProjectService_List_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "projects"}, ""))
@@ -339,9 +545,15 @@ var (
pattern_ProjectService_Update_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v1", "projects", "project.metadata.name"}, ""))
pattern_ProjectService_Delete_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v1", "projects", "name"}, ""))
pattern_ProjectService_ListEvents_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"api", "v1", "projects", "name", "events"}, ""))
)
var (
forward_ProjectService_CreateToken_0 = runtime.ForwardResponseMessage
forward_ProjectService_DeleteToken_0 = runtime.ForwardResponseMessage
forward_ProjectService_Create_0 = runtime.ForwardResponseMessage
forward_ProjectService_List_0 = runtime.ForwardResponseMessage
@@ -351,4 +563,6 @@ var (
forward_ProjectService_Update_0 = runtime.ForwardResponseMessage
forward_ProjectService_Delete_0 = runtime.ForwardResponseMessage
forward_ProjectService_ListEvents_0 = runtime.ForwardResponseMessage
)

View File

@@ -18,6 +18,27 @@ message ProjectCreateRequest {
github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.AppProject project = 1;
}
// ProjectTokenCreateRequest defines project token deletion parameters.
message ProjectTokenDeleteRequest {
string project = 1;
string role = 2;
int64 iat = 3;
}
// ProjectTokenCreateRequest defines project token creation parameters.
message ProjectTokenCreateRequest {
string project = 1;
string description = 2;
string role = 3;
// expiresIn represents a duration in seconds
int64 expiresIn = 4;
}
// ProjectTokenResponse wraps the created token or returns an empty string if deleted.
message ProjectTokenResponse {
string token = 1;
}
// ProjectQuery is a query for Project resources
message ProjectQuery {
string name = 1;
@@ -32,6 +53,19 @@ message EmptyResponse {}
// ProjectService
service ProjectService {
// Create a new project token.
rpc CreateToken(ProjectTokenCreateRequest) returns (ProjectTokenResponse) {
option (google.api.http) = {
post: "/api/v1/projects/{project}/roles/{role}/token"
body: "*"
};
}
// Delete a new project token.
rpc DeleteToken(ProjectTokenDeleteRequest) returns (EmptyResponse) {
option (google.api.http).delete = "/api/v1/projects/{project}/roles/{role}/token";
}
// Create a new project.
rpc Create(ProjectCreateRequest) returns (github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.AppProject) {
option (google.api.http) = {
@@ -62,4 +96,9 @@ service ProjectService {
rpc Delete(ProjectQuery) returns (EmptyResponse) {
option (google.api.http).delete = "/api/v1/projects/{name}";
}
// ListEvents returns a list of project events
rpc ListEvents(ProjectQuery) returns (k8s.io.api.core.v1.EventList) {
option (google.api.http).get = "/api/v1/projects/{name}/events";
}
}

View File

@@ -2,6 +2,7 @@ package project
import (
"context"
"fmt"
"testing"
"github.com/stretchr/testify/assert"
@@ -15,13 +16,19 @@ import (
apps "github.com/argoproj/argo-cd/pkg/client/clientset/versioned/fake"
"github.com/argoproj/argo-cd/test"
"github.com/argoproj/argo-cd/util"
jwtutil "github.com/argoproj/argo-cd/util/jwt"
"github.com/argoproj/argo-cd/util/rbac"
"github.com/argoproj/argo-cd/util/session"
"github.com/argoproj/argo-cd/util/settings"
)
func TestProjectServer(t *testing.T) {
enforcer := rbac.NewEnforcer(fake.NewSimpleClientset(), "default", common.ArgoCDRBACConfigMapName, nil)
enforcer.SetBuiltinPolicy(test.BuiltinPolicy)
enforcer.SetDefaultRole("role:admin")
enforcer.SetClaimsEnforcerFunc(func(rvals ...interface{}) bool {
return true
})
existingProj := v1alpha1.AppProject{
ObjectMeta: v1.ObjectMeta{Name: "test", Namespace: "default"},
Spec: v1alpha1.AppProjectSpec{
@@ -33,13 +40,15 @@ func TestProjectServer(t *testing.T) {
},
}
policyTemplate := "p, proj:%s:%s, applications, %s, %s/%s, %s"
t.Run("TestRemoveDestinationSuccessful", func(t *testing.T) {
existingApp := v1alpha1.Application{
ObjectMeta: v1.ObjectMeta{Name: "test", Namespace: "default"},
Spec: v1alpha1.ApplicationSpec{Project: "test", Destination: v1alpha1.ApplicationDestination{Namespace: "ns3", Server: "https://server3"}},
}
projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(&existingProj, &existingApp), enforcer, util.NewKeyLock())
projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(&existingProj, &existingApp), enforcer, util.NewKeyLock(), nil)
updatedProj := existingProj.DeepCopy()
updatedProj.Spec.Destinations = updatedProj.Spec.Destinations[1:]
@@ -55,7 +64,7 @@ func TestProjectServer(t *testing.T) {
Spec: v1alpha1.ApplicationSpec{Project: "test", Destination: v1alpha1.ApplicationDestination{Namespace: "ns1", Server: "https://server1"}},
}
projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(&existingProj, &existingApp), enforcer, util.NewKeyLock())
projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(&existingProj, &existingApp), enforcer, util.NewKeyLock(), nil)
updatedProj := existingProj.DeepCopy()
updatedProj.Spec.Destinations = updatedProj.Spec.Destinations[1:]
@@ -72,7 +81,7 @@ func TestProjectServer(t *testing.T) {
Spec: v1alpha1.ApplicationSpec{Project: "test"},
}
projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(&existingProj, &existingApp), enforcer, util.NewKeyLock())
projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(&existingProj, &existingApp), enforcer, util.NewKeyLock(), nil)
updatedProj := existingProj.DeepCopy()
updatedProj.Spec.SourceRepos = []string{}
@@ -88,7 +97,7 @@ func TestProjectServer(t *testing.T) {
Spec: v1alpha1.ApplicationSpec{Project: "test", Source: v1alpha1.ApplicationSource{RepoURL: "https://github.com/argoproj/argo-cd.git"}},
}
projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(&existingProj, &existingApp), enforcer, util.NewKeyLock())
projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(&existingProj, &existingApp), enforcer, util.NewKeyLock(), nil)
updatedProj := existingProj.DeepCopy()
updatedProj.Spec.SourceRepos = []string{}
@@ -100,24 +109,221 @@ func TestProjectServer(t *testing.T) {
})
t.Run("TestDeleteProjectSuccessful", func(t *testing.T) {
projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(&existingProj), enforcer, util.NewKeyLock())
projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(&existingProj), enforcer, util.NewKeyLock(), nil)
_, err := projectServer.Delete(context.Background(), &ProjectQuery{Name: "test"})
assert.Nil(t, err)
})
t.Run("TestDeleteDefaultProjectFailure", func(t *testing.T) {
defaultProj := v1alpha1.AppProject{
ObjectMeta: v1.ObjectMeta{Name: "default", Namespace: "default"},
Spec: v1alpha1.AppProjectSpec{},
}
projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(&defaultProj), enforcer, util.NewKeyLock(), nil)
_, err := projectServer.Delete(context.Background(), &ProjectQuery{Name: defaultProj.Name})
assert.Equal(t, codes.InvalidArgument, grpc.Code(err))
})
t.Run("TestDeleteProjectReferencedByApp", func(t *testing.T) {
existingApp := v1alpha1.Application{
ObjectMeta: v1.ObjectMeta{Name: "test", Namespace: "default"},
Spec: v1alpha1.ApplicationSpec{Project: "test"},
}
projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(&existingProj, &existingApp), enforcer, util.NewKeyLock())
projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(&existingProj, &existingApp), enforcer, util.NewKeyLock(), nil)
_, err := projectServer.Delete(context.Background(), &ProjectQuery{Name: "test"})
assert.NotNil(t, err)
assert.Equal(t, codes.InvalidArgument, grpc.Code(err))
})
t.Run("TestCreateTokenSuccesfully", func(t *testing.T) {
sessionMgr := session.NewSessionManager(&settings.ArgoCDSettings{})
projectWithRole := existingProj.DeepCopy()
tokenName := "testToken"
projectWithRole.Spec.Roles = []v1alpha1.ProjectRole{{Name: tokenName}}
projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(projectWithRole), enforcer, util.NewKeyLock(), sessionMgr)
tokenResponse, err := projectServer.CreateToken(context.Background(), &ProjectTokenCreateRequest{Project: projectWithRole.Name, Role: tokenName, ExpiresIn: 1})
assert.Nil(t, err)
claims, err := sessionMgr.Parse(tokenResponse.Token)
assert.Nil(t, err)
mapClaims, err := jwtutil.MapClaims(claims)
subject, ok := mapClaims["sub"].(string)
assert.True(t, ok)
expectedSubject := fmt.Sprintf(JWTTokenSubFormat, projectWithRole.Name, tokenName)
assert.Equal(t, expectedSubject, subject)
assert.Nil(t, err)
})
t.Run("TestDeleteTokenSuccesfully", func(t *testing.T) {
sessionMgr := session.NewSessionManager(&settings.ArgoCDSettings{})
projWithToken := existingProj.DeepCopy()
tokenName := "testToken"
issuedAt := int64(1)
secondIssuedAt := issuedAt + 1
token := v1alpha1.ProjectRole{Name: tokenName, JWTTokens: []v1alpha1.JWTToken{{IssuedAt: issuedAt}, {IssuedAt: secondIssuedAt}}}
projWithToken.Spec.Roles = append(projWithToken.Spec.Roles, token)
projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(projWithToken), enforcer, util.NewKeyLock(), sessionMgr)
_, err := projectServer.DeleteToken(context.Background(), &ProjectTokenDeleteRequest{Project: projWithToken.Name, Role: tokenName, Iat: issuedAt})
assert.Nil(t, err)
projWithoutToken, err := projectServer.Get(context.Background(), &ProjectQuery{Name: projWithToken.Name})
assert.Nil(t, err)
assert.Len(t, projWithoutToken.Spec.Roles, 1)
assert.Len(t, projWithoutToken.Spec.Roles[0].JWTTokens, 1)
assert.Equal(t, projWithoutToken.Spec.Roles[0].JWTTokens[0].IssuedAt, secondIssuedAt)
})
t.Run("TestCreateTwoTokensInRoleSuccess", func(t *testing.T) {
sessionMgr := session.NewSessionManager(&settings.ArgoCDSettings{})
projWithToken := existingProj.DeepCopy()
tokenName := "testToken"
token := v1alpha1.ProjectRole{Name: tokenName, JWTTokens: []v1alpha1.JWTToken{{IssuedAt: 1}}}
projWithToken.Spec.Roles = append(projWithToken.Spec.Roles, token)
projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(projWithToken), enforcer, util.NewKeyLock(), sessionMgr)
_, err := projectServer.CreateToken(context.Background(), &ProjectTokenCreateRequest{Project: projWithToken.Name, Role: tokenName})
assert.Nil(t, err)
projWithTwoTokens, err := projectServer.Get(context.Background(), &ProjectQuery{Name: projWithToken.Name})
assert.Nil(t, err)
assert.Len(t, projWithTwoTokens.Spec.Roles, 1)
assert.Len(t, projWithTwoTokens.Spec.Roles[0].JWTTokens, 2)
})
t.Run("TestAddWildcardSource", func(t *testing.T) {
proj := existingProj.DeepCopy()
wildSouceRepo := "*"
proj.Spec.SourceRepos = append(proj.Spec.SourceRepos, wildSouceRepo)
projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(proj), enforcer, util.NewKeyLock(), nil)
request := &ProjectUpdateRequest{Project: proj}
updatedProj, err := projectServer.Update(context.Background(), request)
assert.Nil(t, err)
assert.Equal(t, wildSouceRepo, updatedProj.Spec.SourceRepos[1])
})
t.Run("TestCreateRolePolicySuccessfully", func(t *testing.T) {
action := "create"
object := "testApplication"
roleName := "testRole"
effect := "allow"
projWithRole := existingProj.DeepCopy()
role := v1alpha1.ProjectRole{Name: roleName, JWTTokens: []v1alpha1.JWTToken{{IssuedAt: 1}}}
policy := fmt.Sprintf(policyTemplate, projWithRole.Name, roleName, action, projWithRole.Name, object, effect)
role.Policies = append(role.Policies, policy)
projWithRole.Spec.Roles = append(projWithRole.Spec.Roles, role)
projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(projWithRole), enforcer, util.NewKeyLock(), nil)
request := &ProjectUpdateRequest{Project: projWithRole}
_, err := projectServer.Update(context.Background(), request)
assert.Nil(t, err)
t.Log(projWithRole.Spec.Roles[0].Policies[0])
expectedPolicy := fmt.Sprintf(policyTemplate, projWithRole.Name, role.Name, action, projWithRole.Name, object, effect)
assert.Equal(t, projWithRole.Spec.Roles[0].Policies[0], expectedPolicy)
})
t.Run("TestValidatePolicyDuplicatePolicyFailure", func(t *testing.T) {
action := "create"
object := "testApplication"
roleName := "testRole"
effect := "allow"
projWithRole := existingProj.DeepCopy()
role := v1alpha1.ProjectRole{Name: roleName, JWTTokens: []v1alpha1.JWTToken{{IssuedAt: 1}}}
policy := fmt.Sprintf(policyTemplate, projWithRole.Name, roleName, action, projWithRole.Name, object, effect)
role.Policies = append(role.Policies, policy)
role.Policies = append(role.Policies, policy)
projWithRole.Spec.Roles = append(projWithRole.Spec.Roles, role)
projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(projWithRole), enforcer, util.NewKeyLock(), nil)
request := &ProjectUpdateRequest{Project: projWithRole}
_, err := projectServer.Update(context.Background(), request)
expectedErr := fmt.Sprintf("rpc error: code = AlreadyExists desc = policy '%s' already exists for role '%s'", policy, roleName)
assert.EqualError(t, err, expectedErr)
})
t.Run("TestValidateProjectAccessToSeparateProjectObjectFailure", func(t *testing.T) {
action := "create"
object := "testApplication"
roleName := "testRole"
otherProject := "other-project"
effect := "allow"
projWithRole := existingProj.DeepCopy()
role := v1alpha1.ProjectRole{Name: roleName, JWTTokens: []v1alpha1.JWTToken{{IssuedAt: 1}}}
policy := fmt.Sprintf(policyTemplate, projWithRole.Name, roleName, action, otherProject, object, effect)
role.Policies = append(role.Policies, policy)
projWithRole.Spec.Roles = append(projWithRole.Spec.Roles, role)
projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(projWithRole), enforcer, util.NewKeyLock(), nil)
request := &ProjectUpdateRequest{Project: projWithRole}
_, err := projectServer.Update(context.Background(), request)
expectedErr := fmt.Sprintf("rpc error: code = InvalidArgument desc = incorrect policy format for '%s' as policies can't grant access to other projects", policy)
assert.EqualError(t, err, expectedErr)
})
t.Run("TestValidateProjectIncorrectProjectInRoleFailure", func(t *testing.T) {
action := "create"
object := "testApplication"
roleName := "testRole"
otherProject := "other-project"
effect := "allow"
projWithRole := existingProj.DeepCopy()
role := v1alpha1.ProjectRole{Name: roleName, JWTTokens: []v1alpha1.JWTToken{{IssuedAt: 1}}}
invalidPolicy := fmt.Sprintf(policyTemplate, otherProject, roleName, action, projWithRole.Name, object, effect)
role.Policies = append(role.Policies, invalidPolicy)
projWithRole.Spec.Roles = append(projWithRole.Spec.Roles, role)
projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(projWithRole), enforcer, util.NewKeyLock(), nil)
request := &ProjectUpdateRequest{Project: projWithRole}
_, err := projectServer.Update(context.Background(), request)
expectedErr := fmt.Sprintf("rpc error: code = InvalidArgument desc = incorrect policy format for '%s' as policy can't grant access to other projects", invalidPolicy)
assert.EqualError(t, err, expectedErr)
})
t.Run("TestValidateProjectIncorrectTokenInRoleFailure", func(t *testing.T) {
action := "create"
object := "testApplication"
roleName := "testRole"
otherToken := "other-token"
effect := "allow"
projWithRole := existingProj.DeepCopy()
role := v1alpha1.ProjectRole{Name: roleName, JWTTokens: []v1alpha1.JWTToken{{IssuedAt: 1}}}
invalidPolicy := fmt.Sprintf(policyTemplate, projWithRole.Name, otherToken, action, projWithRole.Name, object, effect)
role.Policies = append(role.Policies, invalidPolicy)
projWithRole.Spec.Roles = append(projWithRole.Spec.Roles, role)
projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(projWithRole), enforcer, util.NewKeyLock(), nil)
request := &ProjectUpdateRequest{Project: projWithRole}
_, err := projectServer.Update(context.Background(), request)
expectedErr := fmt.Sprintf("rpc error: code = InvalidArgument desc = incorrect policy format for '%s' as policy can't grant access to other roles", invalidPolicy)
assert.EqualError(t, err, expectedErr)
})
t.Run("TestValidateProjectInvalidEffectFailure", func(t *testing.T) {
action := "create"
object := "testApplication"
roleName := "testRole"
effect := "testEffect"
projWithRole := existingProj.DeepCopy()
role := v1alpha1.ProjectRole{Name: roleName, JWTTokens: []v1alpha1.JWTToken{{IssuedAt: 1}}}
invalidPolicy := fmt.Sprintf(policyTemplate, projWithRole.Name, roleName, action, projWithRole.Name, object, effect)
role.Policies = append(role.Policies, invalidPolicy)
projWithRole.Spec.Roles = append(projWithRole.Spec.Roles, role)
projectServer := NewServer("default", fake.NewSimpleClientset(), apps.NewSimpleClientset(projWithRole), enforcer, util.NewKeyLock(), nil)
request := &ProjectUpdateRequest{Project: projWithRole}
_, err := projectServer.Update(context.Background(), request)
expectedErr := fmt.Sprintf("rpc error: code = InvalidArgument desc = incorrect policy format for '%s' as effect can only have value 'allow' or 'deny'", invalidPolicy)
assert.EqualError(t, err, expectedErr)
})
}

View File

@@ -2,6 +2,7 @@ package repository
import (
"path"
"path/filepath"
"reflect"
"github.com/ghodss/yaml"
@@ -86,6 +87,11 @@ func (s *Server) ListApps(ctx context.Context, q *RepoAppsQuery) (*RepoAppsRespo
return nil, err
}
kustomizationRes, err := repoClient.ListDir(ctx, &repository.ListDirRequest{Repo: repo, Revision: revision, Path: "*kustomization.yaml"})
if err != nil {
return nil, err
}
items := make([]*AppInfo, 0)
for i := range ksonnetRes.Items {
@@ -96,6 +102,10 @@ func (s *Server) ListApps(ctx context.Context, q *RepoAppsQuery) (*RepoAppsRespo
items = append(items, &AppInfo{Type: string(repository.AppSourceHelm), Path: helmRes.Items[i]})
}
for i := range kustomizationRes.Items {
items = append(items, &AppInfo{Type: string(repository.AppSourceKustomize), Path: kustomizationRes.Items[i]})
}
return &RepoAppsResponse{Items: items}, nil
}
@@ -149,22 +159,36 @@ func (s *Server) GetAppDetails(ctx context.Context, q *RepoAppDetailsQuery) (*Re
if err != nil {
return nil, err
}
appDir := path.Dir(q.Path)
valuesFilesRes, err := repoClient.ListDir(ctx, &repository.ListDirRequest{
Revision: revision,
Repo: repo,
Path: path.Join(path.Dir(q.Path), "*values*.yaml"),
Path: path.Join(appDir, "*values*.yaml"),
})
if err != nil {
return nil, err
}
appSpec.ValueFiles = valuesFilesRes.Items
appSpec.ValueFiles = make([]string, len(valuesFilesRes.Items))
for i := range valuesFilesRes.Items {
valueFilePath, err := filepath.Rel(appDir, valuesFilesRes.Items[i])
if err != nil {
return nil, err
}
appSpec.ValueFiles[i] = valueFilePath
}
return &RepoAppDetailsResponse{
Type: string(appSourceType),
Helm: &appSpec,
}, nil
case repository.AppSourceKustomize:
appSpec := KustomizeAppSpec{
Path: q.Path,
}
return &RepoAppDetailsResponse{
Type: string(appSourceType),
Kustomize: &appSpec,
}, nil
}
return nil, status.Errorf(codes.InvalidArgument, "specified application path is not supported")
}

View File

@@ -19,6 +19,7 @@
RepoAppsResponse
KsonnetAppSpec
HelmAppSpec
KustomizeAppSpec
KsonnetEnvironment
KsonnetEnvironmentDestination
RepoQuery
@@ -137,9 +138,10 @@ func (m *RepoAppDetailsQuery) GetPath() string {
// RepoAppDetailsResponse application details
type RepoAppDetailsResponse struct {
Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"`
Ksonnet *KsonnetAppSpec `protobuf:"bytes,2,opt,name=ksonnet" json:"ksonnet,omitempty"`
Helm *HelmAppSpec `protobuf:"bytes,3,opt,name=helm" json:"helm,omitempty"`
Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"`
Ksonnet *KsonnetAppSpec `protobuf:"bytes,2,opt,name=ksonnet" json:"ksonnet,omitempty"`
Helm *HelmAppSpec `protobuf:"bytes,3,opt,name=helm" json:"helm,omitempty"`
Kustomize *KustomizeAppSpec `protobuf:"bytes,4,opt,name=kustomize" json:"kustomize,omitempty"`
}
func (m *RepoAppDetailsResponse) Reset() { *m = RepoAppDetailsResponse{} }
@@ -168,6 +170,13 @@ func (m *RepoAppDetailsResponse) GetHelm() *HelmAppSpec {
return nil
}
func (m *RepoAppDetailsResponse) GetKustomize() *KustomizeAppSpec {
if m != nil {
return m.Kustomize
}
return nil
}
// RepoAppsResponse contains applications of specified repository
type RepoAppsResponse struct {
Items []*AppInfo `protobuf:"bytes,1,rep,name=items" json:"items,omitempty"`
@@ -252,6 +261,23 @@ func (m *HelmAppSpec) GetValueFiles() []string {
return nil
}
// KustomizeAppSpec contains kustomize app name and path in source repo
type KustomizeAppSpec struct {
Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"`
}
func (m *KustomizeAppSpec) Reset() { *m = KustomizeAppSpec{} }
func (m *KustomizeAppSpec) String() string { return proto.CompactTextString(m) }
func (*KustomizeAppSpec) ProtoMessage() {}
func (*KustomizeAppSpec) Descriptor() ([]byte, []int) { return fileDescriptorRepository, []int{7} }
func (m *KustomizeAppSpec) GetPath() string {
if m != nil {
return m.Path
}
return ""
}
type KsonnetEnvironment struct {
// Name is the user defined name of an environment
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
@@ -266,7 +292,7 @@ type KsonnetEnvironment struct {
func (m *KsonnetEnvironment) Reset() { *m = KsonnetEnvironment{} }
func (m *KsonnetEnvironment) String() string { return proto.CompactTextString(m) }
func (*KsonnetEnvironment) ProtoMessage() {}
func (*KsonnetEnvironment) Descriptor() ([]byte, []int) { return fileDescriptorRepository, []int{7} }
func (*KsonnetEnvironment) Descriptor() ([]byte, []int) { return fileDescriptorRepository, []int{8} }
func (m *KsonnetEnvironment) GetName() string {
if m != nil {
@@ -307,7 +333,7 @@ func (m *KsonnetEnvironmentDestination) Reset() { *m = KsonnetEnvironmen
func (m *KsonnetEnvironmentDestination) String() string { return proto.CompactTextString(m) }
func (*KsonnetEnvironmentDestination) ProtoMessage() {}
func (*KsonnetEnvironmentDestination) Descriptor() ([]byte, []int) {
return fileDescriptorRepository, []int{8}
return fileDescriptorRepository, []int{9}
}
func (m *KsonnetEnvironmentDestination) GetServer() string {
@@ -332,7 +358,7 @@ type RepoQuery struct {
func (m *RepoQuery) Reset() { *m = RepoQuery{} }
func (m *RepoQuery) String() string { return proto.CompactTextString(m) }
func (*RepoQuery) ProtoMessage() {}
func (*RepoQuery) Descriptor() ([]byte, []int) { return fileDescriptorRepository, []int{9} }
func (*RepoQuery) Descriptor() ([]byte, []int) { return fileDescriptorRepository, []int{10} }
func (m *RepoQuery) GetRepo() string {
if m != nil {
@@ -347,7 +373,7 @@ type RepoResponse struct {
func (m *RepoResponse) Reset() { *m = RepoResponse{} }
func (m *RepoResponse) String() string { return proto.CompactTextString(m) }
func (*RepoResponse) ProtoMessage() {}
func (*RepoResponse) Descriptor() ([]byte, []int) { return fileDescriptorRepository, []int{10} }
func (*RepoResponse) Descriptor() ([]byte, []int) { return fileDescriptorRepository, []int{11} }
type RepoCreateRequest struct {
Repo *github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Repository `protobuf:"bytes,1,opt,name=repo" json:"repo,omitempty"`
@@ -357,7 +383,7 @@ type RepoCreateRequest struct {
func (m *RepoCreateRequest) Reset() { *m = RepoCreateRequest{} }
func (m *RepoCreateRequest) String() string { return proto.CompactTextString(m) }
func (*RepoCreateRequest) ProtoMessage() {}
func (*RepoCreateRequest) Descriptor() ([]byte, []int) { return fileDescriptorRepository, []int{11} }
func (*RepoCreateRequest) Descriptor() ([]byte, []int) { return fileDescriptorRepository, []int{12} }
func (m *RepoCreateRequest) GetRepo() *github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Repository {
if m != nil {
@@ -380,7 +406,7 @@ type RepoUpdateRequest struct {
func (m *RepoUpdateRequest) Reset() { *m = RepoUpdateRequest{} }
func (m *RepoUpdateRequest) String() string { return proto.CompactTextString(m) }
func (*RepoUpdateRequest) ProtoMessage() {}
func (*RepoUpdateRequest) Descriptor() ([]byte, []int) { return fileDescriptorRepository, []int{12} }
func (*RepoUpdateRequest) Descriptor() ([]byte, []int) { return fileDescriptorRepository, []int{13} }
func (m *RepoUpdateRequest) GetRepo() *github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Repository {
if m != nil {
@@ -397,6 +423,7 @@ func init() {
proto.RegisterType((*RepoAppsResponse)(nil), "repository.RepoAppsResponse")
proto.RegisterType((*KsonnetAppSpec)(nil), "repository.KsonnetAppSpec")
proto.RegisterType((*HelmAppSpec)(nil), "repository.HelmAppSpec")
proto.RegisterType((*KustomizeAppSpec)(nil), "repository.KustomizeAppSpec")
proto.RegisterType((*KsonnetEnvironment)(nil), "repository.KsonnetEnvironment")
proto.RegisterType((*KsonnetEnvironmentDestination)(nil), "repository.KsonnetEnvironmentDestination")
proto.RegisterType((*RepoQuery)(nil), "repository.RepoQuery")
@@ -826,6 +853,16 @@ func (m *RepoAppDetailsResponse) MarshalTo(dAtA []byte) (int, error) {
}
i += n2
}
if m.Kustomize != nil {
dAtA[i] = 0x22
i++
i = encodeVarintRepository(dAtA, i, uint64(m.Kustomize.Size()))
n3, err := m.Kustomize.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
i += n3
}
return i, nil
}
@@ -906,11 +943,11 @@ func (m *KsonnetAppSpec) MarshalTo(dAtA []byte) (int, error) {
dAtA[i] = 0x12
i++
i = encodeVarintRepository(dAtA, i, uint64(v.Size()))
n3, err := v.MarshalTo(dAtA[i:])
n4, err := v.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
i += n3
i += n4
}
}
}
@@ -962,6 +999,30 @@ func (m *HelmAppSpec) MarshalTo(dAtA []byte) (int, error) {
return i, nil
}
func (m *KustomizeAppSpec) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalTo(dAtA)
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *KustomizeAppSpec) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
if len(m.Path) > 0 {
dAtA[i] = 0xa
i++
i = encodeVarintRepository(dAtA, i, uint64(len(m.Path)))
i += copy(dAtA[i:], m.Path)
}
return i, nil
}
func (m *KsonnetEnvironment) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
@@ -999,11 +1060,11 @@ func (m *KsonnetEnvironment) MarshalTo(dAtA []byte) (int, error) {
dAtA[i] = 0x22
i++
i = encodeVarintRepository(dAtA, i, uint64(m.Destination.Size()))
n4, err := m.Destination.MarshalTo(dAtA[i:])
n5, err := m.Destination.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
i += n4
i += n5
}
return i, nil
}
@@ -1099,11 +1160,11 @@ func (m *RepoCreateRequest) MarshalTo(dAtA []byte) (int, error) {
dAtA[i] = 0xa
i++
i = encodeVarintRepository(dAtA, i, uint64(m.Repo.Size()))
n5, err := m.Repo.MarshalTo(dAtA[i:])
n6, err := m.Repo.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
i += n5
i += n6
}
if m.Upsert {
dAtA[i] = 0x10
@@ -1137,11 +1198,11 @@ func (m *RepoUpdateRequest) MarshalTo(dAtA []byte) (int, error) {
dAtA[i] = 0xa
i++
i = encodeVarintRepository(dAtA, i, uint64(m.Repo.Size()))
n6, err := m.Repo.MarshalTo(dAtA[i:])
n7, err := m.Repo.MarshalTo(dAtA[i:])
if err != nil {
return 0, err
}
i += n6
i += n7
}
return i, nil
}
@@ -1216,6 +1277,10 @@ func (m *RepoAppDetailsResponse) Size() (n int) {
l = m.Helm.Size()
n += 1 + l + sovRepository(uint64(l))
}
if m.Kustomize != nil {
l = m.Kustomize.Size()
n += 1 + l + sovRepository(uint64(l))
}
return n
}
@@ -1278,6 +1343,16 @@ func (m *HelmAppSpec) Size() (n int) {
return n
}
func (m *KustomizeAppSpec) Size() (n int) {
var l int
_ = l
l = len(m.Path)
if l > 0 {
n += 1 + l + sovRepository(uint64(l))
}
return n
}
func (m *KsonnetEnvironment) Size() (n int) {
var l int
_ = l
@@ -1843,6 +1918,39 @@ func (m *RepoAppDetailsResponse) Unmarshal(dAtA []byte) error {
return err
}
iNdEx = postIndex
case 4:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Kustomize", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowRepository
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthRepository
}
postIndex := iNdEx + msglen
if postIndex > l {
return io.ErrUnexpectedEOF
}
if m.Kustomize == nil {
m.Kustomize = &KustomizeAppSpec{}
}
if err := m.Kustomize.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipRepository(dAtA[iNdEx:])
@@ -2313,6 +2421,85 @@ func (m *HelmAppSpec) Unmarshal(dAtA []byte) error {
}
return nil
}
func (m *KustomizeAppSpec) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowRepository
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: KustomizeAppSpec: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: KustomizeAppSpec: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Path", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowRepository
}
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 ErrInvalidLengthRepository
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Path = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipRepository(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthRepository
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *KsonnetEnvironment) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
@@ -3014,60 +3201,62 @@ var (
func init() { proto.RegisterFile("server/repository/repository.proto", fileDescriptorRepository) }
var fileDescriptorRepository = []byte{
// 880 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x56, 0x4f, 0x6f, 0x1b, 0x45,
0x14, 0xd7, 0xc6, 0xa9, 0x93, 0x3c, 0xb7, 0x55, 0x3b, 0x2d, 0xc1, 0x2c, 0x8e, 0x1b, 0x0d, 0x07,
0x12, 0xa0, 0xbb, 0x8a, 0xe9, 0x21, 0x2a, 0x42, 0x28, 0x90, 0x50, 0xa2, 0x72, 0x80, 0xad, 0x82,
0x54, 0x0e, 0x54, 0x5b, 0xfb, 0xe1, 0x2c, 0x5e, 0xcf, 0x0c, 0x33, 0xe3, 0x95, 0xac, 0x2a, 0x17,
0x24, 0x22, 0x6e, 0x48, 0x70, 0xe7, 0xce, 0x9d, 0x0f, 0xc1, 0x11, 0x89, 0x2f, 0x80, 0x22, 0x6e,
0x7c, 0x09, 0x34, 0xb3, 0xeb, 0xf5, 0x38, 0x5e, 0x1b, 0x84, 0x22, 0x6e, 0x6f, 0xde, 0xbc, 0x3f,
0xbf, 0xf7, 0x9b, 0xf7, 0xde, 0x2e, 0x50, 0x85, 0x32, 0x43, 0x19, 0x4a, 0x14, 0x5c, 0x25, 0x9a,
0xcb, 0xb1, 0x23, 0x06, 0x42, 0x72, 0xcd, 0x09, 0x4c, 0x35, 0xfe, 0xdd, 0x3e, 0xef, 0x73, 0xab,
0x0e, 0x8d, 0x94, 0x5b, 0xf8, 0xad, 0x3e, 0xe7, 0xfd, 0x14, 0xc3, 0x58, 0x24, 0x61, 0xcc, 0x18,
0xd7, 0xb1, 0x4e, 0x38, 0x53, 0xc5, 0x2d, 0x1d, 0xec, 0xab, 0x20, 0xe1, 0xf6, 0xb6, 0xcb, 0x25,
0x86, 0xd9, 0x5e, 0xd8, 0x47, 0x86, 0x32, 0xd6, 0xd8, 0x2b, 0x6c, 0x8e, 0xfb, 0x89, 0x3e, 0x1d,
0x3d, 0x0f, 0xba, 0x7c, 0x18, 0xc6, 0xd2, 0xa6, 0xf8, 0xca, 0x0a, 0xf7, 0xbb, 0xbd, 0x50, 0x0c,
0xfa, 0xc6, 0x59, 0x85, 0xb1, 0x10, 0x69, 0xd2, 0xb5, 0xc1, 0xc3, 0x6c, 0x2f, 0x4e, 0xc5, 0x69,
0x3c, 0x17, 0x8a, 0xbe, 0x07, 0x37, 0x22, 0x14, 0xfc, 0x40, 0x08, 0xf5, 0xe9, 0x08, 0xe5, 0x98,
0x10, 0x58, 0x35, 0x15, 0x34, 0xbd, 0x6d, 0x6f, 0x67, 0x23, 0xb2, 0x32, 0xf1, 0x61, 0x5d, 0x62,
0x96, 0xa8, 0x84, 0xb3, 0xe6, 0x8a, 0xd5, 0x97, 0x67, 0xba, 0x07, 0x6b, 0x07, 0x42, 0x1c, 0xb3,
0x2f, 0xb9, 0x71, 0xd5, 0x63, 0x81, 0x13, 0x57, 0x23, 0x1b, 0x9d, 0x88, 0xf5, 0x69, 0xe1, 0x66,
0x65, 0xfa, 0x14, 0xee, 0x14, 0x39, 0x0f, 0x51, 0xc7, 0x49, 0xfa, 0xdf, 0x32, 0x97, 0xa1, 0x6b,
0x4e, 0xe8, 0xef, 0x3d, 0xd8, 0x9c, 0x8d, 0x1d, 0xa1, 0x12, 0x9c, 0x29, 0xac, 0x44, 0xf7, 0x00,
0xd6, 0x06, 0x8a, 0x33, 0x86, 0xda, 0x46, 0x6f, 0x74, 0xfc, 0xc0, 0x79, 0xd0, 0xc7, 0xf9, 0xd5,
0x81, 0x10, 0x4f, 0x04, 0x76, 0xa3, 0x89, 0x29, 0x79, 0x13, 0x56, 0x4f, 0x31, 0x1d, 0xda, 0xc4,
0x8d, 0xce, 0xcb, 0xae, 0xcb, 0x47, 0x98, 0x0e, 0x27, 0xf6, 0xd6, 0x88, 0xbe, 0x0b, 0xb7, 0x26,
0x04, 0x97, 0x50, 0x76, 0xe1, 0x5a, 0xa2, 0x71, 0xa8, 0x9a, 0xde, 0x76, 0x6d, 0xa7, 0xd1, 0xb9,
0xe3, 0x46, 0x28, 0xc8, 0x8c, 0x72, 0x0b, 0xfa, 0x97, 0x07, 0x37, 0x67, 0x71, 0x98, 0x42, 0x58,
0x3c, 0x2c, 0x0b, 0x31, 0x72, 0x15, 0xcd, 0xe4, 0x13, 0xb8, 0x8e, 0x2c, 0x4b, 0x24, 0x67, 0x43,
0x64, 0x5a, 0x35, 0x6b, 0x36, 0xd9, 0x5b, 0x8b, 0x2b, 0x0c, 0x8e, 0x1c, 0xf3, 0x23, 0xa6, 0xe5,
0x38, 0x9a, 0x89, 0xe0, 0x3f, 0x83, 0xdb, 0x73, 0x26, 0xe4, 0x16, 0xd4, 0x06, 0x38, 0x2e, 0xd0,
0x18, 0x91, 0x3c, 0x80, 0x6b, 0x59, 0x9c, 0x8e, 0xb0, 0xe0, 0xb4, 0x5d, 0x91, 0xd1, 0x09, 0x13,
0xe5, 0xc6, 0x0f, 0x57, 0xf6, 0x3d, 0x7a, 0x02, 0x0d, 0x87, 0xc1, 0x7f, 0x5d, 0x69, 0x1b, 0xc0,
0xc6, 0xf8, 0x30, 0x49, 0x31, 0xaf, 0x73, 0x23, 0x72, 0x34, 0xf4, 0x67, 0x0f, 0xc8, 0x7c, 0xe2,
0xca, 0xf0, 0x6d, 0x80, 0xc1, 0xbe, 0xfa, 0x0c, 0xa5, 0xd3, 0x72, 0x8e, 0xa6, 0xaa, 0xe9, 0xc8,
0x63, 0x68, 0xf4, 0x50, 0xe9, 0x84, 0xd9, 0x59, 0x6b, 0xae, 0xda, 0xaa, 0x77, 0x97, 0x57, 0x7d,
0x38, 0x75, 0x88, 0x5c, 0x6f, 0x7a, 0x02, 0x5b, 0x4b, 0xad, 0xc9, 0x26, 0xd4, 0xf3, 0x35, 0x54,
0xe0, 0x2e, 0x4e, 0xa4, 0x05, 0x1b, 0xa6, 0x02, 0x25, 0xe2, 0x2e, 0x16, 0xc0, 0xa7, 0x0a, 0x7a,
0x0f, 0x36, 0x4c, 0x1b, 0x2e, 0x9c, 0x34, 0x7a, 0x13, 0xae, 0x1b, 0x83, 0x49, 0x8f, 0xd2, 0x73,
0x0f, 0x6e, 0x1b, 0xc5, 0x07, 0x12, 0x63, 0x8d, 0x11, 0x7e, 0x3d, 0x42, 0xa5, 0xc9, 0x53, 0xc7,
0xb3, 0xd1, 0x39, 0x0a, 0xa6, 0x8b, 0x28, 0x98, 0x2c, 0x22, 0x2b, 0x3c, 0xeb, 0xf6, 0x02, 0x31,
0xe8, 0x07, 0x66, 0x11, 0x05, 0xce, 0x22, 0x0a, 0x26, 0x8b, 0x28, 0x88, 0x4a, 0x76, 0x8a, 0x51,
0xdf, 0x84, 0xfa, 0x48, 0x28, 0x94, 0xf9, 0x28, 0xae, 0x47, 0xc5, 0x89, 0xb2, 0x1c, 0xc7, 0x89,
0xe8, 0xfd, 0x2f, 0x38, 0x3a, 0xbf, 0xac, 0xe5, 0x09, 0x73, 0xe5, 0x13, 0x94, 0x59, 0xd2, 0x45,
0x72, 0xee, 0xc1, 0xea, 0xc7, 0x89, 0xd2, 0xe4, 0x25, 0xf7, 0x5d, 0x4b, 0x4a, 0xfd, 0xe3, 0x2b,
0x81, 0x60, 0x32, 0xd0, 0xd6, 0x37, 0xbf, 0xff, 0xf9, 0xe3, 0xca, 0x26, 0xb9, 0x6b, 0xbf, 0x01,
0xd9, 0xde, 0xf4, 0x1b, 0x93, 0xa0, 0x22, 0x43, 0x58, 0x37, 0x56, 0x66, 0x9f, 0x90, 0x57, 0x2e,
0x63, 0x29, 0xd7, 0xb8, 0xdf, 0xaa, 0xba, 0x2a, 0x1f, 0x77, 0xc7, 0xa6, 0xa0, 0x64, 0xbb, 0x2a,
0x45, 0xf8, 0xc2, 0x9c, 0xce, 0xcc, 0xf7, 0x43, 0x91, 0x6f, 0x3d, 0xb8, 0xf1, 0xc8, 0x6e, 0x88,
0x62, 0x9f, 0x92, 0x7b, 0x15, 0x91, 0xdd, 0x3d, 0xee, 0xd3, 0xc5, 0x06, 0x25, 0x80, 0xd0, 0x02,
0xd8, 0x25, 0xaf, 0xff, 0x13, 0x80, 0xf0, 0x85, 0x19, 0xb1, 0x33, 0xf2, 0x83, 0x07, 0xf5, 0xbc,
0x15, 0xc9, 0xd6, 0xe5, 0xf8, 0x33, 0x2d, 0xea, 0x5f, 0x4d, 0x33, 0x50, 0x6a, 0x11, 0xb6, 0x68,
0xe5, 0x2b, 0x3c, 0xcc, 0x5b, 0xf6, 0x3b, 0x0f, 0x6a, 0x8f, 0x70, 0x61, 0x4f, 0x5c, 0x11, 0x92,
0xd7, 0x2c, 0x92, 0x2d, 0xf2, 0xea, 0x12, 0xae, 0xc8, 0x4f, 0x1e, 0xd4, 0xf3, 0x11, 0x99, 0xe7,
0x67, 0x66, 0x74, 0xae, 0x0a, 0x55, 0x60, 0x51, 0xed, 0xf8, 0x4b, 0x5a, 0xc8, 0xe2, 0x38, 0x2b,
0xb8, 0xfa, 0x02, 0xea, 0x87, 0x98, 0xa2, 0xc6, 0x45, 0x6c, 0x35, 0x2f, 0xab, 0xcb, 0x66, 0x29,
0x08, 0x78, 0x63, 0x19, 0x01, 0xef, 0xbf, 0xf3, 0xeb, 0x45, 0xdb, 0xfb, 0xed, 0xa2, 0xed, 0xfd,
0x71, 0xd1, 0xf6, 0x3e, 0xbf, 0xbf, 0xec, 0x0f, 0x69, 0xee, 0x2f, 0xee, 0x79, 0xdd, 0xfe, 0x0c,
0xbd, 0xfd, 0x77, 0x00, 0x00, 0x00, 0xff, 0xff, 0xed, 0x5f, 0xa2, 0x2b, 0xe1, 0x09, 0x00, 0x00,
// 911 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x56, 0x4f, 0x6f, 0x5b, 0x45,
0x10, 0xd7, 0xc6, 0xa9, 0x13, 0x8f, 0xdb, 0x2a, 0xdd, 0x96, 0x60, 0x1e, 0x8e, 0x1b, 0x2d, 0x12,
0x24, 0x40, 0xdf, 0x53, 0x4c, 0x0f, 0x51, 0x10, 0x42, 0x81, 0x84, 0x12, 0x95, 0x03, 0xbc, 0x2a,
0x48, 0xe5, 0x40, 0xf5, 0x6a, 0x0f, 0xce, 0x62, 0xfb, 0xed, 0xf2, 0x76, 0x6d, 0xc9, 0x54, 0xb9,
0x20, 0x51, 0x71, 0x86, 0x3b, 0x77, 0xee, 0x7c, 0x08, 0x24, 0x2e, 0x48, 0x7c, 0x01, 0x14, 0x71,
0xe3, 0x4b, 0xa0, 0xdd, 0xf7, 0xc7, 0xeb, 0xf8, 0xd9, 0x20, 0x14, 0x71, 0x9b, 0x9d, 0xfd, 0xcd,
0xcc, 0x6f, 0x67, 0x66, 0x67, 0x17, 0x98, 0xc2, 0x64, 0x8c, 0x49, 0x90, 0xa0, 0x14, 0x8a, 0x6b,
0x91, 0x4c, 0x1c, 0xd1, 0x97, 0x89, 0xd0, 0x82, 0xc2, 0x54, 0xe3, 0xdd, 0xe9, 0x89, 0x9e, 0xb0,
0xea, 0xc0, 0x48, 0x29, 0xc2, 0x6b, 0xf6, 0x84, 0xe8, 0x0d, 0x30, 0x88, 0x24, 0x0f, 0xa2, 0x38,
0x16, 0x3a, 0xd2, 0x5c, 0xc4, 0x2a, 0xdb, 0x65, 0xfd, 0x7d, 0xe5, 0x73, 0x61, 0x77, 0x3b, 0x22,
0xc1, 0x60, 0xbc, 0x17, 0xf4, 0x30, 0xc6, 0x24, 0xd2, 0xd8, 0xcd, 0x30, 0x27, 0x3d, 0xae, 0xcf,
0x46, 0x4f, 0xfd, 0x8e, 0x18, 0x06, 0x51, 0x62, 0x43, 0x7c, 0x69, 0x85, 0x7b, 0x9d, 0x6e, 0x20,
0xfb, 0x3d, 0x63, 0xac, 0x82, 0x48, 0xca, 0x01, 0xef, 0x58, 0xe7, 0xc1, 0x78, 0x2f, 0x1a, 0xc8,
0xb3, 0x68, 0xce, 0x15, 0x7b, 0x17, 0x6e, 0x84, 0x28, 0xc5, 0xa1, 0x94, 0xea, 0x93, 0x11, 0x26,
0x13, 0x4a, 0x61, 0xd5, 0x9c, 0xa0, 0x41, 0xb6, 0xc9, 0x4e, 0x2d, 0xb4, 0x32, 0xf5, 0x60, 0x3d,
0xc1, 0x31, 0x57, 0x5c, 0xc4, 0x8d, 0x15, 0xab, 0x2f, 0xd6, 0x6c, 0x0f, 0xd6, 0x0e, 0xa5, 0x3c,
0x89, 0xbf, 0x10, 0xc6, 0x54, 0x4f, 0x24, 0xe6, 0xa6, 0x46, 0x36, 0x3a, 0x19, 0xe9, 0xb3, 0xcc,
0xcc, 0xca, 0xec, 0x31, 0xdc, 0xce, 0x62, 0x1e, 0xa1, 0x8e, 0xf8, 0xe0, 0xbf, 0x45, 0x2e, 0x5c,
0x57, 0x1c, 0xd7, 0xbf, 0x12, 0xd8, 0x9c, 0xf5, 0x1d, 0xa2, 0x92, 0x22, 0x56, 0x58, 0xca, 0xee,
0x3e, 0xac, 0xf5, 0x95, 0x88, 0x63, 0xd4, 0xd6, 0x7b, 0xbd, 0xed, 0xf9, 0x4e, 0x41, 0x1f, 0xa6,
0x5b, 0x87, 0x52, 0x3e, 0x92, 0xd8, 0x09, 0x73, 0x28, 0x7d, 0x03, 0x56, 0xcf, 0x70, 0x30, 0xb4,
0x81, 0xeb, 0xed, 0x17, 0x5d, 0x93, 0x0f, 0x71, 0x30, 0xcc, 0xf1, 0x16, 0x44, 0x0f, 0xa0, 0xd6,
0x1f, 0x29, 0x2d, 0x86, 0xfc, 0x6b, 0x6c, 0xac, 0x5a, 0x8b, 0xe6, 0x4c, 0x90, 0x7c, 0x33, 0x37,
0x9b, 0xc2, 0xd9, 0x3b, 0xb0, 0x91, 0x17, 0xa7, 0x38, 0xc6, 0x2e, 0x5c, 0xe3, 0x1a, 0x87, 0xaa,
0x41, 0xb6, 0x2b, 0x3b, 0xf5, 0xf6, 0x6d, 0xd7, 0x57, 0x56, 0x88, 0x30, 0x45, 0xb0, 0xbf, 0x08,
0xdc, 0x9c, 0x3d, 0x83, 0x49, 0x42, 0x1c, 0x0d, 0x8b, 0x24, 0x18, 0xb9, 0xac, 0x44, 0xf4, 0x63,
0xb8, 0x8e, 0xf1, 0x98, 0x27, 0x22, 0x1e, 0x62, 0xac, 0x55, 0xa3, 0x62, 0x83, 0xbd, 0xb9, 0x38,
0x3b, 0xfe, 0xb1, 0x03, 0x3f, 0x8e, 0x75, 0x32, 0x09, 0x67, 0x3c, 0x78, 0x4f, 0xe0, 0xd6, 0x1c,
0x84, 0x6e, 0x40, 0xa5, 0x8f, 0x93, 0x8c, 0x8d, 0x11, 0xe9, 0x7d, 0xb8, 0x36, 0x8e, 0x06, 0x23,
0xcc, 0xea, 0xd1, 0x2a, 0x89, 0xe8, 0xb8, 0x09, 0x53, 0xf0, 0xc1, 0xca, 0x3e, 0x61, 0xa7, 0x50,
0x77, 0xb2, 0xff, 0xaf, 0x4f, 0xda, 0x02, 0xb0, 0x3e, 0x3e, 0xe0, 0x03, 0x4c, 0xcf, 0x59, 0x0b,
0x1d, 0x0d, 0x7b, 0x15, 0x36, 0x2e, 0x97, 0xa8, 0xf0, 0x43, 0x9c, 0xce, 0xfb, 0x89, 0x00, 0x9d,
0x27, 0x58, 0x4a, 0xa3, 0x05, 0xd0, 0xdf, 0x57, 0x9f, 0x62, 0xe2, 0xb4, 0xb5, 0xa3, 0x29, 0x6b,
0x6c, 0xfa, 0x10, 0xea, 0x5d, 0x54, 0x9a, 0xc7, 0xf6, 0x3e, 0x67, 0x8d, 0xb4, 0xbb, 0x3c, 0x3b,
0x47, 0x53, 0x83, 0xd0, 0xb5, 0x66, 0xa7, 0xb0, 0xb5, 0x14, 0x4d, 0x37, 0xa1, 0x9a, 0x8e, 0xba,
0x8c, 0x77, 0xb6, 0xa2, 0x4d, 0xa8, 0x99, 0x13, 0x28, 0x19, 0x75, 0x30, 0x23, 0x3e, 0x55, 0xb0,
0xbb, 0x50, 0x33, 0xed, 0xba, 0xf0, 0x36, 0xb3, 0x9b, 0x70, 0xdd, 0x00, 0xf2, 0x5e, 0x66, 0xcf,
0x09, 0xdc, 0x32, 0x8a, 0xf7, 0x13, 0x8c, 0x34, 0x86, 0xf8, 0xd5, 0x08, 0x95, 0xa6, 0x8f, 0x1d,
0xcb, 0x7a, 0xfb, 0xd8, 0x9f, 0x0e, 0x3b, 0x3f, 0x1f, 0x76, 0x56, 0x78, 0xd2, 0xe9, 0xfa, 0xb2,
0xdf, 0xf3, 0xcd, 0xb0, 0xf3, 0x9d, 0x61, 0xe7, 0xe7, 0xc3, 0xce, 0x0f, 0x8b, 0xec, 0x64, 0xe3,
0x64, 0x13, 0xaa, 0x23, 0xa9, 0x30, 0x49, 0xaf, 0xfb, 0x7a, 0x98, 0xad, 0x58, 0x9c, 0xf2, 0x38,
0x95, 0xdd, 0xff, 0x85, 0x47, 0xfb, 0xe7, 0xb5, 0x34, 0x60, 0xaa, 0x7c, 0x84, 0xc9, 0x98, 0x77,
0x90, 0x3e, 0x27, 0xb0, 0xfa, 0x11, 0x57, 0x9a, 0xbe, 0xe0, 0xd6, 0xb5, 0x48, 0xa9, 0x77, 0x72,
0x25, 0x14, 0x4c, 0x04, 0xd6, 0xfc, 0xe6, 0xf7, 0x3f, 0x7f, 0x58, 0xd9, 0xa4, 0x77, 0xec, 0x3b,
0x33, 0xde, 0x9b, 0xbe, 0x63, 0x1c, 0x15, 0x1d, 0xc2, 0xba, 0x41, 0x99, 0xb9, 0x43, 0x5f, 0xba,
0xcc, 0xa5, 0x78, 0x2a, 0xbc, 0x66, 0xd9, 0x56, 0x51, 0xdc, 0x1d, 0x1b, 0x82, 0xd1, 0xed, 0xb2,
0x10, 0xc1, 0x33, 0xb3, 0x3a, 0x37, 0x6f, 0x94, 0xa2, 0xdf, 0x12, 0xb8, 0xf1, 0xc0, 0x4e, 0x92,
0x6c, 0x66, 0xd3, 0xbb, 0x25, 0x9e, 0xdd, 0xb7, 0xc2, 0x63, 0x8b, 0x01, 0x05, 0x81, 0xc0, 0x12,
0xd8, 0xa5, 0xaf, 0xfd, 0x13, 0x81, 0xe0, 0x99, 0xb9, 0x62, 0xe7, 0xf4, 0x7b, 0x02, 0xd5, 0xb4,
0x15, 0xe9, 0xd6, 0x65, 0xff, 0x33, 0x2d, 0xea, 0x5d, 0x4d, 0x33, 0x30, 0x66, 0x19, 0x36, 0x59,
0x69, 0x15, 0x0e, 0xd2, 0x96, 0xfd, 0x8e, 0x40, 0xe5, 0x01, 0x2e, 0xec, 0x89, 0x2b, 0x62, 0xf2,
0x8a, 0x65, 0xb2, 0x45, 0x5f, 0x5e, 0x92, 0x2b, 0xfa, 0x23, 0x81, 0x6a, 0x7a, 0x45, 0xe6, 0xf3,
0x33, 0x73, 0x75, 0xae, 0x8a, 0x95, 0x6f, 0x59, 0xed, 0x78, 0x4b, 0x5a, 0xc8, 0xf2, 0x38, 0xcf,
0x72, 0xf5, 0x39, 0x54, 0x8f, 0x70, 0x80, 0x1a, 0x17, 0x65, 0xab, 0x71, 0x59, 0x5d, 0x34, 0x4b,
0x96, 0x80, 0xd7, 0x97, 0x25, 0xe0, 0xbd, 0xb7, 0x7f, 0xb9, 0x68, 0x91, 0xdf, 0x2e, 0x5a, 0xe4,
0x8f, 0x8b, 0x16, 0xf9, 0xec, 0xde, 0xb2, 0x5f, 0xd8, 0xdc, 0x4f, 0xf1, 0x69, 0xd5, 0x7e, 0xb8,
0xde, 0xfa, 0x3b, 0x00, 0x00, 0xff, 0xff, 0xe5, 0x27, 0xab, 0x67, 0x45, 0x0a, 0x00, 0x00,
}

View File

@@ -36,6 +36,7 @@ message RepoAppDetailsResponse {
string type = 1;
KsonnetAppSpec ksonnet = 2;
HelmAppSpec helm = 3;
KustomizeAppSpec kustomize = 4;
}
// RepoAppsResponse contains applications of specified repository
@@ -58,6 +59,11 @@ message HelmAppSpec {
repeated string valueFiles = 3;
}
// KustomizeAppSpec contains kustomize app name and path in source repo
message KustomizeAppSpec {
string path = 1;
}
message KsonnetEnvironment {
// Name is the user defined name of an environment
string name = 1;

View File

@@ -12,6 +12,7 @@ import (
"strings"
"time"
jwt "github.com/dgrijalva/jwt-go"
"github.com/gobuffalo/packr"
golang_proto "github.com/golang/protobuf/proto"
"github.com/grpc-ecosystem/go-grpc-middleware"
@@ -20,12 +21,15 @@ import (
"github.com/grpc-ecosystem/grpc-gateway/runtime"
log "github.com/sirupsen/logrus"
"github.com/soheilhy/cmux"
netCtx "golang.org/x/net/context"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/reflection"
"google.golang.org/grpc/status"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/kubernetes"
@@ -33,6 +37,7 @@ import (
"github.com/argoproj/argo-cd/common"
"github.com/argoproj/argo-cd/errors"
"github.com/argoproj/argo-cd/pkg/apiclient"
"github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
appclientset "github.com/argoproj/argo-cd/pkg/client/clientset/versioned"
"github.com/argoproj/argo-cd/reposerver"
"github.com/argoproj/argo-cd/server/account"
@@ -48,14 +53,16 @@ import (
"github.com/argoproj/argo-cd/util/dex"
dexutil "github.com/argoproj/argo-cd/util/dex"
grpc_util "github.com/argoproj/argo-cd/util/grpc"
"github.com/argoproj/argo-cd/util/healthz"
jsonutil "github.com/argoproj/argo-cd/util/json"
jwtutil "github.com/argoproj/argo-cd/util/jwt"
projectutil "github.com/argoproj/argo-cd/util/project"
"github.com/argoproj/argo-cd/util/rbac"
util_session "github.com/argoproj/argo-cd/util/session"
settings_util "github.com/argoproj/argo-cd/util/settings"
"github.com/argoproj/argo-cd/util/swagger"
tlsutil "github.com/argoproj/argo-cd/util/tls"
"github.com/argoproj/argo-cd/util/webhook"
netCtx "golang.org/x/net/context"
)
var (
@@ -63,6 +70,13 @@ var (
ErrNoSession = status.Errorf(codes.Unauthenticated, "no session information")
)
var noCacheHeaders = map[string]string{
"Expires": time.Unix(0, 0).Format(time.RFC1123),
"Cache-Control": "no-cache, private, max-age=0",
"Pragma": "no-cache",
"X-Accel-Expires": "0",
}
var backoff = wait.Backoff{
Steps: 5,
Duration: 500 * time.Millisecond,
@@ -106,6 +120,23 @@ type ArgoCDServerOpts struct {
RepoClientset reposerver.Clientset
}
// initializeDefaultProject creates the default project if it does not already exist
func initializeDefaultProject(opts ArgoCDServerOpts) error {
defaultProj := &v1alpha1.AppProject{
ObjectMeta: metav1.ObjectMeta{Name: common.DefaultAppProjectName, Namespace: opts.Namespace},
Spec: v1alpha1.AppProjectSpec{
SourceRepos: []string{"*"},
Destinations: []v1alpha1.ApplicationDestination{{Server: "*", Namespace: "*"}},
},
}
_, err := opts.AppClientset.ArgoprojV1alpha1().AppProjects(opts.Namespace).Create(defaultProj)
if apierrors.IsAlreadyExists(err) {
return nil
}
return err
}
// initializeSettings sets default secret settings (password set to hostname)
func initializeSettings(settingsMgr *settings_util.SettingsManager, opts ArgoCDServerOpts) (*settings_util.ArgoCDSettings, error) {
@@ -120,8 +151,11 @@ func initializeSettings(settingsMgr *settings_util.SettingsManager, opts ArgoCDS
// NewServer returns a new instance of the ArgoCD API server
func NewServer(opts ArgoCDServerOpts) *ArgoCDServer {
settingsMgr := settings_util.NewSettingsManager(opts.KubeClientset, opts.Namespace)
settings, err := initializeSettings(settingsMgr, opts)
errors.CheckError(err)
err = initializeDefaultProject(opts)
errors.CheckError(err)
sessionMgr := util_session.NewSessionManager(settings)
enf := rbac.NewEnforcer(opts.KubeClientset, opts.Namespace, common.ArgoCDRBACConfigMapName, nil)
@@ -325,7 +359,7 @@ func (a *ArgoCDServer) newGRPCServer() *grpc.Server {
grpc_util.ErrorCodeUnaryServerInterceptor(),
grpc_util.PanicLoggerUnaryServerInterceptor(a.log),
)))
a.enf.SetClaimsEnforcerFunc(EnforceClaims(a.enf, a.AppClientset, a.Namespace))
grpcS := grpc.NewServer(sOpts...)
db := db.NewDB(a.Namespace, a.KubeClientset)
clusterService := cluster.NewServer(db, a.enf)
@@ -333,7 +367,7 @@ func (a *ArgoCDServer) newGRPCServer() *grpc.Server {
sessionService := session.NewServer(a.sessionMgr)
projectLock := util.NewKeyLock()
applicationService := application.NewServer(a.Namespace, a.KubeClientset, a.AppClientset, a.RepoClientset, db, a.enf, projectLock)
projectService := project.NewServer(a.Namespace, a.KubeClientset, a.AppClientset, a.enf, projectLock)
projectService := project.NewServer(a.Namespace, a.KubeClientset, a.AppClientset, a.enf, projectLock, a.sessionMgr)
settingsService := settings.NewServer(a.settingsMgr)
accountService := account.NewServer(a.sessionMgr, a.settingsMgr)
version.RegisterVersionServiceServer(grpcS, &version.Server{})
@@ -404,6 +438,10 @@ func (a *ArgoCDServer) newHTTPServer(ctx context.Context, port int) *http.Server
mustRegisterGWHandler(project.RegisterProjectServiceHandlerFromEndpoint, ctx, gwmux, endpoint, dOpts)
swagger.ServeSwaggerUI(mux, packr.NewBox("."), "/swagger-ui")
healthz.ServeHealthCheck(mux, func() error {
_, err := a.KubeClientset.(*kubernetes.Clientset).ServerVersion()
return err
})
// Dex reverse proxy and client app and OAuth2 login/callback
a.registerDexHandlers(mux)
@@ -425,6 +463,9 @@ func (a *ArgoCDServer) newHTTPServer(ctx context.Context, port int) *http.Server
// serve index.html for non file requests to support HTML5 History API
if acceptHTML && !fileRequest && (request.Method == "GET" || request.Method == "HEAD") {
for k, v := range noCacheHeaders {
writer.Header().Set(k, v)
}
http.ServeFile(writer, request, a.StaticAssetsDir+"/index.html")
} else {
http.ServeFile(writer, request, a.StaticAssetsDir+request.URL.Path)
@@ -583,3 +624,71 @@ func bug21955WorkaroundInterceptor(ctx context.Context, req interface{}, _ *grpc
}
return handler(ctx, req)
}
func EnforceClaims(enf *rbac.Enforcer, a appclientset.Interface, namespace string) func(rvals ...interface{}) bool {
return func(rvals ...interface{}) bool {
claims, ok := rvals[0].(jwt.Claims)
if !ok {
if rvals[0] == nil {
vals := append([]interface{}{""}, rvals[1:]...)
return enf.Enforce(vals...)
}
return enf.Enforce(rvals...)
}
mapClaims, err := jwtutil.MapClaims(claims)
if err != nil {
vals := append([]interface{}{""}, rvals[1:]...)
return enf.Enforce(vals...)
}
groups := jwtutil.GetGroups(mapClaims)
for _, group := range groups {
vals := append([]interface{}{group}, rvals[1:]...)
if enf.Enforcer.Enforce(vals...) {
return true
}
}
user := jwtutil.GetField(mapClaims, "sub")
if strings.HasPrefix(user, "proj:") {
return enforceProjectToken(enf, a, namespace, user, mapClaims, rvals...)
}
vals := append([]interface{}{user}, rvals[1:]...)
return enf.Enforce(vals...)
}
}
func enforceProjectToken(enf *rbac.Enforcer, a appclientset.Interface, namespace string, user string, claims jwt.MapClaims, rvals ...interface{}) bool {
userSplit := strings.Split(user, ":")
if len(userSplit) != 3 {
return false
}
projName := userSplit[1]
tokenName := userSplit[2]
proj, err := a.ArgoprojV1alpha1().AppProjects(namespace).Get(projName, metav1.GetOptions{})
if err != nil {
return false
}
index, err := projectutil.GetRoleIndexByName(proj, tokenName)
if err != nil {
return false
}
if proj.Spec.Roles[index].JWTTokens == nil {
return false
}
iatField, ok := claims["iat"]
if !ok {
return false
}
iatFloat, ok := iatField.(float64)
if !ok {
return false
}
iat := int64(iatFloat)
_, err = projectutil.GetJWTTokenIndexByIssuedAt(proj, index, iat)
if err != nil {
return false
}
vals := append([]interface{}{user}, rvals[1:]...)
return enf.EnforceCustomPolicy(proj.ProjectPoliciesString(), vals...)
}

240
server/server_test.go Normal file
View File

@@ -0,0 +1,240 @@
package server
import (
"fmt"
"testing"
jwt "github.com/dgrijalva/jwt-go"
log "github.com/sirupsen/logrus"
"github.com/stretchr/testify/assert"
apiv1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes/fake"
"github.com/argoproj/argo-cd/common"
"github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
apps "github.com/argoproj/argo-cd/pkg/client/clientset/versioned/fake"
"github.com/argoproj/argo-cd/util/rbac"
)
const (
fakeNamespace = "fake-ns"
builtinPolicyFile = "builtin-policy.csv"
)
func fakeConfigMap() *apiv1.ConfigMap {
cm := apiv1.ConfigMap{
TypeMeta: v1.TypeMeta{
Kind: "ConfigMap",
APIVersion: "v1",
},
ObjectMeta: v1.ObjectMeta{
Name: common.ArgoCDConfigMapName,
Namespace: fakeNamespace,
},
Data: make(map[string]string),
}
return &cm
}
func fakeSecret(policy ...string) *apiv1.Secret {
secret := apiv1.Secret{
TypeMeta: v1.TypeMeta{
Kind: "Secret",
APIVersion: "v1",
},
ObjectMeta: v1.ObjectMeta{
Name: common.ArgoCDSecretName,
Namespace: fakeNamespace,
},
Data: make(map[string][]byte),
}
return &secret
}
func TestEnforceProjectToken(t *testing.T) {
projectName := "testProj"
roleName := "testRole"
subFormat := "proj:%s:%s"
policyTemplate := "p, %s, applications, get, %s/%s, %s"
defaultObject := "*"
defaultEffect := "allow"
defaultTestObject := fmt.Sprintf("%s/%s", projectName, "test")
defaultIssuedAt := int64(1)
defaultSub := fmt.Sprintf(subFormat, projectName, roleName)
defaultPolicy := fmt.Sprintf(policyTemplate, defaultSub, projectName, defaultObject, defaultEffect)
role := v1alpha1.ProjectRole{Name: roleName, Policies: []string{defaultPolicy}, JWTTokens: []v1alpha1.JWTToken{{IssuedAt: defaultIssuedAt}}}
existingProj := v1alpha1.AppProject{
ObjectMeta: v1.ObjectMeta{Name: projectName, Namespace: fakeNamespace},
Spec: v1alpha1.AppProjectSpec{
Roles: []v1alpha1.ProjectRole{role},
},
}
cm := fakeConfigMap()
secret := fakeSecret()
kubeclientset := fake.NewSimpleClientset(cm, secret)
t.Run("TestEnforceProjectTokenSuccessful", func(t *testing.T) {
s := NewServer(ArgoCDServerOpts{Namespace: fakeNamespace, KubeClientset: kubeclientset, AppClientset: apps.NewSimpleClientset(&existingProj)})
s.newGRPCServer()
claims := jwt.MapClaims{"sub": defaultSub, "iat": defaultIssuedAt}
assert.True(t, s.enf.EnforceClaims(claims, "applications", "get", defaultTestObject))
})
t.Run("TestEnforceProjectTokenWithDiffCreateAtFailure", func(t *testing.T) {
s := NewServer(ArgoCDServerOpts{Namespace: fakeNamespace, KubeClientset: kubeclientset, AppClientset: apps.NewSimpleClientset(&existingProj)})
s.newGRPCServer()
diffCreateAt := defaultIssuedAt + 1
claims := jwt.MapClaims{"sub": defaultSub, "iat": diffCreateAt}
assert.False(t, s.enf.EnforceClaims(claims, "applications", "get", defaultTestObject))
})
t.Run("TestEnforceProjectTokenIncorrectSubFormatFailure", func(t *testing.T) {
s := NewServer(ArgoCDServerOpts{Namespace: fakeNamespace, KubeClientset: kubeclientset, AppClientset: apps.NewSimpleClientset(&existingProj)})
s.newGRPCServer()
invalidSub := "proj:test"
claims := jwt.MapClaims{"sub": invalidSub, "iat": defaultIssuedAt}
assert.False(t, s.enf.EnforceClaims(claims, "applications", "get", defaultTestObject))
})
t.Run("TestEnforceProjectTokenNoTokenFailure", func(t *testing.T) {
s := NewServer(ArgoCDServerOpts{Namespace: fakeNamespace, KubeClientset: kubeclientset, AppClientset: apps.NewSimpleClientset(&existingProj)})
s.newGRPCServer()
nonExistentToken := "fake-token"
invalidSub := fmt.Sprintf(subFormat, projectName, nonExistentToken)
claims := jwt.MapClaims{"sub": invalidSub, "iat": defaultIssuedAt}
assert.False(t, s.enf.EnforceClaims(claims, "applications", "get", defaultTestObject))
})
t.Run("TestEnforceProjectTokenNotJWTTokenFailure", func(t *testing.T) {
proj := existingProj.DeepCopy()
proj.Spec.Roles[0].JWTTokens = nil
s := NewServer(ArgoCDServerOpts{Namespace: fakeNamespace, KubeClientset: kubeclientset, AppClientset: apps.NewSimpleClientset(proj)})
s.newGRPCServer()
claims := jwt.MapClaims{"sub": defaultSub, "iat": defaultIssuedAt}
assert.False(t, s.enf.EnforceClaims(claims, "applications", "get", defaultTestObject))
})
t.Run("TestEnforceProjectTokenExplicitDeny", func(t *testing.T) {
denyApp := "testDenyApp"
allowPolicy := fmt.Sprintf(policyTemplate, defaultSub, projectName, defaultObject, defaultEffect)
denyPolicy := fmt.Sprintf(policyTemplate, defaultSub, projectName, denyApp, "deny")
role := v1alpha1.ProjectRole{Name: roleName, Policies: []string{allowPolicy, denyPolicy}, JWTTokens: []v1alpha1.JWTToken{{IssuedAt: defaultIssuedAt}}}
proj := existingProj.DeepCopy()
proj.Spec.Roles[0] = role
s := NewServer(ArgoCDServerOpts{Namespace: fakeNamespace, KubeClientset: kubeclientset, AppClientset: apps.NewSimpleClientset(proj)})
s.newGRPCServer()
claims := jwt.MapClaims{"sub": defaultSub, "iat": defaultIssuedAt}
allowedObject := fmt.Sprintf("%s/%s", projectName, "test")
denyObject := fmt.Sprintf("%s/%s", projectName, denyApp)
assert.True(t, s.enf.EnforceClaims(claims, "applications", "get", allowedObject))
assert.False(t, s.enf.EnforceClaims(claims, "applications", "get", denyObject))
})
}
func TestEnforceClaims(t *testing.T) {
kubeclientset := fake.NewSimpleClientset(fakeConfigMap())
enf := rbac.NewEnforcer(kubeclientset, fakeNamespace, common.ArgoCDConfigMapName, nil)
enf.SetBuiltinPolicy(box.String(builtinPolicyFile))
enf.SetClaimsEnforcerFunc(EnforceClaims(enf, nil, fakeNamespace))
policy := `
g, org2:team2, role:admin
g, bob, role:admin
`
enf.SetUserPolicy(policy)
allowed := []jwt.Claims{
jwt.MapClaims{"groups": []string{"org1:team1", "org2:team2"}},
jwt.StandardClaims{Subject: "admin"},
}
for _, c := range allowed {
if !assert.True(t, enf.EnforceClaims(c, "applications", "delete", "foo/obj")) {
log.Errorf("%v: expected true, got false", c)
}
}
disallowed := []jwt.Claims{
jwt.MapClaims{"groups": []string{"org3:team3"}},
jwt.StandardClaims{Subject: "nobody"},
}
for _, c := range disallowed {
if !assert.False(t, enf.EnforceClaims(c, "applications", "delete", "foo/obj")) {
log.Errorf("%v: expected true, got false", c)
}
}
}
func TestDefaultRoleWithClaims(t *testing.T) {
kubeclientset := fake.NewSimpleClientset()
enf := rbac.NewEnforcer(kubeclientset, fakeNamespace, common.ArgoCDConfigMapName, nil)
enf.SetBuiltinPolicy(box.String(builtinPolicyFile))
enf.SetClaimsEnforcerFunc(EnforceClaims(enf, nil, fakeNamespace))
claims := jwt.MapClaims{"groups": []string{"org1:team1", "org2:team2"}}
assert.False(t, enf.EnforceClaims(claims, "applications", "get", "foo/bar"))
// after setting the default role to be the read-only role, this should now pass
enf.SetDefaultRole("role:readonly")
assert.True(t, enf.EnforceClaims(claims, "applications", "get", "foo/bar"))
}
func TestEnforceNilClaims(t *testing.T) {
kubeclientset := fake.NewSimpleClientset(fakeConfigMap())
enf := rbac.NewEnforcer(kubeclientset, fakeNamespace, common.ArgoCDConfigMapName, nil)
enf.SetBuiltinPolicy(box.String(builtinPolicyFile))
enf.SetClaimsEnforcerFunc(EnforceClaims(enf, nil, fakeNamespace))
assert.False(t, enf.EnforceClaims(nil, "applications", "get", "foo/obj"))
enf.SetDefaultRole("role:readonly")
assert.True(t, enf.EnforceClaims(nil, "applications", "get", "foo/obj"))
}
func TestInitializingExistingDefaultProject(t *testing.T) {
cm := fakeConfigMap()
secret := fakeSecret()
kubeclientset := fake.NewSimpleClientset(cm, secret)
defaultProj := &v1alpha1.AppProject{
ObjectMeta: v1.ObjectMeta{Name: common.DefaultAppProjectName, Namespace: fakeNamespace},
Spec: v1alpha1.AppProjectSpec{},
}
appClientSet := apps.NewSimpleClientset(defaultProj)
argoCDOpts := ArgoCDServerOpts{
Namespace: fakeNamespace,
KubeClientset: kubeclientset,
AppClientset: appClientSet,
}
argocd := NewServer(argoCDOpts)
assert.NotNil(t, argocd)
proj, err := appClientSet.ArgoprojV1alpha1().AppProjects(fakeNamespace).Get(common.DefaultAppProjectName, v1.GetOptions{})
assert.Nil(t, err)
assert.NotNil(t, proj)
assert.Equal(t, proj.Name, common.DefaultAppProjectName)
}
func TestInitializingNotExistingDefaultProject(t *testing.T) {
cm := fakeConfigMap()
secret := fakeSecret()
kubeclientset := fake.NewSimpleClientset(cm, secret)
appClientSet := apps.NewSimpleClientset()
argoCDOpts := ArgoCDServerOpts{
Namespace: fakeNamespace,
KubeClientset: kubeclientset,
AppClientset: appClientSet,
}
argocd := NewServer(argoCDOpts)
assert.NotNil(t, argocd)
proj, err := appClientSet.ArgoprojV1alpha1().AppProjects(fakeNamespace).Get(common.DefaultAppProjectName, v1.GetOptions{})
assert.Nil(t, err)
assert.NotNil(t, proj)
assert.Equal(t, proj.Name, common.DefaultAppProjectName)
}

View File

@@ -34,11 +34,11 @@ func (s *Server) Create(ctx context.Context, q *SessionCreateRequest) (*SessionR
if err != nil {
return nil, err
}
tokenString, err := s.mgr.Create(q.Username, 0)
jwtToken, err := s.mgr.Create(q.Username, 0)
if err != nil {
return nil, err
}
return &SessionResponse{Token: tokenString}, nil
return &SessionResponse{Token: jwtToken}, nil
}
// Delete an authentication cookie from the client. This makes sense only for the Web client.

View File

@@ -291,37 +291,6 @@
}
}
},
"/api/v1/applications/{name}/pods/{podName}": {
"delete": {
"tags": [
"ApplicationService"
],
"summary": "DeletePod returns stream of log entries for the specified pod. Pod",
"operationId": "DeletePod",
"parameters": [
{
"type": "string",
"name": "name",
"in": "path",
"required": true
},
{
"type": "string",
"name": "podName",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "(empty)",
"schema": {
"$ref": "#/definitions/applicationApplicationResponse"
}
}
}
}
},
"/api/v1/applications/{name}/pods/{podName}/logs": {
"get": {
"tags": [
@@ -390,6 +359,31 @@
}
}
},
"/api/v1/applications/{name}/resource": {
"delete": {
"tags": [
"ApplicationService"
],
"summary": "DeleteResource deletes a single application resource",
"operationId": "DeleteResource",
"parameters": [
{
"type": "string",
"name": "name",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "(empty)",
"schema": {
"$ref": "#/definitions/applicationApplicationResponse"
}
}
}
}
},
"/api/v1/applications/{name}/rollback": {
"post": {
"tags": [
@@ -538,6 +532,33 @@
}
}
},
"/api/v1/clusters-kubeconfig": {
"post": {
"tags": [
"ClusterService"
],
"summary": "CreateFromKubeConfig installs the argocd-manager service account into the cluster specified in the given kubeconfig and context",
"operationId": "CreateFromKubeConfig",
"parameters": [
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/clusterClusterCreateFromKubeConfigRequest"
}
}
],
"responses": {
"200": {
"description": "(empty)",
"schema": {
"$ref": "#/definitions/v1alpha1Cluster"
}
}
}
}
},
"/api/v1/clusters/{cluster.server}": {
"put": {
"tags": [
@@ -716,6 +737,31 @@
}
}
},
"/api/v1/projects/{name}/events": {
"get": {
"tags": [
"ProjectService"
],
"summary": "ListEvents returns a list of project events",
"operationId": "ListEvents",
"parameters": [
{
"type": "string",
"name": "name",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "(empty)",
"schema": {
"$ref": "#/definitions/v1EventList"
}
}
}
}
},
"/api/v1/projects/{project.metadata.name}": {
"put": {
"tags": [
@@ -749,6 +795,74 @@
}
}
},
"/api/v1/projects/{project}/roles/{role}/token": {
"post": {
"tags": [
"ProjectService"
],
"summary": "Create a new project token.",
"operationId": "CreateToken",
"parameters": [
{
"type": "string",
"name": "project",
"in": "path",
"required": true
},
{
"type": "string",
"name": "role",
"in": "path",
"required": true
},
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/projectProjectTokenCreateRequest"
}
}
],
"responses": {
"200": {
"description": "(empty)",
"schema": {
"$ref": "#/definitions/projectProjectTokenResponse"
}
}
}
},
"delete": {
"tags": [
"ProjectService"
],
"summary": "Delete a new project token.",
"operationId": "DeleteToken",
"parameters": [
{
"type": "string",
"name": "project",
"in": "path",
"required": true
},
{
"type": "string",
"name": "role",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "(empty)",
"schema": {
"$ref": "#/definitions/projectEmptyResponse"
}
}
}
}
},
"/api/v1/repositories": {
"get": {
"tags": [
@@ -1216,6 +1330,25 @@
"applicationOperationTerminateResponse": {
"type": "object"
},
"clusterClusterCreateFromKubeConfigRequest": {
"type": "object",
"properties": {
"context": {
"type": "string"
},
"inCluster": {
"type": "boolean",
"format": "boolean"
},
"kubeconfig": {
"type": "string"
},
"upsert": {
"type": "boolean",
"format": "boolean"
}
}
},
"clusterClusterResponse": {
"type": "object"
},
@@ -1264,6 +1397,35 @@
}
}
},
"projectProjectTokenCreateRequest": {
"description": "ProjectTokenCreateRequest defines project token creation parameters.",
"type": "object",
"properties": {
"description": {
"type": "string"
},
"expiresIn": {
"type": "string",
"format": "int64",
"title": "expiresIn represents a duration in seconds"
},
"project": {
"type": "string"
},
"role": {
"type": "string"
}
}
},
"projectProjectTokenResponse": {
"description": "ProjectTokenResponse wraps the created token or returns an empty string if deleted.",
"type": "object",
"properties": {
"token": {
"type": "string"
}
}
},
"projectProjectUpdateRequest": {
"type": "object",
"properties": {
@@ -1353,6 +1515,15 @@
}
}
},
"repositoryKustomizeAppSpec": {
"type": "object",
"title": "KustomizeAppSpec contains kustomize app name and path in source repo",
"properties": {
"path": {
"type": "string"
}
}
},
"repositoryManifestResponse": {
"type": "object",
"properties": {
@@ -1389,6 +1560,9 @@
"ksonnet": {
"$ref": "#/definitions/repositoryKsonnetAppSpec"
},
"kustomize": {
"$ref": "#/definitions/repositoryKustomizeAppSpec"
},
"type": {
"type": "string"
}
@@ -1805,6 +1979,12 @@
"$ref": "#/definitions/v1alpha1ApplicationDestination"
}
},
"roles": {
"type": "array",
"items": {
"$ref": "#/definitions/v1alpha1ProjectRole"
}
},
"sourceRepos": {
"type": "array",
"title": "SourceRepos contains list of git repository URLs which can be used for deployment",
@@ -2147,6 +2327,20 @@
}
}
},
"v1alpha1JWTToken": {
"type": "object",
"title": "JWTToken holds the issuedAt and expiresAt values of a token",
"properties": {
"exp": {
"type": "string",
"format": "int64"
},
"iat": {
"type": "string",
"format": "int64"
}
}
},
"v1alpha1Operation": {
"description": "Operation contains requested operation parameters.",
"type": "object",
@@ -2188,6 +2382,31 @@
}
}
},
"v1alpha1ProjectRole": {
"type": "object",
"title": "ProjectRole represents a role that has access to a project",
"properties": {
"description": {
"type": "string"
},
"jwtTokens": {
"type": "array",
"items": {
"$ref": "#/definitions/v1alpha1JWTToken"
}
},
"name": {
"type": "string"
},
"policies": {
"description": "Policies Stores a list of casbin formated strings that define access policies for the role in the project.",
"type": "array",
"items": {
"type": "string"
}
}
}
},
"v1alpha1Repository": {
"type": "object",
"title": "Repository is a Git repository holding application configurations",

View File

@@ -5,17 +5,16 @@ import (
"testing"
"time"
"github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
"github.com/stretchr/testify/assert"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields"
// load the gcp plugin (required to authenticate against GKE clusters).
_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
"github.com/argoproj/argo-cd/util/argo"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/fields"
_ "k8s.io/client-go/plugin/pkg/client/auth/oidc"
"github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
"github.com/argoproj/argo-cd/util/argo"
)
func TestAppManagement(t *testing.T) {

View File

@@ -27,6 +27,7 @@ import (
"github.com/argoproj/argo-cd/cmd/argocd/commands"
"github.com/argoproj/argo-cd/common"
"github.com/argoproj/argo-cd/controller"
"github.com/argoproj/argo-cd/errors"
argocdclient "github.com/argoproj/argo-cd/pkg/apiclient"
"github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
appclientset "github.com/argoproj/argo-cd/pkg/client/clientset/versioned"
@@ -189,7 +190,10 @@ func (f *Fixture) ensureClusterRegistered() error {
return err
}
// Install RBAC resources for managing the cluster
managerBearerToken := common.InstallClusterManagerRBAC(conf)
clientset, err := kubernetes.NewForConfig(conf)
errors.CheckError(err)
managerBearerToken, err := common.InstallClusterManagerRBAC(clientset)
errors.CheckError(err)
clst := commands.NewCluster(f.Config.Host, conf, managerBearerToken)
clstCreateReq := cluster.ClusterCreateRequest{Cluster: clst}
_, err = cluster.NewServer(f.DB, f.Enforcer).Create(context.Background(), &clstCreateReq)
@@ -255,6 +259,7 @@ func NewFixture() (*Fixture, error) {
}
db := db.NewDB(namespace, kubeClient)
enforcer := rbac.NewEnforcer(kubeClient, namespace, common.ArgoCDRBACConfigMapName, nil)
enforcer.SetClaimsEnforcerFunc(server.EnforceClaims(enforcer, appClient, namespace))
err = enforcer.SetBuiltinPolicy(test.BuiltinPolicy)
if err != nil {
return nil, err

View File

@@ -6,12 +6,13 @@ import (
"testing"
"time"
"github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
"github.com/argoproj/argo-cd/util/argo"
"github.com/stretchr/testify/assert"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields"
"github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
"github.com/argoproj/argo-cd/util/argo"
)
func TestProjectManagement(t *testing.T) {
@@ -42,9 +43,7 @@ func TestProjectManagement(t *testing.T) {
"-d", "https://192.168.99.100:8443,default",
"-d", "https://192.168.99.100:8443,service",
"-s", "https://github.com/argoproj/argo-cd.git")
if err != nil {
t.Fatalf("Unable to create project %v", err)
}
assert.Nil(t, err)
proj, err := fixture.AppClient.ArgoprojV1alpha1().AppProjects(fixture.Namespace).Get(projectName, metav1.GetOptions{})
if err != nil {
@@ -202,8 +201,7 @@ func TestProjectManagement(t *testing.T) {
}
_, err = fixture.RunCli("proj", "add-source", projectName, "https://github.com/argoproj/argo-cd.git")
assert.NotNil(t, err)
assert.True(t, strings.Contains(err.Error(), "already defined"))
assert.Nil(t, err)
proj, err := fixture.AppClient.ArgoprojV1alpha1().AppProjects(fixture.Namespace).Get(projectName, metav1.GetOptions{})
if err != nil {
@@ -235,8 +233,7 @@ func TestProjectManagement(t *testing.T) {
}
_, err = fixture.RunCli("proj", "remove-source", projectName, "https://github.com/argoproj/argo-cd.git")
assert.NotNil(t, err)
assert.True(t, strings.Contains(err.Error(), "does not exist"))
assert.Nil(t, err)
proj, err := fixture.AppClient.ArgoprojV1alpha1().AppProjects(fixture.Namespace).Get(projectName, metav1.GetOptions{})
if err != nil {
@@ -246,4 +243,40 @@ func TestProjectManagement(t *testing.T) {
assert.Equal(t, 0, len(proj.Spec.SourceRepos))
assertProjHasEvent(proj, "update", argo.EventReasonResourceUpdated)
})
t.Run("TestUseJWTToken", func(t *testing.T) {
projectName := "proj-" + strconv.FormatInt(time.Now().Unix(), 10)
appName := "app-" + strconv.FormatInt(time.Now().Unix(), 10)
roleName := "roleTest"
testApp := &v1alpha1.Application{
ObjectMeta: metav1.ObjectMeta{
Name: appName,
},
Spec: v1alpha1.ApplicationSpec{
Source: v1alpha1.ApplicationSource{
RepoURL: "https://github.com/argoproj/argo-cd.git", Path: ".", Environment: "minikube",
},
Destination: v1alpha1.ApplicationDestination{
Server: fixture.Config.Host,
Namespace: fixture.Namespace,
},
Project: projectName,
},
}
_, err := fixture.AppClient.ArgoprojV1alpha1().AppProjects(fixture.Namespace).Create(&v1alpha1.AppProject{ObjectMeta: metav1.ObjectMeta{Name: projectName}})
assert.Nil(t, err)
_, err = fixture.AppClient.ArgoprojV1alpha1().Applications(fixture.Namespace).Create(testApp)
assert.Nil(t, err)
_, err = fixture.RunCli("proj", "role", "create", projectName, roleName)
assert.Nil(t, err)
_, err = fixture.RunCli("proj", "role", "create-token", projectName, roleName)
assert.Nil(t, err)
_, err = fixture.RunCli("proj", "role", "add-policy", projectName, roleName, "-a", "get", "-o", "*", "-p", "allow")
assert.Nil(t, err)
})
}

View File

@@ -232,8 +232,8 @@ func GetSpecErrors(
if len(helmConditions) > 0 {
conditions = append(conditions, helmConditions...)
}
case repository.AppSourceDirectory:
maniDirConditions := verifyManifestDirectory(ctx, repoRes, spec, repoClient)
case repository.AppSourceDirectory, repository.AppSourceKustomize:
maniDirConditions := verifyGenerateManifests(ctx, repoRes, spec, repoClient)
if len(maniDirConditions) > 0 {
conditions = append(conditions, maniDirConditions...)
}
@@ -276,16 +276,12 @@ func GetSpecErrors(
return conditions, nil
}
// GetAppProject returns a project from an application
func GetAppProject(spec *argoappv1.ApplicationSpec, appclientset appclientset.Interface, ns string) (*argoappv1.AppProject, error) {
var proj *argoappv1.AppProject
var err error
if spec.BelongsToDefaultProject() {
defaultProj := argoappv1.GetDefaultProject(ns)
proj = &defaultProj
} else {
proj, err = appclientset.ArgoprojV1alpha1().AppProjects(ns).Get(spec.Project, metav1.GetOptions{})
return appclientset.ArgoprojV1alpha1().AppProjects(ns).Get(common.DefaultAppProjectName, metav1.GetOptions{})
}
return proj, err
return appclientset.ArgoprojV1alpha1().AppProjects(ns).Get(spec.Project, metav1.GetOptions{})
}
// queryAppSourceType queries repo server for yaml files in a directory, and determines its
@@ -317,6 +313,9 @@ func queryAppSourceType(ctx context.Context, spec *argoappv1.ApplicationSpec, re
if trimmedPath == "Chart.yaml" {
return repository.AppSourceHelm, nil
}
if trimmedPath == "kustomization.yaml" {
return repository.AppSourceKustomize, nil
}
}
return repository.AppSourceDirectory, nil
}
@@ -410,8 +409,8 @@ func verifyHelmChart(ctx context.Context, repoRes *argoappv1.Repository, spec *a
return conditions
}
// verifyManifestDirectory verifies a repo path contains at least one valid k8s manifest
func verifyManifestDirectory(ctx context.Context, repoRes *argoappv1.Repository, spec *argoappv1.ApplicationSpec, repoClient repository.RepositoryServiceClient) []argoappv1.ApplicationCondition {
// verifyGenerateManifests verifies a repo path can generate manifests
func verifyGenerateManifests(ctx context.Context, repoRes *argoappv1.Repository, spec *argoappv1.ApplicationSpec, repoClient repository.RepositoryServiceClient) []argoappv1.ApplicationCondition {
var conditions []argoappv1.ApplicationCondition
if spec.Destination.Server == "" || spec.Destination.Namespace == "" {
conditions = append(conditions, argoappv1.ApplicationCondition{
@@ -423,8 +422,9 @@ func verifyManifestDirectory(ctx context.Context, repoRes *argoappv1.Repository,
Repo: &argoappv1.Repository{
Repo: spec.Source.RepoURL,
},
Revision: spec.Source.TargetRevision,
Path: spec.Source.Path,
Revision: spec.Source.TargetRevision,
Path: spec.Source.Path,
Namespace: spec.Destination.Namespace,
}
if repoRes != nil {
req.Repo.Username = repoRes.Username
@@ -435,7 +435,7 @@ func verifyManifestDirectory(ctx context.Context, repoRes *argoappv1.Repository,
if err != nil {
conditions = append(conditions, argoappv1.ApplicationCondition{
Type: argoappv1.ApplicationConditionInvalidSpecError,
Message: fmt.Sprintf("Unable to get manifests in %s: %v", spec.Source.Path, err),
Message: fmt.Sprintf("Unable to generate manifests in %s: %v", spec.Source.Path, err),
})
} else if len(manRes.Manifests) == 0 {
conditions = append(conditions, argoappv1.ApplicationCondition{

View File

@@ -29,6 +29,23 @@ func TestRefreshApp(t *testing.T) {
//assert.True(t, ok)
}
func TestGetAppProjectWithNoProjDefined(t *testing.T) {
projName := "default"
namespace := "default"
testProj := &argoappv1.AppProject{
ObjectMeta: metav1.ObjectMeta{Name: projName, Namespace: namespace},
}
var testApp argoappv1.Application
testApp.Name = "test-app"
testApp.Namespace = namespace
appClientset := appclientset.NewSimpleClientset(testProj)
proj, err := GetAppProject(&testApp.Spec, appClientset, namespace)
assert.Nil(t, err)
assert.Equal(t, proj.Name, projName)
}
func TestCheckValidParam(t *testing.T) {
oldAppSet := make(map[string]map[string]bool)
oldAppSet["testComponent"] = make(map[string]bool)

View File

@@ -58,11 +58,10 @@ func (s *db) CreateCluster(ctx context.Context, c *appv1.Cluster) (*appv1.Cluste
},
}
clusterSecret.Data = clusterToData(c)
clusterSecret.Annotations = AnnotationsFromConnectionState(&c.ConnectionState)
clusterSecret, err = s.kubeclientset.CoreV1().Secrets(s.ns).Create(clusterSecret)
if err != nil {
if apierr.IsAlreadyExists(err) {
return nil, status.Errorf(codes.AlreadyExists, "cluster '%s' already exists", c.Server)
return nil, status.Errorf(codes.AlreadyExists, "cluster %q already exists", c.Server)
}
return nil, err
}
@@ -119,7 +118,7 @@ func (s *db) getClusterSecret(server string) (*apiv1.Secret, error) {
clusterSecret, err := s.kubeclientset.CoreV1().Secrets(s.ns).Get(secName, metav1.GetOptions{})
if err != nil {
if apierr.IsNotFound(err) {
return nil, status.Errorf(codes.NotFound, "cluster '%s' not found", server)
return nil, status.Errorf(codes.NotFound, "cluster %q not found", server)
}
return nil, err
}

View File

@@ -136,7 +136,7 @@ func (m *nativeGitClient) setCredentials() error {
func (m *nativeGitClient) Fetch() error {
var err error
log.Debugf("Fetching repo %s at %s", m.repoURL, m.root)
if _, err = m.runCmd("git", "fetch", "origin"); err != nil {
if _, err = m.runCmd("git", "fetch", "origin", "--tags", "--force"); err != nil {
return err
}
// git fetch does not update the HEAD reference. The following command will update the local
@@ -192,7 +192,10 @@ func (m *nativeGitClient) Checkout(revision string) error {
if revision == "" || revision == "HEAD" {
revision = "origin/HEAD"
}
if _, err := m.runCmd("git", "checkout", revision); err != nil {
if _, err := m.runCmd("git", "checkout", "--force", revision); err != nil {
return err
}
if _, err := m.runCmd("git", "clean", "-fd"); err != nil {
return err
}
return nil

View File

@@ -61,6 +61,8 @@ func IsSSHURL(url string) bool {
const gitSSHCommand = "ssh -q -F /dev/null -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=20"
//TODO: Make sure every public method works with '*' repo
// GetGitCommandEnvAndURL returns URL and env options for git operation
func GetGitCommandEnvAndURL(repo, username, password string, sshPrivateKey string) (string, []string, error) {
cmdURL := repo

View File

@@ -33,6 +33,8 @@ func GetAppHealth(obj *unstructured.Unstructured) (*appv1.HealthStatus, error) {
health, err = getReplicaSetHealth(obj)
case kube.DaemonSetKind:
health, err = getDaemonSetHealth(obj)
case kube.PersistentVolumeClaimKind:
health, err = getPvcHealth(obj)
default:
health = &appv1.HealthStatus{Status: appv1.HealthStatusHealthy}
}
@@ -68,6 +70,29 @@ func IsWorse(current, new appv1.HealthStatusCode) bool {
return newIndex > currentIndex
}
func getPvcHealth(obj *unstructured.Unstructured) (*appv1.HealthStatus, error) {
obj, err := kube.ConvertToVersion(obj, "", "v1")
if err != nil {
return nil, err
}
var pvc coreV1.PersistentVolumeClaim
err = runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, &pvc)
if err != nil {
return nil, err
}
switch pvc.Status.Phase {
case coreV1.ClaimLost:
return &appv1.HealthStatus{Status: appv1.HealthStatusDegraded}, nil
case coreV1.ClaimPending:
return &appv1.HealthStatus{Status: appv1.HealthStatusProgressing}, nil
case coreV1.ClaimBound:
return &appv1.HealthStatus{Status: appv1.HealthStatusHealthy}, nil
default:
return &appv1.HealthStatus{Status: appv1.HealthStatusUnknown}, nil
}
}
func getIngressHealth(obj *unstructured.Unstructured) (*appv1.HealthStatus, error) {
obj, err := kube.ConvertToVersion(obj, "extensions", "v1beta1")
if err != nil {
@@ -122,6 +147,7 @@ func getDeploymentHealth(obj *unstructured.Unstructured) (*appv1.HealthStatus, e
if err != nil {
return nil, err
}
// Borrowed at kubernetes/kubectl/rollout_status.go https://github.com/kubernetes/kubernetes/blob/5232ad4a00ec93942d0b2c6359ee6cd1201b46bc/pkg/kubectl/rollout_status.go#L80
if deployment.Generation <= deployment.Status.ObservedGeneration {
cond := getDeploymentCondition(deployment.Status, v1.DeploymentProgressing)

View File

@@ -58,3 +58,27 @@ func TestStatefulSetHealth(t *testing.T) {
assert.NotNil(t, health)
assert.Equal(t, appv1.HealthStatusHealthy, health.Status)
}
func TestPvcHealthy(t *testing.T) {
yamlBytes, err := ioutil.ReadFile("./testdata/pvc-bound.yaml")
assert.Nil(t, err)
var obj unstructured.Unstructured
err = yaml.Unmarshal(yamlBytes, &obj)
assert.Nil(t, err)
health, err := GetAppHealth(&obj)
assert.Nil(t, err)
assert.NotNil(t, health)
assert.Equal(t, appv1.HealthStatusHealthy, health.Status)
}
func TestPvcPending(t *testing.T) {
yamlBytes, err := ioutil.ReadFile("./testdata/pvc-pending.yaml")
assert.Nil(t, err)
var obj unstructured.Unstructured
err = yaml.Unmarshal(yamlBytes, &obj)
assert.Nil(t, err)
health, err := GetAppHealth(&obj)
assert.Nil(t, err)
assert.NotNil(t, health)
assert.Equal(t, appv1.HealthStatusProgressing, health.Status)
}

34
util/health/testdata/pvc-bound.yaml vendored Normal file
View File

@@ -0,0 +1,34 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
annotations:
control-plane.alpha.kubernetes.io/leader: '{"holderIdentity":"e57a9040-a984-11e8-836b-c4b301c4d0d1","leaseDurationSeconds":15,"acquireTime":"2018-08-27T23:00:54Z","renewTime":"2018-08-27T23:00:56Z","leaderTransitions":0}'
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"PersistentVolumeClaim","metadata":{"annotations":{},"labels":{"applications.argoproj.io/app-name":"working-pvc"},"name":"testpvc","namespace":"argocd"},"spec":{"accessModes":["ReadWriteOnce"],"resources":{"requests":{"storage":"2Gi"}}}}
pv.kubernetes.io/bind-completed: "yes"
pv.kubernetes.io/bound-by-controller: "yes"
volume.beta.kubernetes.io/storage-provisioner: docker.io/hostpath
creationTimestamp: 2018-08-27T23:00:54Z
finalizers:
- kubernetes.io/pvc-protection
labels:
applications.argoproj.io/app-name: working-pvc
name: testpvc
namespace: argocd
resourceVersion: "323170"
selfLink: /api/v1/namespaces/argocd/persistentvolumeclaims/testpvc
uid: 0cedda2c-aa4d-11e8-a271-025000000001
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 2Gi
storageClassName: hostpath
volumeName: pvc-0cedda2c-aa4d-11e8-a271-025000000001
status:
accessModes:
- ReadWriteOnce
capacity:
storage: 2Gi
phase: Bound

26
util/health/testdata/pvc-pending.yaml vendored Normal file
View File

@@ -0,0 +1,26 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"PersistentVolumeClaim","metadata":{"annotations":{},"labels":{"applications.argoproj.io/app-name":"working-pvc"},"name":"testpvc-2","namespace":"argocd"},"spec":{"accessModes":["ReadWriteOnce"],"resources":{"requests":{"storage":"2Gi"}},"storageClassName":"slow"}}
volume.beta.kubernetes.io/storage-provisioner: kubernetes.io/aws-ebs
creationTimestamp: 2018-08-27T23:00:54Z
finalizers:
- kubernetes.io/pvc-protection
labels:
applications.argoproj.io/app-name: working-pvc
name: testpvc-2
namespace: argocd
resourceVersion: "323141"
selfLink: /api/v1/namespaces/argocd/persistentvolumeclaims/testpvc-2
uid: 0cedfc44-aa4d-11e8-a271-025000000001
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 2Gi
storageClassName: slow
status:
phase: Pending

21
util/healthz/healthz.go Normal file
View File

@@ -0,0 +1,21 @@
package healthz
import (
"fmt"
"net/http"
log "github.com/sirupsen/logrus"
)
// ServeHealthCheck serves the health check endpoint.
// ServeHealthCheck relies on the provided function to return an error if unhealthy and nil otherwise.
func ServeHealthCheck(mux *http.ServeMux, f func() error) {
mux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
if err := f(); err != nil {
w.WriteHeader(http.StatusServiceUnavailable)
log.Errorln(w, err)
} else {
fmt.Fprintln(w, "ok")
}
})
}

View File

@@ -0,0 +1,59 @@
package healthz
import (
"fmt"
"net"
"net/http"
"testing"
)
func TestHealthCheck(t *testing.T) {
sentinel := false
serve := func(c chan<- string) {
// listen on first available dynamic (unprivileged) port
listener, err := net.Listen("tcp", ":0")
if err != nil {
panic(err)
}
// send back the address so that it can be used
c <- listener.Addr().String()
mux := http.NewServeMux()
ServeHealthCheck(mux, func() error {
if sentinel {
return fmt.Errorf("This is a dummy error")
}
return nil
})
panic(http.Serve(listener, mux))
}
c := make(chan string, 1)
// run a local webserver to test data retrieval
go serve(c)
address := <-c
t.Logf("Listening at address: %s", address)
server := "http://" + address
resp, err := http.Get(server + "/healthz")
if err != nil {
t.Fatal(err)
}
if resp.StatusCode != 200 {
t.Fatalf("Was expecting status code 200 from health check, but got %d instead", resp.StatusCode)
}
sentinel = true
resp, _ = http.Get(server + "/healthz")
if resp.StatusCode != 503 {
t.Fatalf("Was expecting status code 503 from health check, but got %d instead", resp.StatusCode)
}
}

View File

@@ -18,9 +18,15 @@ import (
// Helm provides wrapper functionality around the `helm` command.
type Helm interface {
// Template returns a list of unstructured objects from a `helm template` command
Template(name string, valuesFiles []string, overrides []*argoappv1.ComponentParameter) ([]*unstructured.Unstructured, error)
Template(name, namespace string, valuesFiles []string, overrides []*argoappv1.ComponentParameter) ([]*unstructured.Unstructured, error)
// GetParameters returns a list of chart parameters taking into account values in provided YAML files.
GetParameters(valuesFiles []string) ([]*argoappv1.ComponentParameter, error)
// DependencyBuild runs `helm dependency build` to download a chart's dependencies
DependencyBuild() error
// SetHome sets the helm home location (default "~/.helm")
SetHome(path string)
// Init runs `helm init --client-only`
Init() error
}
// NewHelmApp create a new wrapper to run commands on the `helm` command-line tool.
@@ -30,27 +36,45 @@ func NewHelmApp(path string) Helm {
type helm struct {
path string
home string
}
func (h *helm) Template(name string, valuesFiles []string, overrides []*argoappv1.ComponentParameter) ([]*unstructured.Unstructured, error) {
func (h *helm) Template(name, namespace string, valuesFiles []string, overrides []*argoappv1.ComponentParameter) ([]*unstructured.Unstructured, error) {
args := []string{
"template", h.path, "--name", name,
"template", ".", "--name", name,
}
if namespace != "" {
args = append(args, "--namespace", namespace)
}
for _, valuesFile := range valuesFiles {
args = append(args, "-f", path.Join(h.path, valuesFile))
args = append(args, "-f", valuesFile)
}
for _, p := range overrides {
args = append(args, "--set", fmt.Sprintf("%s=%s", p.Name, p.Value))
}
out, err := helmCmd(args...)
out, err := h.helmCmd(args...)
if err != nil {
return nil, err
}
return kube.SplitYAML(out)
}
func (h *helm) DependencyBuild() error {
_, err := h.helmCmd("dependency", "build")
return err
}
func (h *helm) SetHome(home string) {
h.home = home
}
func (h *helm) Init() error {
_, err := h.helmCmd("init", "--client-only")
return err
}
func (h *helm) GetParameters(valuesFiles []string) ([]*argoappv1.ComponentParameter, error) {
out, err := helmCmd("inspect", "values", h.path)
out, err := h.helmCmd("inspect", "values", ".")
if err != nil {
return nil, err
}
@@ -82,8 +106,12 @@ func (h *helm) GetParameters(valuesFiles []string) ([]*argoappv1.ComponentParame
return params, nil
}
func helmCmd(args ...string) (string, error) {
func (h *helm) helmCmd(args ...string) (string, error) {
cmd := exec.Command("helm", args...)
cmd.Dir = h.path
if h.home != "" {
cmd.Env = append(cmd.Env, fmt.Sprintf("HELM_HOME=%s", h.home))
}
cmdStr := strings.Join(cmd.Args, " ")
log.Info(cmdStr)
outBytes, err := cmd.Output()

View File

@@ -1,6 +1,8 @@
package helm
import (
"io/ioutil"
"os"
"testing"
"github.com/stretchr/testify/assert"
@@ -32,7 +34,7 @@ func TestHelmTemplateParams(t *testing.T) {
Value: "1234",
},
}
objs, err := h.Template("test", nil, overrides)
objs, err := h.Template("test", "", nil, overrides)
assert.Nil(t, err)
assert.Equal(t, 5, len(objs))
@@ -50,7 +52,7 @@ func TestHelmTemplateParams(t *testing.T) {
func TestHelmTemplateValues(t *testing.T) {
h := NewHelmApp("./testdata/redis")
valuesFiles := []string{"values-production.yaml"}
objs, err := h.Template("test", valuesFiles, nil)
objs, err := h.Template("test", "", valuesFiles, nil)
assert.Nil(t, err)
assert.Equal(t, 8, len(objs))
@@ -84,3 +86,24 @@ func TestHelmGetParamsValueFiles(t *testing.T) {
assert.NotNil(t, slaveCountParam)
assert.Equal(t, slaveCountParam.Value, "3")
}
func TestHelmDependencyBuild(t *testing.T) {
clean := func() {
_ = os.RemoveAll("./testdata/wordpress/charts")
}
clean()
defer clean()
h := NewHelmApp("./testdata/wordpress")
helmHome, err := ioutil.TempDir("", "")
assert.NoError(t, err)
defer func() { _ = os.RemoveAll(helmHome) }()
h.SetHome(helmHome)
err = h.Init()
assert.NoError(t, err)
_, err = h.Template("wordpress", "", nil, nil)
assert.Error(t, err)
err = h.DependencyBuild()
assert.NoError(t, err)
_, err = h.Template("wordpress", "", nil, nil)
assert.NoError(t, err)
}

View File

@@ -0,0 +1,5 @@
.git
# OWNERS file for Kubernetes
OWNERS
# example production yaml
values-production.yaml

20
util/helm/testdata/wordpress/Chart.yaml vendored Normal file
View File

@@ -0,0 +1,20 @@
name: wordpress
version: 2.1.10
appVersion: 4.9.8
description: Web publishing platform for building blogs and websites.
icon: https://bitnami.com/assets/stacks/wordpress/img/wordpress-stack-220x234.png
keywords:
- wordpress
- cms
- blog
- http
- web
- application
- php
home: http://www.wordpress.com/
sources:
- https://github.com/bitnami/bitnami-docker-wordpress
maintainers:
- name: bitnami-bot
email: containers@bitnami.com
engine: gotpl

12
util/helm/testdata/wordpress/OWNERS vendored Normal file
View File

@@ -0,0 +1,12 @@
approvers:
- prydonius
- tompizmor
- sameersbn
- carrodher
- juan131
reviewers:
- prydonius
- tompizmor
- sameersbn
- carrodher
- juan131

232
util/helm/testdata/wordpress/README.md vendored Normal file
View File

@@ -0,0 +1,232 @@
# WordPress
[WordPress](https://wordpress.org/) is one of the most versatile open source content management systems on the market. A publishing platform for building blogs and websites.
## TL;DR;
```console
$ helm install stable/wordpress
```
## Introduction
This chart bootstraps a [WordPress](https://github.com/bitnami/bitnami-docker-wordpress) deployment on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager.
It also packages the [Bitnami MariaDB chart](https://github.com/kubernetes/charts/tree/master/stable/mariadb) which is required for bootstrapping a MariaDB deployment for the database requirements of the WordPress application.
## Prerequisites
- Kubernetes 1.4+ with Beta APIs enabled
- PV provisioner support in the underlying infrastructure
## Installing the Chart
To install the chart with the release name `my-release`:
```console
$ helm install --name my-release stable/wordpress
```
The command deploys WordPress on the Kubernetes cluster in the default configuration. The [configuration](#configuration) section lists the parameters that can be configured during installation.
> **Tip**: List all releases using `helm list`
## Uninstalling the Chart
To uninstall/delete the `my-release` deployment:
```console
$ helm delete my-release
```
The command removes all the Kubernetes components associated with the chart and deletes the release.
## Configuration
The following table lists the configurable parameters of the WordPress chart and their default values.
| Parameter | Description | Default |
|----------------------------------|--------------------------------------------|---------------------------------------------------------|
| `image.registry` | WordPress image registry | `docker.io` |
| `image.repository` | WordPress image name | `bitnami/wordpress` |
| `image.tag` | WordPress image tag | `{VERSION}` |
| `image.pullPolicy` | Image pull policy | `Always` if `imageTag` is `latest`, else `IfNotPresent` |
| `image.pullSecrets` | Specify image pull secrets | `nil` |
| `wordpressUsername` | User of the application | `user` |
| `wordpressPassword` | Application password | _random 10 character long alphanumeric string_ |
| `wordpressEmail` | Admin email | `user@example.com` |
| `wordpressFirstName` | First name | `FirstName` |
| `wordpressLastName` | Last name | `LastName` |
| `wordpressBlogName` | Blog name | `User's Blog!` |
| `wordpressTablePrefix` | Table prefix | `wp_` |
| `allowEmptyPassword` | Allow DB blank passwords | `true` |
| `smtpHost` | SMTP host | `nil` |
| `smtpPort` | SMTP port | `nil` |
| `smtpUser` | SMTP user | `nil` |
| `smtpPassword` | SMTP password | `nil` |
| `smtpUsername` | User name for SMTP emails | `nil` |
| `smtpProtocol` | SMTP protocol [`tls`, `ssl`] | `nil` |
| `replicaCount` | Number of WordPress Pods to run | `1` |
| `mariadb.enabled` | Deploy MariaDB container(s) | `true` |
| `mariadb.rootUser.password` | MariaDB admin password | `nil` |
| `mariadb.db.name` | Database name to create | `bitnami_wordpress` |
| `mariadb.db.user` | Database user to create | `bn_wordpress` |
| `mariadb.db.password` | Password for the database | _random 10 character long alphanumeric string_ |
| `externalDatabase.host` | Host of the external database | `localhost` |
| `externalDatabase.user` | Existing username in the external db | `bn_wordpress` |
| `externalDatabase.password` | Password for the above username | `nil` |
| `externalDatabase.database` | Name of the existing database | `bitnami_wordpress` |
| `externalDatabase.port` | Database port number | `3306` |
| `serviceType` | Kubernetes Service type | `LoadBalancer` |
| `serviceExternalTrafficPolicy` | Enable client source IP preservation | `Cluster` |
| `nodePorts.http` | Kubernetes http node port | `""` |
| `nodePorts.https` | Kubernetes https node port | `""` |
| `healthcheckHttps` | Use https for liveliness and readiness | `false` |
| `ingress.enabled` | Enable ingress controller resource | `false` |
| `ingress.hosts[0].name` | Hostname to your WordPress installation | `wordpress.local` |
| `ingress.hosts[0].path` | Path within the url structure | `/` |
| `ingress.hosts[0].tls` | Utilize TLS backend in ingress | `false` |
| `ingress.hosts[0].tlsSecret` | TLS Secret (certificates) | `wordpress.local-tls-secret` |
| `ingress.hosts[0].annotations` | Annotations for this host's ingress record | `[]` |
| `ingress.secrets[0].name` | TLS Secret Name | `nil` |
| `ingress.secrets[0].certificate` | TLS Secret Certificate | `nil` |
| `ingress.secrets[0].key` | TLS Secret Key | `nil` |
| `persistence.enabled` | Enable persistence using PVC | `true` |
| `persistence.existingClaim` | Enable persistence using an existing PVC | `nil` |
| `persistence.storageClass` | PVC Storage Class | `nil` (uses alpha storage class annotation) |
| `persistence.accessMode` | PVC Access Mode | `ReadWriteOnce` |
| `persistence.size` | PVC Storage Request | `10Gi` |
| `nodeSelector` | Node labels for pod assignment | `{}` |
| `tolerations` | List of node taints to tolerate | `[]` |
| `affinity` | Map of node/pod affinities | `{}` |
The above parameters map to the env variables defined in [bitnami/wordpress](http://github.com/bitnami/bitnami-docker-wordpress). For more information please refer to the [bitnami/wordpress](http://github.com/bitnami/bitnami-docker-wordpress) image documentation.
Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example,
```console
$ helm install --name my-release \
--set wordpressUsername=admin,wordpressPassword=password,mariadb.mariadbRootPassword=secretpassword \
stable/wordpress
```
The above command sets the WordPress administrator account username and password to `admin` and `password` respectively. Additionally, it sets the MariaDB `root` user password to `secretpassword`.
Alternatively, a YAML file that specifies the values for the above parameters can be provided while installing the chart. For example,
```console
$ helm install --name my-release -f values.yaml stable/wordpress
```
> **Tip**: You can use the default [values.yaml](values.yaml)
## Production and horizontal scaling
The following repo contains the recommended production settings for wordpress capture in an alternative [values file](values-production.yaml). Please read carefully the comments in the values-production.yaml file to set up your environment appropriately.
To horizontally scale this chart, first download the [values-production.yaml](values-production.yaml) file to your local folder, then:
```console
$ helm install --name my-release -f ./values-production.yaml stable/wordpress
```
Note that [values-production.yaml](values-production.yaml) includes a replicaCount of 3, so there will be 3 WordPress pods. As a result, to use the /admin portal and to ensure you can scale wordpress you need to provide a ReadWriteMany PVC, if you don't have a provisioner for this type of storage, we recommend that you install the nfs provisioner and map it to a RWO volume.
```console
$ helm install stable/nfs-server-provisioner --set persistence.enabled=true,persistence.size=10Gi
$ helm install --name my-release -f values-production.yaml --set persistence.storageClass=nfs stable/wordpress
```
## Persistence
The [Bitnami WordPress](https://github.com/bitnami/bitnami-docker-wordpress) image stores the WordPress data and configurations at the `/bitnami` path of the container.
Persistent Volume Claims are used to keep the data across deployments. This is known to work in GCE, AWS, and minikube.
See the [Configuration](#configuration) section to configure the PVC or to disable persistence.
## Using an external database
Sometimes you may want to have Wordpress connect to an external database rather than installing one inside your cluster, e.g. to use a managed database service, or use run a single database server for all your applications. To do this, the chart allows you to specify credentials for an external database under the [`externalDatabase` parameter](#configuration). You should also disable the MariaDB installation with the `mariadb.enabled` option. For example:
```console
$ helm install stable/wordpress \
--set mariadb.enabled=false,externalDatabase.host=myexternalhost,externalDatabase.user=myuser,externalDatabase.password=mypassword,externalDatabase.database=mydatabase,externalDatabase.port=3306
```
Note also if you disable MariaDB per above you MUST supply values for the `externalDatabase` connection.
## Ingress
This chart provides support for ingress resources. If you have an
ingress controller installed on your cluster, such as [nginx-ingress](https://kubeapps.com/charts/stable/nginx-ingress)
or [traefik](https://kubeapps.com/charts/stable/traefik) you can utilize
the ingress controller to serve your WordPress application.
To enable ingress integration, please set `ingress.enabled` to `true`
### Hosts
Most likely you will only want to have one hostname that maps to this
WordPress installation, however, it is possible to have more than one
host. To facilitate this, the `ingress.hosts` object is an array.
For each item, please indicate a `name`, `tls`, `tlsSecret`, and any
`annotations` that you may want the ingress controller to know about.
Indicating TLS will cause WordPress to generate HTTPS URLs, and
WordPress will be connected to at port 443. The actual secret that
`tlsSecret` references do not have to be generated by this chart.
However, please note that if TLS is enabled, the ingress record will not
work until this secret exists.
For annotations, please see [this document](https://github.com/kubernetes/ingress-nginx/blob/master/docs/annotations.md).
Not all annotations are supported by all ingress controllers, but this
document does a good job of indicating which annotation is supported by
many popular ingress controllers.
### TLS Secrets
This chart will facilitate the creation of TLS secrets for use with the
ingress controller, however, this is not required. There are three
common use cases:
* helm generates/manages certificate secrets
* user generates/manages certificates separately
* an additional tool (like [kube-lego](https://kubeapps.com/charts/stable/kube-lego))
manages the secrets for the application
In the first two cases, one will need a certificate and a key. We would
expect them to look like this:
* certificate files should look like (and there can be more than one
certificate if there is a certificate chain)
```
-----BEGIN CERTIFICATE-----
MIID6TCCAtGgAwIBAgIJAIaCwivkeB5EMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNV
...
jScrvkiBO65F46KioCL9h5tDvomdU1aqpI/CBzhvZn1c0ZTf87tGQR8NK7v7
-----END CERTIFICATE-----
```
* keys should look like:
```
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAvLYcyu8f3skuRyUgeeNpeDvYBCDcgq+LsWap6zbX5f8oLqp4
...
wrj2wDbCDCFmfqnSJ+dKI3vFLlEz44sAV8jX/kd4Y6ZTQhlLbYc=
-----END RSA PRIVATE KEY-----
````
If you are going to use Helm to manage the certificates, please copy
these values into the `certificate` and `key` values for a given
`ingress.secrets` entry.
If you are going are going to manage TLS secrets outside of Helm, please
know that you can create a TLS secret by doing the following:
```
kubectl create secret tls wordpress.local-tls --key /path/to/key.key --cert /path/to/cert.crt
```
Please see [this example](https://github.com/kubernetes/contrib/tree/master/ingress/controllers/nginx/examples/tls)
for more information.

View File

@@ -0,0 +1,6 @@
dependencies:
- name: mariadb
repository: https://kubernetes-charts.storage.googleapis.com/
version: 4.3.1
digest: sha256:82a0e5374376169d2ecf7d452c18a2ed93507f5d17c3393a1457f9ffad7e9b26
generated: 2018-08-02T22:07:51.905271776Z

View File

@@ -0,0 +1,7 @@
dependencies:
- name: mariadb
version: 4.x.x
repository: https://kubernetes-charts.storage.googleapis.com/
condition: mariadb.enabled
tags:
- wordpress-database

View File

@@ -0,0 +1,38 @@
1. Get the WordPress URL:
{{- if .Values.ingress.enabled }}
You should be able to access your new WordPress installation through
{{- range .Values.ingress.hosts }}
{{ if .tls }}https{{ else }}http{{ end }}://{{ .name }}/admin
{{- end }}
{{- else if contains "LoadBalancer" .Values.serviceType }}
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
Watch the status with: 'kubectl get svc --namespace {{ .Release.Namespace }} -w {{ template "fullname" . }}'
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo "WordPress URL: http://$SERVICE_IP/"
echo "WordPress Admin URL: http://$SERVICE_IP/admin"
{{- else if contains "ClusterIP" .Values.serviceType }}
echo "WordPress URL: http://127.0.0.1:8080/"
echo "WordPress Admin URL: http://127.0.0.1:8080/admin"
kubectl port-forward --namespace {{ .Release.Namespace }} svc/{{ template "fullname" . }} 8080:80
{{- else if contains "NodePort" .Values.serviceType }}
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "fullname" . }})
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
echo "WordPress URL: http://$NODE_IP:$NODE_PORT/"
echo "WordPress Admin URL: http://$NODE_IP:$NODE_PORT/admin"
{{- end }}
2. Login with the following credentials to see your blog
echo Username: {{ .Values.wordpressUsername }}
echo Password: $(kubectl get secret --namespace {{ .Release.Namespace }} {{ template "fullname" . }} -o jsonpath="{.data.wordpress-password}" | base64 --decode)

View File

@@ -0,0 +1,24 @@
{{/* vim: set filetype=mustache: */}}
{{/*
Expand the name of the chart.
*/}}
{{- define "name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
*/}}
{{- define "fullname" -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
*/}}
{{- define "mariadb.fullname" -}}
{{- printf "%s-%s" .Release.Name "mariadb" | trunc 63 | trimSuffix "-" -}}
{{- end -}}

View File

@@ -0,0 +1,159 @@
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: {{ template "fullname" . }}
labels:
app: {{ template "fullname" . }}
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
release: "{{ .Release.Name }}"
heritage: "{{ .Release.Service }}"
spec:
replicas: {{ .Values.replicaCount }}
template:
metadata:
labels:
app: {{ template "fullname" . }}
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
release: "{{ .Release.Name }}"
spec:
{{- if .Values.image.pullSecrets }}
imagePullSecrets:
{{- range .Values.image.pullSecrets }}
- name: {{ . }}
{{- end}}
{{- end }}
containers:
- name: {{ template "fullname" . }}
image: "{{ .Values.image.registry }}/{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy | quote }}
env:
- name: ALLOW_EMPTY_PASSWORD
{{- if .Values.allowEmptyPassword }}
value: "yes"
{{- else }}
value: "no"
{{- end }}
- name: MARIADB_HOST
{{- if .Values.mariadb.enabled }}
value: {{ template "mariadb.fullname" . }}
{{- else }}
value: {{ .Values.externalDatabase.host | quote }}
{{- end }}
- name: MARIADB_PORT_NUMBER
{{- if .Values.mariadb.enabled }}
value: "3306"
{{- else }}
value: {{ .Values.externalDatabase.port | quote }}
{{- end }}
- name: WORDPRESS_DATABASE_NAME
{{- if .Values.mariadb.enabled }}
value: {{ .Values.mariadb.db.name | quote }}
{{- else }}
value: {{ .Values.externalDatabase.database | quote }}
{{- end }}
- name: WORDPRESS_DATABASE_USER
{{- if .Values.mariadb.enabled }}
value: {{ .Values.mariadb.db.user | quote }}
{{- else }}
value: {{ .Values.externalDatabase.user | quote }}
{{- end }}
- name: WORDPRESS_DATABASE_PASSWORD
valueFrom:
secretKeyRef:
{{- if .Values.mariadb.enabled }}
name: {{ template "mariadb.fullname" . }}
key: mariadb-password
{{- else }}
name: {{ printf "%s-%s" .Release.Name "externaldb" }}
key: db-password
{{- end }}
- name: WORDPRESS_USERNAME
value: {{ .Values.wordpressUsername | quote }}
- name: WORDPRESS_PASSWORD
valueFrom:
secretKeyRef:
name: {{ template "fullname" . }}
key: wordpress-password
- name: WORDPRESS_EMAIL
value: {{ .Values.wordpressEmail | quote }}
- name: WORDPRESS_FIRST_NAME
value: {{ .Values.wordpressFirstName | quote }}
- name: WORDPRESS_LAST_NAME
value: {{ .Values.wordpressLastName | quote }}
- name: WORDPRESS_BLOG_NAME
value: {{ .Values.wordpressBlogName | quote }}
- name: WORDPRESS_TABLE_PREFIX
value: {{ .Values.wordpressTablePrefix | quote }}
- name: SMTP_HOST
value: {{ .Values.smtpHost | quote }}
- name: SMTP_PORT
value: {{ .Values.smtpPort | quote }}
- name: SMTP_USER
value: {{ .Values.smtpUser | quote }}
- name: SMTP_PASSWORD
valueFrom:
secretKeyRef:
name: {{ template "fullname" . }}
key: smtp-password
- name: SMTP_USERNAME
value: {{ .Values.smtpUsername | quote }}
- name: SMTP_PROTOCOL
value: {{ .Values.smtpProtocol | quote }}
ports:
- name: http
containerPort: 80
- name: https
containerPort: 443
livenessProbe:
httpGet:
path: /wp-login.php
{{- if not .Values.healthcheckHttps }}
port: http
{{- else }}
port: https
scheme: HTTPS
{{- end }}
{{ toYaml .Values.livenessProbe | indent 10 }}
readinessProbe:
httpGet:
path: /wp-login.php
{{- if not .Values.healthcheckHttps }}
port: http
{{- else }}
port: https
scheme: HTTPS
{{- end }}
{{ toYaml .Values.readinessProbe | indent 10 }}
volumeMounts:
- mountPath: /bitnami/apache
name: wordpress-data
subPath: apache
- mountPath: /bitnami/wordpress
name: wordpress-data
subPath: wordpress
- mountPath: /bitnami/php
name: wordpress-data
subPath: php
resources:
{{ toYaml .Values.resources | indent 10 }}
volumes:
- name: wordpress-data
{{- if .Values.persistence.enabled }}
persistentVolumeClaim:
claimName: {{ .Values.persistence.existingClaim | default (include "fullname" .) }}
{{- else }}
emptyDir: {}
{{ end }}
{{- if .Values.nodeSelector }}
nodeSelector:
{{ toYaml .Values.nodeSelector | indent 8 }}
{{- end -}}
{{- with .Values.affinity }}
affinity:
{{ toYaml . | indent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{ toYaml . | indent 8 }}
{{- end }}

View File

@@ -0,0 +1,14 @@
{{- if not .Values.mariadb.enabled }}
apiVersion: v1
kind: Secret
metadata:
name: {{ printf "%s-%s" .Release.Name "externaldb" }}
labels:
app: {{ printf "%s-%s" .Release.Name "externaldb" }}
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
release: "{{ .Release.Name }}"
heritage: "{{ .Release.Service }}"
type: Opaque
data:
db-password: {{ .Values.externalDatabase.password | b64enc | quote }}
{{- end }}

View File

@@ -0,0 +1,36 @@
{{- if .Values.ingress.enabled }}
{{- range .Values.ingress.hosts }}
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: "{{- printf "%s-%s" .name $.Release.Name | trunc 63 | trimSuffix "-" -}}"
labels:
app: {{ template "fullname" $ }}
chart: "{{ $.Chart.Name }}-{{ $.Chart.Version }}"
release: "{{ $.Release.Name }}"
heritage: "{{ $.Release.Service }}"
annotations:
{{- if .tls }}
ingress.kubernetes.io/secure-backends: "true"
{{- end }}
{{- range $key, $value := .annotations }}
{{ $key }}: {{ $value | quote }}
{{- end }}
spec:
rules:
- host: {{ .name }}
http:
paths:
- path: {{ default "/" .path }}
backend:
serviceName: {{ template "fullname" $ }}
servicePort: 80
{{- if .tls }}
tls:
- hosts:
- {{ .name }}
secretName: {{ .tlsSecret }}
{{- end }}
---
{{- end }}
{{- end }}

View File

@@ -0,0 +1,24 @@
{{- if and .Values.persistence.enabled (not .Values.persistence.existingClaim) }}
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: {{ template "fullname" . }}
labels:
app: {{ template "fullname" . }}
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
release: "{{ .Release.Name }}"
heritage: "{{ .Release.Service }}"
spec:
accessModes:
- {{ .Values.persistence.accessMode | quote }}
resources:
requests:
storage: {{ .Values.persistence.size | quote }}
{{- if .Values.persistence.storageClass }}
{{- if (eq "-" .Values.persistence.storageClass) }}
storageClassName: ""
{{- else }}
storageClassName: "{{ .Values.persistence.storageClass }}"
{{- end }}
{{- end }}
{{- end -}}

View File

@@ -0,0 +1,17 @@
apiVersion: v1
kind: Secret
metadata:
name: {{ template "fullname" . }}
labels:
app: {{ template "fullname" . }}
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
release: "{{ .Release.Name }}"
heritage: "{{ .Release.Service }}"
type: Opaque
data:
{{ if .Values.wordpressPassword }}
wordpress-password: {{ default "" .Values.wordpressPassword | b64enc | quote }}
{{ else }}
wordpress-password: {{ randAlphaNum 10 | b64enc | quote }}
{{ end }}
smtp-password: {{ default "" .Values.smtpPassword | b64enc | quote }}

View File

@@ -0,0 +1,29 @@
apiVersion: v1
kind: Service
metadata:
name: {{ template "fullname" . }}
labels:
app: {{ template "fullname" . }}
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
release: "{{ .Release.Name }}"
heritage: "{{ .Release.Service }}"
spec:
type: {{ .Values.serviceType }}
{{- if (or (eq .Values.serviceType "LoadBalancer") (eq .Values.serviceType "NodePort")) }}
externalTrafficPolicy: {{ .Values.serviceExternalTrafficPolicy | quote }}
{{- end }}
ports:
- name: http
port: 80
targetPort: http
{{- if (and (eq .Values.serviceType "NodePort") (not (empty .Values.nodePorts.http)))}}
nodePort: {{ .Values.nodePorts.http }}
{{- end }}
- name: https
port: 443
targetPort: https
{{- if (and (eq .Values.serviceType "NodePort") (not (empty .Values.nodePorts.https)))}}
nodePort: {{ .Values.nodePorts.https }}
{{- end }}
selector:
app: {{ template "fullname" . }}

View File

@@ -0,0 +1,29 @@
{{- if .Values.mariadb.enabled }}
apiVersion: v1
kind: Pod
metadata:
name: "{{ .Release.Name }}-credentials-test"
annotations:
"helm.sh/hook": test-success
spec:
containers:
- name: {{ .Release.Name }}-credentials-test
image: "{{ .Values.image.registry }}/{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy | quote }}
env:
- name: MARIADB_HOST
value: {{ template "mariadb.fullname" . }}
- name: MARIADB_PORT
value: "3306"
- name: WORDPRESS_DATABASE_NAME
value: {{ default "" .Values.mariadb.db.name | quote }}
- name: WORDPRESS_DATABASE_USER
value: {{ default "" .Values.mariadb.db.user | quote }}
- name: WORDPRESS_DATABASE_PASSWORD
valueFrom:
secretKeyRef:
name: {{ template "mariadb.fullname" . }}
key: mariadb-password
command: ["sh", "-c", "mysql --host=$MARIADB_HOST --port=$MARIADB_PORT --user=$WORDPRESS_DATABASE_USER --password=$WORDPRESS_DATABASE_PASSWORD"]
restartPolicy: Never
{{- end }}

View File

@@ -0,0 +1,18 @@
{{- if .Values.ingress.enabled }}
{{- range .Values.ingress.secrets }}
apiVersion: v1
kind: Secret
metadata:
name: {{ .name }}
labels:
app: {{ template "fullname" $ }}
chart: "{{ $.Chart.Name }}-{{ $.Chart.Version }}"
release: "{{ $.Release.Name }}"
heritage: "{{ $.Release.Service }}"
type: kubernetes.io/tls
data:
tls.crt: {{ .certificate | b64enc }}
tls.key: {{ .key | b64enc }}
---
{{- end }}
{{- end }}

View File

@@ -0,0 +1,256 @@
## Bitnami WordPress image version
## ref: https://hub.docker.com/r/bitnami/wordpress/tags/
##
image:
registry: docker.io
repository: bitnami/wordpress
tag: 4.9.8-debian-9
pullPolicy: IfNotPresent
## Optionally specify an array of imagePullSecrets.
## Secrets must be manually created in the namespace.
## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/
##
# pullSecrets:
# - myRegistrKeySecretName
## User of the application
## ref: https://github.com/bitnami/bitnami-docker-wordpress#environment-variables
##
wordpressUsername: user
## Application password
## Defaults to a random 10-character alphanumeric string if not set
## ref: https://github.com/bitnami/bitnami-docker-wordpress#environment-variables
##
# wordpressPassword:
## Admin email
## ref: https://github.com/bitnami/bitnami-docker-wordpress#environment-variables
##
wordpressEmail: user@example.com
## First name
## ref: https://github.com/bitnami/bitnami-docker-wordpress#environment-variables
##
wordpressFirstName: FirstName
## Last name
## ref: https://github.com/bitnami/bitnami-docker-wordpress#environment-variables
##
wordpressLastName: LastName
## Blog name
## ref: https://github.com/bitnami/bitnami-docker-wordpress#environment-variables
##
wordpressBlogName: User's Blog!
## Table prefix
## ref: https://github.com/bitnami/bitnami-docker-wordpress#environment-variables
##
wordpressTablePrefix: wp_
## Set to `yes` to allow the container to be started with blank passwords
## ref: https://github.com/bitnami/bitnami-docker-wordpress#environment-variables
allowEmptyPassword: "yes"
## SMTP mail delivery configuration
## ref: https://github.com/bitnami/bitnami-docker-wordpress/#smtp-configuration
##
# smtpHost:
# smtpPort:
# smtpUser:
# smtpPassword:
# smtpUsername:
# smtpProtocol:
replicaCount: 3
externalDatabase:
## All of these values are only used when mariadb.enabled is set to false
## Database host
host: localhost
## non-root Username for Wordpress Database
user: bn_wordpress
## Database password
password: ""
## Database name
database: bitnami_wordpress
## Database port number
port: 3306
##
## MariaDB chart configuration
##
mariadb:
## Whether to deploy a mariadb server to satisfy the applications database requirements. To use an external database set this to false and configure the externalDatabase parameters
enabled: true
## Disable MariaDB replication
replication:
enabled: false
## Create a database and a database user
## ref: https://github.com/bitnami/bitnami-docker-mariadb/blob/master/README.md#creating-a-database-user-on-first-run
##
db:
name: bitnami_wordpress
user: bn_wordpress
## If the password is not specified, mariadb will generates a random password
##
# password:
## MariaDB admin password
## ref: https://github.com/bitnami/bitnami-docker-mariadb/blob/master/README.md#setting-the-root-password-on-first-run
##
# rootUser:
# password:
## Enable persistence using Persistent Volume Claims
## ref: http://kubernetes.io/docs/user-guide/persistent-volumes/
##
master:
persistence:
enabled: true
## mariadb data Persistent Volume Storage Class
## If defined, storageClassName: <storageClass>
## If set to "-", storageClassName: "", which disables dynamic provisioning
## If undefined (the default) or set to null, no storageClassName spec is
## set, choosing the default provisioner. (gp2 on AWS, standard on
## GKE, AWS & OpenStack)
##
# storageClass: "-"
accessMode: ReadWriteOnce
size: 8Gi
## Kubernetes configuration
## For minikube, set this to NodePort, elsewhere use LoadBalancer or ClusterIP
##
serviceType: ClusterIP
##
## serviceType: NodePort
## nodePorts:
## http: <to set explicitly, choose port between 30000-32767>
## https: <to set explicitly, choose port between 30000-32767>
nodePorts:
http: ""
https: ""
## Enable client source IP preservation
## ref http://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#preserving-the-client-source-ip
##
serviceExternalTrafficPolicy: Local
## Allow health checks to be pointed at the https port
healthcheckHttps: false
## Configure extra options for liveness and readiness probes
## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes)
livenessProbe:
initialDelaySeconds: 120
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 6
successThreshold: 1
readinessProbe:
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 6
successThreshold: 1
## Configure the ingress resource that allows you to access the
## Wordpress installation. Set up the URL
## ref: http://kubernetes.io/docs/user-guide/ingress/
##
ingress:
## Set to true to enable ingress record generation
enabled: true
## The list of hostnames to be covered with this ingress record.
## Most likely this will be just one host, but in the event more hosts are needed, this is an array
## Please make sure to change the name and tlsSecret to your own settings
hosts:
- name: wordpress.local
## Set this to true in order to enable TLS on the ingress record
## A side effect of this will be that the backend wordpress service will be connected at port 443
tls: true
## If TLS is set to true, you must declare what secret will store the key/certificate for TLS
tlsSecret: wordpress.local-tls
## Ingress annotations done as key:value pairs
## If you're using kube-lego, you will want to add:
## kubernetes.io/tls-acme: true
##
## For a full list of possible ingress annotations, please see
## ref: https://github.com/kubernetes/ingress-nginx/blob/master/docs/annotations.md
##
## If tls is set to true, annotation ingress.kubernetes.io/secure-backends: "true" will automatically be set
annotations:
# kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: true
secrets:
## If you're providing your own certificates, please use this to add the certificates as secrets
## key and certificate should start with -----BEGIN CERTIFICATE----- or
## -----BEGIN RSA PRIVATE KEY-----
##
## name should line up with a tlsSecret set further up
## If you're using kube-lego, this is unneeded, as it will create the secret for you if it is not set
##
## It is also possible to create and manage the certificates outside of this helm chart
## Please see README.md for more information
# - name: wordpress.local-tls
# key:
# certificate:
## Enable persistence using Persistent Volume Claims
## ref: http://kubernetes.io/docs/user-guide/persistent-volumes/
##
persistence:
enabled: true
## wordpress data Persistent Volume Storage Class
## If defined, storageClassName: <storageClass>
## If set to "-", storageClassName: "", which disables dynamic provisioning
## If undefined (the default) or set to null, no storageClassName spec is
## set, choosing the default provisioner. (gp2 on AWS, standard on
## GKE, AWS & OpenStack)
##
# storageClass: "-"
##
## If you want to reuse an existing claim, you can pass the name of the PVC using
## the existingClaim variable
# existingClaim: your-claim
##
## To use the /admin portal and to ensure you can scale wordpress you need to provide a
## ReadWriteMany PVC, if you dont have a provisioner for this type of storage
## We recommend that you install the nfs provisioner and map it to a RWO volume
## helm install stable/nfs-server-provisioner --set persistence.enabled=true,persistence.size=10Gi
accessMode: ReadWriteMany
size: 10Gi
## Configure resource requests and limits
## ref: http://kubernetes.io/docs/user-guide/compute-resources/
##
resources:
requests:
memory: 512Mi
cpu: 300m
## Node labels for pod assignment
## Ref: https://kubernetes.io/docs/user-guide/node-selection/
##
nodeSelector: {}
## Tolerations for pod assignment
## Ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/
##
tolerations: []
## Affinity for pod assignment
## Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity
##
affinity: {}

254
util/helm/testdata/wordpress/values.yaml vendored Normal file
View File

@@ -0,0 +1,254 @@
## Bitnami WordPress image version
## ref: https://hub.docker.com/r/bitnami/wordpress/tags/
##
image:
registry: docker.io
repository: bitnami/wordpress
tag: 4.9.8-debian-9
## Specify a imagePullPolicy
## Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent'
## ref: http://kubernetes.io/docs/user-guide/images/#pre-pulling-images
##
pullPolicy: IfNotPresent
## Optionally specify an array of imagePullSecrets.
## Secrets must be manually created in the namespace.
## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/
##
# pullSecrets:
# - myRegistrKeySecretName
## User of the application
## ref: https://github.com/bitnami/bitnami-docker-wordpress#environment-variables
##
wordpressUsername: user
## Application password
## Defaults to a random 10-character alphanumeric string if not set
## ref: https://github.com/bitnami/bitnami-docker-wordpress#environment-variables
##
# wordpressPassword:
## Admin email
## ref: https://github.com/bitnami/bitnami-docker-wordpress#environment-variables
##
wordpressEmail: user@example.com
## First name
## ref: https://github.com/bitnami/bitnami-docker-wordpress#environment-variables
##
wordpressFirstName: FirstName
## Last name
## ref: https://github.com/bitnami/bitnami-docker-wordpress#environment-variables
##
wordpressLastName: LastName
## Blog name
## ref: https://github.com/bitnami/bitnami-docker-wordpress#environment-variables
##
wordpressBlogName: User's Blog!
## Table prefix
## ref: https://github.com/bitnami/bitnami-docker-wordpress#environment-variables
##
wordpressTablePrefix: wp_
## Set to `false` to allow the container to be started with blank passwords
## ref: https://github.com/bitnami/bitnami-docker-wordpress#environment-variables
allowEmptyPassword: true
## SMTP mail delivery configuration
## ref: https://github.com/bitnami/bitnami-docker-wordpress/#smtp-configuration
##
# smtpHost:
# smtpPort:
# smtpUser:
# smtpPassword:
# smtpUsername:
# smtpProtocol:
replicaCount: 1
externalDatabase:
## All of these values are only used when mariadb.enabled is set to false
## Database host
host: localhost
## non-root Username for Wordpress Database
user: bn_wordpress
## Database password
password: ""
## Database name
database: bitnami_wordpress
## Database port number
port: 3306
##
## MariaDB chart configuration
##
mariadb:
## Whether to deploy a mariadb server to satisfy the applications database requirements. To use an external database set this to false and configure the externalDatabase parameters
enabled: true
## Disable MariaDB replication
replication:
enabled: false
## Create a database and a database user
## ref: https://github.com/bitnami/bitnami-docker-mariadb/blob/master/README.md#creating-a-database-user-on-first-run
##
db:
name: bitnami_wordpress
user: bn_wordpress
## If the password is not specified, mariadb will generates a random password
##
# password:
## MariaDB admin password
## ref: https://github.com/bitnami/bitnami-docker-mariadb/blob/master/README.md#setting-the-root-password-on-first-run
##
# rootUser:
# password:
## Enable persistence using Persistent Volume Claims
## ref: http://kubernetes.io/docs/user-guide/persistent-volumes/
##
master:
persistence:
enabled: true
## mariadb data Persistent Volume Storage Class
## If defined, storageClassName: <storageClass>
## If set to "-", storageClassName: "", which disables dynamic provisioning
## If undefined (the default) or set to null, no storageClassName spec is
## set, choosing the default provisioner. (gp2 on AWS, standard on
## GKE, AWS & OpenStack)
##
# storageClass: "-"
accessMode: ReadWriteOnce
size: 8Gi
## Kubernetes configuration
## For minikube, set this to NodePort, elsewhere use LoadBalancer or ClusterIP
##
serviceType: LoadBalancer
##
## serviceType: NodePort
## nodePorts:
## http: <to set explicitly, choose port between 30000-32767>
## https: <to set explicitly, choose port between 30000-32767>
nodePorts:
http: ""
https: ""
## Enable client source IP preservation
## ref http://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#preserving-the-client-source-ip
##
serviceExternalTrafficPolicy: Cluster
## Allow health checks to be pointed at the https port
healthcheckHttps: false
## Configure extra options for liveness and readiness probes
## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes)
livenessProbe:
initialDelaySeconds: 120
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 6
successThreshold: 1
readinessProbe:
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 6
successThreshold: 1
## Configure the ingress resource that allows you to access the
## Wordpress installation. Set up the URL
## ref: http://kubernetes.io/docs/user-guide/ingress/
##
ingress:
## Set to true to enable ingress record generation
enabled: false
## The list of hostnames to be covered with this ingress record.
## Most likely this will be just one host, but in the event more hosts are needed, this is an array
hosts:
- name: wordpress.local
## Set this to true in order to enable TLS on the ingress record
## A side effect of this will be that the backend wordpress service will be connected at port 443
tls: false
## If TLS is set to true, you must declare what secret will store the key/certificate for TLS
tlsSecret: wordpress.local-tls
## Ingress annotations done as key:value pairs
## If you're using kube-lego, you will want to add:
## kubernetes.io/tls-acme: true
##
## For a full list of possible ingress annotations, please see
## ref: https://github.com/kubernetes/ingress-nginx/blob/master/docs/annotations.md
##
## If tls is set to true, annotation ingress.kubernetes.io/secure-backends: "true" will automatically be set
annotations:
# kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: true
secrets:
## If you're providing your own certificates, please use this to add the certificates as secrets
## key and certificate should start with -----BEGIN CERTIFICATE----- or
## -----BEGIN RSA PRIVATE KEY-----
##
## name should line up with a tlsSecret set further up
## If you're using kube-lego, this is unneeded, as it will create the secret for you if it is not set
##
## It is also possible to create and manage the certificates outside of this helm chart
## Please see README.md for more information
# - name: wordpress.local-tls
# key:
# certificate:
## Enable persistence using Persistent Volume Claims
## ref: http://kubernetes.io/docs/user-guide/persistent-volumes/
##
persistence:
enabled: true
## wordpress data Persistent Volume Storage Class
## If defined, storageClassName: <storageClass>
## If set to "-", storageClassName: "", which disables dynamic provisioning
## If undefined (the default) or set to null, no storageClassName spec is
## set, choosing the default provisioner. (gp2 on AWS, standard on
## GKE, AWS & OpenStack)
##
# storageClass: "-"
##
## If you want to reuse an existing claim, you can pass the name of the PVC using
## the existingClaim variable
# existingClaim: your-claim
accessMode: ReadWriteOnce
size: 10Gi
## Configure resource requests and limits
## ref: http://kubernetes.io/docs/user-guide/compute-resources/
##
resources:
requests:
memory: 512Mi
cpu: 300m
## Node labels for pod assignment
## Ref: https://kubernetes.io/docs/user-guide/node-selection/
##
nodeSelector: {}
## Tolerations for pod assignment
## Ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/
##
tolerations: []
## Affinity for pod assignment
## Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity
##
affinity: {}

View File

@@ -119,7 +119,14 @@ func (k *ksonnetApp) Show(environment string) ([]*unstructured.Unstructured, err
if err != nil {
return nil, fmt.Errorf("`ks show` failed: %v", err)
}
return kube.SplitYAML(out)
data, err := kube.SplitYAML(out)
if err == nil {
// Address https://github.com/ksonnet/ksonnet/issues/707
for _, d := range data {
kube.UnsetLabel(d, "ksonnet.io/component")
}
}
return data, err
}
// ListEnvParams returns list of environment parameters

View File

@@ -49,13 +49,14 @@ const (
)
const (
ServiceKind = "Service"
EndpointsKind = "Endpoints"
DeploymentKind = "Deployment"
ReplicaSetKind = "ReplicaSet"
StatefulSetKind = "StatefulSet"
DaemonSetKind = "DaemonSet"
IngressKind = "Ingress"
ServiceKind = "Service"
EndpointsKind = "Endpoints"
DeploymentKind = "Deployment"
ReplicaSetKind = "ReplicaSet"
StatefulSetKind = "StatefulSet"
DaemonSetKind = "DaemonSet"
IngressKind = "Ingress"
PersistentVolumeClaimKind = "PersistentVolumeClaim"
)
const (
@@ -107,6 +108,16 @@ func MustToUnstructured(obj interface{}) *unstructured.Unstructured {
return uObj
}
// UnsetLabel removes our app labels from an unstructured object
func UnsetLabel(target *unstructured.Unstructured, key string) {
if labels := target.GetLabels(); labels != nil {
if _, ok := labels[key]; ok {
delete(labels, key)
target.SetLabels(labels)
}
}
}
// SetLabel sets our app labels against an unstructured object
func SetLabel(target *unstructured.Unstructured, key, val string) error {
labels := target.GetLabels()
@@ -174,7 +185,11 @@ func GetCachedServerResources(host string, disco discovery.DiscoveryInterface) (
}
resList, err = disco.ServerResources()
if err != nil {
return nil, errors.WithStack(err)
if len(resList) == 0 {
return nil, errors.WithStack(err)
}
// It's possible for ServerResources to return error as well as a resource list
log.Warnf("Resource discovery partially successful. Encountered error: %v", err)
}
err = apiResourceCache.Set(&cache.Item{
Key: cacheKey,
@@ -308,12 +323,11 @@ func GetResourcesWithLabel(config *rest.Config, namespace string, labelName stri
var asyncErr error
var result []*unstructured.Unstructured
var wg sync.WaitGroup
var lock sync.Mutex
wg.Add(len(resourceInterfaces))
for i := range resourceInterfaces {
client := resourceInterfaces[i]
go func() {
for _, c := range resourceInterfaces {
go func(client dynamic.ResourceInterface) {
defer wg.Done()
list, err := client.List(metav1.ListOptions{
LabelSelector: fmt.Sprintf("%s=%s", labelName, labelValue),
@@ -328,11 +342,13 @@ func GetResourcesWithLabel(config *rest.Config, namespace string, labelName stri
labels := item.GetLabels()
if labels != nil {
if value, ok := labels[labelName]; ok && value == labelValue {
lock.Lock()
result = append(result, &item)
lock.Unlock()
}
}
}
}()
}(c)
}
wg.Wait()
return result, asyncErr
@@ -350,10 +366,11 @@ func DeleteResourceWithLabel(config *rest.Config, namespace string, labelName st
return err
}
var resourceInterfaces []struct {
type resClient struct {
dynamic.ResourceInterface
bool
deleteCollectionSupported bool
}
var resourceInterfaces []resClient
for _, apiResourcesList := range resources {
for i := range apiResourcesList.APIResources {
@@ -373,10 +390,10 @@ func DeleteResourceWithLabel(config *rest.Config, namespace string, labelName st
}
if deleteCollectionSupported || deleteSupported {
resourceInterfaces = append(resourceInterfaces, struct {
dynamic.ResourceInterface
bool
}{dclient.Resource(&apiResource, namespace), deleteCollectionSupported})
resourceInterfaces = append(resourceInterfaces, resClient{
dclient.Resource(&apiResource, namespace),
deleteCollectionSupported,
})
}
}
}
@@ -387,13 +404,10 @@ func DeleteResourceWithLabel(config *rest.Config, namespace string, labelName st
var wg sync.WaitGroup
wg.Add(len(resourceInterfaces))
for i := range resourceInterfaces {
client := resourceInterfaces[i].ResourceInterface
deleteCollectionSupported := resourceInterfaces[i].bool
go func() {
for _, c := range resourceInterfaces {
go func(client resClient) {
defer wg.Done()
if deleteCollectionSupported {
if client.deleteCollectionSupported {
err = client.DeleteCollection(&metav1.DeleteOptions{
PropagationPolicy: &propagationPolicy,
}, metav1.ListOptions{LabelSelector: fmt.Sprintf("%s=%s", labelName, labelValue)})
@@ -422,7 +436,7 @@ func DeleteResourceWithLabel(config *rest.Config, namespace string, labelName st
}
}
}
}()
}(c)
}
wg.Wait()
return asyncErr

View File

@@ -169,6 +169,49 @@ func TestConvertToVersion(t *testing.T) {
assert.Equal(t, "v1", gvk.Version)
}
const depWithLabel = `
apiVersion: extensions/v1beta2
kind: Deployment
metadata:
name: nginx-deployment
labels:
foo: bar
spec:
template:
metadata:
labels:
app: nginx
spec:
containers:
- image: nginx:1.7.9
name: nginx
ports:
- containerPort: 80
`
func TestUnsetLabels(t *testing.T) {
for _, yamlStr := range []string{depWithLabel} {
var obj unstructured.Unstructured
err := yaml.Unmarshal([]byte(yamlStr), &obj)
assert.Nil(t, err)
err = SetLabel(&obj, "foo", "bar")
assert.Nil(t, err)
UnsetLabel(&obj, "foo")
manifestBytes, err := json.MarshalIndent(obj.Object, "", " ")
assert.Nil(t, err)
log.Println(string(manifestBytes))
var dep extv1beta1.Deployment
err = json.Unmarshal(manifestBytes, &dep)
assert.Nil(t, err)
assert.Equal(t, 0, len(dep.ObjectMeta.Labels))
}
}
const depWithoutSelector = `
apiVersion: extensions/v1beta1
kind: Deployment

View File

@@ -0,0 +1,31 @@
package kustomize
import (
"github.com/argoproj/pkg/exec"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"github.com/argoproj/argo-cd/util/kube"
)
// Kustomize provides wrapper functionality around the `kustomize` command.
type Kustomize interface {
// Build returns a list of unstructured objects from a `kustomize build` command
Build() ([]*unstructured.Unstructured, error)
}
// NewKustomizeApp create a new wrapper to run commands on the `kustomize` command-line tool.
func NewKustomizeApp(path string) Kustomize {
return &kustomize{path: path}
}
type kustomize struct {
path string
}
func (k *kustomize) Build() ([]*unstructured.Unstructured, error) {
out, err := exec.RunCommand("kustomize", "build", k.path)
if err != nil {
return nil, err
}
return kube.SplitYAML(out)
}

Some files were not shown because too many files have changed in this diff Show More