mirror of
https://github.com/argoproj/argo-cd.git
synced 2026-03-17 05:48:56 +01:00
Compare commits
2 Commits
release-0.
...
release-0.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
20693fd44c | ||
|
|
37bb65b0ac |
@@ -29,13 +29,7 @@ spec:
|
||||
- name: cmd
|
||||
value: "{{item}}"
|
||||
withItems:
|
||||
- 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"
|
||||
- dep ensure && make cli lint test
|
||||
- name: test-e2e
|
||||
template: ci-builder
|
||||
arguments:
|
||||
@@ -56,22 +50,12 @@ spec:
|
||||
container:
|
||||
image: argoproj/argo-cd-ci-builder:latest
|
||||
command: [sh, -c]
|
||||
args: ["mkfifo pipe; tee /tmp/logs.txt < pipe & {{inputs.parameters.cmd}} > pipe"]
|
||||
args: ["{{inputs.parameters.cmd}}"]
|
||||
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:
|
||||
@@ -86,7 +70,7 @@ spec:
|
||||
container:
|
||||
image: argoproj/argo-cd-ci-builder:latest
|
||||
command: [sh, -c]
|
||||
args: ["mkfifo pipe; tee /tmp/logs.txt < pipe & until docker ps; do sleep 3; done && {{inputs.parameters.cmd}} > pipe"]
|
||||
args: ["until docker ps; do sleep 3; done && {{inputs.parameters.cmd}}"]
|
||||
workingDir: /go/src/github.com/argoproj/argo-cd
|
||||
env:
|
||||
- name: DOCKER_HOST
|
||||
@@ -101,7 +85,4 @@ spec:
|
||||
securityContext:
|
||||
privileged: true
|
||||
mirrorVolumeMounts: true
|
||||
outputs:
|
||||
artifacts:
|
||||
- name: logs
|
||||
path: /tmp/logs.txt
|
||||
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -7,4 +7,3 @@ dist/
|
||||
# delve debug binaries
|
||||
cmd/**/debug
|
||||
debug.test
|
||||
coverage.out
|
||||
|
||||
160
CHANGELOG.md
160
CHANGELOG.md
@@ -1,165 +1,5 @@
|
||||
# Changelog
|
||||
|
||||
## v0.10.0 (TBD)
|
||||
|
||||
### Changes since v0.9:
|
||||
|
||||
+ Allow more fine-grained sync (issue #508)
|
||||
+ Display init container logs (issue #681)
|
||||
+ Redirect to /auth/login instead of /login when SSO token is used for authenticaion (issue #348)
|
||||
+ Support ability to use a helm values files from a URL (issue #624)
|
||||
+ Support public not-connected repo in app creation UI (issue #426)
|
||||
+ Use ksonnet CLI instead of ksonnet libs (issue #626)
|
||||
+ We should be able to select the order of the `yaml` files while creating a Helm App (#664)
|
||||
* Remove default params from app history (issue #556)
|
||||
* Update to ksonnet v0.13.0
|
||||
* Update to kustomize 1.0.8
|
||||
- API Server fails to return apps due to grpc max message size limit (issue #690)
|
||||
- App Creation UI for Helm Apps shows only files prefixed with `values-` (issue #663)
|
||||
- App creation UI should allow specifying values files outside of helm app directory bug (issue #658)
|
||||
- argocd-server logs credentials in plain text when adding git repositories (issue #653)
|
||||
- Azure Repos do not work as a repository (issue #643)
|
||||
- Better update conflict error handing during app editing (issue #685)
|
||||
- Cluster watch needs to be restarted when CRDs get created (issue #627)
|
||||
- Credentials not being accepted for Google Source Repositories (issue #651)
|
||||
- Default project is created without permission to deploy cluster level resources (issue #679)
|
||||
- Generate role token click resets policy changes (issue #655)
|
||||
- Input type text instead of password on Connect repo panel (issue #693)
|
||||
- Metrics endpoint not reachable through the metrics kubernetes service (issue #672)
|
||||
- Operation stuck in 'in progress' state if application has no resources (issue #682)
|
||||
- Project should influence options for cluster and namespace during app creation (issue #592)
|
||||
- Repo server unable to execute ls-remote for private repos (issue #639)
|
||||
- Resource is always out of sync if it has only 'ksonnet.io/component' label (issue #686)
|
||||
- Resource nodes are 'jumping' on app details page (issue #683)
|
||||
- Sync always suggest using latest revision instead of target UI bug (issue #669)
|
||||
- Temporary ignore service catalog resources (issue #650)
|
||||
|
||||
## v0.9.2 (2018-09-28)
|
||||
|
||||
* Update to kustomize 1.0.8
|
||||
- Fix issue where argocd-server logged credentials in plain text during repo add (issue #653)
|
||||
- Credentials not being accepted for Google Source Repositories (issue #651)
|
||||
- Azure Repos do not work as a repository (issue #643)
|
||||
- Temporary ignore service catalog resources (issue #650)
|
||||
- Normalize policies by always adding space after comma
|
||||
|
||||
## v0.9.1 (2018-09-24)
|
||||
|
||||
- Repo server unable to execute ls-remote for private repos (issue #639)
|
||||
|
||||
## v0.9.0 (2018-09-24)
|
||||
|
||||
### Notes about upgrading from v0.8
|
||||
* Cluster wide resources should be allowed in default project (due to issue #330):
|
||||
|
||||
```
|
||||
argocd project allow-cluster-resource default '*' '*'
|
||||
```
|
||||
|
||||
* Projects now provide the ability to allow or deny deployments of cluster-scoped resources
|
||||
(e.g. Namespaces, ClusterRoles, CustomResourceDefinitions). When upgrading from v0.8 to v0.9, to
|
||||
match the behavior of v0.8 (which did not have restrictions on deploying resources) and continue to
|
||||
allow deployment of cluster-scoped resources, an additional command should be run:
|
||||
|
||||
```bash
|
||||
argocd proj allow-cluster-resource default '*' '*'
|
||||
```
|
||||
|
||||
The above command allows the `default` project to deploy any cluster-scoped resources which matches
|
||||
the behavior of v0.8.
|
||||
|
||||
* The secret keys in the argocd-secret containing the TLS certificate and key, has been renamed from
|
||||
`server.crt` and `server.key` to the standard `tls.crt` and `tls.key` keys. This enables ArgoCD
|
||||
to integrate better with Ingress and cert-manager. When upgrading to v0.9, the `server.crt` and
|
||||
`server.key` keys in argocd-secret should be renamed to the new keys.
|
||||
|
||||
### Changes since v0.8:
|
||||
+ Auto-sync option in application CRD instance (issue #79)
|
||||
+ Support raw jsonnet as an application source (issue #540)
|
||||
+ Reorder K8s resources to correct creation order (issue #102)
|
||||
+ Redact K8s secrets from API server payloads (issue #470)
|
||||
+ Support --in-cluster authentication without providing a kubeconfig (issue #527)
|
||||
+ Special handling of CustomResourceDefinitions (issue #613)
|
||||
+ ArgoCD should download helm chart dependencies (issue #582)
|
||||
+ Export ArgoCD stats as prometheus style metrics (issue #513)
|
||||
+ Support restricting TLS version (issue #609)
|
||||
+ Use 'kubectl auth reconcile' before 'kubectl apply' (issue #523)
|
||||
+ Projects need controls on cluster-scoped resources (issue #330)
|
||||
+ Support IAM Authentication for managing external K8s clusters (issue #482)
|
||||
+ Compatibility with cert manager (issue #617)
|
||||
* Enable TLS for repo server (issue #553)
|
||||
* Split out dex into it's own deployment (instead of sidecar) (issue #555)
|
||||
+ [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)
|
||||
+ [UI] Project Role/Token management from UI (issue #548)
|
||||
+ [UI] App creation wizard should allow specifying source revision (issue #562)
|
||||
+ [UI] Ability to modify application from UI (issue #615)
|
||||
+ [UI] indicate when operation is in progress or has failed (issue #566)
|
||||
- Fix issue where changes were not pulled when tracking a branch (issue #567)
|
||||
- Lazy enforcement of unknown cluster/namespace restricted resources (issue #599)
|
||||
- Fix controller hot loop when app source contains bad manifests (issue #568)
|
||||
- Fix issue where ArgoCD fails to deploy when resources are in a K8s list format (issue #584)
|
||||
- Fix comparison failure when app contains unregistered custom resource (issue #583)
|
||||
- Fix issue where helm hooks were being deployed as part of sync (issue #605)
|
||||
- Fix race conditions in kube.GetResourcesWithLabel and DeleteResourceWithLabel (issue #587)
|
||||
- [UI] Fix issue where projects filter does not work when application got changed
|
||||
- [UI] Creating apps from directories is not obvious (issue #565)
|
||||
- Helm hooks are being deployed as resources (issue #605)
|
||||
- Disagreement in three way diff calculation (issue #597)
|
||||
- SIGSEGV in kube.GetResourcesWithLabel (issue #587)
|
||||
- ArgoCD fails to deploy resources list (issue #584)
|
||||
- Branch tracking not working properly (issue #567)
|
||||
- Controller hot loop when application source has bad manifests (issue #568)
|
||||
|
||||
## 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)
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ 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/).
|
||||
|
||||
136
Dockerfile
136
Dockerfile
@@ -1,136 +0,0 @@
|
||||
####################################################################################################
|
||||
# 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.13.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.11.0
|
||||
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.10
|
||||
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
|
||||
|
||||
ENV AWS_IAM_AUTHENTICATOR_VERSION=0.3.0
|
||||
RUN curl -L -o /usr/local/bin/aws-iam-authenticator https://github.com/kubernetes-sigs/aws-iam-authenticator/releases/download/v0.3.0/heptio-authenticator-aws_${AWS_IAM_AUTHENTICATOR_VERSION}_linux_amd64 && \
|
||||
chmod +x /usr/local/bin/aws-iam-authenticator
|
||||
|
||||
|
||||
####################################################################################################
|
||||
# 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
|
||||
COPY --from=builder /usr/local/bin/aws-iam-authenticator /usr/local/bin/aws-iam-authenticator
|
||||
|
||||
# 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}
|
||||
88
Dockerfile-argocd
Normal file
88
Dockerfile-argocd
Normal file
@@ -0,0 +1,88 @@
|
||||
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}
|
||||
28
Dockerfile-ci-builder
Normal file
28
Dockerfile-ci-builder
Normal file
@@ -0,0 +1,28 @@
|
||||
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
|
||||
499
Gopkg.lock
generated
499
Gopkg.lock
generated
@@ -9,6 +9,16 @@
|
||||
revision = "767c40d6a2e058483c25fa193e963a22da17236d"
|
||||
version = "v0.18.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:6204a59b379aadf05380cf8cf3ae0f5867588ba028fe84f260312a79ae717272"
|
||||
name = "github.com/GeertJohan/go.rice"
|
||||
packages = [
|
||||
".",
|
||||
"embedded",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "c02ca9a983da5807ddf7d796784928f5be4afd09"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:8ec1618fc3ee146af104d6c13be250f25e5976e34557d4afbfe4b28035ce6c05"
|
||||
name = "github.com/Knetic/govaluate"
|
||||
@@ -33,26 +43,15 @@
|
||||
revision = "de5bf2ad457846296e2031421a34e2568e304e35"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:0caf9208419fa5db5a0ca7112affaa9550c54291dda8e2abac0c0e76181c959e"
|
||||
digest = "1:26a8fd03a1fb25aa92c58080d8ca76363d56694c148f6175266e0393c0d2e729"
|
||||
name = "github.com/argoproj/argo"
|
||||
packages = [
|
||||
"pkg/apis/workflow",
|
||||
"pkg/apis/workflow/v1alpha1",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "7ef1cea68c94f7f0e1e2f8bd75bedc5a7df8af90"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:f624a361a427f4c9853f1d4d0bd47dff8323cef0054708d8df56cefe03ce4ac5"
|
||||
name = "github.com/argoproj/pkg"
|
||||
packages = [
|
||||
"exec",
|
||||
"time",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "fc8a50f323ce16f93a34632f7abf780977386fe8"
|
||||
revision = "ac241c95c13f08e868cd6f5ee32c9ce273e239ff"
|
||||
version = "v2.1.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:d8a2bb36a048d1571bcc1aee208b61f39dc16c6c53823feffd37449dde162507"
|
||||
@@ -63,12 +62,12 @@
|
||||
version = "v9"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:c0bec5f9b98d0bc872ff5e834fac186b807b656683bd29cb82fb207a1513fabb"
|
||||
name = "github.com/beorn7/perks"
|
||||
packages = ["quantile"]
|
||||
digest = "1:79421244ba5848aae4b0a5c41e633a04e4894cb0b164a219dc8c15ec7facb7f1"
|
||||
name = "github.com/blang/semver"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "3a771d992973f24aa725d07868b467d1ddfceafb"
|
||||
revision = "2ee87856327ba09384cabd113bc6b5d174e9ec0f"
|
||||
version = "v3.5.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:e04162bd6a6d4950541bae744c968108e14913b1cebccf29f7650b573f44adb3"
|
||||
@@ -104,6 +103,14 @@
|
||||
pruneopts = ""
|
||||
revision = "1180514eaf4d9f38d0d19eef639a1d695e066e72"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:5fd5c4d4282935b7a575299494f2c09e9d2cacded7815c83aff7c1602aff3154"
|
||||
name = "github.com/daaku/go.zipexe"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "a5fe2436ffcb3236e175e5149162b41cd28bd27d"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:56c130d885a4aacae1dd9c7b71cfe39912c7ebc1ff7d2b46083c8812996dc43b"
|
||||
name = "github.com/davecgh/go-spew"
|
||||
@@ -120,14 +127,6 @@
|
||||
revision = "06ea1031745cb8b3dab3f6a236daf2b0aa468b7e"
|
||||
version = "v3.2.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:f1a75a8e00244e5ea77ff274baa9559eb877437b240ee7b278f3fc560d9f08bf"
|
||||
name = "github.com/dustin/go-humanize"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "9f541cc9db5d55bce703bd99987c9d5cb8eea45e"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:971e9ba63a417c5f1f83ab358677bc59e96ff04285f26c6646ff089fb60b15e8"
|
||||
name = "github.com/emicklei/go-restful"
|
||||
@@ -139,21 +138,6 @@
|
||||
revision = "3658237ded108b4134956c1b3050349d93e7b895"
|
||||
version = "v2.7.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:ba7c75e38d81b9cf3e8601c081567be3b71bccca8c11aee5de98871360aa4d7b"
|
||||
name = "github.com/emirpasic/gods"
|
||||
packages = [
|
||||
"containers",
|
||||
"lists",
|
||||
"lists/arraylist",
|
||||
"trees",
|
||||
"trees/binaryheap",
|
||||
"utils",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "f6c17b524822278a87e3b3bd809fec33b51f5b46"
|
||||
version = "v1.9.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:b13707423743d41665fd23f0c36b2f37bb49c30e94adb813319c44188a51ba22"
|
||||
name = "github.com/ghodss/yaml"
|
||||
@@ -287,7 +271,7 @@
|
||||
version = "v1.11.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:6e73003ecd35f4487a5e88270d3ca0a81bc80dc88053ac7e4dcfec5fba30d918"
|
||||
digest = "1:0a3f6a0c68ab8f3d455f8892295503b179e571b7fefe47cc6c556405d1f83411"
|
||||
name = "github.com/gogo/protobuf"
|
||||
packages = [
|
||||
"gogoproto",
|
||||
@@ -311,7 +295,6 @@
|
||||
"protoc-gen-gofast",
|
||||
"protoc-gen-gogo/descriptor",
|
||||
"protoc-gen-gogo/generator",
|
||||
"protoc-gen-gogo/generator/internal/remap",
|
||||
"protoc-gen-gogo/grpc",
|
||||
"protoc-gen-gogo/plugin",
|
||||
"protoc-gen-gogofast",
|
||||
@@ -320,8 +303,8 @@
|
||||
"vanity/command",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "636bf0302bc95575d69441b25a2603156ffdddf1"
|
||||
version = "v1.1.1"
|
||||
revision = "1adfc126b41513cc696b209667c8656ea7aac67c"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
@@ -332,7 +315,8 @@
|
||||
revision = "23def4e6c14b4da8ac2ed8007337bc5eb5007998"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:3dd078fda7500c341bc26cfbc6c6a34614f295a2457149fc1045cab767cbcf18"
|
||||
branch = "master"
|
||||
digest = "1:27828cf74799ad14fcafece9f78f350cdbcd4fbe92c14ad4cba256fbbfa328ef"
|
||||
name = "github.com/golang/protobuf"
|
||||
packages = [
|
||||
"jsonpb",
|
||||
@@ -340,7 +324,6 @@
|
||||
"protoc-gen-go",
|
||||
"protoc-gen-go/descriptor",
|
||||
"protoc-gen-go/generator",
|
||||
"protoc-gen-go/generator/internal/remap",
|
||||
"protoc-gen-go/grpc",
|
||||
"protoc-gen-go/plugin",
|
||||
"ptypes",
|
||||
@@ -351,16 +334,7 @@
|
||||
"ptypes/timestamp",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5"
|
||||
version = "v1.2.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:1e5b1e14524ed08301977b7b8e10c719ed853cbf3f24ecb66fae783a46f207a6"
|
||||
name = "github.com/google/btree"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "4030bb1f1f0c35b30ca7009e9ebd06849dd45306"
|
||||
revision = "e09c5db296004fbe3f74490e84dcd62c3c5ddb1b"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:14d826ee25139b4674e9768ac287a135f4e7c14e1134a5b15e4e152edfd49f41"
|
||||
@@ -393,17 +367,6 @@
|
||||
revision = "ee43cbb60db7bd22502942cccbc39059117352ab"
|
||||
version = "v0.1.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:009a1928b8c096338b68b5822d838a72b4d8520715c1463614476359f3282ec8"
|
||||
name = "github.com/gregjones/httpcache"
|
||||
packages = [
|
||||
".",
|
||||
"diskcache",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "9cad4c3443a7200dd6400aef47183728de563a38"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:9dca8c981b8aed7448d94e78bc68a76784867a38b3036d5aabc0b32d92ffd1f4"
|
||||
@@ -452,6 +415,14 @@
|
||||
pruneopts = ""
|
||||
revision = "0fb14efe8c47ae851c0034ed7a448854d3d34cf3"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:f81c8d7354cc0c6340f2f7a48724ee6c2b3db3e918ecd441c985b4d2d97dd3e7"
|
||||
name = "github.com/howeyc/gopass"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "bf9dde6d0d2c004a008c27aaee91170c786f6db8"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:23bc0b496ba341c6e3ba24d6358ff4a40a704d9eb5f9a3bd8e8fbd57ad869013"
|
||||
name = "github.com/imdario/mergo"
|
||||
@@ -469,35 +440,58 @@
|
||||
version = "v1.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:95abc4eba158a39873bd4fabdee576d0ae13826b550f8b710881d80ae4093a0f"
|
||||
name = "github.com/jbenet/go-context"
|
||||
packages = ["io"]
|
||||
pruneopts = ""
|
||||
revision = "d14ea06fba99483203c19d92cfcd13ebe73135f4"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:31c6f3c4f1e15fcc24fcfc9f5f24603ff3963c56d6fa162116493b4025fb6acc"
|
||||
digest = "1:dd5cdbd84daf24b2a009364f3c24859b1e4de1eab87c451fb3bce09935d909fc"
|
||||
name = "github.com/json-iterator/go"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "f2b4162afba35581b6d4a50d3b8f34e33c144682"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:41e0bed5df4f9fd04c418bf9b6b7179b3671e416ad6175332601ca1c8dc74606"
|
||||
name = "github.com/kevinburke/ssh_config"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "81db2a75821ed34e682567d48be488a1c3121088"
|
||||
version = "0.5"
|
||||
revision = "e7c7f3b33712573affdcc7a107218e7926b9a05b"
|
||||
version = "1.0.6"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:448b4a6e39e46d8740b00dc871f26d58dc39341b160e01267b7917132831a136"
|
||||
name = "github.com/konsorten/go-windows-terminal-sequences"
|
||||
digest = "1:2c5ad58492804c40bdaf5d92039b0cde8b5becd2b7feeb37d7d1cc36a8aa8dbe"
|
||||
name = "github.com/kardianos/osext"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "b729f2633dfe35f4d1d8a32385f6685610ce1cb5"
|
||||
revision = "ae77be60afb1dcacde03767a8c37337fad28ac14"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:2fe45da14d25bce0a58c5a991967149cc5d07f94be327b928a9fd306466815a3"
|
||||
name = "github.com/ksonnet/ksonnet"
|
||||
packages = [
|
||||
"metadata/params",
|
||||
"pkg/app",
|
||||
"pkg/component",
|
||||
"pkg/docparser",
|
||||
"pkg/lib",
|
||||
"pkg/log",
|
||||
"pkg/node",
|
||||
"pkg/params",
|
||||
"pkg/prototype",
|
||||
"pkg/schema",
|
||||
"pkg/util/jsonnet",
|
||||
"pkg/util/kslib",
|
||||
"pkg/util/strings",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "e943ae55d4fe256c8330a047ce8426ad9dac110c"
|
||||
version = "v0.11.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:a165d7829bc54ec7952629870058b748512edb2fcbe244aba797d8de31bb4f03"
|
||||
name = "github.com/ksonnet/ksonnet-lib"
|
||||
packages = [
|
||||
"ksonnet-gen/astext",
|
||||
"ksonnet-gen/jsonnet",
|
||||
"ksonnet-gen/ksonnet",
|
||||
"ksonnet-gen/kubespec",
|
||||
"ksonnet-gen/kubeversion",
|
||||
"ksonnet-gen/nodemaker",
|
||||
"ksonnet-gen/printer",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "dfcaa3d01d0c4948cb596403c35e966c774f2678"
|
||||
version = "v0.1.8"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
@@ -511,22 +505,6 @@
|
||||
pruneopts = ""
|
||||
revision = "32fa128f234d041f196a9f3e0fea5ac9772c08e1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:63722a4b1e1717be7b98fc686e0b30d5e7f734b9e93d7dee86293b6deab7ea28"
|
||||
name = "github.com/matttproud/golang_protobuf_extensions"
|
||||
packages = ["pbutil"]
|
||||
pruneopts = ""
|
||||
revision = "c12348ce28de40eed0136aa2b644d0ee0650e56c"
|
||||
version = "v1.0.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:096a8a9182648da3d00ff243b88407838902b6703fc12657f76890e08d1899bf"
|
||||
name = "github.com/mitchellh/go-homedir"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "ae18d6b8b3205b561c79e8e5f69bff09736185f4"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:eb9117392ee8e7aa44f78e0db603f70b1050ee0ebda4bd40040befb5b218c546"
|
||||
@@ -535,22 +513,6 @@
|
||||
pruneopts = ""
|
||||
revision = "bb74f1db0675b241733089d5a1faa5dd8b0ef57b"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:0c0ff2a89c1bb0d01887e1dac043ad7efbf3ec77482ef058ac423d13497e16fd"
|
||||
name = "github.com/modern-go/concurrent"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "bacd9c7ef1dd9b15be4a9909b8ac7a4e313eec94"
|
||||
version = "1.0.3"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:e32bdbdb7c377a07a9a46378290059822efdce5c8d96fe71940d87cb4f918855"
|
||||
name = "github.com/modern-go/reflect2"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "4b7aa43c6742a2c18fdef89dd197aaae7dac7ccd"
|
||||
version = "1.0.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:4c0404dc03d974acd5fcd8b8d3ce687b13bd169db032b89275e8b9d77b98ce8c"
|
||||
name = "github.com/patrickmn/go-cache"
|
||||
@@ -559,30 +521,6 @@
|
||||
revision = "a3647f8e31d79543b2d0f0ae2fe5c379d72cedc0"
|
||||
version = "v2.1.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:049b5bee78dfdc9628ee0e557219c41f683e5b06c5a5f20eaba0105ccc586689"
|
||||
name = "github.com/pelletier/go-buffruneio"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "c37440a7cf42ac63b919c752ca73a85067e05992"
|
||||
version = "v0.2.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:c24598ffeadd2762552269271b3b1510df2d83ee6696c1e543a0ff653af494bc"
|
||||
name = "github.com/petar/GoLLRB"
|
||||
packages = ["llrb"]
|
||||
pruneopts = ""
|
||||
revision = "53be0d36a84c2a886ca057d34b6aa4468df9ccb4"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:b46305723171710475f2dd37547edd57b67b9de9f2a6267cafdd98331fd6897f"
|
||||
name = "github.com/peterbourgon/diskv"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "5f041e8faa004a95c88a202771f4cc3e991971e6"
|
||||
version = "v2.0.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:7365acd48986e205ccb8652cc746f09c8b7876030d53710ea6ef7d0bd0dcd7ca"
|
||||
name = "github.com/pkg/errors"
|
||||
@@ -610,50 +548,6 @@
|
||||
pruneopts = ""
|
||||
revision = "525d0eb5f91d30e3b1548de401b7ef9ea6898520"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:9d34d575593e3dd27bbd119138ba009ef1535a0df2aad7259e1dd5aed7405eea"
|
||||
name = "github.com/prometheus/client_golang"
|
||||
packages = [
|
||||
"prometheus",
|
||||
"prometheus/internal",
|
||||
"prometheus/promhttp",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "7858729281ec582767b20e0d696b6041d995d5e0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:185cf55b1f44a1bf243558901c3f06efa5c64ba62cfdcbb1bf7bbe8c3fb68561"
|
||||
name = "github.com/prometheus/client_model"
|
||||
packages = ["go"]
|
||||
pruneopts = ""
|
||||
revision = "5c3871d89910bfb32f5fcab2aa4b9ec68e65a99f"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:f477ef7b65d94fb17574fc6548cef0c99a69c1634ea3b6da248b63a61ebe0498"
|
||||
name = "github.com/prometheus/common"
|
||||
packages = [
|
||||
"expfmt",
|
||||
"internal/bitbucket.org/ww/goautoneg",
|
||||
"model",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "c7de2306084e37d54b8be01f3541a8464345e9a5"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:e04aaa0e8f8da0ed3d6c0700bd77eda52a47f38510063209d72d62f0ef807d5e"
|
||||
name = "github.com/prometheus/procfs"
|
||||
packages = [
|
||||
".",
|
||||
"internal/util",
|
||||
"nfs",
|
||||
"xfs",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "05ee40e3a273f7245e8777337fc7b46e533a9a92"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:1ee3e3e12ffdb5ba70b918148685cab6340bbc0d03ba723bcb46062d1bea69c6"
|
||||
@@ -671,12 +565,11 @@
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:01d968ff6535945510c944983eee024e81f1c949043e9bbfe5ab206ebc3588a4"
|
||||
digest = "1:c92f01303e3ab3b5da92657841639cb53d1548f0d2733d12ef3b9fd9d47c869e"
|
||||
name = "github.com/sirupsen/logrus"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "a67f783a3814b8729bd2dac5780b5f78f8dbd64d"
|
||||
version = "v1.1.0"
|
||||
revision = "ea8897e79973357ba785ac2533559a6297e83c44"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
@@ -694,6 +587,16 @@
|
||||
revision = "e09e9389d85d8492d313d73d1469c029e710623f"
|
||||
version = "v0.1.4"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:a35a4db30a6094deac33fdb99de9ed99fefc39a7bf06b57d9f04bcaa425bb183"
|
||||
name = "github.com/spf13/afero"
|
||||
packages = [
|
||||
".",
|
||||
"mem",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "9be650865eab0c12963d8753212f4f9c66cdcf12"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:2208a80fc3259291e43b30f42f844d18f4218036dff510f42c653ec9890d460a"
|
||||
name = "github.com/spf13/cobra"
|
||||
@@ -708,19 +611,7 @@
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "e57e3eeb33f795204c1ca35f56c44f83227c6e66"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:b1861b9a1aa0801b0b62945ed7477c1ab61a4bd03b55dfbc27f6d4f378110c8c"
|
||||
name = "github.com/src-d/gcfg"
|
||||
packages = [
|
||||
".",
|
||||
"scanner",
|
||||
"token",
|
||||
"types",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "f187355171c936ac84a82793659ebb4936bc1c23"
|
||||
version = "v1.3.0"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:306417ea2f31ea733df356a2b895de63776b6a5107085b33458e5cd6eb1d584d"
|
||||
@@ -731,15 +622,15 @@
|
||||
version = "v0.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:c587772fb8ad29ad4db67575dad25ba17a51f072ff18a22b4f0257a4d9c24f75"
|
||||
digest = "1:a30066593578732a356dc7e5d7f78d69184ca65aeeff5939241a3ab10559bb06"
|
||||
name = "github.com/stretchr/testify"
|
||||
packages = [
|
||||
"assert",
|
||||
"mock",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "f35b8ab0b5a2cef36673838d662e249dd9c94686"
|
||||
version = "v1.2.2"
|
||||
revision = "12b6f73e6084dad08a7c6e575284b177ecafbc71"
|
||||
version = "v1.2.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:51cf0fca93f4866709ceaf01b750e51d997c299a7bd2edf7ccd79e3b428754ae"
|
||||
@@ -752,14 +643,6 @@
|
||||
revision = "a053f3dac71df214bfe8b367f34220f0029c9c02"
|
||||
version = "v3.3.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:afc0b8068986a01e2d8f449917829753a54f6bd4d1265c2b4ad9cba75560020f"
|
||||
name = "github.com/xanzy/ssh-agent"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "640f0ab560aeb89d523bb6ac322b1244d5c3796c"
|
||||
version = "v0.2.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:529ed3f98838f69e13761788d0cc71b44e130058fab13bae2ce09f7a176bced4"
|
||||
name = "github.com/yudai/gojsondiff"
|
||||
@@ -786,21 +669,8 @@
|
||||
packages = [
|
||||
"bcrypt",
|
||||
"blowfish",
|
||||
"cast5",
|
||||
"curve25519",
|
||||
"ed25519",
|
||||
"ed25519/internal/edwards25519",
|
||||
"internal/chacha20",
|
||||
"openpgp",
|
||||
"openpgp/armor",
|
||||
"openpgp/elgamal",
|
||||
"openpgp/errors",
|
||||
"openpgp/packet",
|
||||
"openpgp/s2k",
|
||||
"poly1305",
|
||||
"ssh",
|
||||
"ssh/agent",
|
||||
"ssh/knownhosts",
|
||||
"ssh/terminal",
|
||||
]
|
||||
pruneopts = ""
|
||||
@@ -838,22 +708,22 @@
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:b2ea75de0ccb2db2ac79356407f8a4cd8f798fe15d41b381c00abf3ae8e55ed1"
|
||||
digest = "1:8aad4e360d6645abe564e925bd6d8d3b94975e52ce68af0c28f91b5aedb0637f"
|
||||
name = "golang.org/x/sync"
|
||||
packages = ["errgroup"]
|
||||
pruneopts = ""
|
||||
revision = "1d60e4601c6fd243af51cc01ddf169918a5407ca"
|
||||
revision = "fd80eb99c8f653c847d294a001bdf2a3a6f768f5"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:ed900376500543ca05f2a2383e1f541b4606f19cd22f34acb81b17a0b90c7f3e"
|
||||
digest = "1:407b5f905024dd94ee08c1777fabb380fb3d380f92a7f7df2592be005337eeb3"
|
||||
name = "golang.org/x/sys"
|
||||
packages = [
|
||||
"unix",
|
||||
"windows",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "d0be0721c37eeb5299f245a996a483160fc36940"
|
||||
revision = "37707fdb30a5b38865cfb95e5aab41707daec7fd"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
@@ -930,7 +800,7 @@
|
||||
revision = "2b5a72b8730b0b16380010cfe5286c42108d88e7"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:15656947b87a6a240e61dcfae9e71a55a8d5677f240d12ab48f02cdbabf1e309"
|
||||
digest = "1:d2dc833c73202298c92b63a7e180e2b007b5a3c3c763e3b9fe1da249b5c7f5b9"
|
||||
name = "google.golang.org/grpc"
|
||||
packages = [
|
||||
".",
|
||||
@@ -942,13 +812,9 @@
|
||||
"credentials",
|
||||
"encoding",
|
||||
"encoding/proto",
|
||||
"grpclb/grpc_lb_v1/messages",
|
||||
"grpclog",
|
||||
"internal",
|
||||
"internal/backoff",
|
||||
"internal/channelz",
|
||||
"internal/envconfig",
|
||||
"internal/grpcrand",
|
||||
"internal/transport",
|
||||
"keepalive",
|
||||
"metadata",
|
||||
"naming",
|
||||
@@ -961,10 +827,11 @@
|
||||
"stats",
|
||||
"status",
|
||||
"tap",
|
||||
"transport",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "8dea3dc473e90c8179e519d91302d0597c0ca1d1"
|
||||
version = "v1.15.0"
|
||||
revision = "8e4536a86ab602859c20df5ebfd0bd4228d08655"
|
||||
version = "v1.10.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:bf7444e1e6a36e633f4f1624a67b9e4734cfb879c27ac0a2082ac16aff8462ac"
|
||||
@@ -1010,77 +877,6 @@
|
||||
revision = "76dd09796242edb5b897103a75df2645c028c960"
|
||||
version = "v2.1.6"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:c8f3ff1edaf7208bf7633e5952ffb8d697552343f8010aee12427400b434ae63"
|
||||
name = "gopkg.in/src-d/go-billy.v4"
|
||||
packages = [
|
||||
".",
|
||||
"helper/chroot",
|
||||
"helper/polyfill",
|
||||
"osfs",
|
||||
"util",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "59952543636f55de3f860b477b615093d5c2c3e4"
|
||||
version = "v4.2.1"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:a77c60b21f224f0ddc9c7e9407008c6e7dfbca88e5a6e827aa27ecf80497ebb6"
|
||||
name = "gopkg.in/src-d/go-git.v4"
|
||||
packages = [
|
||||
".",
|
||||
"config",
|
||||
"internal/revision",
|
||||
"plumbing",
|
||||
"plumbing/cache",
|
||||
"plumbing/filemode",
|
||||
"plumbing/format/config",
|
||||
"plumbing/format/diff",
|
||||
"plumbing/format/gitignore",
|
||||
"plumbing/format/idxfile",
|
||||
"plumbing/format/index",
|
||||
"plumbing/format/objfile",
|
||||
"plumbing/format/packfile",
|
||||
"plumbing/format/pktline",
|
||||
"plumbing/object",
|
||||
"plumbing/protocol/packp",
|
||||
"plumbing/protocol/packp/capability",
|
||||
"plumbing/protocol/packp/sideband",
|
||||
"plumbing/revlist",
|
||||
"plumbing/storer",
|
||||
"plumbing/transport",
|
||||
"plumbing/transport/client",
|
||||
"plumbing/transport/file",
|
||||
"plumbing/transport/git",
|
||||
"plumbing/transport/http",
|
||||
"plumbing/transport/internal/common",
|
||||
"plumbing/transport/server",
|
||||
"plumbing/transport/ssh",
|
||||
"storage",
|
||||
"storage/filesystem",
|
||||
"storage/filesystem/dotgit",
|
||||
"storage/memory",
|
||||
"utils/binary",
|
||||
"utils/diff",
|
||||
"utils/ioutil",
|
||||
"utils/merkletrie",
|
||||
"utils/merkletrie/filesystem",
|
||||
"utils/merkletrie/index",
|
||||
"utils/merkletrie/internal/frame",
|
||||
"utils/merkletrie/noder",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "d3cec13ac0b195bfb897ed038a08b5130ab9969e"
|
||||
version = "v4.7.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:ceec7e96590fb8168f36df4795fefe17051d4b0c2acc7ec4e260d8138c4dafac"
|
||||
name = "gopkg.in/warnings.v0"
|
||||
packages = ["."]
|
||||
pruneopts = ""
|
||||
revision = "ec4a0fea49c7b46c2aeb0b51aac55779c607e52b"
|
||||
version = "v0.1.2"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:81314a486195626940617e43740b4fa073f265b0715c9f54ce2027fee1cb5f61"
|
||||
name = "gopkg.in/yaml.v2"
|
||||
@@ -1089,8 +885,8 @@
|
||||
revision = "eb3733d160e74a9c7e442f435eb3bea458e1d19f"
|
||||
|
||||
[[projects]]
|
||||
branch = "release-1.12"
|
||||
digest = "1:ed04c5203ecbf6358fb6a774b0ecd40ea992d6dcc42adc1d3b7cf9eceb66b6c8"
|
||||
branch = "release-1.10"
|
||||
digest = "1:5beb32094452970c0d73a2bdacd79aa9cfaa4947a774d521c1bed4b4c2705f15"
|
||||
name = "k8s.io/api"
|
||||
packages = [
|
||||
"admission/v1beta1",
|
||||
@@ -1105,12 +901,10 @@
|
||||
"authorization/v1beta1",
|
||||
"autoscaling/v1",
|
||||
"autoscaling/v2beta1",
|
||||
"autoscaling/v2beta2",
|
||||
"batch/v1",
|
||||
"batch/v1beta1",
|
||||
"batch/v2alpha1",
|
||||
"certificates/v1beta1",
|
||||
"coordination/v1beta1",
|
||||
"core/v1",
|
||||
"events/v1beta1",
|
||||
"extensions/v1beta1",
|
||||
@@ -1121,18 +915,17 @@
|
||||
"rbac/v1alpha1",
|
||||
"rbac/v1beta1",
|
||||
"scheduling/v1alpha1",
|
||||
"scheduling/v1beta1",
|
||||
"settings/v1alpha1",
|
||||
"storage/v1",
|
||||
"storage/v1alpha1",
|
||||
"storage/v1beta1",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "475331a8afff5587f47d0470a93f79c60c573c03"
|
||||
revision = "8b7507fac302640dd5f1efbf9643199952cc58db"
|
||||
|
||||
[[projects]]
|
||||
branch = "release-1.12"
|
||||
digest = "1:39be82077450762b5e14b5268e679a14ac0e9c7d3286e2fcface437556a29e4c"
|
||||
branch = "release-1.10"
|
||||
digest = "1:7cb811fe9560718bd0ada29f2091acab5c4b4380ed23ef2824f64ce7038d899e"
|
||||
name = "k8s.io/apiextensions-apiserver"
|
||||
packages = [
|
||||
"pkg/apis/apiextensions",
|
||||
@@ -1142,17 +935,20 @@
|
||||
"pkg/client/clientset/clientset/typed/apiextensions/v1beta1",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "ca1024863b48cf0701229109df75ac5f0bb4907e"
|
||||
revision = "b13a681559816a9c14f93086bbeeed1c7baf2bcb"
|
||||
|
||||
[[projects]]
|
||||
branch = "release-1.12"
|
||||
digest = "1:5899da40e41bcc8c1df101b72954096bba9d85b763bc17efc846062ccc111c7b"
|
||||
branch = "release-1.10"
|
||||
digest = "1:b9c6e8e91bab6a419c58a63377532782a9f5616552164c38a9527f91c9309bbe"
|
||||
name = "k8s.io/apimachinery"
|
||||
packages = [
|
||||
"pkg/api/equality",
|
||||
"pkg/api/errors",
|
||||
"pkg/api/meta",
|
||||
"pkg/api/resource",
|
||||
"pkg/apimachinery",
|
||||
"pkg/apimachinery/announced",
|
||||
"pkg/apimachinery/registered",
|
||||
"pkg/apis/meta/internalversion",
|
||||
"pkg/apis/meta/v1",
|
||||
"pkg/apis/meta/v1/unstructured",
|
||||
@@ -1179,7 +975,6 @@
|
||||
"pkg/util/intstr",
|
||||
"pkg/util/json",
|
||||
"pkg/util/mergepatch",
|
||||
"pkg/util/naming",
|
||||
"pkg/util/net",
|
||||
"pkg/util/runtime",
|
||||
"pkg/util/sets",
|
||||
@@ -1194,11 +989,11 @@
|
||||
"third_party/forked/golang/reflect",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "f71dbbc36e126f5a371b85f6cca96bc8c57db2b6"
|
||||
revision = "f6313580a4d36c7c74a3d845dda6e116642c4f90"
|
||||
|
||||
[[projects]]
|
||||
branch = "release-9.0"
|
||||
digest = "1:77bf3d9f18ec82e08ac6c4c7e2d9d1a2ef8d16b25d3ff72fcefcf9256d751573"
|
||||
branch = "release-7.0"
|
||||
digest = "1:3a45889089f89cc371fb45b3f8a478248b755e4af17a8cf592e49bdf3481a0b3"
|
||||
name = "k8s.io/client-go"
|
||||
packages = [
|
||||
"discovery",
|
||||
@@ -1216,15 +1011,12 @@
|
||||
"informers/autoscaling",
|
||||
"informers/autoscaling/v1",
|
||||
"informers/autoscaling/v2beta1",
|
||||
"informers/autoscaling/v2beta2",
|
||||
"informers/batch",
|
||||
"informers/batch/v1",
|
||||
"informers/batch/v1beta1",
|
||||
"informers/batch/v2alpha1",
|
||||
"informers/certificates",
|
||||
"informers/certificates/v1beta1",
|
||||
"informers/coordination",
|
||||
"informers/coordination/v1beta1",
|
||||
"informers/core",
|
||||
"informers/core/v1",
|
||||
"informers/events",
|
||||
@@ -1242,7 +1034,6 @@
|
||||
"informers/rbac/v1beta1",
|
||||
"informers/scheduling",
|
||||
"informers/scheduling/v1alpha1",
|
||||
"informers/scheduling/v1beta1",
|
||||
"informers/settings",
|
||||
"informers/settings/v1alpha1",
|
||||
"informers/storage",
|
||||
@@ -1274,8 +1065,6 @@
|
||||
"kubernetes/typed/autoscaling/v1/fake",
|
||||
"kubernetes/typed/autoscaling/v2beta1",
|
||||
"kubernetes/typed/autoscaling/v2beta1/fake",
|
||||
"kubernetes/typed/autoscaling/v2beta2",
|
||||
"kubernetes/typed/autoscaling/v2beta2/fake",
|
||||
"kubernetes/typed/batch/v1",
|
||||
"kubernetes/typed/batch/v1/fake",
|
||||
"kubernetes/typed/batch/v1beta1",
|
||||
@@ -1284,8 +1073,6 @@
|
||||
"kubernetes/typed/batch/v2alpha1/fake",
|
||||
"kubernetes/typed/certificates/v1beta1",
|
||||
"kubernetes/typed/certificates/v1beta1/fake",
|
||||
"kubernetes/typed/coordination/v1beta1",
|
||||
"kubernetes/typed/coordination/v1beta1/fake",
|
||||
"kubernetes/typed/core/v1",
|
||||
"kubernetes/typed/core/v1/fake",
|
||||
"kubernetes/typed/events/v1beta1",
|
||||
@@ -1304,8 +1091,6 @@
|
||||
"kubernetes/typed/rbac/v1beta1/fake",
|
||||
"kubernetes/typed/scheduling/v1alpha1",
|
||||
"kubernetes/typed/scheduling/v1alpha1/fake",
|
||||
"kubernetes/typed/scheduling/v1beta1",
|
||||
"kubernetes/typed/scheduling/v1beta1/fake",
|
||||
"kubernetes/typed/settings/v1alpha1",
|
||||
"kubernetes/typed/settings/v1alpha1/fake",
|
||||
"kubernetes/typed/storage/v1",
|
||||
@@ -1321,12 +1106,10 @@
|
||||
"listers/apps/v1beta2",
|
||||
"listers/autoscaling/v1",
|
||||
"listers/autoscaling/v2beta1",
|
||||
"listers/autoscaling/v2beta2",
|
||||
"listers/batch/v1",
|
||||
"listers/batch/v1beta1",
|
||||
"listers/batch/v2alpha1",
|
||||
"listers/certificates/v1beta1",
|
||||
"listers/coordination/v1beta1",
|
||||
"listers/core/v1",
|
||||
"listers/events/v1beta1",
|
||||
"listers/extensions/v1beta1",
|
||||
@@ -1336,14 +1119,12 @@
|
||||
"listers/rbac/v1alpha1",
|
||||
"listers/rbac/v1beta1",
|
||||
"listers/scheduling/v1alpha1",
|
||||
"listers/scheduling/v1beta1",
|
||||
"listers/settings/v1alpha1",
|
||||
"listers/storage/v1",
|
||||
"listers/storage/v1alpha1",
|
||||
"listers/storage/v1beta1",
|
||||
"pkg/apis/clientauthentication",
|
||||
"pkg/apis/clientauthentication/v1alpha1",
|
||||
"pkg/apis/clientauthentication/v1beta1",
|
||||
"pkg/version",
|
||||
"plugin/pkg/client/auth/exec",
|
||||
"plugin/pkg/client/auth/gcp",
|
||||
@@ -1364,7 +1145,6 @@
|
||||
"transport",
|
||||
"util/buffer",
|
||||
"util/cert",
|
||||
"util/connrotation",
|
||||
"util/flowcontrol",
|
||||
"util/homedir",
|
||||
"util/integer",
|
||||
@@ -1373,11 +1153,11 @@
|
||||
"util/workqueue",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "13596e875accbd333e0b5bd5fd9462185acd9958"
|
||||
revision = "26a26f55b28aa1b338fbaf6fbbe0bcd76aed05e0"
|
||||
|
||||
[[projects]]
|
||||
branch = "release-1.12"
|
||||
digest = "1:e6fffdf0dfeb0d189a7c6d735e76e7564685d3b6513f8b19d3651191cb6b084b"
|
||||
branch = "release-1.10"
|
||||
digest = "1:34b0b3400ffdc2533ed4ea23721956638c2776ba49ca4c5def71dddcf0cdfd9b"
|
||||
name = "k8s.io/code-generator"
|
||||
packages = [
|
||||
"cmd/go-to-protobuf",
|
||||
@@ -1386,7 +1166,7 @@
|
||||
"third_party/forked/golang/reflect",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "3dcf91f64f638563e5106f21f50c31fa361c918d"
|
||||
revision = "9de8e796a74d16d2a285165727d04c185ebca6dc"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
@@ -1414,7 +1194,7 @@
|
||||
revision = "50ae88d24ede7b8bad68e23c805b5d3da5c8abaf"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:6061aa42761235df375f20fa4a1aa6d1845cba3687575f3adb2ef3f3bc540af5"
|
||||
digest = "1:ad247ab9725165a7f289779d46747da832e33a4efe8ae264461afc571f65dac8"
|
||||
name = "k8s.io/kubernetes"
|
||||
packages = [
|
||||
"pkg/apis/apps",
|
||||
@@ -1423,26 +1203,22 @@
|
||||
"pkg/apis/core",
|
||||
"pkg/apis/extensions",
|
||||
"pkg/apis/networking",
|
||||
"pkg/apis/policy",
|
||||
"pkg/kubectl/scheme",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "17c77c7898218073f14c8d573582e8d2313dc740"
|
||||
version = "v1.12.2"
|
||||
revision = "81753b10df112992bf51bbc2c2f85208aad78335"
|
||||
version = "v1.10.2"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
input-imports = [
|
||||
"github.com/argoproj/argo/pkg/apis/workflow/v1alpha1",
|
||||
"github.com/argoproj/pkg/exec",
|
||||
"github.com/argoproj/pkg/time",
|
||||
"github.com/casbin/casbin",
|
||||
"github.com/casbin/casbin/model",
|
||||
"github.com/coreos/dex/api",
|
||||
"github.com/coreos/go-oidc",
|
||||
"github.com/dgrijalva/jwt-go",
|
||||
"github.com/dustin/go-humanize",
|
||||
"github.com/ghodss/yaml",
|
||||
"github.com/go-openapi/loads",
|
||||
"github.com/go-openapi/runtime/middleware",
|
||||
@@ -1453,10 +1229,10 @@
|
||||
"github.com/gogo/protobuf/proto",
|
||||
"github.com/gogo/protobuf/protoc-gen-gofast",
|
||||
"github.com/gogo/protobuf/protoc-gen-gogofast",
|
||||
"github.com/golang/glog",
|
||||
"github.com/golang/protobuf/proto",
|
||||
"github.com/golang/protobuf/protoc-gen-go",
|
||||
"github.com/golang/protobuf/ptypes/empty",
|
||||
"github.com/google/go-jsonnet",
|
||||
"github.com/grpc-ecosystem/go-grpc-middleware",
|
||||
"github.com/grpc-ecosystem/go-grpc-middleware/auth",
|
||||
"github.com/grpc-ecosystem/go-grpc-middleware/logging",
|
||||
@@ -1466,14 +1242,15 @@
|
||||
"github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger",
|
||||
"github.com/grpc-ecosystem/grpc-gateway/runtime",
|
||||
"github.com/grpc-ecosystem/grpc-gateway/utilities",
|
||||
"github.com/ksonnet/ksonnet/pkg/app",
|
||||
"github.com/ksonnet/ksonnet/pkg/component",
|
||||
"github.com/patrickmn/go-cache",
|
||||
"github.com/pkg/errors",
|
||||
"github.com/prometheus/client_golang/prometheus",
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp",
|
||||
"github.com/qiangmzsx/string-adapter",
|
||||
"github.com/sirupsen/logrus",
|
||||
"github.com/skratchdot/open-golang/open",
|
||||
"github.com/soheilhy/cmux",
|
||||
"github.com/spf13/afero",
|
||||
"github.com/spf13/cobra",
|
||||
"github.com/spf13/pflag",
|
||||
"github.com/stretchr/testify/assert",
|
||||
@@ -1482,7 +1259,6 @@
|
||||
"github.com/yudai/gojsondiff",
|
||||
"github.com/yudai/gojsondiff/formatter",
|
||||
"golang.org/x/crypto/bcrypt",
|
||||
"golang.org/x/crypto/ssh",
|
||||
"golang.org/x/crypto/ssh/terminal",
|
||||
"golang.org/x/net/context",
|
||||
"golang.org/x/oauth2",
|
||||
@@ -1499,13 +1275,6 @@
|
||||
"gopkg.in/go-playground/webhooks.v3/bitbucket",
|
||||
"gopkg.in/go-playground/webhooks.v3/github",
|
||||
"gopkg.in/go-playground/webhooks.v3/gitlab",
|
||||
"gopkg.in/src-d/go-git.v4",
|
||||
"gopkg.in/src-d/go-git.v4/config",
|
||||
"gopkg.in/src-d/go-git.v4/plumbing",
|
||||
"gopkg.in/src-d/go-git.v4/plumbing/transport",
|
||||
"gopkg.in/src-d/go-git.v4/plumbing/transport/http",
|
||||
"gopkg.in/src-d/go-git.v4/plumbing/transport/ssh",
|
||||
"gopkg.in/src-d/go-git.v4/storage/memory",
|
||||
"k8s.io/api/apps/v1",
|
||||
"k8s.io/api/apps/v1beta1",
|
||||
"k8s.io/api/apps/v1beta2",
|
||||
|
||||
54
Gopkg.toml
54
Gopkg.toml
@@ -1,63 +1,55 @@
|
||||
# Packages should only be added to the following list when we use them *outside* of our go code.
|
||||
# (e.g. we want to build the binary to invoke as part of the build process, such as in
|
||||
# generate-proto.sh). Normal use of golang packages should be added via `dep ensure`, and pinned
|
||||
# with a [[constraint]] or [[override]] when version is important.
|
||||
required = [
|
||||
"github.com/golang/protobuf/protoc-gen-go",
|
||||
"github.com/gogo/protobuf/protoc-gen-gofast",
|
||||
"github.com/gogo/protobuf/protoc-gen-gogofast",
|
||||
"golang.org/x/sync/errgroup",
|
||||
"k8s.io/code-generator/cmd/go-to-protobuf",
|
||||
"github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway",
|
||||
"github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger",
|
||||
"golang.org/x/sync/errgroup",
|
||||
"github.com/golang/protobuf/protoc-gen-go",
|
||||
]
|
||||
|
||||
[[constraint]]
|
||||
name = "google.golang.org/grpc"
|
||||
version = "1.15.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/gogo/protobuf"
|
||||
version = "1.1.1"
|
||||
|
||||
# override github.com/grpc-ecosystem/go-grpc-middleware's constraint on master
|
||||
[[override]]
|
||||
name = "github.com/golang/protobuf"
|
||||
version = "1.2.0"
|
||||
version = "1.9.2"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/grpc-ecosystem/grpc-gateway"
|
||||
version = "v1.3.1"
|
||||
|
||||
# prometheus does not believe in semversioning yet
|
||||
[[constraint]]
|
||||
name = "github.com/prometheus/client_golang"
|
||||
revision = "7858729281ec582767b20e0d696b6041d995d5e0"
|
||||
|
||||
[[constraint]]
|
||||
branch = "release-1.12"
|
||||
# override argo outdated dependency
|
||||
[[override]]
|
||||
branch = "release-1.10"
|
||||
name = "k8s.io/api"
|
||||
|
||||
[[override]]
|
||||
branch = "release-1.10"
|
||||
name = "k8s.io/apimachinery"
|
||||
|
||||
[[constraint]]
|
||||
name = "k8s.io/apiextensions-apiserver"
|
||||
branch = "release-1.12"
|
||||
branch = "release-1.10"
|
||||
|
||||
[[constraint]]
|
||||
branch = "release-1.12"
|
||||
branch = "release-1.10"
|
||||
name = "k8s.io/code-generator"
|
||||
|
||||
[[constraint]]
|
||||
branch = "release-9.0"
|
||||
[[override]]
|
||||
branch = "release-7.0"
|
||||
name = "k8s.io/client-go"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/stretchr/testify"
|
||||
version = "1.2.2"
|
||||
version = "1.2.1"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/ksonnet/ksonnet"
|
||||
version = "v0.11.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/gobuffalo/packr"
|
||||
version = "v1.11.0"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/argoproj/pkg"
|
||||
# override ksonnet's logrus dependency
|
||||
[[override]]
|
||||
name = "github.com/sirupsen/logrus"
|
||||
revision = "ea8897e79973357ba785ac2533559a6297e83c44"
|
||||
|
||||
31
Makefile
31
Makefile
@@ -62,24 +62,25 @@ cli: clean-debug
|
||||
|
||||
.PHONY: cli-linux
|
||||
cli-linux: clean-debug
|
||||
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 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 create --name tmp-argocd-linux `cat /tmp/argocd-linux-id`
|
||||
docker cp tmp-argocd-linux:/go/src/github.com/argoproj/argo-cd/dist/argocd-linux-amd64 dist/
|
||||
docker cp tmp-argocd-linux:/root/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 argocd-build --build-arg MAKE_TARGET="cli GOOS=darwin IMAGE_TAG=$(IMAGE_TAG) IMAGE_NAMESPACE=$(IMAGE_NAMESPACE) CLI_NAME=argocd-darwin-amd64" .
|
||||
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 create --name tmp-argocd-darwin `cat /tmp/argocd-darwin-id`
|
||||
docker cp tmp-argocd-darwin:/go/src/github.com/argoproj/argo-cd/dist/argocd-darwin-amd64 dist/
|
||||
docker cp tmp-argocd-darwin:/root/go/src/github.com/argoproj/argo-cd/dist/argocd-darwin-amd64 dist/
|
||||
docker rm tmp-argocd-darwin
|
||||
|
||||
.PHONY: argocd-util
|
||||
argocd-util: clean-debug
|
||||
CGO_ENABLED=0 go build -v -i -ldflags '${LDFLAGS} -extldflags "-static"' -o ${DIST_DIR}/argocd-util ./cmd/argocd-util
|
||||
|
||||
.PHONY: manifests
|
||||
manifests:
|
||||
.PHONY: install-manifest
|
||||
install-manifest:
|
||||
if [ "${IMAGE_NAMESPACE}" = "" ] ; then echo "IMAGE_NAMESPACE must be set to build install manifest" ; exit 1 ; fi
|
||||
./hack/update-manifests.sh
|
||||
|
||||
.PHONY: server
|
||||
@@ -88,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) .
|
||||
docker build --build-arg BINARY=argocd-server -t $(IMAGE_PREFIX)argocd-server:$(IMAGE_TAG) -f Dockerfile-argocd .
|
||||
@if [ "$(DOCKER_PUSH)" = "true" ] ; then docker push $(IMAGE_PREFIX)argocd-server:$(IMAGE_TAG) ; fi
|
||||
|
||||
.PHONY: repo-server
|
||||
@@ -97,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) .
|
||||
docker build --build-arg BINARY=argocd-repo-server -t $(IMAGE_PREFIX)argocd-repo-server:$(IMAGE_TAG) -f Dockerfile-argocd .
|
||||
@if [ "$(DOCKER_PUSH)" = "true" ] ; then docker push $(IMAGE_PREFIX)argocd-repo-server:$(IMAGE_TAG) ; fi
|
||||
|
||||
.PHONY: controller
|
||||
@@ -106,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) .
|
||||
docker build --build-arg BINARY=argocd-application-controller -t $(IMAGE_PREFIX)argocd-application-controller:$(IMAGE_TAG) -f Dockerfile-argocd .
|
||||
@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) .
|
||||
docker build --build-arg BINARY=argocd -t $(IMAGE_PREFIX)argocd-cli:$(IMAGE_TAG) -f Dockerfile-argocd .
|
||||
@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) --target builder .
|
||||
docker build -t $(IMAGE_PREFIX)argo-cd-ci-builder:$(IMAGE_TAG) -f Dockerfile-ci-builder .
|
||||
|
||||
.PHONY: lint
|
||||
lint:
|
||||
@@ -126,11 +127,6 @@ 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
|
||||
@@ -148,10 +144,9 @@ clean: clean-debug
|
||||
precheckin: test lint
|
||||
|
||||
.PHONY: release-precheck
|
||||
release-precheck: manifests
|
||||
release-precheck: install-manifest
|
||||
@if [ "$(GIT_TREE_STATE)" != "clean" ]; then echo 'git tree state is $(GIT_TREE_STATE)' ; exit 1; fi
|
||||
@if [ -z "$(GIT_TAG)" ]; then echo 'commit must be tagged to perform release' ; exit 1; fi
|
||||
@if [ "$(GIT_TAG)" != "v`cat VERSION`" ]; then echo 'VERSION does not match git tag'; exit 1; fi
|
||||
|
||||
.PHONY: release
|
||||
release: release-precheck precheckin cli-darwin cli-linux server-image controller-image repo-server-image cli-image
|
||||
|
||||
15
README.md
15
README.md
@@ -1,4 +1,3 @@
|
||||
[](https://coveralls.io/github/argoproj/argo-cd?branch=master)
|
||||
|
||||
# Argo CD - Declarative Continuous Delivery for Kubernetes
|
||||
|
||||
@@ -23,21 +22,14 @@ is provided for additional features.
|
||||
Argo CD follows the **GitOps** pattern of using git repositories as the source of truth for defining
|
||||
the desired application state. Kubernetes manifests can be specified in several ways:
|
||||
* [ksonnet](https://ksonnet.io) applications
|
||||
* [kustomize](https://kustomize.io) applications
|
||||
* [helm](https://helm.sh) charts
|
||||
* Plain directory of YAML/json manifests
|
||||
* Simple directory of YAML/json manifests
|
||||
|
||||
Argo CD automates the deployment of the desired application states in the specified target environments.
|
||||
Application deployments can track updates to branches, tags, or pinned to a specific version of
|
||||
manifests at a git commit. See [tracking strategies](docs/tracking_strategies.md) for additional
|
||||
details about the different tracking strategies available.
|
||||
|
||||
For a quick 10 minute overview of ArgoCD, check out the demo presented to the Sig Apps community
|
||||
meeting:
|
||||
[](https://youtu.be/aWDIQMbp1cc?t=1m4s)
|
||||
|
||||
|
||||
|
||||
## Architecture
|
||||
|
||||

|
||||
@@ -55,7 +47,6 @@ For additional details, see [architecture overview](docs/architecture.md).
|
||||
## Features
|
||||
|
||||
* Automated deployment of applications to specified target environments
|
||||
* Flexibility in support for multiple config management tools (Ksonnet, Kustomize, Helm, plain-YAML)
|
||||
* Continuous monitoring of deployed applications
|
||||
* Automated or manual syncing of applications to its desired state
|
||||
* Web and CLI based visualization of applications and differences between live vs. desired state
|
||||
@@ -66,11 +57,13 @@ For additional details, see [architecture overview](docs/architecture.md).
|
||||
* PreSync, Sync, PostSync hooks to support complex application rollouts (e.g.blue/green & canary upgrades)
|
||||
* Audit trails for application events and API calls
|
||||
* Parameter overrides for overriding ksonnet/helm parameters in git
|
||||
* Service account/access key management for CI pipelines
|
||||
|
||||
## Development Status
|
||||
* Argo CD is being used in production to deploy SaaS services at Intuit
|
||||
|
||||
## Roadmap
|
||||
* Auto-sync toggle to directly apply git state changes to live state
|
||||
* Service account/access key management for CI pipelines
|
||||
* Support for additional config management tools (Kustomize?)
|
||||
* Revamped UI, and feature parity with CLI
|
||||
* Customizable application actions
|
||||
|
||||
@@ -12,7 +12,6 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
|
||||
// load the gcp plugin (required to authenticate against GKE clusters).
|
||||
_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
|
||||
// load the oidc plugin (required to authenticate with OpenID Connect).
|
||||
@@ -24,6 +23,7 @@ import (
|
||||
appclientset "github.com/argoproj/argo-cd/pkg/client/clientset/versioned"
|
||||
"github.com/argoproj/argo-cd/reposerver"
|
||||
"github.com/argoproj/argo-cd/util/cli"
|
||||
"github.com/argoproj/argo-cd/util/db"
|
||||
"github.com/argoproj/argo-cd/util/stats"
|
||||
)
|
||||
|
||||
@@ -66,14 +66,25 @@ func newCommand() *cobra.Command {
|
||||
namespace, _, err := clientConfig.Namespace()
|
||||
errors.CheckError(err)
|
||||
|
||||
// TODO (amatyushentsev): Use config map to store controller configuration
|
||||
controllerConfig := controller.ApplicationControllerConfig{
|
||||
Namespace: namespace,
|
||||
InstanceID: "",
|
||||
}
|
||||
db := db.NewDB(namespace, kubeClient)
|
||||
resyncDuration := time.Duration(appResyncPeriod) * time.Second
|
||||
repoClientset := reposerver.NewRepositoryServerClientset(repoServerAddress)
|
||||
appStateManager := controller.NewAppStateManager(db, appClient, repoClientset, namespace)
|
||||
|
||||
appController := controller.NewApplicationController(
|
||||
namespace,
|
||||
kubeClient,
|
||||
appClient,
|
||||
repoClientset,
|
||||
resyncDuration)
|
||||
db,
|
||||
appStateManager,
|
||||
resyncDuration,
|
||||
&controllerConfig)
|
||||
secretController := controller.NewSecretController(kubeClient, repoClientset, resyncDuration, namespace)
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
@@ -17,7 +17,6 @@ import (
|
||||
"github.com/argoproj/argo-cd/util/git"
|
||||
"github.com/argoproj/argo-cd/util/ksonnet"
|
||||
"github.com/argoproj/argo-cd/util/stats"
|
||||
"github.com/argoproj/argo-cd/util/tls"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -28,8 +27,7 @@ const (
|
||||
|
||||
func newCommand() *cobra.Command {
|
||||
var (
|
||||
logLevel string
|
||||
tlsConfigCustomizerSrc func() (tls.ConfigCustomizer, error)
|
||||
logLevel string
|
||||
)
|
||||
var command = cobra.Command{
|
||||
Use: cliName,
|
||||
@@ -39,11 +37,7 @@ func newCommand() *cobra.Command {
|
||||
errors.CheckError(err)
|
||||
log.SetLevel(level)
|
||||
|
||||
tlsConfigCustomizer, err := tlsConfigCustomizerSrc()
|
||||
errors.CheckError(err)
|
||||
|
||||
server, err := reposerver.NewServer(git.NewFactory(), newCache(), tlsConfigCustomizer)
|
||||
errors.CheckError(err)
|
||||
server := reposerver.NewServer(git.NewFactory(), newCache())
|
||||
grpc := server.CreateGRPC()
|
||||
listener, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
|
||||
errors.CheckError(err)
|
||||
@@ -63,7 +57,6 @@ func newCommand() *cobra.Command {
|
||||
}
|
||||
|
||||
command.Flags().StringVar(&logLevel, "loglevel", "info", "Set the logging level. One of: debug|info|warn|error")
|
||||
tlsConfigCustomizerSrc = tls.AddTLSFlagsToCmd(&command)
|
||||
return &command
|
||||
}
|
||||
|
||||
|
||||
@@ -17,20 +17,18 @@ import (
|
||||
"github.com/argoproj/argo-cd/server"
|
||||
"github.com/argoproj/argo-cd/util/cli"
|
||||
"github.com/argoproj/argo-cd/util/stats"
|
||||
"github.com/argoproj/argo-cd/util/tls"
|
||||
)
|
||||
|
||||
// NewCommand returns a new instance of an argocd command
|
||||
func NewCommand() *cobra.Command {
|
||||
var (
|
||||
insecure bool
|
||||
logLevel string
|
||||
glogLevel int
|
||||
clientConfig clientcmd.ClientConfig
|
||||
staticAssetsDir string
|
||||
repoServerAddress string
|
||||
disableAuth bool
|
||||
tlsConfigCustomizerSrc func() (tls.ConfigCustomizer, error)
|
||||
insecure bool
|
||||
logLevel string
|
||||
glogLevel int
|
||||
clientConfig clientcmd.ClientConfig
|
||||
staticAssetsDir string
|
||||
repoServerAddress string
|
||||
disableAuth bool
|
||||
)
|
||||
var command = &cobra.Command{
|
||||
Use: cliName,
|
||||
@@ -52,22 +50,18 @@ func NewCommand() *cobra.Command {
|
||||
namespace, _, err := clientConfig.Namespace()
|
||||
errors.CheckError(err)
|
||||
|
||||
tlsConfigCustomizer, err := tlsConfigCustomizerSrc()
|
||||
errors.CheckError(err)
|
||||
|
||||
kubeclientset := kubernetes.NewForConfigOrDie(config)
|
||||
appclientset := appclientset.NewForConfigOrDie(config)
|
||||
repoclientset := reposerver.NewRepositoryServerClientset(repoServerAddress)
|
||||
|
||||
argoCDOpts := server.ArgoCDServerOpts{
|
||||
Insecure: insecure,
|
||||
Namespace: namespace,
|
||||
StaticAssetsDir: staticAssetsDir,
|
||||
KubeClientset: kubeclientset,
|
||||
AppClientset: appclientset,
|
||||
RepoClientset: repoclientset,
|
||||
DisableAuth: disableAuth,
|
||||
TLSConfigCustomizer: tlsConfigCustomizer,
|
||||
Insecure: insecure,
|
||||
Namespace: namespace,
|
||||
StaticAssetsDir: staticAssetsDir,
|
||||
KubeClientset: kubeclientset,
|
||||
AppClientset: appclientset,
|
||||
RepoClientset: repoclientset,
|
||||
DisableAuth: disableAuth,
|
||||
}
|
||||
|
||||
stats.RegisterStackDumper()
|
||||
@@ -92,6 +86,5 @@ func NewCommand() *cobra.Command {
|
||||
command.Flags().StringVar(&repoServerAddress, "repo-server", "localhost:8081", "Repo server address.")
|
||||
command.Flags().BoolVar(&disableAuth, "disable-auth", false, "Disable client authentication")
|
||||
command.AddCommand(cli.NewVersionCmd(cliName))
|
||||
tlsConfigCustomizerSrc = tls.AddTLSFlagsToCmd(command)
|
||||
return command
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ import (
|
||||
"github.com/argoproj/argo-cd/util/cli"
|
||||
"github.com/argoproj/argo-cd/util/db"
|
||||
"github.com/argoproj/argo-cd/util/dex"
|
||||
"github.com/argoproj/argo-cd/util/kube"
|
||||
"github.com/argoproj/argo-cd/util/settings"
|
||||
"github.com/ghodss/yaml"
|
||||
log "github.com/sirupsen/logrus"
|
||||
@@ -60,7 +59,6 @@ func NewCommand() *cobra.Command {
|
||||
command.AddCommand(NewImportCommand())
|
||||
command.AddCommand(NewExportCommand())
|
||||
command.AddCommand(NewSettingsCommand())
|
||||
command.AddCommand(NewClusterConfig())
|
||||
|
||||
command.Flags().StringVar(&logLevel, "loglevel", "info", "Set the logging level. One of: debug|info|warn|error")
|
||||
return command
|
||||
@@ -368,8 +366,7 @@ func NewSettingsCommand() *cobra.Command {
|
||||
errors.CheckError(err)
|
||||
settingsMgr := settings.NewSettingsManager(kubeclientset, namespace)
|
||||
|
||||
_, err = settings.UpdateSettings(superuserPassword, settingsMgr, updateSignature, updateSuperuser, namespace)
|
||||
errors.CheckError(err)
|
||||
_ = settings.UpdateSettings(superuserPassword, settingsMgr, updateSignature, updateSuperuser, namespace)
|
||||
},
|
||||
}
|
||||
command.Flags().BoolVar(&updateSuperuser, "update-superuser", false, "force updating the superuser password")
|
||||
@@ -379,42 +376,6 @@ func NewSettingsCommand() *cobra.Command {
|
||||
return command
|
||||
}
|
||||
|
||||
// NewClusterConfig returns a new instance of `argocd-util cluster-kubeconfig` command
|
||||
func NewClusterConfig() *cobra.Command {
|
||||
var (
|
||||
clientConfig clientcmd.ClientConfig
|
||||
)
|
||||
var command = &cobra.Command{
|
||||
Use: "cluster-kubeconfig CLUSTER_URL OUTPUT_PATH",
|
||||
Short: "Generates kubeconfig for the specified cluster",
|
||||
Run: func(c *cobra.Command, args []string) {
|
||||
if len(args) != 2 {
|
||||
c.HelpFunc()(c, args)
|
||||
os.Exit(1)
|
||||
}
|
||||
serverUrl := args[0]
|
||||
output := args[1]
|
||||
conf, err := clientConfig.ClientConfig()
|
||||
errors.CheckError(err)
|
||||
namespace, wasSpecified, err := clientConfig.Namespace()
|
||||
errors.CheckError(err)
|
||||
if !(wasSpecified) {
|
||||
namespace = "argocd"
|
||||
}
|
||||
|
||||
kubeclientset, err := kubernetes.NewForConfig(conf)
|
||||
errors.CheckError(err)
|
||||
|
||||
cluster, err := db.NewDB(namespace, kubeclientset).GetCluster(context.Background(), serverUrl)
|
||||
errors.CheckError(err)
|
||||
err = kube.WriteKubeConfig(cluster.RESTConfig(), namespace, output)
|
||||
errors.CheckError(err)
|
||||
},
|
||||
}
|
||||
clientConfig = cli.AddKubectlFlagsToCmd(command)
|
||||
return command
|
||||
}
|
||||
|
||||
func main() {
|
||||
if err := NewCommand().Execute(); err != nil {
|
||||
fmt.Println(err)
|
||||
|
||||
@@ -50,9 +50,7 @@ func NewAccountUpdatePasswordCommand(clientOpts *argocdclient.ClientOptions) *co
|
||||
fmt.Print("\n")
|
||||
}
|
||||
if newPassword == "" {
|
||||
var err error
|
||||
newPassword, err = settings.ReadAndConfirmPassword()
|
||||
errors.CheckError(err)
|
||||
newPassword = settings.ReadAndConfirmPassword()
|
||||
}
|
||||
|
||||
updatePasswordRequest := account.UpdatePasswordRequest{
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"io"
|
||||
"net/url"
|
||||
"os"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
@@ -119,18 +118,6 @@ func NewApplicationCreateCommand(clientOpts *argocdclient.ClientOptions) *cobra.
|
||||
if len(appOpts.valuesFiles) > 0 {
|
||||
app.Spec.Source.ValuesFiles = appOpts.valuesFiles
|
||||
}
|
||||
switch appOpts.syncPolicy {
|
||||
case "automated":
|
||||
app.Spec.SyncPolicy = &argoappv1.SyncPolicy{
|
||||
Automated: &argoappv1.SyncPolicyAutomated{
|
||||
Prune: appOpts.autoPrune,
|
||||
},
|
||||
}
|
||||
case "none", "":
|
||||
app.Spec.SyncPolicy = nil
|
||||
default:
|
||||
log.Fatalf("Invalid sync-policy: %s", appOpts.syncPolicy)
|
||||
}
|
||||
conn, appIf := argocdclient.NewClientOrDie(clientOpts).NewApplicationClientOrDie()
|
||||
defer util.Close(conn)
|
||||
appCreateRequest := application.ApplicationCreateRequest{
|
||||
@@ -194,16 +181,6 @@ func NewApplicationGetCommand(clientOpts *argocdclient.ClientOptions) *cobra.Com
|
||||
if len(app.Spec.Source.ValuesFiles) > 0 {
|
||||
fmt.Printf(printOpFmtStr, "Helm Values:", strings.Join(app.Spec.Source.ValuesFiles, ","))
|
||||
}
|
||||
var syncPolicy string
|
||||
if app.Spec.SyncPolicy != nil && app.Spec.SyncPolicy.Automated != nil {
|
||||
syncPolicy = "Automated"
|
||||
if app.Spec.SyncPolicy.Automated.Prune {
|
||||
syncPolicy += " (Prune)"
|
||||
}
|
||||
} else {
|
||||
syncPolicy = "<none>"
|
||||
}
|
||||
fmt.Printf(printOpFmtStr, "Sync Policy:", syncPolicy)
|
||||
|
||||
if len(app.Status.Conditions) > 0 {
|
||||
fmt.Println()
|
||||
@@ -335,17 +312,6 @@ func NewApplicationSetCommand(clientOpts *argocdclient.ClientOptions) *cobra.Com
|
||||
app.Spec.Destination.Namespace = appOpts.destNamespace
|
||||
case "project":
|
||||
app.Spec.Project = appOpts.project
|
||||
case "sync-policy":
|
||||
switch appOpts.syncPolicy {
|
||||
case "automated":
|
||||
app.Spec.SyncPolicy = &argoappv1.SyncPolicy{
|
||||
Automated: &argoappv1.SyncPolicyAutomated{},
|
||||
}
|
||||
case "none":
|
||||
app.Spec.SyncPolicy = nil
|
||||
default:
|
||||
log.Fatalf("Invalid sync-policy: %s", appOpts.syncPolicy)
|
||||
}
|
||||
}
|
||||
})
|
||||
if visited == 0 {
|
||||
@@ -353,13 +319,6 @@ func NewApplicationSetCommand(clientOpts *argocdclient.ClientOptions) *cobra.Com
|
||||
c.HelpFunc()(c, args)
|
||||
os.Exit(1)
|
||||
}
|
||||
if c.Flags().Changed("auto-prune") {
|
||||
if app.Spec.SyncPolicy == nil || app.Spec.SyncPolicy.Automated == nil {
|
||||
log.Fatal("Cannot set --auto-prune: application not configured with automatic sync")
|
||||
}
|
||||
app.Spec.SyncPolicy.Automated.Prune = appOpts.autoPrune
|
||||
}
|
||||
|
||||
setParameterOverrides(app, appOpts.parameters)
|
||||
oldOverrides := app.Spec.Source.ComponentParameterOverrides
|
||||
updatedSpec, err := appIf.UpdateSpec(context.Background(), &application.ApplicationUpdateSpecRequest{
|
||||
@@ -398,8 +357,6 @@ type appOptions struct {
|
||||
parameters []string
|
||||
valuesFiles []string
|
||||
project string
|
||||
syncPolicy string
|
||||
autoPrune bool
|
||||
}
|
||||
|
||||
func addAppFlags(command *cobra.Command, opts *appOptions) {
|
||||
@@ -412,8 +369,6 @@ func addAppFlags(command *cobra.Command, opts *appOptions) {
|
||||
command.Flags().StringArrayVarP(&opts.parameters, "parameter", "p", []string{}, "set a parameter override (e.g. -p guestbook=image=example/guestbook:latest)")
|
||||
command.Flags().StringArrayVar(&opts.valuesFiles, "values", []string{}, "Helm values file(s) to use")
|
||||
command.Flags().StringVar(&opts.project, "project", "", "Application project name")
|
||||
command.Flags().StringVar(&opts.syncPolicy, "sync-policy", "", "Set the sync policy (one of: automated, none)")
|
||||
command.Flags().BoolVar(&opts.autoPrune, "auto-prune", false, "Set automatic pruning when sync is automated")
|
||||
}
|
||||
|
||||
// NewApplicationUnsetCommand returns a new instance of an `argocd app unset` command
|
||||
@@ -702,7 +657,7 @@ func NewApplicationWaitCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
|
||||
conn, appIf := argocdclient.NewClientOrDie(clientOpts).NewApplicationClientOrDie()
|
||||
defer util.Close(conn)
|
||||
|
||||
_, err := waitOnApplicationStatus(appIf, appName, timeout, watchSync, watchHealth, watchOperations, nil)
|
||||
_, err := waitOnApplicationStatus(appIf, appName, timeout, watchSync, watchHealth, watchOperations)
|
||||
errors.CheckError(err)
|
||||
},
|
||||
}
|
||||
@@ -778,6 +733,8 @@ func printAppResources(w io.Writer, app *argoappv1.Application, showOperation bo
|
||||
if opState != nil {
|
||||
if opState.SyncResult != nil {
|
||||
syncRes = opState.SyncResult
|
||||
} else if opState.RollbackResult != nil {
|
||||
syncRes = opState.RollbackResult
|
||||
}
|
||||
}
|
||||
if syncRes != nil {
|
||||
@@ -821,17 +778,12 @@ func printAppResources(w io.Writer, app *argoappv1.Application, showOperation bo
|
||||
// NewApplicationSyncCommand returns a new instance of an `argocd app sync` command
|
||||
func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
|
||||
var (
|
||||
revision string
|
||||
resources *[]string
|
||||
prune bool
|
||||
dryRun bool
|
||||
timeout uint
|
||||
strategy string
|
||||
force bool
|
||||
)
|
||||
const (
|
||||
resourceFieldDelimiter = ":"
|
||||
resourceFieldCount = 3
|
||||
revision string
|
||||
prune bool
|
||||
dryRun bool
|
||||
timeout uint
|
||||
strategy string
|
||||
force bool
|
||||
)
|
||||
var command = &cobra.Command{
|
||||
Use: "sync APPNAME",
|
||||
@@ -844,28 +796,11 @@ func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
|
||||
conn, appIf := argocdclient.NewClientOrDie(clientOpts).NewApplicationClientOrDie()
|
||||
defer util.Close(conn)
|
||||
appName := args[0]
|
||||
var syncResources []argoappv1.SyncOperationResource
|
||||
if resources != nil {
|
||||
syncResources = []argoappv1.SyncOperationResource{}
|
||||
for _, r := range *resources {
|
||||
fields := strings.Split(r, resourceFieldDelimiter)
|
||||
if len(fields) != resourceFieldCount {
|
||||
log.Fatalf("Resource should have GROUP%sKIND%sNAME, but instead got: %s", resourceFieldDelimiter, resourceFieldDelimiter, r)
|
||||
}
|
||||
rsrc := argoappv1.SyncOperationResource{
|
||||
Group: fields[0],
|
||||
Kind: fields[1],
|
||||
Name: fields[2],
|
||||
}
|
||||
syncResources = append(syncResources, rsrc)
|
||||
}
|
||||
}
|
||||
syncReq := application.ApplicationSyncRequest{
|
||||
Name: &appName,
|
||||
DryRun: dryRun,
|
||||
Revision: revision,
|
||||
Resources: syncResources,
|
||||
Prune: prune,
|
||||
Name: &appName,
|
||||
DryRun: dryRun,
|
||||
Revision: revision,
|
||||
Prune: prune,
|
||||
}
|
||||
switch strategy {
|
||||
case "apply":
|
||||
@@ -881,7 +816,7 @@ func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
|
||||
_, err := appIf.Sync(ctx, &syncReq)
|
||||
errors.CheckError(err)
|
||||
|
||||
app, err := waitOnApplicationStatus(appIf, appName, timeout, false, false, true, syncResources)
|
||||
app, err := waitOnApplicationStatus(appIf, appName, timeout, false, false, true)
|
||||
errors.CheckError(err)
|
||||
|
||||
pruningRequired := 0
|
||||
@@ -902,7 +837,6 @@ func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
|
||||
command.Flags().BoolVar(&dryRun, "dry-run", false, "Preview apply without affecting cluster")
|
||||
command.Flags().BoolVar(&prune, "prune", false, "Allow deleting unexpected resources")
|
||||
command.Flags().StringVar(&revision, "revision", "", "Sync to a specific revision. Preserves parameter overrides")
|
||||
resources = command.Flags().StringArray("resource", nil, fmt.Sprintf("Sync only specific resources as GROUP%sKIND%sNAME. Fields may be blank. This option may be specified repeatedly", resourceFieldDelimiter, resourceFieldDelimiter))
|
||||
command.Flags().UintVar(&timeout, "timeout", defaultCheckTimeoutSeconds, "Time out after this many seconds")
|
||||
command.Flags().StringVar(&strategy, "strategy", "", "Sync strategy (one of: apply|hook)")
|
||||
command.Flags().BoolVar(&force, "force", false, "Use a force apply")
|
||||
@@ -911,22 +845,23 @@ 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
|
||||
Status string
|
||||
Health string
|
||||
Hook string
|
||||
Message string
|
||||
Kind string
|
||||
Name string
|
||||
PrevState string
|
||||
Fields map[string]string
|
||||
Updated bool
|
||||
}
|
||||
|
||||
func newResourceState(kind, name, status, health, hook, message string) *resourceState {
|
||||
func newResourceState(kind, name, status, healthStatus, resType, message string) *resourceState {
|
||||
return &resourceState{
|
||||
Kind: kind,
|
||||
Name: name,
|
||||
Status: status,
|
||||
Health: health,
|
||||
Hook: hook,
|
||||
Message: message,
|
||||
Kind: kind,
|
||||
Name: name,
|
||||
Fields: map[string]string{
|
||||
"status": status,
|
||||
"healthStatus": healthStatus,
|
||||
"type": resType,
|
||||
"message": message,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -935,107 +870,47 @@ func (rs *resourceState) Key() string {
|
||||
return fmt.Sprintf("%s/%s", rs.Kind, rs.Name)
|
||||
}
|
||||
|
||||
func (rs *resourceState) String() string {
|
||||
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)
|
||||
// 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
|
||||
}
|
||||
|
||||
// Merge merges the new state with any different contents from another resourceState.
|
||||
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"])
|
||||
}
|
||||
|
||||
// Update a resourceState 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.
|
||||
// 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
|
||||
func (rs *resourceState) Update(newState *resourceState) {
|
||||
for k, v := range newState.Fields {
|
||||
if v != "" {
|
||||
rs.Fields[k] = v
|
||||
}
|
||||
}
|
||||
return updated
|
||||
}
|
||||
|
||||
func calculateResourceStates(app *argoappv1.Application, syncResources []argoappv1.SyncOperationResource) 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)
|
||||
}
|
||||
if syncResources != nil && !argo.ContainsSyncResource(obj, syncResources) {
|
||||
continue
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
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 bool, watchHealth bool, watchOperation bool, syncResources []argoappv1.SyncOperationResource) (*argoappv1.Application, error) {
|
||||
func waitOnApplicationStatus(appClient application.ApplicationServiceClient, appName string, timeout uint, watchSync, watchHealth, watchOperations bool) (*argoappv1.Application, error) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
// 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
|
||||
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)
|
||||
|
||||
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)
|
||||
}
|
||||
fmt.Printf(printOpFmtStr, "Application:", appName)
|
||||
printOperationResult(app.Status.OperationState)
|
||||
|
||||
if len(app.Status.ComparisonResult.Resources) > 0 {
|
||||
fmt.Println()
|
||||
w := tabwriter.NewWriter(os.Stdout, 5, 0, 2, ' ', 0)
|
||||
printAppResources(w, app, watchOperation)
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
||||
printAppResources(w, app, true)
|
||||
_ = w.Flush()
|
||||
}
|
||||
}
|
||||
@@ -1043,47 +918,89 @@ func waitOnApplicationStatus(appClient application.ApplicationServiceClient, app
|
||||
if timeout != 0 {
|
||||
time.AfterFunc(time.Duration(timeout)*time.Second, func() {
|
||||
cancel()
|
||||
printFinalStatus()
|
||||
})
|
||||
}
|
||||
|
||||
w := tabwriter.NewWriter(os.Stdout, 5, 0, 2, ' ', 0)
|
||||
// print the initial components to format the tabwriter columns
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
||||
fmt.Fprintln(w, "KIND\tNAME\tSTATUS\tHEALTH\tHOOK\tOPERATIONMSG")
|
||||
_ = w.Flush()
|
||||
|
||||
prevStates := make(map[string]*resourceState)
|
||||
appEventCh := watchApp(ctx, appClient, appName)
|
||||
var app *argoappv1.Application
|
||||
|
||||
for appEvent := range appEventCh {
|
||||
app = &appEvent.Application
|
||||
if app.Operation != nil {
|
||||
refresh = true
|
||||
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)
|
||||
for appEvent := range appEventCh {
|
||||
app := appEvent.Application
|
||||
|
||||
printCompResults(&app.Status.ComparisonResult)
|
||||
|
||||
if opState := app.Status.OperationState; opState != nil {
|
||||
printOpResults(opState.SyncResult)
|
||||
printOpResults(opState.RollbackResult)
|
||||
}
|
||||
|
||||
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 := !watchOperation || appEvent.Application.Operation == nil
|
||||
operational := !watchOperations || appEvent.Application.Operation == nil
|
||||
if len(app.Status.GetErrorConditions()) == 0 && synced && healthy && operational {
|
||||
printFinalStatus(app)
|
||||
return app, nil
|
||||
log.Printf("App %q matches desired state", appName)
|
||||
printFinalStatus()
|
||||
return &app, nil
|
||||
}
|
||||
|
||||
newStates := calculateResourceStates(app, syncResources)
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -1168,9 +1085,7 @@ func NewApplicationHistoryCommand(clientOpts *argocdclient.ClientOptions) *cobra
|
||||
for _, depInfo := range app.Status.History {
|
||||
switch output {
|
||||
case "wide":
|
||||
manifest, err := appIf.GetManifests(context.Background(), &application.ApplicationManifestQuery{Name: &appName, Revision: depInfo.Revision})
|
||||
errors.CheckError(err)
|
||||
paramStr := paramString(manifest.GetParams())
|
||||
paramStr := paramString(depInfo.Params)
|
||||
fmt.Fprintf(w, "%d\t%s\t%s\t%s\n", depInfo.ID, depInfo.DeployedAt, depInfo.Revision, paramStr)
|
||||
default:
|
||||
fmt.Fprintf(w, "%d\t%s\t%s\n", depInfo.ID, depInfo.DeployedAt, depInfo.Revision)
|
||||
@@ -1183,7 +1098,7 @@ func NewApplicationHistoryCommand(clientOpts *argocdclient.ClientOptions) *cobra
|
||||
return command
|
||||
}
|
||||
|
||||
func paramString(params []*argoappv1.ComponentParameter) string {
|
||||
func paramString(params []argoappv1.ComponentParameter) string {
|
||||
if len(params) == 0 {
|
||||
return ""
|
||||
}
|
||||
@@ -1234,7 +1149,7 @@ func NewApplicationRollbackCommand(clientOpts *argocdclient.ClientOptions) *cobr
|
||||
})
|
||||
errors.CheckError(err)
|
||||
|
||||
_, err = waitOnApplicationStatus(appIf, appName, timeout, false, false, true, nil)
|
||||
_, err = waitOnApplicationStatus(appIf, appName, timeout, false, false, true)
|
||||
errors.CheckError(err)
|
||||
},
|
||||
}
|
||||
@@ -1249,6 +1164,8 @@ const defaultCheckTimeoutSeconds = 0
|
||||
func printOperationResult(opState *argoappv1.OperationState) {
|
||||
if opState.SyncResult != nil {
|
||||
fmt.Printf(printOpFmtStr, "Operation:", "Sync")
|
||||
} else if opState.RollbackResult != nil {
|
||||
fmt.Printf(printOpFmtStr, "Operation:", "Rollback")
|
||||
}
|
||||
fmt.Printf(printOpFmtStr, "Phase:", opState.Phase)
|
||||
fmt.Printf(printOpFmtStr, "Start:", opState.StartedAt)
|
||||
|
||||
@@ -18,7 +18,6 @@ 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"
|
||||
)
|
||||
@@ -44,10 +43,8 @@ func NewClusterCommand(clientOpts *argocdclient.ClientOptions, pathOpts *clientc
|
||||
// NewClusterAddCommand returns a new instance of an `argocd cluster add` command
|
||||
func NewClusterAddCommand(clientOpts *argocdclient.ClientOptions, pathOpts *clientcmd.PathOptions) *cobra.Command {
|
||||
var (
|
||||
inCluster bool
|
||||
upsert bool
|
||||
awsRoleArn string
|
||||
awsClusterName string
|
||||
inCluster bool
|
||||
upsert bool
|
||||
)
|
||||
var command = &cobra.Command{
|
||||
Use: "add",
|
||||
@@ -65,7 +62,6 @@ func NewClusterAddCommand(clientOpts *argocdclient.ClientOptions, pathOpts *clie
|
||||
if clstContext == nil {
|
||||
log.Fatalf("Context %s does not exist in kubeconfig", args[0])
|
||||
}
|
||||
|
||||
overrides := clientcmd.ConfigOverrides{
|
||||
Context: *clstContext,
|
||||
}
|
||||
@@ -73,23 +69,12 @@ func NewClusterAddCommand(clientOpts *argocdclient.ClientOptions, pathOpts *clie
|
||||
conf, err := clientConfig.ClientConfig()
|
||||
errors.CheckError(err)
|
||||
|
||||
managerBearerToken := ""
|
||||
var awsAuthConf *argoappv1.AWSAuthConfig
|
||||
if awsClusterName != "" {
|
||||
awsAuthConf = &argoappv1.AWSAuthConfig{
|
||||
ClusterName: awsClusterName,
|
||||
RoleARN: awsRoleArn,
|
||||
}
|
||||
} else {
|
||||
// Install RBAC resources for managing the cluster
|
||||
clientset, err := kubernetes.NewForConfig(conf)
|
||||
errors.CheckError(err)
|
||||
managerBearerToken, err = common.InstallClusterManagerRBAC(clientset)
|
||||
errors.CheckError(err)
|
||||
}
|
||||
// Install RBAC resources for managing the cluster
|
||||
managerBearerToken := common.InstallClusterManagerRBAC(conf)
|
||||
|
||||
conn, clusterIf := argocdclient.NewClientOrDie(clientOpts).NewClusterClientOrDie()
|
||||
defer util.Close(conn)
|
||||
clst := NewCluster(args[0], conf, managerBearerToken, awsAuthConf)
|
||||
clst := NewCluster(args[0], conf, managerBearerToken)
|
||||
if inCluster {
|
||||
clst.Server = common.KubernetesInternalAPIServerAddr
|
||||
}
|
||||
@@ -105,8 +90,6 @@ func NewClusterAddCommand(clientOpts *argocdclient.ClientOptions, pathOpts *clie
|
||||
command.PersistentFlags().StringVar(&pathOpts.LoadingRules.ExplicitPath, pathOpts.ExplicitFileFlag, pathOpts.LoadingRules.ExplicitPath, "use a particular kubeconfig file")
|
||||
command.Flags().BoolVar(&inCluster, "in-cluster", false, "Indicates ArgoCD resides inside this cluster and should connect using the internal k8s hostname (kubernetes.default.svc)")
|
||||
command.Flags().BoolVar(&upsert, "upsert", false, "Override an existing cluster with the same name even if the spec differs")
|
||||
command.Flags().StringVar(&awsClusterName, "aws-cluster-name", "", "AWS Cluster name if set then aws-iam-authenticator will be used to access cluster")
|
||||
command.Flags().StringVar(&awsRoleArn, "aws-role-arn", "", "Optional AWS role arn. If set then AWS IAM Authenticator assume a role to perform cluster operations instead of the default AWS credential provider chain.")
|
||||
return command
|
||||
}
|
||||
|
||||
@@ -149,7 +132,7 @@ func printKubeContexts(ca clientcmd.ConfigAccess) {
|
||||
}
|
||||
}
|
||||
|
||||
func NewCluster(name string, conf *rest.Config, managerBearerToken string, awsAuthConf *argoappv1.AWSAuthConfig) *argoappv1.Cluster {
|
||||
func NewCluster(name string, conf *rest.Config, managerBearerToken string) *argoappv1.Cluster {
|
||||
tlsClientConfig := argoappv1.TLSClientConfig{
|
||||
Insecure: conf.TLSClientConfig.Insecure,
|
||||
ServerName: conf.TLSClientConfig.ServerName,
|
||||
@@ -178,7 +161,6 @@ func NewCluster(name string, conf *rest.Config, managerBearerToken string, awsAu
|
||||
Config: argoappv1.ClusterConfig{
|
||||
BearerToken: managerBearerToken,
|
||||
TLSClientConfig: tlsClientConfig,
|
||||
AWSAuthConfig: awsAuthConf,
|
||||
},
|
||||
}
|
||||
return &clst
|
||||
@@ -220,14 +202,9 @@ 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
|
||||
// err := common.UninstallClusterManagerRBAC(clientset)
|
||||
// errors.CheckError(err)
|
||||
// common.UninstallClusterManagerRBAC(conf)
|
||||
_, err := clusterIf.Delete(context.Background(), &cluster.ClusterQuery{Server: clusterName})
|
||||
errors.CheckError(err)
|
||||
}
|
||||
|
||||
@@ -1,20 +1,17 @@
|
||||
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"
|
||||
"github.com/spf13/pflag"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"strings"
|
||||
|
||||
"context"
|
||||
|
||||
"fmt"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/argoproj/argo-cd/errors"
|
||||
argocdclient "github.com/argoproj/argo-cd/pkg/apiclient"
|
||||
@@ -22,11 +19,8 @@ import (
|
||||
"github.com/argoproj/argo-cd/server/project"
|
||||
"github.com/argoproj/argo-cd/util"
|
||||
"github.com/argoproj/argo-cd/util/git"
|
||||
projectutil "github.com/argoproj/argo-cd/util/project"
|
||||
)
|
||||
|
||||
const (
|
||||
policyTemplate = "p, proj:%s:%s, applications, %s, %s/%s, %s"
|
||||
"github.com/spf13/pflag"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
type projectOpts struct {
|
||||
@@ -35,12 +29,6 @@ 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 {
|
||||
@@ -67,7 +55,6 @@ 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))
|
||||
@@ -76,349 +63,14 @@ func NewProjectCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
|
||||
command.AddCommand(NewProjectRemoveDestinationCommand(clientOpts))
|
||||
command.AddCommand(NewProjectAddSourceCommand(clientOpts))
|
||||
command.AddCommand(NewProjectRemoveSourceCommand(clientOpts))
|
||||
command.AddCommand(NewProjectAllowClusterResourceCommand(clientOpts))
|
||||
command.AddCommand(NewProjectDenyClusterResourceCommand(clientOpts))
|
||||
command.AddCommand(NewProjectAllowNamespaceResourceCommand(clientOpts))
|
||||
command.AddCommand(NewProjectDenyNamespaceResourceCommand(clientOpts))
|
||||
return command
|
||||
}
|
||||
|
||||
func addProjFlags(command *cobra.Command, opts *projectOpts) {
|
||||
command.Flags().StringVarP(&opts.description, "description", "", "", "Project description")
|
||||
command.Flags().StringVarP(&opts.description, "description", "", "desc", "Project description")
|
||||
command.Flags().StringArrayVarP(&opts.destinations, "dest", "d", []string{},
|
||||
"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))
|
||||
"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.")
|
||||
}
|
||||
|
||||
// NewProjectCreateCommand returns a new instance of an `argocd proj create` command
|
||||
@@ -590,13 +242,8 @@ 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.Info("Specified source repository is already defined in project")
|
||||
return
|
||||
log.Fatal("Specified source repository is already defined in project")
|
||||
}
|
||||
}
|
||||
proj.Spec.SourceRepos = append(proj.Spec.SourceRepos, url)
|
||||
@@ -607,104 +254,6 @@ func NewProjectAddSourceCommand(clientOpts *argocdclient.ClientOptions) *cobra.C
|
||||
return command
|
||||
}
|
||||
|
||||
func modifyProjectResourceCmd(cmdUse, cmdDesc string, clientOpts *argocdclient.ClientOptions, action func(proj *v1alpha1.AppProject, group string, kind string) bool) *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: cmdUse,
|
||||
Short: cmdDesc,
|
||||
Run: func(c *cobra.Command, args []string) {
|
||||
if len(args) != 3 {
|
||||
c.HelpFunc()(c, args)
|
||||
os.Exit(1)
|
||||
}
|
||||
projName, group, kind := args[0], args[1], args[2]
|
||||
conn, projIf := argocdclient.NewClientOrDie(clientOpts).NewProjectClientOrDie()
|
||||
defer util.Close(conn)
|
||||
|
||||
proj, err := projIf.Get(context.Background(), &project.ProjectQuery{Name: projName})
|
||||
errors.CheckError(err)
|
||||
|
||||
if action(proj, group, kind) {
|
||||
_, err = projIf.Update(context.Background(), &project.ProjectUpdateRequest{Project: proj})
|
||||
errors.CheckError(err)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewProjectAllowNamespaceResourceCommand returns a new instance of an `deny-cluster-resources` command
|
||||
func NewProjectAllowNamespaceResourceCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
|
||||
use := "allow-namespace-resource PROJECT GROUP KIND"
|
||||
desc := "Removes a namespaced API resource from the blacklist"
|
||||
return modifyProjectResourceCmd(use, desc, clientOpts, func(proj *v1alpha1.AppProject, group string, kind string) bool {
|
||||
index := -1
|
||||
for i, item := range proj.Spec.NamespaceResourceBlacklist {
|
||||
if item.Group == group && item.Kind == kind {
|
||||
index = i
|
||||
break
|
||||
}
|
||||
}
|
||||
if index == -1 {
|
||||
log.Info("Specified cluster resource is not blacklisted")
|
||||
return false
|
||||
}
|
||||
proj.Spec.NamespaceResourceBlacklist = append(proj.Spec.NamespaceResourceBlacklist[:index], proj.Spec.NamespaceResourceBlacklist[index+1:]...)
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
// NewProjectDenyNamespaceResourceCommand returns a new instance of an `argocd proj deny-namespace-resource` command
|
||||
func NewProjectDenyNamespaceResourceCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
|
||||
use := "deny-namespace-resource PROJECT GROUP KIND"
|
||||
desc := "Adds a namespaced API resource to the blacklist"
|
||||
return modifyProjectResourceCmd(use, desc, clientOpts, func(proj *v1alpha1.AppProject, group string, kind string) bool {
|
||||
for _, item := range proj.Spec.NamespaceResourceBlacklist {
|
||||
if item.Group == group && item.Kind == kind {
|
||||
log.Infof("Group '%s' and kind '%s' are already blacklisted in project", item.Group, item.Kind)
|
||||
return false
|
||||
}
|
||||
}
|
||||
proj.Spec.NamespaceResourceBlacklist = append(proj.Spec.NamespaceResourceBlacklist, v1.GroupKind{Group: group, Kind: kind})
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
// NewProjectDenyClusterResourceCommand returns a new instance of an `deny-cluster-resource` command
|
||||
func NewProjectDenyClusterResourceCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
|
||||
use := "deny-cluster-resource PROJECT GROUP KIND"
|
||||
desc := "Removes a cluster-scoped API resource from the whitelist"
|
||||
return modifyProjectResourceCmd(use, desc, clientOpts, func(proj *v1alpha1.AppProject, group string, kind string) bool {
|
||||
index := -1
|
||||
for i, item := range proj.Spec.ClusterResourceWhitelist {
|
||||
if item.Group == group && item.Kind == kind {
|
||||
index = i
|
||||
break
|
||||
}
|
||||
}
|
||||
if index == -1 {
|
||||
log.Info("Specified cluster resource already denied in project")
|
||||
return false
|
||||
}
|
||||
proj.Spec.ClusterResourceWhitelist = append(proj.Spec.ClusterResourceWhitelist[:index], proj.Spec.ClusterResourceWhitelist[index+1:]...)
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
// NewProjectAllowClusterResourceCommand returns a new instance of an `argocd proj allow-cluster-resource` command
|
||||
func NewProjectAllowClusterResourceCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
|
||||
use := "allow-cluster-resource PROJECT GROUP KIND"
|
||||
desc := "Adds a cluster-scoped API resource to the whitelist"
|
||||
return modifyProjectResourceCmd(use, desc, clientOpts, func(proj *v1alpha1.AppProject, group string, kind string) bool {
|
||||
for _, item := range proj.Spec.ClusterResourceWhitelist {
|
||||
if item.Group == group && item.Kind == kind {
|
||||
log.Infof("Group '%s' and kind '%s' are already whitelisted in project", item.Group, item.Kind)
|
||||
return false
|
||||
}
|
||||
}
|
||||
proj.Spec.ClusterResourceWhitelist = append(proj.Spec.ClusterResourceWhitelist, v1.GroupKind{Group: group, Kind: kind})
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
// NewProjectRemoveSourceCommand returns a new instance of an `argocd proj remove-src` command
|
||||
func NewProjectRemoveSourceCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
|
||||
var command = &cobra.Command{
|
||||
@@ -725,17 +274,13 @@ 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.Info("Specified source repository does not exist in project")
|
||||
log.Fatal("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})
|
||||
@@ -779,9 +324,9 @@ func NewProjectListCommand(clientOpts *argocdclient.ClientOptions) *cobra.Comman
|
||||
projects, err := projIf.List(context.Background(), &project.ProjectQuery{})
|
||||
errors.CheckError(err)
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
||||
fmt.Fprintf(w, "NAME\tDESCRIPTION\tDESTINATIONS\tSOURCES\tCLUSTER-RESOURCE-WHITELIST\tNAMESPACE-RESOURCE-BLACKLIST\n")
|
||||
fmt.Fprintf(w, "NAME\tDESCRIPTION\tDESTINATIONS\n")
|
||||
for _, p := range projects.Items {
|
||||
fmt.Fprintf(w, "%s\t%s\t%v\t%v\t%v\t%v\n", p.Name, p.Spec.Description, p.Spec.Destinations, p.Spec.SourceRepos, p.Spec.ClusterResourceWhitelist, p.Spec.NamespaceResourceBlacklist)
|
||||
fmt.Fprintf(w, "%s\t%s\t%v\n", p.Name, p.Spec.Description, p.Spec.Destinations)
|
||||
}
|
||||
_ = w.Flush()
|
||||
},
|
||||
|
||||
@@ -87,7 +87,7 @@ func NewRepoAddCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
|
||||
}
|
||||
command.Flags().StringVar(&repo.Username, "username", "", "username to the repository")
|
||||
command.Flags().StringVar(&repo.Password, "password", "", "password to the repository")
|
||||
command.Flags().StringVar(&sshPrivateKeyPath, "ssh-private-key-path", "", "path to the private ssh key (e.g. ~/.ssh/id_rsa)")
|
||||
command.Flags().StringVar(&sshPrivateKeyPath, "sshPrivateKeyPath", "", "path to the private ssh key (e.g. ~/.ssh/id_rsa)")
|
||||
command.Flags().BoolVar(&upsert, "upsert", false, "Override an existing repository with the same name even if the spec differs")
|
||||
return command
|
||||
}
|
||||
|
||||
@@ -102,8 +102,4 @@ var ArgoCDManagerPolicyRules = []rbacv1.PolicyRule{
|
||||
Resources: []string{"*"},
|
||||
Verbs: []string{"*"},
|
||||
},
|
||||
{
|
||||
NonResourceURLs: []string{"*"},
|
||||
Verbs: []string{"*"},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ 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"
|
||||
@@ -11,6 +12,7 @@ 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
|
||||
@@ -18,7 +20,7 @@ func CreateServiceAccount(
|
||||
clientset kubernetes.Interface,
|
||||
serviceAccountName string,
|
||||
namespace string,
|
||||
) error {
|
||||
) {
|
||||
serviceAccount := apiv1.ServiceAccount{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "v1",
|
||||
@@ -32,13 +34,12 @@ func CreateServiceAccount(
|
||||
_, err := clientset.CoreV1().ServiceAccounts(namespace).Create(&serviceAccount)
|
||||
if err != nil {
|
||||
if !apierr.IsAlreadyExists(err) {
|
||||
return fmt.Errorf("Failed to create service account %q: %v", serviceAccountName, err)
|
||||
log.Fatalf("Failed to create service account '%s': %v\n", serviceAccountName, err)
|
||||
}
|
||||
log.Infof("ServiceAccount %q already exists", serviceAccountName)
|
||||
return nil
|
||||
fmt.Printf("ServiceAccount '%s' already exists\n", serviceAccountName)
|
||||
return
|
||||
}
|
||||
log.Infof("ServiceAccount %q created", serviceAccountName)
|
||||
return nil
|
||||
fmt.Printf("ServiceAccount '%s' created\n", serviceAccountName)
|
||||
}
|
||||
|
||||
// CreateClusterRole creates a cluster role
|
||||
@@ -46,7 +47,7 @@ func CreateClusterRole(
|
||||
clientset kubernetes.Interface,
|
||||
clusterRoleName string,
|
||||
rules []rbacv1.PolicyRule,
|
||||
) error {
|
||||
) {
|
||||
clusterRole := rbacv1.ClusterRole{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "rbac.authorization.k8s.io/v1",
|
||||
@@ -61,17 +62,16 @@ func CreateClusterRole(
|
||||
_, err := crclient.Create(&clusterRole)
|
||||
if err != nil {
|
||||
if !apierr.IsAlreadyExists(err) {
|
||||
return fmt.Errorf("Failed to create ClusterRole %q: %v", clusterRoleName, err)
|
||||
log.Fatalf("Failed to create ClusterRole '%s': %v\n", clusterRoleName, err)
|
||||
}
|
||||
_, err = crclient.Update(&clusterRole)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to update ClusterRole %q: %v", clusterRoleName, err)
|
||||
log.Fatalf("Failed to update ClusterRole '%s': %v\n", clusterRoleName, err)
|
||||
}
|
||||
log.Infof("ClusterRole %q updated", clusterRoleName)
|
||||
fmt.Printf("ClusterRole '%s' updated\n", clusterRoleName)
|
||||
} else {
|
||||
log.Infof("ClusterRole %q created", clusterRoleName)
|
||||
fmt.Printf("ClusterRole '%s' created\n", 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,34 +106,22 @@ func CreateClusterRoleBinding(
|
||||
_, err := clientset.RbacV1().ClusterRoleBindings().Create(&roleBinding)
|
||||
if err != nil {
|
||||
if !apierr.IsAlreadyExists(err) {
|
||||
return fmt.Errorf("Failed to create ClusterRoleBinding %s: %v", clusterBindingRoleName, err)
|
||||
log.Fatalf("Failed to create ClusterRoleBinding %s: %v\n", clusterBindingRoleName, err)
|
||||
}
|
||||
log.Infof("ClusterRoleBinding %q already exists", clusterBindingRoleName)
|
||||
return nil
|
||||
fmt.Printf("ClusterRoleBinding '%s' already exists\n", clusterBindingRoleName)
|
||||
return
|
||||
}
|
||||
log.Infof("ClusterRoleBinding %q created, bound %q to %q", clusterBindingRoleName, serviceAccountName, clusterRoleName)
|
||||
return nil
|
||||
fmt.Printf("ClusterRoleBinding '%s' created, bound '%s' to '%s'\n", clusterBindingRoleName, serviceAccountName, clusterRoleName)
|
||||
}
|
||||
|
||||
// InstallClusterManagerRBAC installs RBAC resources for a cluster manager to operate a cluster. Returns a token
|
||||
func InstallClusterManagerRBAC(clientset kubernetes.Interface) (string, error) {
|
||||
func InstallClusterManagerRBAC(conf *rest.Config) string {
|
||||
const ns = "kube-system"
|
||||
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
|
||||
}
|
||||
clientset, err := kubernetes.NewForConfig(conf)
|
||||
errors.CheckError(err)
|
||||
CreateServiceAccount(clientset, ArgoCDManagerServiceAccount, ns)
|
||||
CreateClusterRole(clientset, ArgoCDManagerClusterRole, ArgoCDManagerPolicyRules)
|
||||
CreateClusterRoleBinding(clientset, ArgoCDManagerClusterRoleBinding, ArgoCDManagerServiceAccount, ArgoCDManagerClusterRole, ns)
|
||||
|
||||
var serviceAccount *apiv1.ServiceAccount
|
||||
var secretName string
|
||||
@@ -149,51 +137,52 @@ func InstallClusterManagerRBAC(clientset kubernetes.Interface) (string, error) {
|
||||
return true, nil
|
||||
})
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Failed to wait for service account secret: %v", err)
|
||||
log.Fatalf("Failed to wait for service account secret: %v", err)
|
||||
}
|
||||
secret, err := clientset.CoreV1().Secrets(ns).Get(secretName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Failed to retrieve secret %q: %v", secretName, err)
|
||||
log.Fatalf("Failed to retrieve secret '%s': %v", secretName, err)
|
||||
}
|
||||
token, ok := secret.Data["token"]
|
||||
if !ok {
|
||||
return "", fmt.Errorf("Secret %q for service account %q did not have a token", secretName, serviceAccount)
|
||||
log.Fatalf("Secret '%s' for service account '%s' did not have a token", secretName, serviceAccount)
|
||||
}
|
||||
return string(token), nil
|
||||
return string(token)
|
||||
}
|
||||
|
||||
// UninstallClusterManagerRBAC removes RBAC resources for a cluster manager to operate a cluster
|
||||
func UninstallClusterManagerRBAC(clientset kubernetes.Interface) error {
|
||||
return UninstallRBAC(clientset, "kube-system", ArgoCDManagerClusterRoleBinding, ArgoCDManagerClusterRole, ArgoCDManagerServiceAccount)
|
||||
func UninstallClusterManagerRBAC(conf *rest.Config) {
|
||||
clientset, err := kubernetes.NewForConfig(conf)
|
||||
errors.CheckError(err)
|
||||
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) error {
|
||||
func UninstallRBAC(clientset kubernetes.Interface, namespace, bindingName, roleName, serviceAccount string) {
|
||||
if err := clientset.RbacV1().ClusterRoleBindings().Delete(bindingName, &metav1.DeleteOptions{}); err != nil {
|
||||
if !apierr.IsNotFound(err) {
|
||||
return fmt.Errorf("Failed to delete ClusterRoleBinding: %v", err)
|
||||
log.Fatalf("Failed to delete ClusterRoleBinding: %v\n", err)
|
||||
}
|
||||
log.Infof("ClusterRoleBinding %q not found", bindingName)
|
||||
fmt.Printf("ClusterRoleBinding '%s' not found\n", bindingName)
|
||||
} else {
|
||||
log.Infof("ClusterRoleBinding %q deleted", bindingName)
|
||||
fmt.Printf("ClusterRoleBinding '%s' deleted\n", bindingName)
|
||||
}
|
||||
|
||||
if err := clientset.RbacV1().ClusterRoles().Delete(roleName, &metav1.DeleteOptions{}); err != nil {
|
||||
if !apierr.IsNotFound(err) {
|
||||
return fmt.Errorf("Failed to delete ClusterRole: %v", err)
|
||||
log.Fatalf("Failed to delete ClusterRole: %v\n", err)
|
||||
}
|
||||
log.Infof("ClusterRole %q not found", roleName)
|
||||
fmt.Printf("ClusterRole '%s' not found\n", roleName)
|
||||
} else {
|
||||
log.Infof("ClusterRole %q deleted", roleName)
|
||||
fmt.Printf("ClusterRole '%s' deleted\n", roleName)
|
||||
}
|
||||
|
||||
if err := clientset.CoreV1().ServiceAccounts(namespace).Delete(serviceAccount, &metav1.DeleteOptions{}); err != nil {
|
||||
if !apierr.IsNotFound(err) {
|
||||
return fmt.Errorf("Failed to delete ServiceAccount: %v", err)
|
||||
log.Fatalf("Failed to delete ServiceAccount: %v\n", err)
|
||||
}
|
||||
log.Infof("ServiceAccount %q in namespace %q not found", serviceAccount, namespace)
|
||||
fmt.Printf("ServiceAccount '%s' in namespace '%s' not found\n", serviceAccount, namespace)
|
||||
} else {
|
||||
log.Infof("ServiceAccount %q deleted", serviceAccount)
|
||||
fmt.Printf("ServiceAccount '%s' deleted\n", serviceAccount)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -14,7 +14,9 @@ import (
|
||||
"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/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/selection"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/strategicpatch"
|
||||
@@ -44,7 +46,6 @@ const (
|
||||
type ApplicationController struct {
|
||||
namespace string
|
||||
kubeClientset kubernetes.Interface
|
||||
kubectl kube.Kubectl
|
||||
applicationClientset appclientset.Interface
|
||||
auditLogger *argo.AuditLogger
|
||||
appRefreshQueue workqueue.RateLimitingInterface
|
||||
@@ -69,28 +70,28 @@ func NewApplicationController(
|
||||
kubeClientset kubernetes.Interface,
|
||||
applicationClientset appclientset.Interface,
|
||||
repoClientset reposerver.Clientset,
|
||||
db db.ArgoDB,
|
||||
appStateManager AppStateManager,
|
||||
appResyncPeriod time.Duration,
|
||||
config *ApplicationControllerConfig,
|
||||
) *ApplicationController {
|
||||
db := db.NewDB(namespace, kubeClientset)
|
||||
kubectlCmd := kube.KubectlCmd{}
|
||||
appStateManager := NewAppStateManager(db, applicationClientset, repoClientset, namespace, kubectlCmd)
|
||||
ctrl := ApplicationController{
|
||||
appRefreshQueue := workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter())
|
||||
appOperationQueue := workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter())
|
||||
return &ApplicationController{
|
||||
namespace: namespace,
|
||||
kubeClientset: kubeClientset,
|
||||
kubectl: kubectlCmd,
|
||||
applicationClientset: applicationClientset,
|
||||
repoClientset: repoClientset,
|
||||
appRefreshQueue: workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter()),
|
||||
appOperationQueue: workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter()),
|
||||
appRefreshQueue: appRefreshQueue,
|
||||
appOperationQueue: appOperationQueue,
|
||||
appStateManager: appStateManager,
|
||||
appInformer: newApplicationInformer(applicationClientset, appRefreshQueue, appOperationQueue, appResyncPeriod, config),
|
||||
db: db,
|
||||
statusRefreshTimeout: appResyncPeriod,
|
||||
forceRefreshApps: make(map[string]bool),
|
||||
forceRefreshAppsMutex: &sync.Mutex{},
|
||||
auditLogger: argo.NewAuditLogger(namespace, kubeClientset, "application-controller"),
|
||||
}
|
||||
ctrl.appInformer = ctrl.newApplicationInformer()
|
||||
return &ctrl
|
||||
}
|
||||
|
||||
// Run starts the Application CRD controller.
|
||||
@@ -99,14 +100,13 @@ func (ctrl *ApplicationController) Run(ctx context.Context, statusProcessors int
|
||||
defer ctrl.appRefreshQueue.ShutDown()
|
||||
|
||||
go ctrl.appInformer.Run(ctx.Done())
|
||||
go ctrl.watchAppsResources()
|
||||
|
||||
if !cache.WaitForCacheSync(ctx.Done(), ctrl.appInformer.HasSynced) {
|
||||
log.Error("Timed out waiting for caches to sync")
|
||||
return
|
||||
}
|
||||
|
||||
go ctrl.watchAppsResources()
|
||||
|
||||
for i := 0; i < statusProcessors; i++ {
|
||||
go wait.Until(func() {
|
||||
for ctrl.processAppRefreshQueueItem() {
|
||||
@@ -142,35 +142,14 @@ func (ctrl *ApplicationController) isRefreshForced(appName string) bool {
|
||||
|
||||
// watchClusterResources watches for resource changes annotated with application label on specified cluster and schedule corresponding app refresh.
|
||||
func (ctrl *ApplicationController) watchClusterResources(ctx context.Context, item appv1.Cluster) {
|
||||
retryUntilSucceed(func() (err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
err = fmt.Errorf("Recovered from panic: %v\n", r)
|
||||
}
|
||||
}()
|
||||
config := item.RESTConfig()
|
||||
watchStartTime := time.Now()
|
||||
ch, err := ctrl.kubectl.WatchResources(ctx, config, "", func(gvk schema.GroupVersionKind) metav1.ListOptions {
|
||||
ops := metav1.ListOptions{}
|
||||
if !kube.IsCRDGroupVersionKind(gvk) {
|
||||
ops.LabelSelector = common.LabelApplicationName
|
||||
}
|
||||
return ops
|
||||
})
|
||||
|
||||
config := item.RESTConfig()
|
||||
retryUntilSucceed(func() error {
|
||||
ch, err := kube.WatchResourcesWithLabel(ctx, config, "", common.LabelApplicationName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for event := range ch {
|
||||
eventObj := event.Object.(*unstructured.Unstructured)
|
||||
if kube.IsCRD(eventObj) {
|
||||
// restart if new CRD has been created after watch started
|
||||
if event.Type == watch.Added && watchStartTime.Before(eventObj.GetCreationTimestamp().Time) {
|
||||
return fmt.Errorf("Restarting the watch because a new CRD was added.")
|
||||
} else if event.Type == watch.Deleted {
|
||||
return fmt.Errorf("Restarting the watch because a CRD was deleted.")
|
||||
}
|
||||
}
|
||||
objLabels := eventObj.GetLabels()
|
||||
if objLabels == nil {
|
||||
objLabels = make(map[string]string)
|
||||
@@ -181,68 +160,26 @@ func (ctrl *ApplicationController) watchClusterResources(ctx context.Context, it
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("resource updates channel has closed")
|
||||
}, fmt.Sprintf("watch app resources on %s", item.Server), ctx, watchResourcesRetryTimeout)
|
||||
}, fmt.Sprintf("watch app resources on %s", config.Host), ctx, watchResourcesRetryTimeout)
|
||||
|
||||
}
|
||||
|
||||
func isClusterHasApps(apps []interface{}, cluster *appv1.Cluster) bool {
|
||||
for _, obj := range apps {
|
||||
if app, ok := obj.(*appv1.Application); ok && app.Spec.Destination.Server == cluster.Server {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// WatchAppsResources watches for resource changes annotated with application label on all registered clusters and schedule corresponding app refresh.
|
||||
func (ctrl *ApplicationController) watchAppsResources() {
|
||||
watchingClusters := make(map[string]struct {
|
||||
cancel context.CancelFunc
|
||||
cluster *appv1.Cluster
|
||||
})
|
||||
watchingClusters := make(map[string]context.CancelFunc)
|
||||
|
||||
retryUntilSucceed(func() error {
|
||||
clusterEventCallback := func(event *db.ClusterEvent) {
|
||||
info, ok := watchingClusters[event.Cluster.Server]
|
||||
hasApps := isClusterHasApps(ctrl.appInformer.GetStore().List(), event.Cluster)
|
||||
|
||||
// cluster resources must be watched only if cluster has at least one app
|
||||
if (event.Type == watch.Deleted || !hasApps) && ok {
|
||||
info.cancel()
|
||||
return ctrl.db.WatchClusters(context.Background(), func(event *db.ClusterEvent) {
|
||||
cancel, ok := watchingClusters[event.Cluster.Server]
|
||||
if event.Type == watch.Deleted && ok {
|
||||
cancel()
|
||||
delete(watchingClusters, event.Cluster.Server)
|
||||
} else if event.Type != watch.Deleted && !ok && hasApps {
|
||||
} else if event.Type != watch.Deleted && !ok {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
watchingClusters[event.Cluster.Server] = struct {
|
||||
cancel context.CancelFunc
|
||||
cluster *appv1.Cluster
|
||||
}{
|
||||
cancel: cancel,
|
||||
cluster: event.Cluster,
|
||||
}
|
||||
watchingClusters[event.Cluster.Server] = cancel
|
||||
go ctrl.watchClusterResources(ctx, *event.Cluster)
|
||||
}
|
||||
}
|
||||
|
||||
onAppModified := func(obj interface{}) {
|
||||
if app, ok := obj.(*appv1.Application); ok {
|
||||
var cluster *appv1.Cluster
|
||||
info, infoOk := watchingClusters[app.Spec.Destination.Server]
|
||||
if infoOk {
|
||||
cluster = info.cluster
|
||||
} else {
|
||||
cluster, _ = ctrl.db.GetCluster(context.Background(), app.Spec.Destination.Server)
|
||||
}
|
||||
if cluster != nil {
|
||||
// trigger cluster event every time when app created/deleted to either start or stop watching resources
|
||||
clusterEventCallback(&db.ClusterEvent{Cluster: cluster, Type: watch.Modified})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ctrl.appInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{AddFunc: onAppModified, DeleteFunc: onAppModified})
|
||||
|
||||
return ctrl.db.WatchClusters(context.Background(), clusterEventCallback)
|
||||
|
||||
})
|
||||
}, "watch clusters", context.Background(), watchResourcesRetryTimeout)
|
||||
|
||||
<-context.Background().Done()
|
||||
@@ -315,13 +252,12 @@ func (ctrl *ApplicationController) processAppOperationQueueItem() (processNext b
|
||||
}
|
||||
|
||||
func (ctrl *ApplicationController) finalizeApplicationDeletion(app *appv1.Application) {
|
||||
logCtx := log.WithField("application", app.Name)
|
||||
logCtx.Infof("Deleting resources")
|
||||
log.Infof("Deleting resources for application %s", app.Name)
|
||||
// Get refreshed application info, since informer app copy might be stale
|
||||
app, err := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(app.Namespace).Get(app.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
if !errors.IsNotFound(err) {
|
||||
logCtx.Errorf("Unable to get refreshed application info prior deleting resources: %v", err)
|
||||
log.Errorf("Unable to get refreshed application info prior deleting resources: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -330,7 +266,7 @@ func (ctrl *ApplicationController) finalizeApplicationDeletion(app *appv1.Applic
|
||||
|
||||
if err == nil {
|
||||
config := clst.RESTConfig()
|
||||
err = kube.DeleteResourcesWithLabel(config, app.Spec.Destination.Namespace, common.LabelApplicationName, app.Name)
|
||||
err = kube.DeleteResourceWithLabel(config, app.Spec.Destination.Namespace, common.LabelApplicationName, app.Name)
|
||||
if err == nil {
|
||||
app.SetCascadedDeletion(false)
|
||||
var patch []byte
|
||||
@@ -345,14 +281,14 @@ func (ctrl *ApplicationController) finalizeApplicationDeletion(app *appv1.Applic
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
log.Errorf("Unable to delete application resources: %v", err)
|
||||
ctrl.setAppCondition(app, appv1.ApplicationCondition{
|
||||
Type: appv1.ApplicationConditionDeletionError,
|
||||
Message: err.Error(),
|
||||
})
|
||||
message := fmt.Sprintf("Unable to delete application resources: %v", err)
|
||||
ctrl.auditLogger.LogAppEvent(app, argo.EventInfo{Reason: argo.EventReasonStatusRefreshed, Type: v1.EventTypeWarning}, message)
|
||||
ctrl.auditLogger.LogAppEvent(app, argo.EventInfo{Reason: argo.EventReasonStatusRefreshed, Action: "refresh_status"}, v1.EventTypeWarning)
|
||||
} else {
|
||||
logCtx.Info("Successfully deleted resources")
|
||||
log.Infof("Successfully deleted resources for application %s", app.Name)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -384,12 +320,11 @@ func (ctrl *ApplicationController) setAppCondition(app *appv1.Application, condi
|
||||
}
|
||||
|
||||
func (ctrl *ApplicationController) processRequestedAppOperation(app *appv1.Application) {
|
||||
logCtx := log.WithField("application", app.Name)
|
||||
var state *appv1.OperationState
|
||||
// Recover from any unexpected panics and automatically set the status to be failed
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
logCtx.Errorf("Recovered from panic: %+v\n%s", r, debug.Stack())
|
||||
log.Errorf("Recovered from panic: %+v\n%s", r, debug.Stack())
|
||||
state.Phase = appv1.OperationError
|
||||
if rerr, ok := r.(error); ok {
|
||||
state.Message = rerr.Error()
|
||||
@@ -406,20 +341,20 @@ func (ctrl *ApplicationController) processRequestedAppOperation(app *appv1.Appli
|
||||
// again. To detect this, always retrieve the latest version to ensure it is not stale.
|
||||
freshApp, err := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(ctrl.namespace).Get(app.ObjectMeta.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
logCtx.Errorf("Failed to retrieve latest application state: %v", err)
|
||||
log.Errorf("Failed to retrieve latest application state: %v", err)
|
||||
return
|
||||
}
|
||||
if !isOperationInProgress(freshApp) {
|
||||
logCtx.Infof("Skipping operation on stale application state")
|
||||
log.Infof("Skipping operation on stale application state (%s)", app.ObjectMeta.Name)
|
||||
return
|
||||
}
|
||||
app = freshApp
|
||||
state = app.Status.OperationState.DeepCopy()
|
||||
logCtx.Infof("Resuming in-progress operation. phase: %s, message: %s", state.Phase, state.Message)
|
||||
log.Infof("Resuming in-progress operation. app: %s, phase: %s, message: %s", app.ObjectMeta.Name, state.Phase, state.Message)
|
||||
} else {
|
||||
state = &appv1.OperationState{Phase: appv1.OperationRunning, Operation: *app.Operation, StartedAt: metav1.Now()}
|
||||
ctrl.setOperationState(app, state)
|
||||
logCtx.Infof("Initialized new operation: %v", *app.Operation)
|
||||
log.Infof("Initialized new operation. app: %s, operation: %v", app.ObjectMeta.Name, *app.Operation)
|
||||
}
|
||||
ctrl.appStateManager.SyncAppState(app, state)
|
||||
|
||||
@@ -465,6 +400,7 @@ func (ctrl *ApplicationController) setOperationState(app *appv1.Application, sta
|
||||
// If operation is completed, clear the operation field to indicate no operation is
|
||||
// in progress.
|
||||
patch["operation"] = nil
|
||||
ctrl.auditLogger.LogAppEvent(app, argo.EventInfo{Reason: argo.EventReasonResourceUpdated, Action: "refresh_status"}, v1.EventTypeNormal)
|
||||
}
|
||||
if reflect.DeepEqual(app.Status.OperationState, state) {
|
||||
log.Infof("No operation updates necessary to '%s'. Skipping patch", app.Name)
|
||||
@@ -480,18 +416,6 @@ func (ctrl *ApplicationController) setOperationState(app *appv1.Application, sta
|
||||
return err
|
||||
}
|
||||
log.Infof("updated '%s' operation (phase: %s)", app.Name, state.Phase)
|
||||
if state.Phase.Completed() {
|
||||
eventInfo := argo.EventInfo{Reason: argo.EventReasonOperationCompleted}
|
||||
var message string
|
||||
if state.Phase.Successful() {
|
||||
eventInfo.Type = v1.EventTypeNormal
|
||||
message = "Operation succeeded"
|
||||
} else {
|
||||
eventInfo.Type = v1.EventTypeWarning
|
||||
message = fmt.Sprintf("Operation failed: %v", state.Message)
|
||||
}
|
||||
ctrl.auditLogger.LogAppEvent(app, eventInfo, message)
|
||||
}
|
||||
return nil
|
||||
}, "Update application operation state", context.Background(), updateOperationStateTimeout)
|
||||
}
|
||||
@@ -551,16 +475,10 @@ func (ctrl *ApplicationController) processAppRefreshQueueItem() (processNext boo
|
||||
parameters = manifestInfo.Params
|
||||
}
|
||||
|
||||
healthState, err := setApplicationHealth(ctrl.kubectl, comparisonResult)
|
||||
healthState, err := setApplicationHealth(comparisonResult)
|
||||
if err != nil {
|
||||
conditions = append(conditions, appv1.ApplicationCondition{Type: appv1.ApplicationConditionComparisonError, Message: err.Error()})
|
||||
}
|
||||
|
||||
syncErrCond := ctrl.autoSync(app, comparisonResult)
|
||||
if syncErrCond != nil {
|
||||
conditions = append(conditions, *syncErrCond)
|
||||
}
|
||||
|
||||
ctrl.updateAppStatus(app, comparisonResult, healthState, parameters, conditions)
|
||||
return
|
||||
}
|
||||
@@ -568,20 +486,18 @@ func (ctrl *ApplicationController) processAppRefreshQueueItem() (processNext boo
|
||||
// needRefreshAppStatus answers if application status needs to be refreshed.
|
||||
// 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 {
|
||||
logCtx := log.WithFields(log.Fields{"application": app.Name})
|
||||
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 && expired {
|
||||
} else if app.Status.ComparisonResult.Status == appv1.ComparisonStatusUnknown {
|
||||
reason = "comparison status unknown"
|
||||
} else if !app.Spec.Source.Equals(app.Status.ComparisonResult.ComparedTo) {
|
||||
reason = "spec.source differs"
|
||||
} else if expired {
|
||||
} else if app.Status.ComparisonResult.ComparedAt.Add(statusRefreshTimeout).Before(time.Now().UTC()) {
|
||||
reason = fmt.Sprintf("comparison expired. comparedAt: %v, expiry: %v", app.Status.ComparisonResult.ComparedAt, statusRefreshTimeout)
|
||||
}
|
||||
if reason != "" {
|
||||
logCtx.Infof("Refreshing app status (%s)", reason)
|
||||
log.Infof("Refreshing application '%s' status (%s)", app.Name, reason)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
@@ -620,7 +536,6 @@ func (ctrl *ApplicationController) refreshAppConditions(app *appv1.Application)
|
||||
appv1.ApplicationConditionUnknownError: true,
|
||||
appv1.ApplicationConditionComparisonError: true,
|
||||
appv1.ApplicationConditionSharedResourceWarning: true,
|
||||
appv1.ApplicationConditionSyncError: true,
|
||||
}
|
||||
appConditions := make([]appv1.ApplicationCondition, 0)
|
||||
for i := 0; i < len(app.Status.Conditions); i++ {
|
||||
@@ -642,7 +557,7 @@ func (ctrl *ApplicationController) refreshAppConditions(app *appv1.Application)
|
||||
}
|
||||
|
||||
// setApplicationHealth updates the health statuses of all resources performed in the comparison
|
||||
func setApplicationHealth(kubectl kube.Kubectl, comparisonResult *appv1.ComparisonResult) (*appv1.HealthStatus, error) {
|
||||
func setApplicationHealth(comparisonResult *appv1.ComparisonResult) (*appv1.HealthStatus, error) {
|
||||
var savedErr error
|
||||
appHealth := appv1.HealthStatus{Status: appv1.HealthStatusHealthy}
|
||||
if comparisonResult.Status == appv1.ComparisonStatusUnknown {
|
||||
@@ -657,7 +572,7 @@ func setApplicationHealth(kubectl kube.Kubectl, comparisonResult *appv1.Comparis
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
healthState, err := health.GetAppHealth(kubectl, &obj)
|
||||
healthState, err := health.GetAppHealth(&obj)
|
||||
if err != nil && savedErr == nil {
|
||||
savedErr = err
|
||||
}
|
||||
@@ -679,21 +594,12 @@ func (ctrl *ApplicationController) updateAppStatus(
|
||||
parameters []*appv1.ComponentParameter,
|
||||
conditions []appv1.ApplicationCondition,
|
||||
) {
|
||||
logCtx := log.WithFields(log.Fields{"application": app.Name})
|
||||
modifiedApp := app.DeepCopy()
|
||||
if comparisonResult != nil {
|
||||
modifiedApp.Status.ComparisonResult = *comparisonResult
|
||||
if app.Status.ComparisonResult.Status != comparisonResult.Status {
|
||||
message := fmt.Sprintf("Updated sync status: %s -> %s", app.Status.ComparisonResult.Status, comparisonResult.Status)
|
||||
ctrl.auditLogger.LogAppEvent(app, argo.EventInfo{Reason: argo.EventReasonResourceUpdated, Type: v1.EventTypeNormal}, message)
|
||||
}
|
||||
logCtx.Infof("Comparison result: prev: %s. current: %s", app.Status.ComparisonResult.Status, comparisonResult.Status)
|
||||
log.Infof("App %s comparison result: prev: %s. current: %s", app.Name, app.Status.ComparisonResult.Status, comparisonResult.Status)
|
||||
}
|
||||
if healthState != nil {
|
||||
if modifiedApp.Status.Health.Status != healthState.Status {
|
||||
message := fmt.Sprintf("Updated health status: %s -> %s", modifiedApp.Status.Health.Status, healthState.Status)
|
||||
ctrl.auditLogger.LogAppEvent(app, argo.EventInfo{Reason: argo.EventReasonResourceUpdated, Type: v1.EventTypeNormal}, message)
|
||||
}
|
||||
modifiedApp.Status.Health = *healthState
|
||||
}
|
||||
if parameters != nil {
|
||||
@@ -707,104 +613,59 @@ func (ctrl *ApplicationController) updateAppStatus(
|
||||
}
|
||||
origBytes, err := json.Marshal(app)
|
||||
if err != nil {
|
||||
logCtx.Errorf("Error updating (marshal orig app): %v", err)
|
||||
log.Errorf("Error updating application %s (marshal orig app): %v", app.Name, err)
|
||||
return
|
||||
}
|
||||
modifiedBytes, err := json.Marshal(modifiedApp)
|
||||
if err != nil {
|
||||
logCtx.Errorf("Error updating (marshal modified app): %v", err)
|
||||
log.Errorf("Error updating application %s (marshal modified app): %v", app.Name, err)
|
||||
return
|
||||
}
|
||||
patch, err := strategicpatch.CreateTwoWayMergePatch(origBytes, modifiedBytes, appv1.Application{})
|
||||
if err != nil {
|
||||
logCtx.Errorf("Error calculating patch for update: %v", err)
|
||||
log.Errorf("Error calculating patch for app %s update: %v", app.Name, err)
|
||||
return
|
||||
}
|
||||
if string(patch) == "{}" {
|
||||
logCtx.Infof("No status changes. Skipping patch")
|
||||
log.Infof("No status changes to %s. Skipping patch", app.Name)
|
||||
return
|
||||
}
|
||||
appClient := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(app.Namespace)
|
||||
_, err = appClient.Patch(app.Name, types.MergePatchType, patch)
|
||||
if err != nil {
|
||||
logCtx.Warnf("Error updating application: %v", err)
|
||||
log.Warnf("Error updating application %s: %v", app.Name, err)
|
||||
} else {
|
||||
logCtx.Infof("Update successful")
|
||||
log.Infof("Application %s update successful", app.Name)
|
||||
}
|
||||
}
|
||||
|
||||
// autoSync will initiate a sync operation for an application configured with automated sync
|
||||
func (ctrl *ApplicationController) autoSync(app *appv1.Application, comparisonResult *appv1.ComparisonResult) *appv1.ApplicationCondition {
|
||||
if app.Spec.SyncPolicy == nil || app.Spec.SyncPolicy.Automated == nil {
|
||||
return nil
|
||||
}
|
||||
logCtx := log.WithFields(log.Fields{"application": app.Name})
|
||||
if app.Operation != nil {
|
||||
logCtx.Infof("Skipping auto-sync: another operation is in progress")
|
||||
return nil
|
||||
}
|
||||
// Only perform auto-sync if we detect OutOfSync status. This is to prevent us from attempting
|
||||
// a sync when application is already in a Synced or Unknown state
|
||||
if comparisonResult.Status != appv1.ComparisonStatusOutOfSync {
|
||||
logCtx.Infof("Skipping auto-sync: application status is %s", comparisonResult.Status)
|
||||
return nil
|
||||
}
|
||||
desiredCommitSHA := comparisonResult.Revision
|
||||
func newApplicationInformer(
|
||||
appClientset appclientset.Interface,
|
||||
appQueue workqueue.RateLimitingInterface,
|
||||
appOperationQueue workqueue.RateLimitingInterface,
|
||||
appResyncPeriod time.Duration,
|
||||
config *ApplicationControllerConfig) cache.SharedIndexInformer {
|
||||
|
||||
// It is possible for manifests to remain OutOfSync even after a sync/kubectl apply (e.g.
|
||||
// auto-sync with pruning disabled). We need to ensure that we do not keep Syncing an
|
||||
// application in an infinite loop. To detect this, we only attempt the Sync if the revision
|
||||
// and parameter overrides are different from our most recent sync operation.
|
||||
if alreadyAttemptedSync(app, desiredCommitSHA) {
|
||||
if app.Status.OperationState.Phase != appv1.OperationSucceeded {
|
||||
logCtx.Warnf("Skipping auto-sync: failed previous sync attempt to %s", desiredCommitSHA)
|
||||
message := fmt.Sprintf("Failed sync attempt to %s: %s", desiredCommitSHA, app.Status.OperationState.Message)
|
||||
return &appv1.ApplicationCondition{Type: appv1.ApplicationConditionSyncError, Message: message}
|
||||
}
|
||||
logCtx.Infof("Skipping auto-sync: most recent sync already to %s", desiredCommitSHA)
|
||||
return nil
|
||||
}
|
||||
|
||||
op := appv1.Operation{
|
||||
Sync: &appv1.SyncOperation{
|
||||
Revision: desiredCommitSHA,
|
||||
Prune: app.Spec.SyncPolicy.Automated.Prune,
|
||||
ParameterOverrides: app.Spec.Source.ComponentParameterOverrides,
|
||||
},
|
||||
}
|
||||
appIf := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(app.Namespace)
|
||||
_, err := argo.SetAppOperation(context.Background(), appIf, ctrl.auditLogger, app.Name, &op)
|
||||
if err != nil {
|
||||
logCtx.Errorf("Failed to initiate auto-sync to %s: %v", desiredCommitSHA, err)
|
||||
return &appv1.ApplicationCondition{Type: appv1.ApplicationConditionSyncError, Message: err.Error()}
|
||||
}
|
||||
message := fmt.Sprintf("Initiated automated sync to '%s'", desiredCommitSHA)
|
||||
ctrl.auditLogger.LogAppEvent(app, argo.EventInfo{Reason: argo.EventReasonOperationStarted, Type: v1.EventTypeNormal}, message)
|
||||
logCtx.Info(message)
|
||||
return nil
|
||||
}
|
||||
|
||||
// alreadyAttemptedSync returns whether or not the most recent sync was performed against the
|
||||
// commitSHA and with the same parameter overrides which are currently set in the app
|
||||
func alreadyAttemptedSync(app *appv1.Application, commitSHA string) bool {
|
||||
if app.Status.OperationState == nil || app.Status.OperationState.Operation.Sync == nil || app.Status.OperationState.SyncResult == nil {
|
||||
return false
|
||||
}
|
||||
if app.Status.OperationState.SyncResult.Revision != commitSHA {
|
||||
return false
|
||||
}
|
||||
if !reflect.DeepEqual(appv1.ParameterOverrides(app.Spec.Source.ComponentParameterOverrides), app.Status.OperationState.Operation.Sync.ParameterOverrides) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (ctrl *ApplicationController) newApplicationInformer() cache.SharedIndexInformer {
|
||||
appInformerFactory := appinformers.NewFilteredSharedInformerFactory(
|
||||
ctrl.applicationClientset,
|
||||
ctrl.statusRefreshTimeout,
|
||||
ctrl.namespace,
|
||||
func(options *metav1.ListOptions) {},
|
||||
appClientset,
|
||||
appResyncPeriod,
|
||||
config.Namespace,
|
||||
func(options *metav1.ListOptions) {
|
||||
var instanceIDReq *labels.Requirement
|
||||
var err error
|
||||
if config.InstanceID != "" {
|
||||
instanceIDReq, err = labels.NewRequirement(common.LabelKeyApplicationControllerInstanceID, selection.Equals, []string{config.InstanceID})
|
||||
} else {
|
||||
instanceIDReq, err = labels.NewRequirement(common.LabelKeyApplicationControllerInstanceID, selection.DoesNotExist, nil)
|
||||
}
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
options.FieldSelector = fields.Everything().String()
|
||||
labelSelector := labels.NewSelector().Add(*instanceIDReq)
|
||||
options.LabelSelector = labelSelector.String()
|
||||
},
|
||||
)
|
||||
informer := appInformerFactory.Argoproj().V1alpha1().Applications().Informer()
|
||||
informer.AddEventHandler(
|
||||
@@ -812,32 +673,23 @@ func (ctrl *ApplicationController) newApplicationInformer() cache.SharedIndexInf
|
||||
AddFunc: func(obj interface{}) {
|
||||
key, err := cache.MetaNamespaceKeyFunc(obj)
|
||||
if err == nil {
|
||||
ctrl.appRefreshQueue.Add(key)
|
||||
ctrl.appOperationQueue.Add(key)
|
||||
appQueue.Add(key)
|
||||
appOperationQueue.Add(key)
|
||||
}
|
||||
},
|
||||
UpdateFunc: func(old, new interface{}) {
|
||||
key, err := cache.MetaNamespaceKeyFunc(new)
|
||||
if err != nil {
|
||||
return
|
||||
if err == nil {
|
||||
appQueue.Add(key)
|
||||
appOperationQueue.Add(key)
|
||||
}
|
||||
oldApp, oldOK := old.(*appv1.Application)
|
||||
newApp, newOK := new.(*appv1.Application)
|
||||
if oldOK && newOK {
|
||||
if toggledAutomatedSync(oldApp, newApp) {
|
||||
log.WithField("application", newApp.Name).Info("Enabled automated sync")
|
||||
ctrl.forceAppRefresh(newApp.Name)
|
||||
}
|
||||
}
|
||||
ctrl.appRefreshQueue.Add(key)
|
||||
ctrl.appOperationQueue.Add(key)
|
||||
},
|
||||
DeleteFunc: func(obj interface{}) {
|
||||
// IndexerInformer uses a delta queue, therefore for deletes we have to use this
|
||||
// key function.
|
||||
key, err := cache.DeletionHandlingMetaNamespaceKeyFunc(obj)
|
||||
if err == nil {
|
||||
ctrl.appRefreshQueue.Add(key)
|
||||
appQueue.Add(key)
|
||||
}
|
||||
},
|
||||
},
|
||||
@@ -848,17 +700,3 @@ func (ctrl *ApplicationController) newApplicationInformer() cache.SharedIndexInf
|
||||
func isOperationInProgress(app *appv1.Application) bool {
|
||||
return app.Status.OperationState != nil && !app.Status.OperationState.Phase.Completed()
|
||||
}
|
||||
|
||||
// toggledAutomatedSync tests if an app went from auto-sync disabled to enabled.
|
||||
// if it was toggled to be enabled, the informer handler will force a refresh
|
||||
func toggledAutomatedSync(old *appv1.Application, new *appv1.Application) bool {
|
||||
if new.Spec.SyncPolicy == nil || new.Spec.SyncPolicy.Automated == nil {
|
||||
return false
|
||||
}
|
||||
// auto-sync is enabled. check if it was previously disabled
|
||||
if old.Spec.SyncPolicy == nil || old.Spec.SyncPolicy.Automated == nil {
|
||||
return true
|
||||
}
|
||||
// nothing changed
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -1,231 +0,0 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/client-go/kubernetes/fake"
|
||||
|
||||
argoappv1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
|
||||
appclientset "github.com/argoproj/argo-cd/pkg/client/clientset/versioned/fake"
|
||||
reposerver "github.com/argoproj/argo-cd/reposerver/mocks"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func newFakeController(apps ...runtime.Object) *ApplicationController {
|
||||
kubeClientset := fake.NewSimpleClientset()
|
||||
appClientset := appclientset.NewSimpleClientset(apps...)
|
||||
repoClientset := reposerver.Clientset{}
|
||||
return NewApplicationController(
|
||||
"argocd",
|
||||
kubeClientset,
|
||||
appClientset,
|
||||
&repoClientset,
|
||||
time.Minute,
|
||||
)
|
||||
}
|
||||
|
||||
var fakeApp = `
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: my-app
|
||||
namespace: argocd
|
||||
spec:
|
||||
destination:
|
||||
namespace: dummy-namespace
|
||||
server: https://localhost:6443
|
||||
project: default
|
||||
source:
|
||||
path: some/path
|
||||
repoURL: https://github.com/argoproj/argocd-example-apps.git
|
||||
syncPolicy:
|
||||
automated: {}
|
||||
status:
|
||||
operationState:
|
||||
finishedAt: 2018-09-21T23:50:29Z
|
||||
message: successfully synced
|
||||
operation:
|
||||
sync:
|
||||
revision: HEAD
|
||||
phase: Succeeded
|
||||
startedAt: 2018-09-21T23:50:25Z
|
||||
syncResult:
|
||||
resources:
|
||||
- kind: RoleBinding
|
||||
message: |-
|
||||
rolebinding.rbac.authorization.k8s.io/always-outofsync reconciled
|
||||
rolebinding.rbac.authorization.k8s.io/always-outofsync configured
|
||||
name: always-outofsync
|
||||
namespace: default
|
||||
status: Synced
|
||||
revision: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
`
|
||||
|
||||
func newFakeApp() *argoappv1.Application {
|
||||
var app argoappv1.Application
|
||||
err := yaml.Unmarshal([]byte(fakeApp), &app)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return &app
|
||||
}
|
||||
|
||||
func TestAutoSync(t *testing.T) {
|
||||
app := newFakeApp()
|
||||
ctrl := newFakeController(app)
|
||||
compRes := argoappv1.ComparisonResult{
|
||||
Status: argoappv1.ComparisonStatusOutOfSync,
|
||||
Revision: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
|
||||
}
|
||||
cond := ctrl.autoSync(app, &compRes)
|
||||
assert.Nil(t, cond)
|
||||
app, err := ctrl.applicationClientset.ArgoprojV1alpha1().Applications("argocd").Get("my-app", metav1.GetOptions{})
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, app.Operation)
|
||||
assert.NotNil(t, app.Operation.Sync)
|
||||
assert.False(t, app.Operation.Sync.Prune)
|
||||
}
|
||||
|
||||
func TestSkipAutoSync(t *testing.T) {
|
||||
// Verify we skip when we previously synced to it in our most recent history
|
||||
// Set current to 'aaaaa', desired to 'aaaa' and mark system OutOfSync
|
||||
app := newFakeApp()
|
||||
ctrl := newFakeController(app)
|
||||
compRes := argoappv1.ComparisonResult{
|
||||
Status: argoappv1.ComparisonStatusOutOfSync,
|
||||
Revision: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
}
|
||||
cond := ctrl.autoSync(app, &compRes)
|
||||
assert.Nil(t, cond)
|
||||
app, err := ctrl.applicationClientset.ArgoprojV1alpha1().Applications("argocd").Get("my-app", metav1.GetOptions{})
|
||||
assert.NoError(t, err)
|
||||
assert.Nil(t, app.Operation)
|
||||
|
||||
// Verify we skip when we are already Synced (even if revision is different)
|
||||
app = newFakeApp()
|
||||
ctrl = newFakeController(app)
|
||||
compRes = argoappv1.ComparisonResult{
|
||||
Status: argoappv1.ComparisonStatusSynced,
|
||||
Revision: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
|
||||
}
|
||||
cond = ctrl.autoSync(app, &compRes)
|
||||
assert.Nil(t, cond)
|
||||
app, err = ctrl.applicationClientset.ArgoprojV1alpha1().Applications("argocd").Get("my-app", metav1.GetOptions{})
|
||||
assert.NoError(t, err)
|
||||
assert.Nil(t, app.Operation)
|
||||
|
||||
// Verify we skip when auto-sync is disabled
|
||||
app = newFakeApp()
|
||||
app.Spec.SyncPolicy = nil
|
||||
ctrl = newFakeController(app)
|
||||
compRes = argoappv1.ComparisonResult{
|
||||
Status: argoappv1.ComparisonStatusOutOfSync,
|
||||
Revision: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
|
||||
}
|
||||
cond = ctrl.autoSync(app, &compRes)
|
||||
assert.Nil(t, cond)
|
||||
app, err = ctrl.applicationClientset.ArgoprojV1alpha1().Applications("argocd").Get("my-app", metav1.GetOptions{})
|
||||
assert.NoError(t, err)
|
||||
assert.Nil(t, app.Operation)
|
||||
|
||||
// Verify we skip when previous sync attempt failed and return error condition
|
||||
// Set current to 'aaaaa', desired to 'bbbbb' and add 'bbbbb' to failure history
|
||||
app = newFakeApp()
|
||||
app.Status.OperationState = &argoappv1.OperationState{
|
||||
Operation: argoappv1.Operation{
|
||||
Sync: &argoappv1.SyncOperation{},
|
||||
},
|
||||
Phase: argoappv1.OperationFailed,
|
||||
SyncResult: &argoappv1.SyncOperationResult{
|
||||
Revision: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
|
||||
},
|
||||
}
|
||||
ctrl = newFakeController(app)
|
||||
compRes = argoappv1.ComparisonResult{
|
||||
Status: argoappv1.ComparisonStatusOutOfSync,
|
||||
Revision: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
|
||||
}
|
||||
cond = ctrl.autoSync(app, &compRes)
|
||||
assert.NotNil(t, cond)
|
||||
app, err = ctrl.applicationClientset.ArgoprojV1alpha1().Applications("argocd").Get("my-app", metav1.GetOptions{})
|
||||
assert.NoError(t, err)
|
||||
assert.Nil(t, app.Operation)
|
||||
}
|
||||
|
||||
// TestAutoSyncIndicateError verifies we skip auto-sync and return error condition if previous sync failed
|
||||
func TestAutoSyncIndicateError(t *testing.T) {
|
||||
app := newFakeApp()
|
||||
app.Spec.Source.ComponentParameterOverrides = []argoappv1.ComponentParameter{
|
||||
{
|
||||
Name: "a",
|
||||
Value: "1",
|
||||
},
|
||||
}
|
||||
ctrl := newFakeController(app)
|
||||
compRes := argoappv1.ComparisonResult{
|
||||
Status: argoappv1.ComparisonStatusOutOfSync,
|
||||
Revision: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
}
|
||||
app.Status.OperationState = &argoappv1.OperationState{
|
||||
Operation: argoappv1.Operation{
|
||||
Sync: &argoappv1.SyncOperation{
|
||||
ParameterOverrides: argoappv1.ParameterOverrides{
|
||||
{
|
||||
Name: "a",
|
||||
Value: "1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Phase: argoappv1.OperationFailed,
|
||||
SyncResult: &argoappv1.SyncOperationResult{
|
||||
Revision: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
},
|
||||
}
|
||||
cond := ctrl.autoSync(app, &compRes)
|
||||
assert.NotNil(t, cond)
|
||||
app, err := ctrl.applicationClientset.ArgoprojV1alpha1().Applications("argocd").Get("my-app", metav1.GetOptions{})
|
||||
assert.NoError(t, err)
|
||||
assert.Nil(t, app.Operation)
|
||||
}
|
||||
|
||||
// TestAutoSyncParameterOverrides verifies we auto-sync if revision is same but parameter overrides are different
|
||||
func TestAutoSyncParameterOverrides(t *testing.T) {
|
||||
app := newFakeApp()
|
||||
app.Spec.Source.ComponentParameterOverrides = []argoappv1.ComponentParameter{
|
||||
{
|
||||
Name: "a",
|
||||
Value: "1",
|
||||
},
|
||||
}
|
||||
ctrl := newFakeController(app)
|
||||
compRes := argoappv1.ComparisonResult{
|
||||
Status: argoappv1.ComparisonStatusOutOfSync,
|
||||
Revision: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
}
|
||||
app.Status.OperationState = &argoappv1.OperationState{
|
||||
Operation: argoappv1.Operation{
|
||||
Sync: &argoappv1.SyncOperation{
|
||||
ParameterOverrides: argoappv1.ParameterOverrides{
|
||||
{
|
||||
Name: "a",
|
||||
Value: "2", // this value changed
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Phase: argoappv1.OperationFailed,
|
||||
SyncResult: &argoappv1.SyncOperationResult{
|
||||
Revision: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
},
|
||||
}
|
||||
cond := ctrl.autoSync(app, &compRes)
|
||||
assert.Nil(t, cond)
|
||||
app, err := ctrl.applicationClientset.ArgoprojV1alpha1().Applications("argocd").Get("my-app", metav1.GetOptions{})
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, app.Operation)
|
||||
}
|
||||
@@ -3,9 +3,16 @@ package controller
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"runtime/debug"
|
||||
"time"
|
||||
|
||||
"runtime/debug"
|
||||
|
||||
"github.com/argoproj/argo-cd/common"
|
||||
"github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/reposerver"
|
||||
"github.com/argoproj/argo-cd/reposerver/repository"
|
||||
"github.com/argoproj/argo-cd/util"
|
||||
"github.com/argoproj/argo-cd/util/db"
|
||||
log "github.com/sirupsen/logrus"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -18,12 +25,6 @@ import (
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
"k8s.io/client-go/util/workqueue"
|
||||
|
||||
"github.com/argoproj/argo-cd/common"
|
||||
"github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/reposerver"
|
||||
"github.com/argoproj/argo-cd/util/db"
|
||||
"github.com/argoproj/argo-cd/util/git"
|
||||
)
|
||||
|
||||
type SecretController struct {
|
||||
@@ -92,13 +93,22 @@ func (ctrl *SecretController) getRepoConnectionState(repo *v1alpha1.Repository)
|
||||
ModifiedAt: repo.ConnectionState.ModifiedAt,
|
||||
Status: v1alpha1.ConnectionStatusUnknown,
|
||||
}
|
||||
err := git.TestRepo(repo.Repo, repo.Username, repo.Password, repo.SSHPrivateKey)
|
||||
closer, client, err := ctrl.repoClientset.NewRepositoryClient()
|
||||
if err != nil {
|
||||
log.Errorf("Unable to create repository client: %v", err)
|
||||
return state
|
||||
}
|
||||
|
||||
defer util.Close(closer)
|
||||
|
||||
_, err = client.ListDir(context.Background(), &repository.ListDirRequest{Repo: repo, Path: ".gitignore"})
|
||||
if err == nil {
|
||||
state.Status = v1alpha1.ConnectionStatusSuccessful
|
||||
} else {
|
||||
state.Status = v1alpha1.ConnectionStatusFailed
|
||||
state.Message = err.Error()
|
||||
}
|
||||
|
||||
return state
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ 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"
|
||||
@@ -36,11 +35,10 @@ type AppStateManager interface {
|
||||
SyncAppState(app *v1alpha1.Application, state *v1alpha1.OperationState)
|
||||
}
|
||||
|
||||
// appStateManager allows to compare application using KSonnet CLI
|
||||
type appStateManager struct {
|
||||
// ksonnetAppStateManager allows to compare application using KSonnet CLI
|
||||
type ksonnetAppStateManager struct {
|
||||
db db.ArgoDB
|
||||
appclientset appclientset.Interface
|
||||
kubectl kubeutil.Kubectl
|
||||
repoClientset reposerver.Clientset
|
||||
namespace string
|
||||
}
|
||||
@@ -85,7 +83,7 @@ func groupLiveObjects(liveObjs []*unstructured.Unstructured, targetObjs []*unstr
|
||||
return liveByFullName
|
||||
}
|
||||
|
||||
func (s *appStateManager) getTargetObjs(app *v1alpha1.Application, revision string, overrides []v1alpha1.ComponentParameter) ([]*unstructured.Unstructured, *repository.ManifestResponse, error) {
|
||||
func (s *ksonnetAppStateManager) getTargetObjs(app *v1alpha1.Application, revision string, overrides []v1alpha1.ComponentParameter) ([]*unstructured.Unstructured, *repository.ManifestResponse, error) {
|
||||
repo := s.getRepo(app.Spec.Source.RepoURL)
|
||||
conn, repoClient, err := s.repoClientset.NewRepositoryClient()
|
||||
if err != nil {
|
||||
@@ -123,7 +121,6 @@ func (s *appStateManager) getTargetObjs(app *v1alpha1.Application, revision stri
|
||||
ComponentParameterOverrides: mfReqOverrides,
|
||||
AppLabel: app.Name,
|
||||
ValueFiles: app.Spec.Source.ValuesFiles,
|
||||
Namespace: app.Spec.Destination.Namespace,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
@@ -143,7 +140,7 @@ func (s *appStateManager) getTargetObjs(app *v1alpha1.Application, revision stri
|
||||
return targetObjs, manifestInfo, nil
|
||||
}
|
||||
|
||||
func (s *appStateManager) getLiveObjs(app *v1alpha1.Application, targetObjs []*unstructured.Unstructured) (
|
||||
func (s *ksonnetAppStateManager) getLiveObjs(app *v1alpha1.Application, targetObjs []*unstructured.Unstructured) (
|
||||
[]*unstructured.Unstructured, map[string]*unstructured.Unstructured, error) {
|
||||
|
||||
// Get the REST config for the cluster corresponding to the environment
|
||||
@@ -171,10 +168,7 @@ func (s *appStateManager) getLiveObjs(app *v1alpha1.Application, targetObjs []*u
|
||||
controlledLiveObj := make([]*unstructured.Unstructured, len(targetObjs))
|
||||
|
||||
// Move live resources which have corresponding target object to controlledLiveObj
|
||||
dynamicIf, err := dynamic.NewForConfig(restConfig)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
dynClientPool := dynamic.NewDynamicClientPool(restConfig)
|
||||
disco, err := discovery.NewDiscoveryClientForConfig(restConfig)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
@@ -188,29 +182,30 @@ func (s *appStateManager) getLiveObjs(app *v1alpha1.Application, targetObjs []*u
|
||||
// of ArgoCD. In order to determine that it is truly missing, we fall back to perform a
|
||||
// direct lookup of the resource by name. See issue #141
|
||||
gvk := targetObj.GroupVersionKind()
|
||||
dclient, err := dynClientPool.ClientForGroupVersionKind(gvk)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
apiResource, err := kubeutil.ServerResourceForGroupVersionKind(disco, gvk)
|
||||
if err != nil {
|
||||
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(dynamicIf, targetObj, apiResource, app.Spec.Destination.Namespace)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return nil, nil, err
|
||||
}
|
||||
liveObj, err = kubeutil.GetLiveResource(dclient, targetObj, apiResource, app.Spec.Destination.Namespace)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
controlledLiveObj[i] = liveObj
|
||||
delete(liveObjByFullName, fullName)
|
||||
}
|
||||
|
||||
return controlledLiveObj, liveObjByFullName, nil
|
||||
}
|
||||
|
||||
// CompareAppState compares application git state to the live app state, using the specified
|
||||
// revision and supplied overrides. If revision or overrides are empty, then compares against
|
||||
// revision and overrides in the app spec.
|
||||
func (s *appStateManager) CompareAppState(app *v1alpha1.Application, revision string, overrides []v1alpha1.ComponentParameter) (
|
||||
func (s *ksonnetAppStateManager) CompareAppState(app *v1alpha1.Application, revision string, overrides []v1alpha1.ComponentParameter) (
|
||||
*v1alpha1.ComparisonResult, *repository.ManifestResponse, []v1alpha1.ApplicationCondition, error) {
|
||||
|
||||
failedToLoadObjs := false
|
||||
@@ -323,10 +318,6 @@ func (s *appStateManager) CompareAppState(app *v1alpha1.Application, revision st
|
||||
Resources: resources,
|
||||
Status: comparisonStatus,
|
||||
}
|
||||
|
||||
if manifestInfo != nil {
|
||||
compResult.Revision = manifestInfo.Revision
|
||||
}
|
||||
return &compResult, manifestInfo, conditions, nil
|
||||
}
|
||||
|
||||
@@ -369,7 +360,7 @@ func getResourceFullName(obj *unstructured.Unstructured) string {
|
||||
return fmt.Sprintf("%s:%s", obj.GetKind(), obj.GetName())
|
||||
}
|
||||
|
||||
func (s *appStateManager) getRepo(repoURL string) *v1alpha1.Repository {
|
||||
func (s *ksonnetAppStateManager) getRepo(repoURL string) *v1alpha1.Repository {
|
||||
repo, err := s.db.GetRepository(context.Background(), repoURL)
|
||||
if err != nil {
|
||||
// If we couldn't retrieve from the repo service, assume public repositories
|
||||
@@ -378,7 +369,7 @@ func (s *appStateManager) getRepo(repoURL string) *v1alpha1.Repository {
|
||||
return repo
|
||||
}
|
||||
|
||||
func (s *appStateManager) persistDeploymentInfo(
|
||||
func (s *ksonnetAppStateManager) persistDeploymentInfo(
|
||||
app *v1alpha1.Application, revision string, envParams []*v1alpha1.ComponentParameter, overrides *[]v1alpha1.ComponentParameter) error {
|
||||
|
||||
params := make([]v1alpha1.ComponentParameter, len(envParams))
|
||||
@@ -393,6 +384,7 @@ func (s *appStateManager) persistDeploymentInfo(
|
||||
history := append(app.Status.History, v1alpha1.DeploymentInfo{
|
||||
ComponentParameterOverrides: app.Spec.Source.ComponentParameterOverrides,
|
||||
Revision: revision,
|
||||
Params: params,
|
||||
DeployedAt: metav1.NewTime(time.Now().UTC()),
|
||||
ID: nextID,
|
||||
})
|
||||
@@ -419,12 +411,10 @@ func NewAppStateManager(
|
||||
appclientset appclientset.Interface,
|
||||
repoClientset reposerver.Clientset,
|
||||
namespace string,
|
||||
kubectl kubeutil.Kubectl,
|
||||
) AppStateManager {
|
||||
return &appStateManager{
|
||||
return &ksonnetAppStateManager{
|
||||
db: db,
|
||||
appclientset: appclientset,
|
||||
kubectl: kubectl,
|
||||
repoClientset: repoClientset,
|
||||
namespace: namespace,
|
||||
}
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
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))
|
||||
}
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
@@ -30,16 +29,13 @@ import (
|
||||
|
||||
type syncContext struct {
|
||||
appName string
|
||||
proj *appv1.AppProject
|
||||
comparison *appv1.ComparisonResult
|
||||
config *rest.Config
|
||||
dynamicIf dynamic.Interface
|
||||
disco discovery.DiscoveryInterface
|
||||
kubectl kube.Kubectl
|
||||
dynClientPool dynamic.ClientPool
|
||||
disco *discovery.DiscoveryClient
|
||||
namespace string
|
||||
syncOp *appv1.SyncOperation
|
||||
syncRes *appv1.SyncOperationResult
|
||||
syncResources []appv1.SyncOperationResource
|
||||
opState *appv1.OperationState
|
||||
manifestInfo *repository.ManifestResponse
|
||||
log *log.Entry
|
||||
@@ -47,8 +43,8 @@ type syncContext struct {
|
||||
lock sync.Mutex
|
||||
}
|
||||
|
||||
func (s *appStateManager) SyncAppState(app *appv1.Application, state *appv1.OperationState) {
|
||||
// Sync requests might be requested with ambiguous revisions (e.g. master, HEAD, v1.2.3).
|
||||
func (s *ksonnetAppStateManager) SyncAppState(app *appv1.Application, state *appv1.OperationState) {
|
||||
// Sync requests are usually requested with ambiguous revisions (e.g. master, HEAD, v1.2.3).
|
||||
// This can change meaning when resuming operations (e.g a hook sync). After calculating a
|
||||
// concrete git commit SHA, the SHA is remembered in the status.operationState.syncResult and
|
||||
// rollbackResult fields. This ensures that when resuming an operation, we sync to the same
|
||||
@@ -56,13 +52,10 @@ func (s *appStateManager) SyncAppState(app *appv1.Application, state *appv1.Oper
|
||||
var revision string
|
||||
var syncOp appv1.SyncOperation
|
||||
var syncRes *appv1.SyncOperationResult
|
||||
var syncResources []appv1.SyncOperationResource
|
||||
var overrides []appv1.ComponentParameter
|
||||
|
||||
if state.Operation.Sync != nil {
|
||||
syncOp = *state.Operation.Sync
|
||||
syncResources = syncOp.Resources
|
||||
overrides = []appv1.ComponentParameter(state.Operation.Sync.ParameterOverrides)
|
||||
if state.SyncResult != nil {
|
||||
syncRes = state.SyncResult
|
||||
revision = state.SyncResult.Revision
|
||||
@@ -70,6 +63,34 @@ func (s *appStateManager) SyncAppState(app *appv1.Application, state *appv1.Oper
|
||||
syncRes = &appv1.SyncOperationResult{}
|
||||
state.SyncResult = syncRes
|
||||
}
|
||||
} else if state.Operation.Rollback != nil {
|
||||
var deploymentInfo *appv1.DeploymentInfo
|
||||
for _, info := range app.Status.History {
|
||||
if info.ID == app.Operation.Rollback.ID {
|
||||
deploymentInfo = &info
|
||||
break
|
||||
}
|
||||
}
|
||||
if deploymentInfo == nil {
|
||||
state.Phase = appv1.OperationFailed
|
||||
state.Message = fmt.Sprintf("application %s does not have deployment with id %v", app.Name, app.Operation.Rollback.ID)
|
||||
return
|
||||
}
|
||||
// Rollback is just a convenience around Sync
|
||||
syncOp = appv1.SyncOperation{
|
||||
Revision: deploymentInfo.Revision,
|
||||
DryRun: state.Operation.Rollback.DryRun,
|
||||
Prune: state.Operation.Rollback.Prune,
|
||||
SyncStrategy: &appv1.SyncStrategy{Apply: &appv1.SyncStrategyApply{}},
|
||||
}
|
||||
overrides = deploymentInfo.ComponentParameterOverrides
|
||||
if state.RollbackResult != nil {
|
||||
syncRes = state.RollbackResult
|
||||
revision = state.RollbackResult.Revision
|
||||
} else {
|
||||
syncRes = &appv1.SyncOperationResult{}
|
||||
state.RollbackResult = syncRes
|
||||
}
|
||||
} else {
|
||||
state.Phase = appv1.OperationFailed
|
||||
state.Message = "Invalid operation request: no operation specified"
|
||||
@@ -82,7 +103,6 @@ func (s *appStateManager) SyncAppState(app *appv1.Application, state *appv1.Oper
|
||||
// Take the value in the requested operation. We will resolve this to a SHA later.
|
||||
revision = syncOp.Revision
|
||||
}
|
||||
|
||||
comparison, manifestInfo, conditions, err := s.CompareAppState(app, revision, overrides)
|
||||
if err != nil {
|
||||
state.Phase = appv1.OperationError
|
||||
@@ -112,38 +132,23 @@ func (s *appStateManager) SyncAppState(app *appv1.Application, state *appv1.Oper
|
||||
}
|
||||
|
||||
restConfig := clst.RESTConfig()
|
||||
dynamicIf, err := dynamic.NewForConfig(restConfig)
|
||||
dynClientPool := dynamic.NewDynamicClientPool(restConfig)
|
||||
disco, err := discovery.NewDiscoveryClientForConfig(restConfig)
|
||||
if err != nil {
|
||||
state.Phase = appv1.OperationError
|
||||
state.Message = fmt.Sprintf("Failed to initialize dynamic client: %v", err)
|
||||
return
|
||||
}
|
||||
disco, err := discovery.NewDiscoveryClientForConfig(restConfig)
|
||||
if err != nil {
|
||||
state.Phase = appv1.OperationError
|
||||
state.Message = fmt.Sprintf("Failed to initialize discovery client: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
proj, err := argo.GetAppProject(&app.Spec, s.appclientset, s.namespace)
|
||||
if err != nil {
|
||||
state.Phase = appv1.OperationError
|
||||
state.Message = fmt.Sprintf("Failed to load application project: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
syncCtx := syncContext{
|
||||
appName: app.Name,
|
||||
proj: proj,
|
||||
comparison: comparison,
|
||||
config: restConfig,
|
||||
dynamicIf: dynamicIf,
|
||||
dynClientPool: dynClientPool,
|
||||
disco: disco,
|
||||
kubectl: s.kubectl,
|
||||
namespace: app.Spec.Destination.Namespace,
|
||||
syncOp: &syncOp,
|
||||
syncRes: syncRes,
|
||||
syncResources: syncResources,
|
||||
opState: state,
|
||||
manifestInfo: manifestInfo,
|
||||
log: log.WithFields(log.Fields{"application": app.Name}),
|
||||
@@ -155,7 +160,7 @@ func (s *appStateManager) SyncAppState(app *appv1.Application, state *appv1.Oper
|
||||
syncCtx.sync()
|
||||
}
|
||||
|
||||
if !syncOp.DryRun && len(syncOp.Resources) == 0 && syncCtx.opState.Phase.Successful() {
|
||||
if !syncOp.DryRun && syncCtx.opState.Phase.Successful() {
|
||||
err := s.persistDeploymentInfo(app, manifestInfo.Revision, manifestInfo.Params, nil)
|
||||
if err != nil {
|
||||
state.Phase = appv1.OperationError
|
||||
@@ -244,22 +249,13 @@ func (sc *syncContext) generateSyncTasks() ([]syncTask, bool) {
|
||||
sc.setOperationPhase(appv1.OperationError, fmt.Sprintf("Failed to unmarshal target object: %v", err))
|
||||
return nil, false
|
||||
}
|
||||
if sc.syncResources == nil || argo.ContainsSyncResource(liveObj, sc.syncResources) || argo.ContainsSyncResource(targetObj, sc.syncResources) {
|
||||
syncTask := syncTask{
|
||||
liveObj: liveObj,
|
||||
targetObj: targetObj,
|
||||
}
|
||||
syncTasks = append(syncTasks, syncTask)
|
||||
syncTask := syncTask{
|
||||
liveObj: liveObj,
|
||||
targetObj: targetObj,
|
||||
}
|
||||
syncTasks = append(syncTasks, syncTask)
|
||||
}
|
||||
if len(syncTasks) == 0 {
|
||||
if len(sc.comparison.Resources) == 0 {
|
||||
sc.setOperationPhase(appv1.OperationError, fmt.Sprintf("Application has no resources"))
|
||||
} else {
|
||||
sc.setOperationPhase(appv1.OperationError, fmt.Sprintf("Specified resources filter does not match any application resource"))
|
||||
}
|
||||
}
|
||||
return syncTasks, len(syncTasks) > 0
|
||||
return syncTasks, true
|
||||
}
|
||||
|
||||
// startedPreSyncPhase detects if we already started the PreSync stage of a sync operation.
|
||||
@@ -314,13 +310,12 @@ func (sc *syncContext) applyObject(targetObj *unstructured.Unstructured, dryRun
|
||||
Kind: targetObj.GetKind(),
|
||||
Namespace: sc.namespace,
|
||||
}
|
||||
message, err := sc.kubectl.ApplyResource(sc.config, targetObj, sc.namespace, dryRun, force)
|
||||
message, err := kube.ApplyResource(sc.config, targetObj, sc.namespace, dryRun, force)
|
||||
if err != nil {
|
||||
resDetails.Message = err.Error()
|
||||
resDetails.Status = appv1.ResourceDetailsSyncFailed
|
||||
return resDetails
|
||||
}
|
||||
|
||||
resDetails.Message = message
|
||||
resDetails.Status = appv1.ResourceDetailsSynced
|
||||
return resDetails
|
||||
@@ -338,7 +333,7 @@ func (sc *syncContext) pruneObject(liveObj *unstructured.Unstructured, prune, dr
|
||||
resDetails.Message = "pruned (dry run)"
|
||||
resDetails.Status = appv1.ResourceDetailsSyncedAndPruned
|
||||
} else {
|
||||
err := sc.kubectl.DeleteResource(sc.config, liveObj, sc.namespace)
|
||||
err := kube.DeleteResource(sc.config, liveObj, sc.namespace)
|
||||
if err != nil {
|
||||
resDetails.Message = err.Error()
|
||||
resDetails.Status = appv1.ResourceDetailsSyncFailed
|
||||
@@ -354,49 +349,26 @@ func (sc *syncContext) pruneObject(liveObj *unstructured.Unstructured, prune, dr
|
||||
return resDetails
|
||||
}
|
||||
|
||||
func hasCRDOfGroupKind(tasks []syncTask, group, kind string) bool {
|
||||
for _, task := range tasks {
|
||||
if kube.IsCRD(task.targetObj) {
|
||||
crdGroup, ok, err := unstructured.NestedString(task.targetObj.Object, "spec", "group")
|
||||
if err != nil || !ok {
|
||||
continue
|
||||
}
|
||||
crdKind, ok, err := unstructured.NestedString(task.targetObj.Object, "spec", "names", "kind")
|
||||
if err != nil || !ok {
|
||||
continue
|
||||
}
|
||||
if group == crdGroup && crdKind == kind {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// performs a apply based sync of the given sync tasks (possibly pruning the objects).
|
||||
// If update is true, will updates the resource details with the result.
|
||||
// Or if the prune/apply failed, will also update the result.
|
||||
func (sc *syncContext) doApplySync(syncTasks []syncTask, dryRun, force, update bool) bool {
|
||||
syncSuccessful := true
|
||||
|
||||
var createTasks []syncTask
|
||||
var pruneTasks []syncTask
|
||||
for _, syncTask := range syncTasks {
|
||||
if syncTask.targetObj == nil {
|
||||
pruneTasks = append(pruneTasks, syncTask)
|
||||
} else {
|
||||
createTasks = append(createTasks, syncTask)
|
||||
}
|
||||
}
|
||||
sort.Sort(newKindSorter(createTasks, resourceOrder))
|
||||
|
||||
// apply all resources in parallel
|
||||
var wg sync.WaitGroup
|
||||
for _, task := range pruneTasks {
|
||||
for _, task := range syncTasks {
|
||||
wg.Add(1)
|
||||
go func(t syncTask) {
|
||||
defer wg.Done()
|
||||
var resDetails appv1.ResourceDetails
|
||||
resDetails = sc.pruneObject(t.liveObj, sc.syncOp.Prune, dryRun)
|
||||
if t.targetObj == nil {
|
||||
resDetails = sc.pruneObject(t.liveObj, sc.syncOp.Prune, dryRun)
|
||||
} else {
|
||||
if isHook(t.targetObj) {
|
||||
return
|
||||
}
|
||||
resDetails = sc.applyObject(t.targetObj, dryRun, force)
|
||||
}
|
||||
if !resDetails.Status.Successful() {
|
||||
syncSuccessful = false
|
||||
}
|
||||
@@ -406,76 +378,6 @@ func (sc *syncContext) doApplySync(syncTasks []syncTask, dryRun, force, update b
|
||||
}(task)
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
processCreateTasks := func(tasks []syncTask, gvk schema.GroupVersionKind) {
|
||||
serverRes, err := kube.ServerResourceForGroupVersionKind(sc.disco, gvk)
|
||||
if err != nil {
|
||||
// Special case for custom resources: if custom resource definition is not supported by the cluster by defined in application then
|
||||
// skip verification using `kubectl apply --dry-run` and since CRD should be created during app synchronization.
|
||||
if dryRun && apierr.IsNotFound(err) && hasCRDOfGroupKind(createTasks, gvk.Group, gvk.Kind) {
|
||||
return
|
||||
} else {
|
||||
syncSuccessful = false
|
||||
for _, task := range tasks {
|
||||
sc.setResourceDetails(&appv1.ResourceDetails{
|
||||
Name: task.targetObj.GetName(),
|
||||
Kind: task.targetObj.GetKind(),
|
||||
Namespace: sc.namespace,
|
||||
Message: err.Error(),
|
||||
Status: appv1.ResourceDetailsSyncFailed,
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if !sc.proj.IsResourcePermitted(metav1.GroupKind{Group: gvk.Group, Kind: gvk.Kind}, serverRes.Namespaced) {
|
||||
syncSuccessful = false
|
||||
for _, task := range tasks {
|
||||
sc.setResourceDetails(&appv1.ResourceDetails{
|
||||
Name: task.targetObj.GetName(),
|
||||
Kind: task.targetObj.GetKind(),
|
||||
Namespace: sc.namespace,
|
||||
Message: fmt.Sprintf("Resource %s:%s is not permitted in project %s.", gvk.Group, gvk.Kind, sc.proj.Name),
|
||||
Status: appv1.ResourceDetailsSyncFailed,
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var createWg sync.WaitGroup
|
||||
for i := range tasks {
|
||||
createWg.Add(1)
|
||||
go func(t syncTask) {
|
||||
defer createWg.Done()
|
||||
if isHook(t.targetObj) {
|
||||
return
|
||||
}
|
||||
resDetails := sc.applyObject(t.targetObj, dryRun, force)
|
||||
if !resDetails.Status.Successful() {
|
||||
syncSuccessful = false
|
||||
}
|
||||
if update || !resDetails.Status.Successful() {
|
||||
sc.setResourceDetails(&resDetails)
|
||||
}
|
||||
}(tasks[i])
|
||||
}
|
||||
createWg.Wait()
|
||||
}
|
||||
|
||||
var tasksGroup []syncTask
|
||||
for _, task := range createTasks {
|
||||
//Only wait if the type of the next task is different than the previous type
|
||||
if len(tasksGroup) > 0 && tasksGroup[0].targetObj.GetKind() != task.targetObj.GetKind() {
|
||||
processCreateTasks(tasksGroup, tasksGroup[0].targetObj.GroupVersionKind())
|
||||
tasksGroup = []syncTask{task}
|
||||
} else {
|
||||
tasksGroup = append(tasksGroup, task)
|
||||
}
|
||||
}
|
||||
if len(tasksGroup) > 0 {
|
||||
processCreateTasks(tasksGroup, tasksGroup[0].targetObj.GroupVersionKind())
|
||||
}
|
||||
return syncSuccessful
|
||||
}
|
||||
|
||||
@@ -510,7 +412,7 @@ func (sc *syncContext) doHookSync(syncTasks []syncTask, hooks []*unstructured.Un
|
||||
// already started the post-sync phase, then we do not need to perform the health check.
|
||||
postSyncHooks, _ := sc.getHooks(appv1.HookTypePostSync)
|
||||
if len(postSyncHooks) > 0 && !sc.startedPostSyncPhase() {
|
||||
healthState, err := setApplicationHealth(sc.kubectl, sc.comparison)
|
||||
healthState, err := setApplicationHealth(sc.comparison)
|
||||
sc.log.Infof("PostSync application health check: %s", healthState.Status)
|
||||
if err != nil {
|
||||
sc.setOperationPhase(appv1.OperationError, fmt.Sprintf("failed to check application health: %v", err))
|
||||
@@ -632,12 +534,15 @@ func (sc *syncContext) runHook(hook *unstructured.Unstructured, hookType appv1.H
|
||||
}
|
||||
|
||||
gvk := hook.GroupVersionKind()
|
||||
dclient, err := sc.dynClientPool.ClientForGroupVersionKind(gvk)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
apiResource, err := kube.ServerResourceForGroupVersionKind(sc.disco, gvk)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
resource := kube.ToGroupVersionResource(gvk.GroupVersion().String(), apiResource)
|
||||
resIf := kube.ToResourceInterface(sc.dynamicIf, apiResource, resource, sc.namespace)
|
||||
resIf := dclient.Resource(apiResource, sc.namespace)
|
||||
|
||||
var liveObj *unstructured.Unstructured
|
||||
existing, err := resIf.Get(hook.GetName(), metav1.GetOptions{})
|
||||
@@ -650,7 +555,7 @@ func (sc *syncContext) runHook(hook *unstructured.Unstructured, hookType appv1.H
|
||||
if err != nil {
|
||||
sc.log.Warnf("Failed to set application label on hook %v: %v", hook, err)
|
||||
}
|
||||
_, err := sc.kubectl.ApplyResource(sc.config, hook, sc.namespace, false, false)
|
||||
_, err := kube.ApplyResource(sc.config, hook, sc.namespace, false, false)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("Failed to create %s hook %s '%s': %v", hookType, gvk, hook.GetName(), err)
|
||||
}
|
||||
@@ -722,7 +627,7 @@ func isHelmHook(obj *unstructured.Unstructured) bool {
|
||||
if annotations == nil {
|
||||
return false
|
||||
}
|
||||
_, ok := annotations[common.AnnotationHelmHook]
|
||||
_, ok := annotations[common.AnnotationHook]
|
||||
return ok
|
||||
}
|
||||
|
||||
@@ -940,97 +845,14 @@ func (sc *syncContext) deleteHook(name, kind, apiVersion string) error {
|
||||
Version: groupVersion[1],
|
||||
Kind: kind,
|
||||
}
|
||||
dclient, err := sc.dynClientPool.ClientForGroupVersionKind(gvk)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
apiResource, err := kube.ServerResourceForGroupVersionKind(sc.disco, gvk)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resource := kube.ToGroupVersionResource(gvk.GroupVersion().String(), apiResource)
|
||||
resIf := kube.ToResourceInterface(sc.dynamicIf, apiResource, resource, sc.namespace)
|
||||
resIf := dclient.Resource(apiResource, sc.namespace)
|
||||
return resIf.Delete(name, &metav1.DeleteOptions{})
|
||||
}
|
||||
|
||||
// This code is mostly taken from https://github.com/helm/helm/blob/release-2.10/pkg/tiller/kind_sorter.go
|
||||
|
||||
// sortOrder is an ordering of Kinds.
|
||||
type sortOrder []string
|
||||
|
||||
// resourceOrder represents the correct order of Kubernetes resources within a manifest
|
||||
var resourceOrder sortOrder = []string{
|
||||
"Namespace",
|
||||
"ResourceQuota",
|
||||
"LimitRange",
|
||||
"PodSecurityPolicy",
|
||||
"Secret",
|
||||
"ConfigMap",
|
||||
"StorageClass",
|
||||
"PersistentVolume",
|
||||
"PersistentVolumeClaim",
|
||||
"ServiceAccount",
|
||||
"CustomResourceDefinition",
|
||||
"ClusterRole",
|
||||
"ClusterRoleBinding",
|
||||
"Role",
|
||||
"RoleBinding",
|
||||
"Service",
|
||||
"DaemonSet",
|
||||
"Pod",
|
||||
"ReplicationController",
|
||||
"ReplicaSet",
|
||||
"Deployment",
|
||||
"StatefulSet",
|
||||
"Job",
|
||||
"CronJob",
|
||||
"Ingress",
|
||||
"APIService",
|
||||
}
|
||||
|
||||
type kindSorter struct {
|
||||
ordering map[string]int
|
||||
manifests []syncTask
|
||||
}
|
||||
|
||||
func newKindSorter(m []syncTask, s sortOrder) *kindSorter {
|
||||
o := make(map[string]int, len(s))
|
||||
for v, k := range s {
|
||||
o[k] = v
|
||||
}
|
||||
|
||||
return &kindSorter{
|
||||
manifests: m,
|
||||
ordering: o,
|
||||
}
|
||||
}
|
||||
|
||||
func (k *kindSorter) Len() int { return len(k.manifests) }
|
||||
|
||||
func (k *kindSorter) Swap(i, j int) { k.manifests[i], k.manifests[j] = k.manifests[j], k.manifests[i] }
|
||||
|
||||
func (k *kindSorter) Less(i, j int) bool {
|
||||
a := k.manifests[i].targetObj
|
||||
if a == nil {
|
||||
return false
|
||||
}
|
||||
b := k.manifests[j].targetObj
|
||||
if b == nil {
|
||||
return true
|
||||
}
|
||||
first, aok := k.ordering[a.GetKind()]
|
||||
second, bok := k.ordering[b.GetKind()]
|
||||
// if same kind (including unknown) sub sort alphanumeric
|
||||
if first == second {
|
||||
// if both are unknown and of different kind sort by kind alphabetically
|
||||
if !aok && !bok && a.GetKind() != b.GetKind() {
|
||||
return a.GetKind() < b.GetKind()
|
||||
}
|
||||
return a.GetName() < b.GetName()
|
||||
}
|
||||
// unknown kind is last
|
||||
if !aok {
|
||||
return false
|
||||
}
|
||||
if !bok {
|
||||
return true
|
||||
}
|
||||
// sort different kinds
|
||||
return first < second
|
||||
}
|
||||
|
||||
@@ -1,402 +1,26 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
|
||||
"github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/util/kube"
|
||||
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/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
fakedisco "k8s.io/client-go/discovery/fake"
|
||||
"k8s.io/client-go/rest"
|
||||
testcore "k8s.io/client-go/testing"
|
||||
)
|
||||
|
||||
type kubectlOutput struct {
|
||||
output string
|
||||
err error
|
||||
}
|
||||
|
||||
type mockKubectlCmd struct {
|
||||
commands map[string]kubectlOutput
|
||||
events chan watch.Event
|
||||
}
|
||||
|
||||
func (k mockKubectlCmd) WatchResources(
|
||||
ctx context.Context, config *rest.Config, namespace string, selector func(kind schema.GroupVersionKind) v1.ListOptions) (chan watch.Event, error) {
|
||||
|
||||
return k.events, nil
|
||||
}
|
||||
|
||||
func (k mockKubectlCmd) DeleteResource(config *rest.Config, obj *unstructured.Unstructured, namespace string) error {
|
||||
command, ok := k.commands[obj.GetName()]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return command.err
|
||||
}
|
||||
|
||||
func (k mockKubectlCmd) ApplyResource(config *rest.Config, obj *unstructured.Unstructured, namespace string, dryRun, force bool) (string, error) {
|
||||
command, ok := k.commands[obj.GetName()]
|
||||
if !ok {
|
||||
return "", nil
|
||||
}
|
||||
return command.output, command.err
|
||||
}
|
||||
|
||||
// ConvertToVersion converts an unstructured object into the specified group/version
|
||||
func (k mockKubectlCmd) ConvertToVersion(obj *unstructured.Unstructured, group, version string) (*unstructured.Unstructured, error) {
|
||||
return obj, nil
|
||||
}
|
||||
|
||||
func newTestSyncCtx(resources ...*v1.APIResourceList) *syncContext {
|
||||
fakeDisco := &fakedisco.FakeDiscovery{Fake: &testcore.Fake{}}
|
||||
fakeDisco.Resources = append(resources, &v1.APIResourceList{
|
||||
APIResources: []v1.APIResource{
|
||||
{Kind: "pod", Namespaced: true},
|
||||
{Kind: "deployment", Namespaced: true},
|
||||
{Kind: "service", Namespaced: true},
|
||||
},
|
||||
})
|
||||
kube.FlushServerResourcesCache()
|
||||
func newTestSyncCtx() *syncContext {
|
||||
return &syncContext{
|
||||
comparison: &v1alpha1.ComparisonResult{},
|
||||
config: &rest.Config{},
|
||||
namespace: "test-namespace",
|
||||
syncRes: &v1alpha1.SyncOperationResult{},
|
||||
syncOp: &v1alpha1.SyncOperation{
|
||||
Prune: true,
|
||||
SyncStrategy: &v1alpha1.SyncStrategy{
|
||||
Apply: &v1alpha1.SyncStrategyApply{},
|
||||
},
|
||||
},
|
||||
proj: &v1alpha1.AppProject{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: "test",
|
||||
},
|
||||
Spec: v1alpha1.AppProjectSpec{
|
||||
ClusterResourceWhitelist: []v1.GroupKind{
|
||||
{Group: "*", Kind: "*"},
|
||||
},
|
||||
},
|
||||
},
|
||||
opState: &v1alpha1.OperationState{},
|
||||
disco: fakeDisco,
|
||||
log: log.WithFields(log.Fields{"application": "fake-app"}),
|
||||
syncOp: &v1alpha1.SyncOperation{},
|
||||
opState: &v1alpha1.OperationState{},
|
||||
log: log.WithFields(log.Fields{"application": "fake-app"}),
|
||||
}
|
||||
}
|
||||
|
||||
func TestSyncCreateInSortedOrder(t *testing.T) {
|
||||
syncCtx := newTestSyncCtx()
|
||||
syncCtx.kubectl = mockKubectlCmd{}
|
||||
syncCtx.comparison = &v1alpha1.ComparisonResult{
|
||||
Resources: []v1alpha1.ResourceState{{
|
||||
LiveState: "",
|
||||
TargetState: "{\"kind\":\"pod\"}",
|
||||
}, {
|
||||
LiveState: "",
|
||||
TargetState: "{\"kind\":\"service\"}",
|
||||
},
|
||||
},
|
||||
}
|
||||
syncCtx.sync()
|
||||
assert.Len(t, syncCtx.syncRes.Resources, 2)
|
||||
for i := range syncCtx.syncRes.Resources {
|
||||
if syncCtx.syncRes.Resources[i].Kind == "pod" {
|
||||
assert.Equal(t, v1alpha1.ResourceDetailsSynced, syncCtx.syncRes.Resources[i].Status)
|
||||
} else if syncCtx.syncRes.Resources[i].Kind == "service" {
|
||||
assert.Equal(t, v1alpha1.ResourceDetailsSynced, syncCtx.syncRes.Resources[i].Status)
|
||||
} else {
|
||||
t.Error("Resource isn't a pod or a service")
|
||||
}
|
||||
}
|
||||
syncCtx.sync()
|
||||
assert.Equal(t, syncCtx.opState.Phase, v1alpha1.OperationSucceeded)
|
||||
}
|
||||
|
||||
func TestSyncCreateNotWhitelistedClusterResources(t *testing.T) {
|
||||
syncCtx := newTestSyncCtx(&v1.APIResourceList{
|
||||
GroupVersion: v1alpha1.SchemeGroupVersion.String(),
|
||||
APIResources: []v1.APIResource{
|
||||
{Name: "workflows", Namespaced: false, Kind: "Workflow", Group: "argoproj.io"},
|
||||
{Name: "application", Namespaced: false, Kind: "Application", Group: "argoproj.io"},
|
||||
},
|
||||
}, &v1.APIResourceList{
|
||||
GroupVersion: "rbac.authorization.k8s.io/v1",
|
||||
APIResources: []v1.APIResource{
|
||||
{Name: "clusterroles", Namespaced: false, Kind: "ClusterRole", Group: "rbac.authorization.k8s.io"},
|
||||
},
|
||||
})
|
||||
|
||||
syncCtx.proj.Spec.ClusterResourceWhitelist = []v1.GroupKind{
|
||||
{Group: "argoproj.io", Kind: "*"},
|
||||
}
|
||||
|
||||
syncCtx.kubectl = mockKubectlCmd{}
|
||||
syncCtx.comparison = &v1alpha1.ComparisonResult{
|
||||
Resources: []v1alpha1.ResourceState{{
|
||||
LiveState: "",
|
||||
TargetState: `{"apiVersion": "rbac.authorization.k8s.io/v1", "kind": "ClusterRole", "metadata": {"name": "argo-ui-cluster-role" }}`,
|
||||
}},
|
||||
}
|
||||
syncCtx.sync()
|
||||
assert.Len(t, syncCtx.syncRes.Resources, 1)
|
||||
assert.Equal(t, v1alpha1.ResourceDetailsSyncFailed, syncCtx.syncRes.Resources[0].Status)
|
||||
assert.Contains(t, syncCtx.syncRes.Resources[0].Message, "not permitted in project")
|
||||
}
|
||||
|
||||
func TestSyncBlacklistedNamespacedResources(t *testing.T) {
|
||||
syncCtx := newTestSyncCtx()
|
||||
|
||||
syncCtx.proj.Spec.NamespaceResourceBlacklist = []v1.GroupKind{
|
||||
{Group: "*", Kind: "deployment"},
|
||||
}
|
||||
|
||||
syncCtx.kubectl = mockKubectlCmd{}
|
||||
syncCtx.comparison = &v1alpha1.ComparisonResult{
|
||||
Resources: []v1alpha1.ResourceState{{
|
||||
LiveState: "",
|
||||
TargetState: "{\"kind\":\"deployment\"}",
|
||||
}},
|
||||
}
|
||||
syncCtx.sync()
|
||||
assert.Len(t, syncCtx.syncRes.Resources, 1)
|
||||
assert.Equal(t, v1alpha1.ResourceDetailsSyncFailed, syncCtx.syncRes.Resources[0].Status)
|
||||
assert.Contains(t, syncCtx.syncRes.Resources[0].Message, "not permitted in project")
|
||||
}
|
||||
|
||||
func TestSyncSuccessfully(t *testing.T) {
|
||||
syncCtx := newTestSyncCtx()
|
||||
syncCtx.kubectl = mockKubectlCmd{}
|
||||
syncCtx.comparison = &v1alpha1.ComparisonResult{
|
||||
Resources: []v1alpha1.ResourceState{{
|
||||
LiveState: "",
|
||||
TargetState: "{\"kind\":\"service\"}",
|
||||
}, {
|
||||
LiveState: "{\"kind\":\"pod\"}",
|
||||
TargetState: "",
|
||||
},
|
||||
},
|
||||
}
|
||||
syncCtx.sync()
|
||||
assert.Len(t, syncCtx.syncRes.Resources, 2)
|
||||
for i := range syncCtx.syncRes.Resources {
|
||||
if syncCtx.syncRes.Resources[i].Kind == "pod" {
|
||||
assert.Equal(t, v1alpha1.ResourceDetailsSyncedAndPruned, syncCtx.syncRes.Resources[i].Status)
|
||||
} else if syncCtx.syncRes.Resources[i].Kind == "service" {
|
||||
assert.Equal(t, v1alpha1.ResourceDetailsSynced, syncCtx.syncRes.Resources[i].Status)
|
||||
} else {
|
||||
t.Error("Resource isn't a pod or a service")
|
||||
}
|
||||
}
|
||||
syncCtx.sync()
|
||||
assert.Equal(t, syncCtx.opState.Phase, v1alpha1.OperationSucceeded)
|
||||
}
|
||||
|
||||
func TestSyncDeleteSuccessfully(t *testing.T) {
|
||||
syncCtx := newTestSyncCtx()
|
||||
syncCtx.kubectl = mockKubectlCmd{}
|
||||
syncCtx.comparison = &v1alpha1.ComparisonResult{
|
||||
Resources: []v1alpha1.ResourceState{{
|
||||
LiveState: "{\"kind\":\"service\"}",
|
||||
TargetState: "",
|
||||
}, {
|
||||
LiveState: "{\"kind\":\"pod\"}",
|
||||
TargetState: "",
|
||||
},
|
||||
},
|
||||
}
|
||||
syncCtx.sync()
|
||||
for i := range syncCtx.syncRes.Resources {
|
||||
if syncCtx.syncRes.Resources[i].Kind == "pod" {
|
||||
assert.Equal(t, v1alpha1.ResourceDetailsSyncedAndPruned, syncCtx.syncRes.Resources[i].Status)
|
||||
} else if syncCtx.syncRes.Resources[i].Kind == "service" {
|
||||
assert.Equal(t, v1alpha1.ResourceDetailsSyncedAndPruned, syncCtx.syncRes.Resources[i].Status)
|
||||
} else {
|
||||
t.Error("Resource isn't a pod or a service")
|
||||
}
|
||||
}
|
||||
syncCtx.sync()
|
||||
assert.Equal(t, syncCtx.opState.Phase, v1alpha1.OperationSucceeded)
|
||||
}
|
||||
|
||||
func TestSyncCreateFailure(t *testing.T) {
|
||||
syncCtx := newTestSyncCtx()
|
||||
syncCtx.kubectl = mockKubectlCmd{
|
||||
commands: map[string]kubectlOutput{
|
||||
"test-service": {
|
||||
output: "",
|
||||
err: fmt.Errorf("error: error validating \"test.yaml\": error validating data: apiVersion not set; if you choose to ignore these errors, turn validation off with --validate=false"),
|
||||
},
|
||||
},
|
||||
}
|
||||
syncCtx.comparison = &v1alpha1.ComparisonResult{
|
||||
Resources: []v1alpha1.ResourceState{{
|
||||
LiveState: "",
|
||||
TargetState: "{\"kind\":\"service\", \"metadata\":{\"name\":\"test-service\"}}",
|
||||
},
|
||||
},
|
||||
}
|
||||
syncCtx.sync()
|
||||
assert.Len(t, syncCtx.syncRes.Resources, 1)
|
||||
assert.Equal(t, v1alpha1.ResourceDetailsSyncFailed, syncCtx.syncRes.Resources[0].Status)
|
||||
}
|
||||
|
||||
func TestSyncPruneFailure(t *testing.T) {
|
||||
syncCtx := newTestSyncCtx()
|
||||
syncCtx.kubectl = mockKubectlCmd{
|
||||
commands: map[string]kubectlOutput{
|
||||
"test-service": {
|
||||
output: "",
|
||||
err: fmt.Errorf(" error: timed out waiting for \"test-service\" to be synced"),
|
||||
},
|
||||
},
|
||||
}
|
||||
syncCtx.comparison = &v1alpha1.ComparisonResult{
|
||||
Resources: []v1alpha1.ResourceState{{
|
||||
LiveState: "{\"kind\":\"service\", \"metadata\":{\"name\":\"test-service\"}}",
|
||||
TargetState: "",
|
||||
},
|
||||
},
|
||||
}
|
||||
syncCtx.sync()
|
||||
assert.Len(t, syncCtx.syncRes.Resources, 1)
|
||||
assert.Equal(t, v1alpha1.ResourceDetailsSyncFailed, syncCtx.syncRes.Resources[0].Status)
|
||||
}
|
||||
|
||||
func TestRunWorkflows(t *testing.T) {
|
||||
// syncCtx := newTestSyncCtx()
|
||||
// syncCtx.doWorkflowSync(nil, nil)
|
||||
|
||||
}
|
||||
|
||||
func unsortedManifest() []syncTask {
|
||||
return []syncTask{
|
||||
{
|
||||
targetObj: &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"GroupVersion": apiv1.SchemeGroupVersion.String(),
|
||||
"kind": "Pod",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
targetObj: &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"GroupVersion": apiv1.SchemeGroupVersion.String(),
|
||||
"kind": "Service",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
targetObj: &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"GroupVersion": apiv1.SchemeGroupVersion.String(),
|
||||
"kind": "PersistentVolume",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
targetObj: &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"GroupVersion": apiv1.SchemeGroupVersion.String(),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
targetObj: &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"GroupVersion": apiv1.SchemeGroupVersion.String(),
|
||||
"kind": "ConfigMap",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func sortedManifest() []syncTask {
|
||||
return []syncTask{
|
||||
{
|
||||
targetObj: &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"GroupVersion": apiv1.SchemeGroupVersion.String(),
|
||||
"kind": "ConfigMap",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
targetObj: &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"GroupVersion": apiv1.SchemeGroupVersion.String(),
|
||||
"kind": "PersistentVolume",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
targetObj: &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"GroupVersion": apiv1.SchemeGroupVersion.String(),
|
||||
"kind": "Service",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
targetObj: &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"GroupVersion": apiv1.SchemeGroupVersion.String(),
|
||||
"kind": "Pod",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
targetObj: &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"GroupVersion": apiv1.SchemeGroupVersion.String(),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func TestSortKubernetesResourcesSuccessfully(t *testing.T) {
|
||||
unsorted := unsortedManifest()
|
||||
ks := newKindSorter(unsorted, resourceOrder)
|
||||
sort.Sort(ks)
|
||||
|
||||
expectedOrder := sortedManifest()
|
||||
assert.Equal(t, len(unsorted), len(expectedOrder))
|
||||
for i, sorted := range unsorted {
|
||||
assert.Equal(t, expectedOrder[i], sorted)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestSortManifestHandleNil(t *testing.T) {
|
||||
task := syncTask{
|
||||
targetObj: &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"GroupVersion": apiv1.SchemeGroupVersion.String(),
|
||||
"kind": "Service",
|
||||
},
|
||||
},
|
||||
}
|
||||
manifest := []syncTask{
|
||||
{},
|
||||
task,
|
||||
}
|
||||
ks := newKindSorter(manifest, resourceOrder)
|
||||
sort.Sort(ks)
|
||||
assert.Equal(t, task, manifest[0])
|
||||
assert.Nil(t, manifest[1].targetObj)
|
||||
|
||||
}
|
||||
|
||||
@@ -9,14 +9,8 @@
|
||||
## Features
|
||||
* [Application Sources](application_sources.md)
|
||||
* [Application Parameters](parameters.md)
|
||||
* [Projects](projects.md)
|
||||
* [Automated Sync](auto_sync.md)
|
||||
* [Resource Health](health.md)
|
||||
* [Resource Hooks](resource_hooks.md)
|
||||
* [Single Sign On](sso.md)
|
||||
* [Webhooks](webhook.md)
|
||||
* [RBAC](rbac.md)
|
||||
|
||||
## Other
|
||||
* [Configuring Ingress](ingress.md)
|
||||
* [F.A.Q.](faq.md)
|
||||
* [RBAC](rbac.md)
|
||||
@@ -3,9 +3,8 @@
|
||||
ArgoCD supports several different ways in which kubernetes manifests can be defined:
|
||||
|
||||
* [ksonnet](https://ksonnet.io) applications
|
||||
* [kustomize](https://kustomize.io) applications
|
||||
* [helm](https://helm.sh) charts
|
||||
* Directory of YAML/json/jsonnet manifests
|
||||
* Simple directory of YAML/json manifests
|
||||
|
||||
Some additional considerations should be made when deploying apps of a particular type:
|
||||
|
||||
|
||||
@@ -50,29 +50,3 @@ 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
|
||||
```
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
# Automated Sync Policy
|
||||
|
||||
ArgoCD has the ability to automatically sync an application when it detects differences between
|
||||
the desired manifests in git, and the live state in the cluster. A benefit of automatic sync is that
|
||||
CI/CD pipelines no longer need direct access to the ArgoCD API server to perform the deployment.
|
||||
Instead, the pipeline makes a commit and push to the git repository with the changes to the
|
||||
manifests in the tracking git repo.
|
||||
|
||||
To configure automated sync run:
|
||||
```bash
|
||||
argocd app set <APPNAME> --sync-policy automated
|
||||
```
|
||||
|
||||
Alternatively, if creating the application an application manifest, specify a syncPolicy with an
|
||||
`automated` policy.
|
||||
```yaml
|
||||
spec:
|
||||
syncPolicy:
|
||||
automated: {}
|
||||
```
|
||||
|
||||
## Automatic Pruning
|
||||
|
||||
By default (and as a safety mechanism), automated sync will not delete resources when ArgoCD detects
|
||||
the resource is no longer defined in git. To prune the resources, a manual sync can always be
|
||||
performed (with pruning checked). Pruning can also be enabled to happen automatically as part of the
|
||||
automated sync by running:
|
||||
|
||||
```bash
|
||||
argocd app set <APPNAME> --auto-prune
|
||||
```
|
||||
|
||||
Or by setting the prune option to true in the automated sync policy:
|
||||
|
||||
```yaml
|
||||
spec:
|
||||
syncPolicy:
|
||||
automated:
|
||||
prune: true
|
||||
```
|
||||
|
||||
## Automated Sync Semantics
|
||||
|
||||
* An automated sync will only be performed if the application is OutOfSync. Applications in a
|
||||
Synced or error state will not attempt automated sync.
|
||||
* Automated sync will only attempt one synchronization per unique combination of commit SHA1 and
|
||||
application parameters. If the most recent successful sync in the history was already performed
|
||||
against the same commit-SHA and parameters, a second sync will not be attempted.
|
||||
* Automatic sync will not reattempt a sync if the previous sync attempt against the same commit-SHA
|
||||
and parameters had failed.
|
||||
* Rollback cannot be performed against an application with automated sync enabled.
|
||||
16
docs/faq.md
16
docs/faq.md
@@ -1,16 +0,0 @@
|
||||
# FAQ
|
||||
|
||||
## Why is my application still `OutOfSync` immediately after a successful Sync?
|
||||
|
||||
It is possible for an application to still be `OutOfSync` even immediately after a successful Sync
|
||||
operation. Some reasons for this might be:
|
||||
* There may be problems in manifests themselves, which may contain extra/unknown fields from the
|
||||
actual K8s spec. These extra fields would get dropped when querying Kubernetes for the live state,
|
||||
resulting in an `OutOfSync` status indicating a missing field was detected.
|
||||
* The sync was performed (with pruning disabled), and there are resources which need to be deleted.
|
||||
* A mutating webhook altered the manifest after it was submitted to Kubernetes
|
||||
|
||||
To debug `OutOfSync` issues, run the `app diff` command to see the differences between git and live:
|
||||
```
|
||||
argocd app diff APPNAME
|
||||
```
|
||||
@@ -7,15 +7,15 @@ An example guestbook application is provided to demonstrate how ArgoCD works.
|
||||
* Have a [kubeconfig](https://kubernetes.io/docs/tasks/access-application-cluster/configure-access-multiple-clusters/) file (default location is `~/.kube/config`).
|
||||
|
||||
## 1. Install ArgoCD
|
||||
```bash
|
||||
```
|
||||
kubectl create namespace argocd
|
||||
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/v0.9.2/manifests/install.yaml
|
||||
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/v0.7.1/manifests/install.yaml
|
||||
```
|
||||
This will create a new namespace, `argocd`, where ArgoCD services and application resources will live.
|
||||
|
||||
NOTE:
|
||||
* On GKE with RBAC enabled, you may need to grant your account the ability to create new cluster roles
|
||||
```bash
|
||||
```
|
||||
kubectl create clusterrolebinding YOURNAME-cluster-admin-binding --clusterrole=cluster-admin --user=YOUREMAIL@gmail.com
|
||||
```
|
||||
|
||||
@@ -24,86 +24,86 @@ kubectl create clusterrolebinding YOURNAME-cluster-admin-binding --clusterrole=c
|
||||
Download the latest ArgoCD version:
|
||||
|
||||
On Mac:
|
||||
```bash
|
||||
```
|
||||
brew install argoproj/tap/argocd
|
||||
```
|
||||
|
||||
On Linux:
|
||||
|
||||
```bash
|
||||
curl -sSL -o /usr/local/bin/argocd https://github.com/argoproj/argo-cd/releases/download/v0.9.2/argocd-linux-amd64
|
||||
```
|
||||
curl -sSL -o /usr/local/bin/argocd https://github.com/argoproj/argo-cd/releases/download/v0.7.1/argocd-linux-amd64
|
||||
chmod +x /usr/local/bin/argocd
|
||||
```
|
||||
|
||||
## 3. Access the ArgoCD API server
|
||||
## 3. Open access to ArgoCD API server
|
||||
|
||||
By default, the ArgoCD API server is not exposed with an external IP. To access the API server,
|
||||
choose one of the following means to expose the ArgoCD API server:
|
||||
By default, the ArgoCD API server is not exposed with an external IP. To expose the API server,
|
||||
change the service type to `LoadBalancer`:
|
||||
|
||||
### Service Type LoadBalancer
|
||||
Change the argocd-server service type to `LoadBalancer`:
|
||||
|
||||
```bash
|
||||
```
|
||||
kubectl patch svc argocd-server -n argocd -p '{"spec": {"type": "LoadBalancer"}}'
|
||||
```
|
||||
|
||||
### Ingress
|
||||
Follow the [ingress documentation](ingress.md) on how to configure ArgoCD with ingress.
|
||||
## 4. Login to the server from the CLI
|
||||
|
||||
### Port Forwarding
|
||||
`kubectl port-forward` can also be used to connect to the API server without exposing the service.
|
||||
The API server can be accessed using the localhost address/port.
|
||||
|
||||
|
||||
## 4. Login using the CLI
|
||||
|
||||
Login as the `admin` user. The initial password is autogenerated to be the pod name of the
|
||||
Login with using the `admin` user. The initial password is autogenerated to be the pod name of the
|
||||
ArgoCD API server. This can be retrieved with the command:
|
||||
```bash
|
||||
```
|
||||
kubectl get pods -n argocd -l app=argocd-server -o name | cut -d'/' -f 2
|
||||
```
|
||||
|
||||
Using the above password, login to ArgoCD's external IP:
|
||||
```bash
|
||||
|
||||
On Minikube:
|
||||
```
|
||||
argocd login $(minikube service argocd-server -n argocd --url | cut -d'/' -f 3) --name minikube
|
||||
```
|
||||
Other clusters:
|
||||
```
|
||||
kubectl get svc -n argocd argocd-server
|
||||
argocd login <EXTERNAL-IP>
|
||||
```
|
||||
|
||||
After logging in, change the password using the command:
|
||||
```bash
|
||||
```
|
||||
argocd account update-password
|
||||
argocd relogin
|
||||
```
|
||||
|
||||
|
||||
## 5. Register a cluster to deploy apps to (optional)
|
||||
## 5. Register a cluster to deploy apps to
|
||||
|
||||
This step registers a cluster's credentials to ArgoCD, and is only necessary when deploying to
|
||||
an external cluster. When deploying internally (to the same cluster that ArgoCD is running in),
|
||||
https://kubernetes.default.svc should be used as the application's K8s API server address.
|
||||
|
||||
First list all clusters contexts in your current kubconfig:
|
||||
```bash
|
||||
We will now register a cluster to deploy applications to. First list all clusters contexts in your
|
||||
kubconfig:
|
||||
```
|
||||
argocd cluster add
|
||||
```
|
||||
|
||||
Choose a context name from the list and supply it to `argocd cluster add CONTEXTNAME`. For example,
|
||||
for docker-for-desktop context, run:
|
||||
```bash
|
||||
argocd cluster add docker-for-desktop
|
||||
for minikube context, run:
|
||||
```
|
||||
argocd cluster add minikube --in-cluster
|
||||
```
|
||||
|
||||
The above command installs an `argocd-manager` ServiceAccount and ClusterRole into the cluster
|
||||
associated with the supplied kubectl context. ArgoCD uses this service account token to perform its
|
||||
associated with the supplied kubectl context. ArgoCD uses the service account token to perform its
|
||||
management tasks (i.e. deploy/monitoring).
|
||||
|
||||
The `--in-cluster` option indicates that the cluster we are registering, is the same cluster that
|
||||
ArgoCD is running in. This allows ArgoCD to connect to the cluster using the internal kubernetes
|
||||
hostname (kubernetes.default.svc). When registering a cluster external to ArgoCD, the `--in-cluster`
|
||||
flag should be omitted.
|
||||
|
||||
## 6. Create an application from a git repository location
|
||||
## 6. Create the application from a git repository
|
||||
|
||||
### Creating apps via UI
|
||||
|
||||
Open a browser to the ArgoCD external UI, and login using the credentials set in step 4, and the
|
||||
external IP/hostname set in step 4.
|
||||
Open a browser to the ArgoCD external UI, and login using the credentials set in step 4.
|
||||
|
||||
On Minikube:
|
||||
```
|
||||
minikube service argocd-server -n argocd
|
||||
```
|
||||
|
||||
Connect a git repository containing your apps. An example repository containing a sample
|
||||
guestbook application is available at https://github.com/argoproj/argocd-example-apps.git.
|
||||
@@ -122,8 +122,8 @@ After connecting a git repository, select the guestbook application for creation
|
||||
|
||||
Applications can be also be created using the ArgoCD CLI:
|
||||
|
||||
```bash
|
||||
argocd app create guestbook-default --repo https://github.com/argoproj/argocd-example-apps.git --path ksonnet-guestbook
|
||||
```
|
||||
argocd app create guestbook-default --repo https://github.com/argoproj/argocd-example-apps.git --path guestbook --env default
|
||||
```
|
||||
|
||||
## 7. Sync (deploy) the application
|
||||
@@ -131,10 +131,10 @@ argocd app create guestbook-default --repo https://github.com/argoproj/argocd-ex
|
||||
Once the guestbook application is created, you can now view its status:
|
||||
|
||||
From UI:
|
||||

|
||||

|
||||
|
||||
From CLI:
|
||||
```bash
|
||||
```
|
||||
$ argocd app get guestbook-default
|
||||
Name: guestbook-default
|
||||
Server: https://kubernetes.default.svc
|
||||
@@ -153,7 +153,7 @@ Deployment guestbook-ui OutOfSync
|
||||
The application status is initially in an `OutOfSync` state, since the application has yet to be
|
||||
deployed, and no Kubernetes resources have been created. To sync (deploy) the application, run:
|
||||
|
||||
```bash
|
||||
```
|
||||
$ argocd app sync guestbook-default
|
||||
Application: guestbook-default
|
||||
Operation: Sync
|
||||
@@ -166,12 +166,12 @@ Deployment guestbook-ui deployment.apps "guestbook-ui" created
|
||||
```
|
||||
|
||||
This command retrieves the manifests from git repository and performs a `kubectl apply` of the
|
||||
manifests. The guestbook app is now running and you can now view its resource components, logs,
|
||||
events, and assessed health status:
|
||||
manifests. The guestbook app is now running and you can now view its resource
|
||||
components, logs, events, and assessed health:
|
||||
|
||||

|
||||
|
||||
## 8. Next Steps
|
||||
|
||||
ArgoCD supports additional features such as automated sync, SSO, WebHooks, RBAC, Projects. See the
|
||||
rest of the [documentation](./) for details.
|
||||
ArgoCD supports additional features such as SSO, WebHooks, RBAC, Projects. See the rest of
|
||||
the [documentation](./) for details.
|
||||
|
||||
@@ -6,6 +6,7 @@ surfaced to the overall Application health status as a whole. The following chec
|
||||
specific types of kuberentes resources:
|
||||
|
||||
### Deployment, ReplicaSet, StatefulSet DaemonSet
|
||||
|
||||
* Observed generation is equal to desired generation.
|
||||
* Number of **updated** replicas equals the number of desired replicas.
|
||||
|
||||
@@ -15,6 +16,3 @@ with at least one value for `hostname` or `IP`.
|
||||
|
||||
### Ingress
|
||||
* The `status.loadBalancer.ingress` list is non-empty, with at least one value for `hostname` or `IP`.
|
||||
|
||||
### PersistentVolumeClaim
|
||||
* The `status.phase` is `Bound`
|
||||
|
||||
126
docs/ingress.md
126
docs/ingress.md
@@ -1,126 +0,0 @@
|
||||
# Ingress Configuration
|
||||
|
||||
ArgoCD runs both a gRPC server (used by the CLI), as well as a HTTP/HTTPS server (used by the UI).
|
||||
Both protocols are exposed by the argocd-server service object on the following ports:
|
||||
* 443 - gRPC/HTTPS
|
||||
* 80 - HTTP (redirects to HTTPS)
|
||||
|
||||
There are several ways how Ingress can be configured.
|
||||
|
||||
## [kubernetes/ingress-nginx](https://github.com/kubernetes/ingress-nginx)
|
||||
|
||||
### Option 1: ssl-passthrough
|
||||
|
||||
Because ArgoCD serves multiple protocols (gRPC/HTTPS) on the same port (443), this provides a
|
||||
challenge when attempting to define a single nginx ingress object and rule for the argocd-service,
|
||||
since the `nginx.ingress.kubernetes.io/backend-protocol` [annotation](https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#backend-protocol)
|
||||
accepts only a single value for the backend protocol (e.g. HTTP, HTTPS, GRPC, GRPCS).
|
||||
|
||||
In order to expose the ArgoCD API server with a single ingress rule and hostname, the
|
||||
`nginx.ingress.kubernetes.io/ssl-passthrough` [annotation](https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#ssl-passthrough)
|
||||
must be used to passthrough TLS connections and terminate TLS at the ArgoCD API server.
|
||||
|
||||
```yaml
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: argocd-server-ingress
|
||||
annotations:
|
||||
kubernetes.io/ingress.class: nginx
|
||||
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
|
||||
nginx.ingress.kubernetes.io/ssl-passthrough: "true"
|
||||
spec:
|
||||
rules:
|
||||
- host: argocd.example.com
|
||||
http:
|
||||
paths:
|
||||
- backend:
|
||||
serviceName: argocd-server
|
||||
servicePort: https
|
||||
```
|
||||
|
||||
The above rule terminates TLS at the ArgoCD API server, which detects the protocol being used,
|
||||
and responds appropriately. Note that the `nginx.ingress.kubernetes.io/ssl-passthrough` annotation
|
||||
requires that the `--enable-ssl-passthrough` flag be added to the command line arguments to
|
||||
`nginx-ingress-controller`.
|
||||
|
||||
### Option 2: Multiple ingress objects and hosts
|
||||
|
||||
Since ingress-nginx Ingress supports only a single protocol per Ingress object, an alternative
|
||||
way would be to define two Ingress objects. One for HTTP/HTTPS, and the other for gRPC:
|
||||
|
||||
HTTP/HTTPS Ingress:
|
||||
```yaml
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: argocd-server-http-ingress
|
||||
annotations:
|
||||
kubernetes.io/ingress.class: "nginx"
|
||||
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
|
||||
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
|
||||
spec:
|
||||
rules:
|
||||
- http:
|
||||
paths:
|
||||
- backend:
|
||||
serviceName: argocd-server
|
||||
servicePort: http
|
||||
host: argocd.example.com
|
||||
tls:
|
||||
- hosts:
|
||||
- argocd.example.com
|
||||
secretName: argocd-secret
|
||||
```
|
||||
|
||||
gRPC Ingress:
|
||||
```yaml
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: argocd-server-grpc-ingress
|
||||
annotations:
|
||||
kubernetes.io/ingress.class: "nginx"
|
||||
nginx.ingress.kubernetes.io/backend-protocol: "GRPC"
|
||||
spec:
|
||||
rules:
|
||||
- http:
|
||||
paths:
|
||||
- backend:
|
||||
serviceName: argocd-server
|
||||
servicePort: https
|
||||
host: grpc.argocd.example.com
|
||||
tls:
|
||||
- hosts:
|
||||
- grpc.argocd.example.com
|
||||
secretName: argocd-secret
|
||||
```
|
||||
|
||||
The API server should then be run with TLS disabled. Edit the `argocd-server` deployment to add the
|
||||
`--insecure` flag to the argocd-server command:
|
||||
|
||||
```yaml
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
name: argocd-server
|
||||
containers:
|
||||
- command:
|
||||
- /argocd-server
|
||||
- --staticassets
|
||||
- /shared/app
|
||||
- --repo-server
|
||||
- argocd-repo-server:8081
|
||||
- --insecure
|
||||
```
|
||||
|
||||
The obvious disadvantage to this approach is that this technique require two separate hostnames for
|
||||
the API server -- one for gRPC and the other for HTTP/HTTPS. However it allow TLS termination to
|
||||
happen at the ingress controller.
|
||||
|
||||
|
||||
## AWS Application Load Balancers (ALBs) and Classic ELB (HTTP mode)
|
||||
|
||||
Neither ALBs and Classic ELB in HTTP mode, do not have full support for HTTP2/gRPC which is the
|
||||
protocol used by the `argocd` CLI. Thus, when using an AWS load balancer, either Classic ELB in
|
||||
passthrough mode is needed, or NLBs.
|
||||
@@ -1,47 +0,0 @@
|
||||
# ArgoCD Release Instructions
|
||||
|
||||
1. Tag, build, and push argo-cd-ui
|
||||
```bash
|
||||
cd argo-cd-ui
|
||||
git checkout -b release-X.Y
|
||||
git tag vX.Y.Z
|
||||
git push upstream release-X.Y --tags
|
||||
IMAGE_NAMESPACE=argoproj IMAGE_TAG=vX.Y.Z DOCKER_PUSH=true yarn docker
|
||||
```
|
||||
|
||||
2. Create release-X.Y branch (if creating initial X.Y release)
|
||||
```bash
|
||||
git checkout -b release-X.Y
|
||||
git push upstream release-X.Y
|
||||
```
|
||||
|
||||
3. Update VERSION and manifests with new version
|
||||
```bash
|
||||
vi VERSION # ensure value is desired X.Y.Z semantic version
|
||||
vi manifests/base/kustomization.yaml # update with new image tags
|
||||
make manifests
|
||||
git commit -a -m "Update manifests to vX.Y.Z"
|
||||
git push upstream release-X.Y
|
||||
```
|
||||
|
||||
4. Tag, build, and push release to docker hub
|
||||
```bash
|
||||
git tag vX.Y.Z
|
||||
make release IMAGE_NAMESPACE=argoproj IMAGE_TAG=vX.Y.Z DOCKER_PUSH=true
|
||||
git push upstream vX.Y.Z
|
||||
```
|
||||
|
||||
5. Update argocd brew formula
|
||||
```bash
|
||||
git clone https://github.com/argoproj/homebrew-tap
|
||||
cd homebrew-tap
|
||||
shasum -a 256 ~/go/src/github.com/argoproj/argo-cd/dist/argocd-darwin-amd64
|
||||
# edit argocd.rb with version and checksum
|
||||
git commit -a -m "Update argocd to vX.Y.Z"
|
||||
git push
|
||||
```
|
||||
|
||||
6. Update documentation:
|
||||
* Edit CHANGELOG.md with release notes
|
||||
* Update getting_started.md with new version
|
||||
* Create GitHub release from new tag and upload binaries (e.g. dist/argocd-darwin-amd64)
|
||||
181
docs/projects.md
181
docs/projects.md
@@ -1,181 +0,0 @@
|
||||
## Projects
|
||||
|
||||
Projects provide a logical grouping of applications, which is useful when ArgoCD is used by multiple
|
||||
teams. Projects provide the following features:
|
||||
|
||||
* ability to restrict *what* may be deployed (the git source repositories)
|
||||
* ability to restrict *where* apps may be deployed (the destination clusters and namespaces)
|
||||
* ability to control what type of objects may be deployed (e.g. RBAC, CRDs, DaemonSets, NetworkPolicy etc...)
|
||||
|
||||
### The default project
|
||||
|
||||
Every application belongs to a single project. If unspecified, an application belongs to the
|
||||
`default` project, which is created automatically and by default, permits deployments from any
|
||||
source repo, to any cluster, and all resource Kinds. The default project can be modified, but not
|
||||
deleted. When initially created, it's specification is configured to be the most permissive:
|
||||
|
||||
```yaml
|
||||
spec:
|
||||
sourceRepos:
|
||||
- '*'
|
||||
destinations:
|
||||
- namespace: '*'
|
||||
server: '*'
|
||||
clusterResourceWhitelist:
|
||||
- group: '*'
|
||||
kind: '*'
|
||||
```
|
||||
|
||||
### Creating Projects
|
||||
|
||||
Additional projects can be created to give separate teams different levels of access to namespaces.
|
||||
The following command creates a new project `myproject` which can deploy applications to namespace
|
||||
`mynamespace` of cluster `https://kubernetes.default.svc`. The permitted git source repository is
|
||||
set to `https://github.com/argoproj/argocd-example-apps.git` repository.
|
||||
|
||||
```
|
||||
argocd proj create myproject -d https://kubernetes.default.svc,mynamespace -s https://github.com/argoproj/argocd-example-apps.git
|
||||
```
|
||||
|
||||
### Managing Projects
|
||||
|
||||
Permitted source git repositories are managed using commands:
|
||||
|
||||
```bash
|
||||
argocd project add-source <PROJECT> <REPO>
|
||||
argocd project remove-source <PROJECT> <REPO>
|
||||
```
|
||||
|
||||
Permitted destination clusters and namespaces are managed with the commands:
|
||||
```
|
||||
argocd project add-destination <PROJECT> <CLUSTER>,<NAMESPACE>
|
||||
argocd project remove-destination <PROJECT> <CLUSTER>,<NAMESPACE>
|
||||
```
|
||||
|
||||
Permitted destination K8s resource kinds are managed with the commands. Note that namespaced-scoped
|
||||
resources are restricted via a blacklist, whereas cluster-scoped resources are restricted via
|
||||
whitelist.
|
||||
```
|
||||
argocd project allow-cluster-resource <PROJECT> <GROUP> <KIND>
|
||||
argocd project allow-namespace-resource <PROJECT> <GROUP> <KIND>
|
||||
argocd project deny-cluster-resource <PROJECT> <GROUP> <KIND>
|
||||
argocd project deny-namespace-resource <PROJECT> <GROUP> <KIND>
|
||||
```
|
||||
|
||||
### Assign application to a project
|
||||
|
||||
The application project can be changed using `app set` command. In order to change the project of
|
||||
an app, the user must have permissions to access the new project.
|
||||
|
||||
```
|
||||
argocd app set guestbook-default --project myproject
|
||||
```
|
||||
|
||||
### Configuring RBAC with projects
|
||||
|
||||
Once projects have been defined, RBAC rules can be written to restrict access to the applications
|
||||
in the project. The following example configures RBAC for two GitHub teams: `team1` and `team2`,
|
||||
both in the GitHub org, `some-github-org`. There are two projects, `project-a` and `project-b`.
|
||||
`team1` can only manage applications in `project-a`, while `team2` can only manage applications in
|
||||
`project-b`. Both `team1` and `team2` have the ability to manage repositories.
|
||||
|
||||
*ConfigMap `argocd-rbac-cm` example:*
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: argocd-rbac-cm
|
||||
data:
|
||||
policy.default: ""
|
||||
policy.csv: |
|
||||
p, some-github-org:team1, applications, *, project-a/*, allow
|
||||
p, some-github-org:team2, applications, *, project-a/*, allow
|
||||
|
||||
p, role:org-admin, repositories, get, *, allow
|
||||
p, role:org-admin, repositories, create, *, allow
|
||||
p, role:org-admin, repositories, update, *, allow
|
||||
p, role:org-admin, repositories, delete, *, allow
|
||||
|
||||
g, some-github-org:team1, org-admin
|
||||
g, some-github-org:team2, org-admin
|
||||
```
|
||||
|
||||
## Project Roles
|
||||
|
||||
Projects include a feature called roles that enable automated access to a project's applications.
|
||||
These can be used to give a CI pipeline a restricted set of permissions. For example, a CI system
|
||||
may only be able to sync a single app (but not change its source or destination).
|
||||
|
||||
Projects 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 policy 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.
|
||||
|
||||
```bash
|
||||
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 in itself are not useful without generating a token to associate to that role. ArgoCD
|
||||
supports JWT tokens as the means to authenticate to a role. 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.
|
||||
|
||||
The following commands are used to manage the JWT tokens.
|
||||
|
||||
```bash
|
||||
argoproj proj role create-token PROJECT ROLE-NAME
|
||||
argoproj proj role delete-token PROJECT ROLE-NAME ISSUED-AT
|
||||
```
|
||||
|
||||
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 cannot be used if
|
||||
the token has been revoked.
|
||||
|
||||
Below is an example of leveraging a JWT token to access a guestbook application. It makes the
|
||||
assumption that the user already has a project named myproject and an application called
|
||||
guestbook-default.
|
||||
|
||||
```bash
|
||||
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
|
||||
```
|
||||
|
||||
105
docs/rbac.md
105
docs/rbac.md
@@ -2,39 +2,102 @@
|
||||
|
||||
## Overview
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
## Configure RBAC
|
||||
|
||||
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)
|
||||
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.
|
||||
|
||||
Additional roles and groups can be configured in `argocd-rbac-cm` ConfigMap. The example below
|
||||
configures a custom role, named `org-admin`. The role is assigned to any user which belongs to
|
||||
`your-github-org:your-team` group. All other users get the default policy of `role:readonly`,
|
||||
which cannot modify ArgoCD settings.
|
||||
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.
|
||||
|
||||
*ConfigMap `argocd-rbac-cm` example:*
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: argocd-rbac-cm
|
||||
data:
|
||||
policy.default: role:readonly
|
||||
policy.csv: |
|
||||
p, role:org-admin, applications, *, */*, allow
|
||||
p, role:org-admin, clusters, get, *, allow
|
||||
p, role:org-admin, repositories, get, *, allow
|
||||
p, role:org-admin, repositories, create, *, allow
|
||||
p, role:org-admin, repositories, update, *, allow
|
||||
p, role:org-admin, repositories, delete, *, allow
|
||||
p, role:org-admin, applications, *, */*
|
||||
p, role:org-admin, applications/*, *, */*
|
||||
|
||||
p, role:org-admin, clusters, get, *
|
||||
p, role:org-admin, repositories, get, *
|
||||
p, role:org-admin, repositories/apps, get, *
|
||||
|
||||
p, role:org-admin, repositories, create, *
|
||||
p, role:org-admin, repositories, update, *
|
||||
p, role:org-admin, repositories, delete, *
|
||||
|
||||
g, your-github-org:your-team, role:org-admin
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: argocd-rbac-cm
|
||||
```
|
||||
|
||||
## Configure Projects
|
||||
|
||||
Argo projects allow grouping applications which is useful if ArgoCD is used by multiple teams. Additionally, projects restrict source repositories and destination
|
||||
Kubernetes clusters which can be used by applications belonging to the project.
|
||||
|
||||
### 1. Create new project
|
||||
|
||||
Following command creates project `myproject` which can deploy applications to namespace `default` of cluster `https://kubernetes.default.svc`. The valid application source is defined in the `https://github.com/argoproj/argocd-example-apps.git` repository.
|
||||
|
||||
```
|
||||
argocd proj create myproject -d https://kubernetes.default.svc,default -s https://github.com/argoproj/argocd-example-apps.git
|
||||
```
|
||||
|
||||
Project sources and destinations can be managed using commands
|
||||
```
|
||||
argocd project add-destination
|
||||
argocd project remove-destination
|
||||
argocd project add-source
|
||||
argocd project remove-source
|
||||
```
|
||||
|
||||
### 2. Assign application to a project
|
||||
|
||||
Each application belongs to a project. By default, all application belongs to the default project which provides access to any source repo/cluster. The application project can be
|
||||
changes using `app set` command:
|
||||
|
||||
```
|
||||
argocd app set guestbook-default --project myproject
|
||||
```
|
||||
|
||||
### 3. Update RBAC rules
|
||||
|
||||
Following example configure admin access for two teams. Each team has access only two application of one project (`team1` can access `default` project and `team2` can access
|
||||
`myproject` project).
|
||||
|
||||
*ConfigMap `argocd-rbac-cm` example:*
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
data:
|
||||
policy.default: ""
|
||||
policy.csv: |
|
||||
p, role:team1-admin, applications, *, default/*
|
||||
p, role:team1-admin, applications/*, *, default/*
|
||||
|
||||
p, role:team1-admin, applications, *, myproject/*
|
||||
p, role:team1-admin, applications/*, *, myproject/*
|
||||
|
||||
p, role:org-admin, clusters, get, *
|
||||
p, role:org-admin, repositories, get, *
|
||||
p, role:org-admin, repositories/apps, get, *
|
||||
|
||||
p, role:org-admin, repositories, create, *
|
||||
p, role:org-admin, repositories, update, *
|
||||
p, role:org-admin, repositories, delete, *
|
||||
|
||||
g, role:team1-admin, org-admin
|
||||
g, role:team2-admin, org-admin
|
||||
g, your-github-org:your-team1, role:team1-admin
|
||||
g, your-github-org:your-team2, role:team2-admin
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: argocd-rbac-cm
|
||||
```
|
||||
|
||||
@@ -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 or more GitHub organization. In the
|
||||
* You will very likely want to restrict logins to one ore 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.
|
||||
|
||||
|
||||
@@ -4,14 +4,13 @@ An ArgoCD application spec provides several different ways of track kubernetes r
|
||||
git. This document describes the different techniques and the means of deploying those manifests to
|
||||
the target environment.
|
||||
|
||||
## HEAD / Branch Tracking
|
||||
## Branch Tracking
|
||||
|
||||
If a branch name, or a symbolic reference (like HEAD) is specified, ArgoCD will continually compare
|
||||
live state against the resource manifests defined at the tip of the specified branch or the
|
||||
deferenced commit of the symbolic reference.
|
||||
If a branch name is specified, ArgoCD will continually compare live state against the resource
|
||||
manifests defined at the tip of the specified branch.
|
||||
|
||||
To redeploy an application, a user makes changes to the manifests, and commit/pushes those the
|
||||
changes to the tracked branch/symbolic reference, which will then be detected by ArgoCD controller.
|
||||
changes to the tracked branch, which will then be detected by ArgoCD controller.
|
||||
|
||||
## Tag Tracking
|
||||
|
||||
@@ -34,9 +33,9 @@ which is pinned to a commit, is by updating the tracking revision in the applica
|
||||
commit containing the new manifests. Note that [parameter overrides](parameters.md) can still be set
|
||||
on an application which is pinned to a revision.
|
||||
|
||||
## Automated Sync
|
||||
## Auto-Sync [(Not Yet Implemented)]((https://github.com/argoproj/argo-cd/issues/79))
|
||||
|
||||
In all tracking strategies, the application has the option to sync automatically. If [auto-sync](auto_sync.md)
|
||||
In all tracking strategies, the application will have the option to sync automatically. If auto-sync
|
||||
is configured, the new resources manifests will be applied automatically -- as soon as a difference
|
||||
is detected between the target state (git) and live state. If auto-sync is disabled, a manual sync
|
||||
will be needed using the Argo UI, CLI, or API.
|
||||
|
||||
@@ -64,8 +64,8 @@ for i in ${PROTO_FILES}; do
|
||||
# Path to the google API gateway annotations.proto will be different depending if we are
|
||||
# building natively (e.g. from workspace) vs. part of a docker build.
|
||||
if [ -f /.dockerenv ]; then
|
||||
GOOGLE_PROTO_API_PATH=$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis
|
||||
GOGO_PROTOBUF_PATH=$GOPATH/src/github.com/gogo/protobuf
|
||||
GOOGLE_PROTO_API_PATH=/root/go/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis
|
||||
GOGO_PROTOBUF_PATH=/root/go/src/github.com/gogo/protobuf
|
||||
else
|
||||
GOOGLE_PROTO_API_PATH=${PROJECT_ROOT}/vendor/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis
|
||||
GOGO_PROTOBUF_PATH=${PROJECT_ROOT}/vendor/github.com/gogo/protobuf
|
||||
@@ -117,6 +117,6 @@ clean_swagger() {
|
||||
/usr/bin/find "${SWAGGER_ROOT}" -name '*.swagger.json' -delete
|
||||
}
|
||||
|
||||
collect_swagger server 21
|
||||
collect_swagger server 15
|
||||
clean_swagger server
|
||||
clean_swagger reposerver
|
||||
|
||||
168
hack/migrate/migrate0.3.0to0.4.0.go
Normal file
168
hack/migrate/migrate0.3.0to0.4.0.go
Normal file
@@ -0,0 +1,168 @@
|
||||
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)
|
||||
}
|
||||
@@ -1,22 +1,11 @@
|
||||
#!/bin/sh
|
||||
|
||||
SRCROOT="$( cd "$(dirname "$0")/.." ; pwd -P )"
|
||||
AUTOGENMSG="# This is an auto-generated file. DO NOT EDIT"
|
||||
IMAGE_NAMESPACE=${IMAGE_NAMESPACE:='argoproj'}
|
||||
IMAGE_TAG=${IMAGE_TAG:='latest'}
|
||||
|
||||
update_image () {
|
||||
if [ ! -z "${IMAGE_NAMESPACE}" ]; then
|
||||
sed -i '' 's| image: \(.*\)/\(argocd-.*\)| image: '"${IMAGE_NAMESPACE}"'/\2|g' ${1}
|
||||
fi
|
||||
if [ ! -z "${IMAGE_TAG}" ]; then
|
||||
sed -i '' 's|\( image: .*/argocd-.*\)\:.*|\1:'"${IMAGE_TAG}"'|g' ${1}
|
||||
fi
|
||||
}
|
||||
|
||||
echo "${AUTOGENMSG}" > ${SRCROOT}/manifests/install.yaml
|
||||
kustomize build ${SRCROOT}/manifests/cluster-install >> ${SRCROOT}/manifests/install.yaml
|
||||
update_image ${SRCROOT}/manifests/install.yaml
|
||||
|
||||
echo "${AUTOGENMSG}" > ${SRCROOT}/manifests/namespace-install.yaml
|
||||
kustomize build ${SRCROOT}/manifests/base >> ${SRCROOT}/manifests/namespace-install.yaml
|
||||
update_image ${SRCROOT}/manifests/namespace-install.yaml
|
||||
for i in "$(ls manifests/components/*.yaml)"; do
|
||||
sed -i '' 's@\( image: \(.*\)/\(argocd-.*\):.*\)@ image: '"${IMAGE_NAMESPACE}"'/\3:'"${IMAGE_TAG}"'@g' $i
|
||||
done
|
||||
|
||||
echo "# This is an auto-generated file. DO NOT EDIT" > manifests/install.yaml
|
||||
cat manifests/components/*.yaml >> manifests/install.yaml
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
# ArgoCD Installation Manifests
|
||||
|
||||
Two sets of installation manifests are provided:
|
||||
|
||||
* [install.yaml](install.yaml) - Standard ArgoCD installation with cluster-admin access. Use this
|
||||
manifest set if you plan to use ArgoCD to deploy applications in the same cluster that ArgoCD runs
|
||||
in (i.e. kubernetes.svc.default). Will still be able to deploy to external clusters with inputted
|
||||
credentials.
|
||||
|
||||
* [namespace-install.yaml](namespace-install.yaml) - Installation of ArgoCD which requires only
|
||||
namespace level privileges (does not need cluster roles). Use this manifest set if you do not
|
||||
need ArgoCD to deploy applications in the same cluster that ArgoCD runs in, and will rely solely
|
||||
on inputted cluster credentials. An example of using this set of manifests is if you run several
|
||||
ArgoCD instances for different teams, where each instance will bedeploying applications to
|
||||
external clusters. Will still be possible to deploy to the same cluster (kubernetes.svc.default)
|
||||
with inputted credentials (i.e. `argocd cluster add <CONTEXT> --in-cluster`).
|
||||
@@ -1,23 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: argocd-cm
|
||||
# data:
|
||||
# # ArgoCD's externally facing base URL. Required for configuring SSO
|
||||
# # url: https://argo-cd-demo.argoproj.io
|
||||
#
|
||||
# # A dex connector configuration. See documentation on how to configure SSO:
|
||||
# # https://github.com/argoproj/argo-cd/blob/master/docs/sso.md#2-configure-argocd-for-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
|
||||
@@ -1,12 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: argocd-metrics
|
||||
spec:
|
||||
ports:
|
||||
- name: http
|
||||
protocol: TCP
|
||||
port: 8082
|
||||
targetPort: 8082
|
||||
selector:
|
||||
app: argocd-server
|
||||
@@ -1,15 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: argocd-rbac-cm
|
||||
# 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
|
||||
#
|
||||
# # The default role ArgoCD will fall back to, when authorizing API requests
|
||||
# policy.default: role:readonly
|
||||
@@ -1,26 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: argocd-secret
|
||||
type: Opaque
|
||||
# data:
|
||||
# # TLS certificate and private key for API server.
|
||||
# # Autogenerated with a self-signed ceritificate if keys are missing.
|
||||
# tls.crt:
|
||||
# tls.key:
|
||||
#
|
||||
# # bcrypt hash of the admin password and it's last modified time. Autogenerated on initial
|
||||
# # startup. To reset a forgotten password, delete both keys and restart argocd-server.
|
||||
# admin.password:
|
||||
# admin.passwordMtime:
|
||||
#
|
||||
# # random server signature key for session validation. Autogenerated on initial startup
|
||||
# server.secretkey:
|
||||
#
|
||||
# # 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:
|
||||
@@ -1,34 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: dex-server
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: dex-server
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: dex-server
|
||||
spec:
|
||||
serviceAccountName: dex-server
|
||||
initContainers:
|
||||
- name: copyutil
|
||||
image: argoproj/argocd-server:latest
|
||||
command: [cp, /argocd-util, /shared]
|
||||
volumeMounts:
|
||||
- mountPath: /shared
|
||||
name: static-files
|
||||
containers:
|
||||
- name: dex
|
||||
image: quay.io/dexidp/dex:v2.11.0
|
||||
command: [/shared/argocd-util, rundex]
|
||||
ports:
|
||||
- containerPort: 5556
|
||||
- containerPort: 5557
|
||||
volumeMounts:
|
||||
- mountPath: /shared
|
||||
name: static-files
|
||||
volumes:
|
||||
- emptyDir: {}
|
||||
name: static-files
|
||||
@@ -1,14 +0,0 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: dex-server-role
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- secrets
|
||||
- configmaps
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
@@ -1,11 +0,0 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: dex-server-role-binding
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: dex-server-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: dex-server
|
||||
@@ -1,4 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: dex-server
|
||||
@@ -1,16 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: dex-server
|
||||
spec:
|
||||
ports:
|
||||
- name: http
|
||||
protocol: TCP
|
||||
port: 5556
|
||||
targetPort: 5556
|
||||
- name: grpc
|
||||
protocol: TCP
|
||||
port: 5557
|
||||
targetPort: 5557
|
||||
selector:
|
||||
app: dex-server
|
||||
@@ -1,33 +0,0 @@
|
||||
resources:
|
||||
- application-crd.yaml
|
||||
- appproject-crd.yaml
|
||||
- argocd-cm.yaml
|
||||
- argocd-secret.yaml
|
||||
- argocd-rbac-cm.yaml
|
||||
- application-controller-sa.yaml
|
||||
- application-controller-role.yaml
|
||||
- application-controller-rolebinding.yaml
|
||||
- application-controller-deployment.yaml
|
||||
- argocd-server-sa.yaml
|
||||
- argocd-server-role.yaml
|
||||
- argocd-server-rolebinding.yaml
|
||||
- argocd-server-deployment.yaml
|
||||
- argocd-server-service.yaml
|
||||
- argocd-metrics-service.yaml
|
||||
- argocd-repo-server-deployment.yaml
|
||||
- argocd-repo-server-service.yaml
|
||||
- dex-server-sa.yaml
|
||||
- dex-server-role.yaml
|
||||
- dex-server-rolebinding.yaml
|
||||
- dex-server-deployment.yaml
|
||||
- dex-server-service.yaml
|
||||
|
||||
imageTags:
|
||||
- name: argoproj/argocd-server
|
||||
newTag: v0.10.6
|
||||
- name: argoproj/argocd-ui
|
||||
newTag: v0.10.6
|
||||
- name: argoproj/argocd-repo-server
|
||||
newTag: v0.10.6
|
||||
- name: argoproj/argocd-application-controller
|
||||
newTag: v0.10.6
|
||||
@@ -1,15 +0,0 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: application-controller-clusterrole
|
||||
rules:
|
||||
- apiGroups:
|
||||
- '*'
|
||||
resources:
|
||||
- '*'
|
||||
verbs:
|
||||
- '*'
|
||||
- nonResourceURLs:
|
||||
- '*'
|
||||
verbs:
|
||||
- '*'
|
||||
@@ -1,12 +0,0 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: application-controller-clusterrolebinding
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: application-controller-clusterrole
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: application-controller
|
||||
namespace: argocd
|
||||
@@ -1,24 +0,0 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: argocd-server-clusterrole
|
||||
rules:
|
||||
- apiGroups:
|
||||
- '*'
|
||||
resources:
|
||||
- '*'
|
||||
verbs:
|
||||
- delete
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- events
|
||||
verbs:
|
||||
- list
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- pods
|
||||
- pods/log
|
||||
verbs:
|
||||
- get
|
||||
@@ -1,12 +0,0 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: argocd-server-clusterrolebinding
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: argocd-server-clusterrole
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: argocd-server
|
||||
namespace: argocd
|
||||
@@ -1,8 +0,0 @@
|
||||
bases:
|
||||
- ../base
|
||||
|
||||
resources:
|
||||
- application-controller-clusterrole.yaml
|
||||
- application-controller-clusterrolebinding.yaml
|
||||
- argocd-server-clusterrole.yaml
|
||||
- argocd-server-clusterrolebinding.yaml
|
||||
@@ -1,3 +1,4 @@
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1beta1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
@@ -1,3 +1,4 @@
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1beta1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
14
manifests/components/02a_argocd-cm.yaml
Normal file
14
manifests/components/02a_argocd-cm.yaml
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
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
|
||||
|
||||
# URL is the external URL of ArgoCD
|
||||
#url:
|
||||
|
||||
# A dex connector configuration
|
||||
#dex.config:
|
||||
24
manifests/components/02b_argocd-secret.yaml
Normal file
24
manifests/components/02b_argocd-secret.yaml
Normal file
@@ -0,0 +1,24 @@
|
||||
---
|
||||
# NOTE: the values in this secret will be populated by the initial startup of the API
|
||||
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:
|
||||
|
||||
# TLS certificate and private key for API server
|
||||
#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:
|
||||
26
manifests/components/02c_argocd-rbac-cm.yaml
Normal file
26
manifests/components/02c_argocd-rbac-cm.yaml
Normal file
@@ -0,0 +1,26 @@
|
||||
---
|
||||
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: ""
|
||||
|
||||
# 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
|
||||
@@ -1,3 +1,4 @@
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
@@ -1,3 +1,4 @@
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
@@ -1,3 +1,4 @@
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
@@ -1,3 +1,4 @@
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
@@ -12,14 +13,7 @@ spec:
|
||||
app: application-controller
|
||||
spec:
|
||||
containers:
|
||||
- command:
|
||||
- /argocd-application-controller
|
||||
- --repo-server
|
||||
- argocd-repo-server:8081
|
||||
- --status-processors
|
||||
- "20"
|
||||
- --operation-processors
|
||||
- "10"
|
||||
image: argoproj/argocd-application-controller:latest
|
||||
- command: [/argocd-application-controller, --repo-server, 'argocd-repo-server:8081']
|
||||
image: argoproj/argocd-application-controller:v0.7.2
|
||||
name: application-controller
|
||||
serviceAccountName: application-controller
|
||||
@@ -1,3 +1,4 @@
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
@@ -1,3 +1,4 @@
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
@@ -1,3 +1,4 @@
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
@@ -1,3 +1,4 @@
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
@@ -13,25 +14,31 @@ spec:
|
||||
spec:
|
||||
serviceAccountName: argocd-server
|
||||
initContainers:
|
||||
- name: copyutil
|
||||
image: argoproj/argocd-server:v0.7.2
|
||||
command: [cp, /argocd-util, /shared]
|
||||
volumeMounts:
|
||||
- mountPath: /shared
|
||||
name: static-files
|
||||
- name: ui
|
||||
image: argoproj/argocd-ui:latest
|
||||
image: argoproj/argocd-ui:v0.7.2
|
||||
command: [cp, -r, /app, /shared]
|
||||
volumeMounts:
|
||||
- mountPath: /shared
|
||||
name: static-files
|
||||
containers:
|
||||
- name: argocd-server
|
||||
image: argoproj/argocd-server:latest
|
||||
image: argoproj/argocd-server:v0.7.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]
|
||||
volumeMounts:
|
||||
- mountPath: /shared
|
||||
name: static-files
|
||||
volumes:
|
||||
- emptyDir: {}
|
||||
name: static-files
|
||||
@@ -1,3 +1,4 @@
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
@@ -1,3 +1,4 @@
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
@@ -11,15 +12,9 @@ spec:
|
||||
labels:
|
||||
app: argocd-repo-server
|
||||
spec:
|
||||
automountServiceAccountToken: false
|
||||
containers:
|
||||
- name: argocd-repo-server
|
||||
image: argoproj/argocd-repo-server:latest
|
||||
image: argoproj/argocd-repo-server:v0.7.2
|
||||
command: [/argocd-repo-server]
|
||||
ports:
|
||||
- containerPort: 8081
|
||||
readinessProbe:
|
||||
tcpSocket:
|
||||
port: 8081
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
- containerPort: 8081
|
||||
@@ -1,3 +1,4 @@
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
@@ -1,4 +1,5 @@
|
||||
# This is an auto-generated file. DO NOT EDIT
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1beta1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
@@ -29,20 +30,74 @@ spec:
|
||||
version: v1alpha1
|
||||
---
|
||||
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
|
||||
|
||||
# URL is the external URL of ArgoCD
|
||||
#url:
|
||||
|
||||
# A dex connector configuration
|
||||
#dex.config:
|
||||
---
|
||||
# NOTE: the values in this secret will be populated by the initial startup of the API
|
||||
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:
|
||||
|
||||
# TLS certificate and private key for API server
|
||||
#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:
|
||||
---
|
||||
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: ""
|
||||
|
||||
# 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
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: application-controller
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: argocd-server
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: dex-server
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
@@ -78,101 +133,7 @@ rules:
|
||||
verbs:
|
||||
- create
|
||||
- list
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: argocd-server-role
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- secrets
|
||||
- configmaps
|
||||
verbs:
|
||||
- create
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- update
|
||||
- patch
|
||||
- delete
|
||||
- apiGroups:
|
||||
- argoproj.io
|
||||
resources:
|
||||
- applications
|
||||
- appprojects
|
||||
verbs:
|
||||
- create
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- update
|
||||
- delete
|
||||
- patch
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- events
|
||||
verbs:
|
||||
- create
|
||||
- list
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: dex-server-role
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- secrets
|
||||
- configmaps
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: application-controller-clusterrole
|
||||
rules:
|
||||
- apiGroups:
|
||||
- '*'
|
||||
resources:
|
||||
- '*'
|
||||
verbs:
|
||||
- '*'
|
||||
- nonResourceURLs:
|
||||
- '*'
|
||||
verbs:
|
||||
- '*'
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: argocd-server-clusterrole
|
||||
rules:
|
||||
- apiGroups:
|
||||
- '*'
|
||||
resources:
|
||||
- '*'
|
||||
verbs:
|
||||
- delete
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- events
|
||||
verbs:
|
||||
- list
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- pods
|
||||
- pods/log
|
||||
verbs:
|
||||
- get
|
||||
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
@@ -186,130 +147,6 @@ subjects:
|
||||
- kind: ServiceAccount
|
||||
name: application-controller
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: argocd-server-role-binding
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: argocd-server-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: argocd-server
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: dex-server-role-binding
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: dex-server-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: dex-server
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: application-controller-clusterrolebinding
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: application-controller-clusterrole
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: application-controller
|
||||
namespace: argocd
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: argocd-server-clusterrolebinding
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: argocd-server-clusterrole
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: argocd-server
|
||||
namespace: argocd
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: argocd-cm
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: argocd-rbac-cm
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: argocd-secret
|
||||
type: Opaque
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: argocd-metrics
|
||||
spec:
|
||||
ports:
|
||||
- name: http
|
||||
port: 8082
|
||||
protocol: TCP
|
||||
targetPort: 8082
|
||||
selector:
|
||||
app: argocd-server
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: argocd-repo-server
|
||||
spec:
|
||||
ports:
|
||||
- port: 8081
|
||||
targetPort: 8081
|
||||
selector:
|
||||
app: argocd-repo-server
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: argocd-server
|
||||
spec:
|
||||
ports:
|
||||
- name: http
|
||||
port: 80
|
||||
protocol: TCP
|
||||
targetPort: 8080
|
||||
- name: https
|
||||
port: 443
|
||||
protocol: TCP
|
||||
targetPort: 8080
|
||||
selector:
|
||||
app: argocd-server
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: dex-server
|
||||
spec:
|
||||
ports:
|
||||
- name: http
|
||||
port: 5556
|
||||
protocol: TCP
|
||||
targetPort: 5556
|
||||
- name: grpc
|
||||
port: 5557
|
||||
protocol: TCP
|
||||
targetPort: 5557
|
||||
selector:
|
||||
app: dex-server
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
@@ -324,44 +161,66 @@ spec:
|
||||
app: application-controller
|
||||
spec:
|
||||
containers:
|
||||
- command:
|
||||
- /argocd-application-controller
|
||||
- --repo-server
|
||||
- argocd-repo-server:8081
|
||||
- --status-processors
|
||||
- "20"
|
||||
- --operation-processors
|
||||
- "10"
|
||||
image: argoproj/argocd-application-controller:v0.10.6
|
||||
- command: [/argocd-application-controller, --repo-server, 'argocd-repo-server:8081']
|
||||
image: argoproj/argocd-application-controller:v0.7.2
|
||||
name: application-controller
|
||||
serviceAccountName: application-controller
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: argocd-repo-server
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: argocd-repo-server
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: argocd-repo-server
|
||||
spec:
|
||||
automountServiceAccountToken: false
|
||||
containers:
|
||||
- command:
|
||||
- /argocd-repo-server
|
||||
image: argoproj/argocd-repo-server:v0.10.6
|
||||
name: argocd-repo-server
|
||||
ports:
|
||||
- containerPort: 8081
|
||||
readinessProbe:
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
tcpSocket:
|
||||
port: 8081
|
||||
name: argocd-server
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: argocd-server-role
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- secrets
|
||||
- configmaps
|
||||
verbs:
|
||||
- create
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- update
|
||||
- patch
|
||||
- delete
|
||||
- apiGroups:
|
||||
- argoproj.io
|
||||
resources:
|
||||
- applications
|
||||
- appprojects
|
||||
verbs:
|
||||
- create
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- update
|
||||
- delete
|
||||
- patch
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- events
|
||||
verbs:
|
||||
- create
|
||||
- list
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: argocd-server-role-binding
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: argocd-server-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: argocd-server
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
@@ -376,76 +235,81 @@ spec:
|
||||
labels:
|
||||
app: argocd-server
|
||||
spec:
|
||||
containers:
|
||||
- command:
|
||||
- /argocd-server
|
||||
- --staticassets
|
||||
- /shared/app
|
||||
- --repo-server
|
||||
- argocd-repo-server:8081
|
||||
image: argoproj/argocd-server:v0.10.6
|
||||
name: argocd-server
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: 8080
|
||||
initialDelaySeconds: 3
|
||||
periodSeconds: 30
|
||||
volumeMounts:
|
||||
- mountPath: /shared
|
||||
name: static-files
|
||||
initContainers:
|
||||
- command:
|
||||
- cp
|
||||
- -r
|
||||
- /app
|
||||
- /shared
|
||||
image: argoproj/argocd-ui:v0.10.6
|
||||
name: ui
|
||||
volumeMounts:
|
||||
- mountPath: /shared
|
||||
name: static-files
|
||||
serviceAccountName: argocd-server
|
||||
initContainers:
|
||||
- name: copyutil
|
||||
image: argoproj/argocd-server:v0.7.2
|
||||
command: [cp, /argocd-util, /shared]
|
||||
volumeMounts:
|
||||
- mountPath: /shared
|
||||
name: static-files
|
||||
- name: ui
|
||||
image: argoproj/argocd-ui:v0.7.2
|
||||
command: [cp, -r, /app, /shared]
|
||||
volumeMounts:
|
||||
- mountPath: /shared
|
||||
name: static-files
|
||||
containers:
|
||||
- name: argocd-server
|
||||
image: argoproj/argocd-server:v0.7.2
|
||||
command: [/argocd-server, --staticassets, /shared/app, --repo-server, 'argocd-repo-server:8081']
|
||||
volumeMounts:
|
||||
- mountPath: /shared
|
||||
name: static-files
|
||||
- name: dex
|
||||
image: quay.io/coreos/dex:v2.10.0
|
||||
command: [/shared/argocd-util, rundex]
|
||||
volumeMounts:
|
||||
- mountPath: /shared
|
||||
name: static-files
|
||||
volumes:
|
||||
- emptyDir: {}
|
||||
name: static-files
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: argocd-server
|
||||
spec:
|
||||
ports:
|
||||
- name: http
|
||||
protocol: TCP
|
||||
port: 80
|
||||
targetPort: 8080
|
||||
- name: https
|
||||
protocol: TCP
|
||||
port: 443
|
||||
targetPort: 8080
|
||||
selector:
|
||||
app: argocd-server
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: dex-server
|
||||
name: argocd-repo-server
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: dex-server
|
||||
app: argocd-repo-server
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: dex-server
|
||||
app: argocd-repo-server
|
||||
spec:
|
||||
containers:
|
||||
- command:
|
||||
- /shared/argocd-util
|
||||
- rundex
|
||||
image: quay.io/dexidp/dex:v2.11.0
|
||||
name: dex
|
||||
- name: argocd-repo-server
|
||||
image: argoproj/argocd-repo-server:v0.7.2
|
||||
command: [/argocd-repo-server]
|
||||
ports:
|
||||
- containerPort: 5556
|
||||
- containerPort: 5557
|
||||
volumeMounts:
|
||||
- mountPath: /shared
|
||||
name: static-files
|
||||
initContainers:
|
||||
- command:
|
||||
- cp
|
||||
- /argocd-util
|
||||
- /shared
|
||||
image: argoproj/argocd-server:v0.10.6
|
||||
name: copyutil
|
||||
volumeMounts:
|
||||
- mountPath: /shared
|
||||
name: static-files
|
||||
serviceAccountName: dex-server
|
||||
volumes:
|
||||
- emptyDir: {}
|
||||
name: static-files
|
||||
- containerPort: 8081
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: argocd-repo-server
|
||||
spec:
|
||||
ports:
|
||||
- port: 8081
|
||||
targetPort: 8081
|
||||
selector:
|
||||
app: argocd-repo-server
|
||||
|
||||
@@ -1,384 +0,0 @@
|
||||
# This is an auto-generated file. DO NOT EDIT
|
||||
apiVersion: apiextensions.k8s.io/v1beta1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
name: applications.argoproj.io
|
||||
spec:
|
||||
group: argoproj.io
|
||||
names:
|
||||
kind: Application
|
||||
plural: applications
|
||||
shortNames:
|
||||
- app
|
||||
scope: Namespaced
|
||||
version: v1alpha1
|
||||
---
|
||||
apiVersion: apiextensions.k8s.io/v1beta1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
name: appprojects.argoproj.io
|
||||
spec:
|
||||
group: argoproj.io
|
||||
names:
|
||||
kind: AppProject
|
||||
plural: appprojects
|
||||
shortNames:
|
||||
- appproj
|
||||
- appprojs
|
||||
scope: Namespaced
|
||||
version: v1alpha1
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: application-controller
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: argocd-server
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: dex-server
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: application-controller-role
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- secrets
|
||||
verbs:
|
||||
- get
|
||||
- watch
|
||||
- list
|
||||
- patch
|
||||
- update
|
||||
- apiGroups:
|
||||
- argoproj.io
|
||||
resources:
|
||||
- applications
|
||||
- appprojects
|
||||
verbs:
|
||||
- create
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- update
|
||||
- patch
|
||||
- delete
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- events
|
||||
verbs:
|
||||
- create
|
||||
- list
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: argocd-server-role
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- secrets
|
||||
- configmaps
|
||||
verbs:
|
||||
- create
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- update
|
||||
- patch
|
||||
- delete
|
||||
- apiGroups:
|
||||
- argoproj.io
|
||||
resources:
|
||||
- applications
|
||||
- appprojects
|
||||
verbs:
|
||||
- create
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- update
|
||||
- delete
|
||||
- patch
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- events
|
||||
verbs:
|
||||
- create
|
||||
- list
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: dex-server-role
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- secrets
|
||||
- configmaps
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: application-controller-role-binding
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: application-controller-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: application-controller
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: argocd-server-role-binding
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: argocd-server-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: argocd-server
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: dex-server-role-binding
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: dex-server-role
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: dex-server
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: argocd-cm
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: argocd-rbac-cm
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: argocd-secret
|
||||
type: Opaque
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: argocd-metrics
|
||||
spec:
|
||||
ports:
|
||||
- name: http
|
||||
port: 8082
|
||||
protocol: TCP
|
||||
targetPort: 8082
|
||||
selector:
|
||||
app: argocd-server
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: argocd-repo-server
|
||||
spec:
|
||||
ports:
|
||||
- port: 8081
|
||||
targetPort: 8081
|
||||
selector:
|
||||
app: argocd-repo-server
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: argocd-server
|
||||
spec:
|
||||
ports:
|
||||
- name: http
|
||||
port: 80
|
||||
protocol: TCP
|
||||
targetPort: 8080
|
||||
- name: https
|
||||
port: 443
|
||||
protocol: TCP
|
||||
targetPort: 8080
|
||||
selector:
|
||||
app: argocd-server
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: dex-server
|
||||
spec:
|
||||
ports:
|
||||
- name: http
|
||||
port: 5556
|
||||
protocol: TCP
|
||||
targetPort: 5556
|
||||
- name: grpc
|
||||
port: 5557
|
||||
protocol: TCP
|
||||
targetPort: 5557
|
||||
selector:
|
||||
app: dex-server
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: application-controller
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: application-controller
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: application-controller
|
||||
spec:
|
||||
containers:
|
||||
- command:
|
||||
- /argocd-application-controller
|
||||
- --repo-server
|
||||
- argocd-repo-server:8081
|
||||
- --status-processors
|
||||
- "20"
|
||||
- --operation-processors
|
||||
- "10"
|
||||
image: argoproj/argocd-application-controller:v0.10.6
|
||||
name: application-controller
|
||||
serviceAccountName: application-controller
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: argocd-repo-server
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: argocd-repo-server
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: argocd-repo-server
|
||||
spec:
|
||||
automountServiceAccountToken: false
|
||||
containers:
|
||||
- command:
|
||||
- /argocd-repo-server
|
||||
image: argoproj/argocd-repo-server:v0.10.6
|
||||
name: argocd-repo-server
|
||||
ports:
|
||||
- containerPort: 8081
|
||||
readinessProbe:
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
tcpSocket:
|
||||
port: 8081
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: argocd-server
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: argocd-server
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: argocd-server
|
||||
spec:
|
||||
containers:
|
||||
- command:
|
||||
- /argocd-server
|
||||
- --staticassets
|
||||
- /shared/app
|
||||
- --repo-server
|
||||
- argocd-repo-server:8081
|
||||
image: argoproj/argocd-server:v0.10.6
|
||||
name: argocd-server
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: 8080
|
||||
initialDelaySeconds: 3
|
||||
periodSeconds: 30
|
||||
volumeMounts:
|
||||
- mountPath: /shared
|
||||
name: static-files
|
||||
initContainers:
|
||||
- command:
|
||||
- cp
|
||||
- -r
|
||||
- /app
|
||||
- /shared
|
||||
image: argoproj/argocd-ui:v0.10.6
|
||||
name: ui
|
||||
volumeMounts:
|
||||
- mountPath: /shared
|
||||
name: static-files
|
||||
serviceAccountName: argocd-server
|
||||
volumes:
|
||||
- emptyDir: {}
|
||||
name: static-files
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: dex-server
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: dex-server
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: dex-server
|
||||
spec:
|
||||
containers:
|
||||
- command:
|
||||
- /shared/argocd-util
|
||||
- rundex
|
||||
image: quay.io/dexidp/dex:v2.11.0
|
||||
name: dex
|
||||
ports:
|
||||
- containerPort: 5556
|
||||
- containerPort: 5557
|
||||
volumeMounts:
|
||||
- mountPath: /shared
|
||||
name: static-files
|
||||
initContainers:
|
||||
- command:
|
||||
- cp
|
||||
- /argocd-util
|
||||
- /shared
|
||||
image: argoproj/argocd-server:v0.10.6
|
||||
name: copyutil
|
||||
volumeMounts:
|
||||
- mountPath: /shared
|
||||
name: static-files
|
||||
serviceAccountName: dex-server
|
||||
volumes:
|
||||
- emptyDir: {}
|
||||
name: static-files
|
||||
@@ -40,8 +40,6 @@ const (
|
||||
EnvArgoCDServer = "ARGOCD_SERVER"
|
||||
// EnvArgoCDAuthToken is the environment variable to look for an ArgoCD auth token
|
||||
EnvArgoCDAuthToken = "ARGOCD_AUTH_TOKEN"
|
||||
// MaxGRPCMessageSize contains max grpc message size
|
||||
MaxGRPCMessageSize = 100 * 1024 * 1024
|
||||
)
|
||||
|
||||
// Client defines an interface for interaction with an Argo CD server.
|
||||
@@ -279,8 +277,7 @@ func (c *client) NewConn() (*grpc.ClientConn, error) {
|
||||
endpointCredentials := jwtCredentials{
|
||||
Token: c.AuthToken,
|
||||
}
|
||||
return grpc_util.BlockingDial(context.Background(), "tcp", c.ServerAddr, creds,
|
||||
grpc.WithPerRPCCredentials(endpointCredentials), grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(MaxGRPCMessageSize)))
|
||||
return grpc_util.BlockingDial(context.Background(), "tcp", c.ServerAddr, creds, grpc.WithPerRPCCredentials(endpointCredentials))
|
||||
}
|
||||
|
||||
func (c *client) tlsConfig() (*tls.Config, error) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -8,19 +8,11 @@ package github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1;
|
||||
import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto";
|
||||
import "k8s.io/apimachinery/pkg/runtime/generated.proto";
|
||||
import "k8s.io/apimachinery/pkg/runtime/schema/generated.proto";
|
||||
import "k8s.io/apimachinery/pkg/util/intstr/generated.proto";
|
||||
|
||||
// Package-wide variables from generator "generated".
|
||||
option go_package = "v1alpha1";
|
||||
|
||||
// AWSAuthConfig is an AWS IAM authentication configuration
|
||||
message AWSAuthConfig {
|
||||
// ClusterName contains AWS cluster name
|
||||
optional string clusterName = 1;
|
||||
|
||||
// RoleARN contains optional role ARN. If set then AWS IAM Authenticator assume a role to perform cluster operations instead of the default AWS credential provider chain.
|
||||
optional string roleARN = 2;
|
||||
}
|
||||
|
||||
// AppProject is a definition of AppProject resource.
|
||||
// +genclient
|
||||
// +genclient:noStatus
|
||||
@@ -49,14 +41,6 @@ message AppProjectSpec {
|
||||
|
||||
// Description contains optional project description
|
||||
optional string description = 3;
|
||||
|
||||
repeated ProjectRole roles = 4;
|
||||
|
||||
// ClusterResourceWhitelist contains list of whitelisted cluster level resources
|
||||
repeated k8s.io.apimachinery.pkg.apis.meta.v1.GroupKind clusterResourceWhitelist = 5;
|
||||
|
||||
// NamespaceResourceBlacklist contains list of blacklisted namespace level resources
|
||||
repeated k8s.io.apimachinery.pkg.apis.meta.v1.GroupKind namespaceResourceBlacklist = 6;
|
||||
}
|
||||
|
||||
// Application is a definition of Application resource.
|
||||
@@ -131,9 +115,6 @@ message ApplicationSpec {
|
||||
|
||||
// Project is a application project name. Empty name means that application belongs to 'default' project.
|
||||
optional string project = 3;
|
||||
|
||||
// SyncPolicy controls when a sync will be performed
|
||||
optional SyncPolicy syncPolicy = 4;
|
||||
}
|
||||
|
||||
// ApplicationStatus contains information about application status in target environment.
|
||||
@@ -193,9 +174,6 @@ message ClusterConfig {
|
||||
|
||||
// TLSClientConfig contains settings to enable transport layer security
|
||||
optional TLSClientConfig tlsClientConfig = 4;
|
||||
|
||||
// AWSAuthConfig contains IAM authentication configuration
|
||||
optional AWSAuthConfig awsAuthConfig = 5;
|
||||
}
|
||||
|
||||
// ClusterList is a collection of Clusters.
|
||||
@@ -214,8 +192,6 @@ message ComparisonResult {
|
||||
optional string status = 5;
|
||||
|
||||
repeated ResourceState resources = 6;
|
||||
|
||||
optional string revision = 7;
|
||||
}
|
||||
|
||||
// ComponentParameter contains information about component parameter value
|
||||
@@ -238,6 +214,8 @@ message ConnectionState {
|
||||
|
||||
// DeploymentInfo contains information relevant to an application deployment
|
||||
message DeploymentInfo {
|
||||
repeated ComponentParameter params = 1;
|
||||
|
||||
optional string revision = 2;
|
||||
|
||||
repeated ComponentParameter componentParameterOverrides = 3;
|
||||
@@ -274,16 +252,11 @@ 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;
|
||||
|
||||
optional RollbackOperation rollback = 2;
|
||||
}
|
||||
|
||||
// OperationState contains information about state of currently performing operation on application.
|
||||
@@ -300,6 +273,9 @@ message OperationState {
|
||||
// SyncResult is the result of a Sync operation
|
||||
optional SyncOperationResult syncResult = 4;
|
||||
|
||||
// RollbackResult is the result of a Rollback operation
|
||||
optional SyncOperationResult rollbackResult = 5;
|
||||
|
||||
// StartedAt contains time of operation start
|
||||
optional k8s.io.apimachinery.pkg.apis.meta.v1.Time startedAt = 6;
|
||||
|
||||
@@ -307,27 +283,6 @@ message OperationState {
|
||||
optional k8s.io.apimachinery.pkg.apis.meta.v1.Time finishedAt = 7;
|
||||
}
|
||||
|
||||
// ParameterOverrides masks the value so protobuf can generate
|
||||
// +protobuf.nullable=true
|
||||
// +protobuf.options.(gogoproto.goproto_stringer)=false
|
||||
message ParameterOverrides {
|
||||
// items, if empty, will result in an empty slice
|
||||
|
||||
repeated ComponentParameter items = 1;
|
||||
}
|
||||
|
||||
// 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;
|
||||
@@ -380,10 +335,17 @@ message ResourceState {
|
||||
optional HealthStatus health = 5;
|
||||
}
|
||||
|
||||
message RollbackOperation {
|
||||
optional int64 id = 1;
|
||||
|
||||
optional bool prune = 2;
|
||||
|
||||
optional bool dryRun = 3;
|
||||
}
|
||||
|
||||
// SyncOperation contains sync operation details.
|
||||
message SyncOperation {
|
||||
// Revision is the git revision in which to sync the application to.
|
||||
// If omitted, will use the revision specified in app spec.
|
||||
// Revision is the git revision in which to sync the application to
|
||||
optional string revision = 1;
|
||||
|
||||
// Prune deletes resources that are no longer tracked in git
|
||||
@@ -394,23 +356,6 @@ message SyncOperation {
|
||||
|
||||
// SyncStrategy describes how to perform the sync
|
||||
optional SyncStrategy syncStrategy = 4;
|
||||
|
||||
// ParameterOverrides applies any parameter overrides as part of the sync
|
||||
// If nil, uses the parameter override set in application.
|
||||
// If empty, sets no parameter overrides
|
||||
optional ParameterOverrides parameterOverrides = 5;
|
||||
|
||||
// Resources describes which resources to sync
|
||||
repeated SyncOperationResource resources = 6;
|
||||
}
|
||||
|
||||
// SyncOperationResource contains resources to sync.
|
||||
message SyncOperationResource {
|
||||
optional string group = 1;
|
||||
|
||||
optional string kind = 2;
|
||||
|
||||
optional string name = 3;
|
||||
}
|
||||
|
||||
// SyncOperationResult represent result of sync operation
|
||||
@@ -425,24 +370,12 @@ message SyncOperationResult {
|
||||
repeated HookStatus hooks = 3;
|
||||
}
|
||||
|
||||
// SyncPolicy controls when a sync will be performed in response to updates in git
|
||||
message SyncPolicy {
|
||||
// Automated will keep an application synced to the target revision
|
||||
optional SyncPolicyAutomated automated = 1;
|
||||
}
|
||||
|
||||
// SyncPolicyAutomated controls the behavior of an automated sync
|
||||
message SyncPolicyAutomated {
|
||||
// Prune will prune resources automatically as part of automated sync (default: false)
|
||||
optional bool prune = 1;
|
||||
}
|
||||
|
||||
// SyncStrategy controls the manner in which a sync is performed
|
||||
// SyncStrategy indicates the
|
||||
message SyncStrategy {
|
||||
// Apply wil perform a `kubectl apply` to perform the sync.
|
||||
// Apply wil perform a `kubectl apply` to perform the sync. This is the default strategy
|
||||
optional SyncStrategyApply apply = 1;
|
||||
|
||||
// Hook will submit any referenced resources to perform the sync. This is the default strategy
|
||||
// Hook will submit any referenced resources to perform the sync
|
||||
optional SyncStrategyHook hook = 2;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,8 +2,6 @@ package v1alpha1
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
fmt "fmt"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
@@ -11,32 +9,14 @@ import (
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/clientcmd/api"
|
||||
|
||||
"github.com/argoproj/argo-cd/common"
|
||||
"github.com/argoproj/argo-cd/util/git"
|
||||
)
|
||||
|
||||
// SyncOperationResource contains resources to sync.
|
||||
type SyncOperationResource struct {
|
||||
Group string `json:"group,omitempty" protobuf:"bytes,1,opt,name=group"`
|
||||
Kind string `json:"kind" protobuf:"bytes,2,opt,name=kind"`
|
||||
Name string `json:"name" protobuf:"bytes,3,opt,name=name"`
|
||||
}
|
||||
|
||||
// HasIdentity determines whether a sync operation is identified by a manifest.
|
||||
func (r SyncOperationResource) HasIdentity(u *unstructured.Unstructured) bool {
|
||||
gvk := u.GroupVersionKind()
|
||||
if u.GetName() == r.Name && gvk.Kind == r.Kind && gvk.Group == r.Group {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// SyncOperation contains sync operation details.
|
||||
type SyncOperation struct {
|
||||
// Revision is the git revision in which to sync the application to.
|
||||
// If omitted, will use the revision specified in app spec.
|
||||
// Revision is the git revision in which to sync the application to
|
||||
Revision string `json:"revision,omitempty" protobuf:"bytes,1,opt,name=revision"`
|
||||
// Prune deletes resources that are no longer tracked in git
|
||||
Prune bool `json:"prune,omitempty" protobuf:"bytes,2,opt,name=prune"`
|
||||
@@ -44,26 +24,18 @@ type SyncOperation struct {
|
||||
DryRun bool `json:"dryRun,omitempty" protobuf:"bytes,3,opt,name=dryRun"`
|
||||
// SyncStrategy describes how to perform the sync
|
||||
SyncStrategy *SyncStrategy `json:"syncStrategy,omitempty" protobuf:"bytes,4,opt,name=syncStrategy"`
|
||||
// ParameterOverrides applies any parameter overrides as part of the sync
|
||||
// If nil, uses the parameter override set in application.
|
||||
// If empty, sets no parameter overrides
|
||||
ParameterOverrides ParameterOverrides `json:"parameterOverrides" protobuf:"bytes,5,opt,name=parameterOverrides"`
|
||||
// Resources describes which resources to sync
|
||||
Resources []SyncOperationResource `json:"resources,omitempty" protobuf:"bytes,6,opt,name=resources"`
|
||||
}
|
||||
|
||||
// ParameterOverrides masks the value so protobuf can generate
|
||||
// +protobuf.nullable=true
|
||||
// +protobuf.options.(gogoproto.goproto_stringer)=false
|
||||
type ParameterOverrides []ComponentParameter
|
||||
|
||||
func (po ParameterOverrides) String() string {
|
||||
return fmt.Sprintf("%v", []ComponentParameter(po))
|
||||
type RollbackOperation struct {
|
||||
ID int64 `json:"id" protobuf:"bytes,1,opt,name=id"`
|
||||
Prune bool `json:"prune,omitempty" protobuf:"bytes,2,opt,name=prune"`
|
||||
DryRun bool `json:"dryRun,omitempty" protobuf:"bytes,3,opt,name=dryRun"`
|
||||
}
|
||||
|
||||
// Operation contains requested operation parameters.
|
||||
type Operation struct {
|
||||
Sync *SyncOperation `json:"sync,omitempty" protobuf:"bytes,1,opt,name=sync"`
|
||||
Sync *SyncOperation `json:"sync,omitempty" protobuf:"bytes,1,opt,name=sync"`
|
||||
Rollback *RollbackOperation `json:"rollback,omitempty" protobuf:"bytes,2,opt,name=rollback"`
|
||||
}
|
||||
|
||||
type OperationPhase string
|
||||
@@ -98,29 +70,19 @@ type OperationState struct {
|
||||
Message string `json:"message,omitempty" protobuf:"bytes,3,opt,name=message"`
|
||||
// SyncResult is the result of a Sync operation
|
||||
SyncResult *SyncOperationResult `json:"syncResult,omitempty" protobuf:"bytes,4,opt,name=syncResult"`
|
||||
// RollbackResult is the result of a Rollback operation
|
||||
RollbackResult *SyncOperationResult `json:"rollbackResult,omitempty" protobuf:"bytes,5,opt,name=rollbackResult"`
|
||||
// StartedAt contains time of operation start
|
||||
StartedAt metav1.Time `json:"startedAt" protobuf:"bytes,6,opt,name=startedAt"`
|
||||
// FinishedAt contains time of operation completion
|
||||
FinishedAt *metav1.Time `json:"finishedAt" protobuf:"bytes,7,opt,name=finishedAt"`
|
||||
}
|
||||
|
||||
// SyncPolicy controls when a sync will be performed in response to updates in git
|
||||
type SyncPolicy struct {
|
||||
// Automated will keep an application synced to the target revision
|
||||
Automated *SyncPolicyAutomated `json:"automated,omitempty" protobuf:"bytes,1,opt,name=automated"`
|
||||
}
|
||||
|
||||
// SyncPolicyAutomated controls the behavior of an automated sync
|
||||
type SyncPolicyAutomated struct {
|
||||
// Prune will prune resources automatically as part of automated sync (default: false)
|
||||
Prune bool `json:"prune,omitempty" protobuf:"bytes,1,opt,name=prune"`
|
||||
}
|
||||
|
||||
// SyncStrategy controls the manner in which a sync is performed
|
||||
// SyncStrategy indicates the
|
||||
type SyncStrategy struct {
|
||||
// Apply wil perform a `kubectl apply` to perform the sync.
|
||||
// Apply wil perform a `kubectl apply` to perform the sync. This is the default strategy
|
||||
Apply *SyncStrategyApply `json:"apply,omitempty" protobuf:"bytes,1,opt,name=apply"`
|
||||
// Hook will submit any referenced resources to perform the sync. This is the default strategy
|
||||
// Hook will submit any referenced resources to perform the sync
|
||||
Hook *SyncStrategyHook `json:"hook,omitempty" protobuf:"bytes,2,opt,name=hook"`
|
||||
}
|
||||
|
||||
@@ -209,6 +171,7 @@ type ResourceDetails struct {
|
||||
|
||||
// DeploymentInfo contains information relevant to an application deployment
|
||||
type DeploymentInfo struct {
|
||||
Params []ComponentParameter `json:"params" protobuf:"bytes,1,name=params"`
|
||||
Revision string `json:"revision" protobuf:"bytes,2,opt,name=revision"`
|
||||
ComponentParameterOverrides []ComponentParameter `json:"componentParameterOverrides,omitempty" protobuf:"bytes,3,opt,name=componentParameterOverrides"`
|
||||
DeployedAt metav1.Time `json:"deployedAt" protobuf:"bytes,4,opt,name=deployedAt"`
|
||||
@@ -255,8 +218,6 @@ type ApplicationSpec struct {
|
||||
Destination ApplicationDestination `json:"destination" protobuf:"bytes,2,name=destination"`
|
||||
// Project is a application project name. Empty name means that application belongs to 'default' project.
|
||||
Project string `json:"project" protobuf:"bytes,3,name=project"`
|
||||
// SyncPolicy controls when a sync will be performed
|
||||
SyncPolicy *SyncPolicy `json:"syncPolicy,omitempty" protobuf:"bytes,4,name=syncPolicy"`
|
||||
}
|
||||
|
||||
// ComponentParameter contains information about component parameter value
|
||||
@@ -322,10 +283,8 @@ const (
|
||||
ApplicationConditionDeletionError = "DeletionError"
|
||||
// ApplicationConditionInvalidSpecError indicates that application source is invalid
|
||||
ApplicationConditionInvalidSpecError = "InvalidSpecError"
|
||||
// ApplicationConditionComparisonError indicates controller failed to compare application state
|
||||
// ApplicationComparisonError indicates controller failed to compare application state
|
||||
ApplicationConditionComparisonError = "ComparisonError"
|
||||
// ApplicationConditionSyncError indicates controller failed to automatically sync the application
|
||||
ApplicationConditionSyncError = "SyncError"
|
||||
// ApplicationConditionUnknownError indicates an unknown controller error
|
||||
ApplicationConditionUnknownError = "UnknownError"
|
||||
// ApplicationConditionSharedResourceWarning indicates that controller detected resources which belongs to more than one application
|
||||
@@ -346,7 +305,6 @@ type ComparisonResult struct {
|
||||
ComparedTo ApplicationSource `json:"comparedTo" protobuf:"bytes,2,opt,name=comparedTo"`
|
||||
Status ComparisonStatus `json:"status" protobuf:"bytes,5,opt,name=status,casttype=ComparisonStatus"`
|
||||
Resources []ResourceState `json:"resources" protobuf:"bytes,6,opt,name=resources"`
|
||||
Revision string `json:"revision" protobuf:"bytes,7,opt,name=revision"`
|
||||
}
|
||||
|
||||
type HealthStatus struct {
|
||||
@@ -416,15 +374,6 @@ type ClusterList struct {
|
||||
Items []Cluster `json:"items" protobuf:"bytes,2,rep,name=items"`
|
||||
}
|
||||
|
||||
// AWSAuthConfig is an AWS IAM authentication configuration
|
||||
type AWSAuthConfig struct {
|
||||
// ClusterName contains AWS cluster name
|
||||
ClusterName string `json:"clusterName,omitempty" protobuf:"bytes,1,opt,name=clusterName"`
|
||||
|
||||
// RoleARN contains optional role ARN. If set then AWS IAM Authenticator assume a role to perform cluster operations instead of the default AWS credential provider chain.
|
||||
RoleARN string `json:"roleARN,omitempty" protobuf:"bytes,2,opt,name=roleARN"`
|
||||
}
|
||||
|
||||
// ClusterConfig is the configuration attributes. This structure is subset of the go-client
|
||||
// rest.Config with annotations added for marshalling.
|
||||
type ClusterConfig struct {
|
||||
@@ -439,9 +388,6 @@ type ClusterConfig struct {
|
||||
|
||||
// TLSClientConfig contains settings to enable transport layer security
|
||||
TLSClientConfig `json:"tlsClientConfig" protobuf:"bytes,4,opt,name=tlsClientConfig"`
|
||||
|
||||
// AWSAuthConfig contains IAM authentication configuration
|
||||
AWSAuthConfig *AWSAuthConfig `json:"awsAuthConfig" protobuf:"bytes,5,opt,name=awsAuthConfig"`
|
||||
}
|
||||
|
||||
// TLSClientConfig contains settings to enable transport layer security
|
||||
@@ -497,17 +443,6 @@ 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 {
|
||||
projectPolicy := fmt.Sprintf("p, proj:%s:%s, projects, get, %s, allow", proj.ObjectMeta.Name, role.Name, proj.ObjectMeta.Name)
|
||||
policies = append(policies, projectPolicy)
|
||||
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
|
||||
@@ -518,29 +453,15 @@ 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"`
|
||||
|
||||
// ClusterResourceWhitelist contains list of whitelisted cluster level resources
|
||||
ClusterResourceWhitelist []metav1.GroupKind `json:"clusterResourceWhitelist,omitempty" protobuf:"bytes,5,opt,name=clusterResourceWhitelist"`
|
||||
|
||||
// NamespaceResourceBlacklist contains list of blacklisted namespace level resources
|
||||
NamespaceResourceBlacklist []metav1.GroupKind `json:"namespaceResourceBlacklist,omitempty" protobuf:"bytes,6,opt,name=namespaceResourceBlacklist"`
|
||||
}
|
||||
|
||||
// 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 GetDefaultProject(namespace string) AppProject {
|
||||
return AppProject{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: common.DefaultAppProjectName,
|
||||
Namespace: namespace,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (app *Application) getFinalizerIndex(name string) int {
|
||||
@@ -603,35 +524,16 @@ func (spec ApplicationSpec) GetProject() string {
|
||||
return spec.Project
|
||||
}
|
||||
|
||||
func isResourceInList(res metav1.GroupKind, list []metav1.GroupKind) bool {
|
||||
for _, item := range list {
|
||||
ok, err := filepath.Match(item.Kind, res.Kind)
|
||||
if ok && err == nil {
|
||||
ok, err = filepath.Match(item.Group, res.Group)
|
||||
if ok && err == nil {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
func (proj AppProject) IsDefault() bool {
|
||||
return proj.Name == "" || proj.Name == common.DefaultAppProjectName
|
||||
}
|
||||
|
||||
func (proj AppProject) IsResourcePermitted(res metav1.GroupKind, namespaced bool) bool {
|
||||
if namespaced {
|
||||
return !isResourceInList(res, proj.Spec.NamespaceResourceBlacklist)
|
||||
} else {
|
||||
return isResourceInList(res, proj.Spec.ClusterResourceWhitelist)
|
||||
}
|
||||
}
|
||||
|
||||
// IsSourcePermitted validates 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
|
||||
}
|
||||
@@ -639,13 +541,13 @@ 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.Server == "*" {
|
||||
if item.Namespace == dst.Namespace || item.Namespace == "*" {
|
||||
return true
|
||||
}
|
||||
if item.Server == dst.Server && item.Namespace == dst.Namespace {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
@@ -653,42 +555,18 @@ func (proj AppProject) IsDestinationPermitted(dst ApplicationDestination) bool {
|
||||
|
||||
// RESTConfig returns a go-client REST config from cluster
|
||||
func (c *Cluster) RESTConfig() *rest.Config {
|
||||
if c.Server == common.KubernetesInternalAPIServerAddr && c.Config.Username == "" && c.Config.Password == "" && c.Config.BearerToken == "" {
|
||||
config, err := rest.InClusterConfig()
|
||||
if err != nil {
|
||||
panic("Unable to create in-cluster config")
|
||||
}
|
||||
return config
|
||||
}
|
||||
tlsClientConfig := rest.TLSClientConfig{
|
||||
Insecure: c.Config.TLSClientConfig.Insecure,
|
||||
ServerName: c.Config.TLSClientConfig.ServerName,
|
||||
CertData: c.Config.TLSClientConfig.CertData,
|
||||
KeyData: c.Config.TLSClientConfig.KeyData,
|
||||
CAData: c.Config.TLSClientConfig.CAData,
|
||||
}
|
||||
if c.Config.AWSAuthConfig != nil {
|
||||
args := []string{"token", "-i", c.Config.AWSAuthConfig.ClusterName}
|
||||
if c.Config.AWSAuthConfig.RoleARN != "" {
|
||||
args = append(args, "-r", c.Config.AWSAuthConfig.RoleARN)
|
||||
}
|
||||
return &rest.Config{
|
||||
Host: c.Server,
|
||||
TLSClientConfig: tlsClientConfig,
|
||||
ExecProvider: &api.ExecConfig{
|
||||
APIVersion: "client.authentication.k8s.io/v1alpha1",
|
||||
Command: "aws-iam-authenticator",
|
||||
Args: args,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return &rest.Config{
|
||||
Host: c.Server,
|
||||
Username: c.Config.Username,
|
||||
Password: c.Config.Password,
|
||||
BearerToken: c.Config.BearerToken,
|
||||
TLSClientConfig: tlsClientConfig,
|
||||
Host: c.Server,
|
||||
Username: c.Config.Username,
|
||||
Password: c.Config.Password,
|
||||
BearerToken: c.Config.BearerToken,
|
||||
TLSClientConfig: rest.TLSClientConfig{
|
||||
Insecure: c.Config.TLSClientConfig.Insecure,
|
||||
ServerName: c.Config.TLSClientConfig.ServerName,
|
||||
CertData: c.Config.TLSClientConfig.CertData,
|
||||
KeyData: c.Config.TLSClientConfig.KeyData,
|
||||
CAData: c.Config.TLSClientConfig.CAData,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,22 +9,6 @@ import (
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *AWSAuthConfig) DeepCopyInto(out *AWSAuthConfig) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AWSAuthConfig.
|
||||
func (in *AWSAuthConfig) DeepCopy() *AWSAuthConfig {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(AWSAuthConfig)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *AppProject) DeepCopyInto(out *AppProject) {
|
||||
*out = *in
|
||||
@@ -98,23 +82,6 @@ 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])
|
||||
}
|
||||
}
|
||||
if in.ClusterResourceWhitelist != nil {
|
||||
in, out := &in.ClusterResourceWhitelist, &out.ClusterResourceWhitelist
|
||||
*out = make([]v1.GroupKind, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.NamespaceResourceBlacklist != nil {
|
||||
in, out := &in.NamespaceResourceBlacklist, &out.NamespaceResourceBlacklist
|
||||
*out = make([]v1.GroupKind, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -261,15 +228,6 @@ func (in *ApplicationSpec) DeepCopyInto(out *ApplicationSpec) {
|
||||
*out = *in
|
||||
in.Source.DeepCopyInto(&out.Source)
|
||||
out.Destination = in.Destination
|
||||
if in.SyncPolicy != nil {
|
||||
in, out := &in.SyncPolicy, &out.SyncPolicy
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(SyncPolicy)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -366,15 +324,6 @@ func (in *Cluster) DeepCopy() *Cluster {
|
||||
func (in *ClusterConfig) DeepCopyInto(out *ClusterConfig) {
|
||||
*out = *in
|
||||
in.TLSClientConfig.DeepCopyInto(&out.TLSClientConfig)
|
||||
if in.AWSAuthConfig != nil {
|
||||
in, out := &in.AWSAuthConfig, &out.AWSAuthConfig
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(AWSAuthConfig)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -481,6 +430,11 @@ func (in *ConnectionState) DeepCopy() *ConnectionState {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *DeploymentInfo) DeepCopyInto(out *DeploymentInfo) {
|
||||
*out = *in
|
||||
if in.Params != nil {
|
||||
in, out := &in.Params, &out.Params
|
||||
*out = make([]ComponentParameter, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.ComponentParameterOverrides != nil {
|
||||
in, out := &in.ComponentParameterOverrides, &out.ComponentParameterOverrides
|
||||
*out = make([]ComponentParameter, len(*in))
|
||||
@@ -532,22 +486,6 @@ 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
|
||||
@@ -560,6 +498,15 @@ func (in *Operation) DeepCopyInto(out *Operation) {
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
if in.Rollback != nil {
|
||||
in, out := &in.Rollback, &out.Rollback
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(RollbackOperation)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -586,6 +533,15 @@ func (in *OperationState) DeepCopyInto(out *OperationState) {
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
if in.RollbackResult != nil {
|
||||
in, out := &in.RollbackResult, &out.RollbackResult
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(SyncOperationResult)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
in.StartedAt.DeepCopyInto(&out.StartedAt)
|
||||
if in.FinishedAt != nil {
|
||||
in, out := &in.FinishedAt, &out.FinishedAt
|
||||
@@ -609,32 +565,6 @@ 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
|
||||
@@ -739,6 +669,22 @@ func (in *ResourceState) DeepCopy() *ResourceState {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *RollbackOperation) DeepCopyInto(out *RollbackOperation) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RollbackOperation.
|
||||
func (in *RollbackOperation) DeepCopy() *RollbackOperation {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(RollbackOperation)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *SyncOperation) DeepCopyInto(out *SyncOperation) {
|
||||
*out = *in
|
||||
@@ -751,16 +697,6 @@ func (in *SyncOperation) DeepCopyInto(out *SyncOperation) {
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
if in.ParameterOverrides != nil {
|
||||
in, out := &in.ParameterOverrides, &out.ParameterOverrides
|
||||
*out = make(ParameterOverrides, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.Resources != nil {
|
||||
in, out := &in.Resources, &out.Resources
|
||||
*out = make([]SyncOperationResource, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -774,22 +710,6 @@ func (in *SyncOperation) DeepCopy() *SyncOperation {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *SyncOperationResource) DeepCopyInto(out *SyncOperationResource) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SyncOperationResource.
|
||||
func (in *SyncOperationResource) DeepCopy() *SyncOperationResource {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(SyncOperationResource)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *SyncOperationResult) DeepCopyInto(out *SyncOperationResult) {
|
||||
*out = *in
|
||||
@@ -830,47 +750,6 @@ func (in *SyncOperationResult) DeepCopy() *SyncOperationResult {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *SyncPolicy) DeepCopyInto(out *SyncPolicy) {
|
||||
*out = *in
|
||||
if in.Automated != nil {
|
||||
in, out := &in.Automated, &out.Automated
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(SyncPolicyAutomated)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SyncPolicy.
|
||||
func (in *SyncPolicy) DeepCopy() *SyncPolicy {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(SyncPolicy)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *SyncPolicyAutomated) DeepCopyInto(out *SyncPolicyAutomated) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SyncPolicyAutomated.
|
||||
func (in *SyncPolicyAutomated) DeepCopy() *SyncPolicyAutomated {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(SyncPolicyAutomated)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *SyncStrategy) DeepCopyInto(out *SyncStrategy) {
|
||||
*out = *in
|
||||
|
||||
@@ -2,6 +2,7 @@ package versioned
|
||||
|
||||
import (
|
||||
argoprojv1alpha1 "github.com/argoproj/argo-cd/pkg/client/clientset/versioned/typed/application/v1alpha1"
|
||||
glog "github.com/golang/glog"
|
||||
discovery "k8s.io/client-go/discovery"
|
||||
rest "k8s.io/client-go/rest"
|
||||
flowcontrol "k8s.io/client-go/util/flowcontrol"
|
||||
@@ -55,6 +56,7 @@ func NewForConfig(c *rest.Config) (*Clientset, error) {
|
||||
|
||||
cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfig(&configShallowCopy)
|
||||
if err != nil {
|
||||
glog.Errorf("failed to create the DiscoveryClient: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
return &cs, nil
|
||||
|
||||
@@ -23,10 +23,9 @@ func NewSimpleClientset(objects ...runtime.Object) *Clientset {
|
||||
}
|
||||
}
|
||||
|
||||
cs := &Clientset{}
|
||||
cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake}
|
||||
cs.AddReactor("*", "*", testing.ObjectReaction(o))
|
||||
cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) {
|
||||
fakePtr := testing.Fake{}
|
||||
fakePtr.AddReactor("*", "*", testing.ObjectReaction(o))
|
||||
fakePtr.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) {
|
||||
gvr := action.GetResource()
|
||||
ns := action.GetNamespace()
|
||||
watch, err := o.Watch(gvr, ns)
|
||||
@@ -36,7 +35,7 @@ func NewSimpleClientset(objects ...runtime.Object) *Clientset {
|
||||
return true, watch, nil
|
||||
})
|
||||
|
||||
return cs
|
||||
return &Clientset{fakePtr, &fakediscovery.FakeDiscovery{Fake: &fakePtr}}
|
||||
}
|
||||
|
||||
// Clientset implements clientset.Interface. Meant to be embedded into a
|
||||
|
||||
@@ -6,14 +6,15 @@ import (
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
serializer "k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
util_runtime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
)
|
||||
|
||||
var scheme = runtime.NewScheme()
|
||||
var codecs = serializer.NewCodecFactory(scheme)
|
||||
var parameterCodec = runtime.NewParameterCodec(scheme)
|
||||
var localSchemeBuilder = runtime.SchemeBuilder{
|
||||
argoprojv1alpha1.AddToScheme,
|
||||
|
||||
func init() {
|
||||
v1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"})
|
||||
AddToScheme(scheme)
|
||||
}
|
||||
|
||||
// AddToScheme adds all types of this clientset into the given scheme. This allows composition
|
||||
@@ -26,13 +27,10 @@ var localSchemeBuilder = runtime.SchemeBuilder{
|
||||
// )
|
||||
//
|
||||
// kclientset, _ := kubernetes.NewForConfig(c)
|
||||
// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme)
|
||||
// aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme)
|
||||
//
|
||||
// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types
|
||||
// correctly.
|
||||
var AddToScheme = localSchemeBuilder.AddToScheme
|
||||
|
||||
func init() {
|
||||
v1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"})
|
||||
util_runtime.Must(AddToScheme(scheme))
|
||||
func AddToScheme(scheme *runtime.Scheme) {
|
||||
argoprojv1alpha1.AddToScheme(scheme)
|
||||
}
|
||||
|
||||
@@ -6,14 +6,15 @@ import (
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
schema "k8s.io/apimachinery/pkg/runtime/schema"
|
||||
serializer "k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
util_runtime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
)
|
||||
|
||||
var Scheme = runtime.NewScheme()
|
||||
var Codecs = serializer.NewCodecFactory(Scheme)
|
||||
var ParameterCodec = runtime.NewParameterCodec(Scheme)
|
||||
var localSchemeBuilder = runtime.SchemeBuilder{
|
||||
argoprojv1alpha1.AddToScheme,
|
||||
|
||||
func init() {
|
||||
v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"})
|
||||
AddToScheme(Scheme)
|
||||
}
|
||||
|
||||
// AddToScheme adds all types of this clientset into the given scheme. This allows composition
|
||||
@@ -26,13 +27,10 @@ var localSchemeBuilder = runtime.SchemeBuilder{
|
||||
// )
|
||||
//
|
||||
// kclientset, _ := kubernetes.NewForConfig(c)
|
||||
// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme)
|
||||
// aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme)
|
||||
//
|
||||
// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types
|
||||
// correctly.
|
||||
var AddToScheme = localSchemeBuilder.AddToScheme
|
||||
|
||||
func init() {
|
||||
v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"})
|
||||
util_runtime.Must(AddToScheme(Scheme))
|
||||
func AddToScheme(scheme *runtime.Scheme) {
|
||||
argoprojv1alpha1.AddToScheme(scheme)
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ func (c *FakeApplications) List(opts v1.ListOptions) (result *v1alpha1.Applicati
|
||||
if label == nil {
|
||||
label = labels.Everything()
|
||||
}
|
||||
list := &v1alpha1.ApplicationList{ListMeta: obj.(*v1alpha1.ApplicationList).ListMeta}
|
||||
list := &v1alpha1.ApplicationList{}
|
||||
for _, item := range obj.(*v1alpha1.ApplicationList).Items {
|
||||
if label.Matches(labels.Set(item.Labels)) {
|
||||
list.Items = append(list.Items, item)
|
||||
|
||||
@@ -44,7 +44,7 @@ func (c *FakeAppProjects) List(opts v1.ListOptions) (result *v1alpha1.AppProject
|
||||
if label == nil {
|
||||
label = labels.Everything()
|
||||
}
|
||||
list := &v1alpha1.AppProjectList{ListMeta: obj.(*v1alpha1.AppProjectList).ListMeta}
|
||||
list := &v1alpha1.AppProjectList{}
|
||||
for _, item := range obj.(*v1alpha1.AppProjectList).Items {
|
||||
if label.Matches(labels.Set(item.Labels)) {
|
||||
list.Items = append(list.Items, item)
|
||||
|
||||
@@ -14,16 +14,12 @@ import (
|
||||
cache "k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
// SharedInformerOption defines the functional option type for SharedInformerFactory.
|
||||
type SharedInformerOption func(*sharedInformerFactory) *sharedInformerFactory
|
||||
|
||||
type sharedInformerFactory struct {
|
||||
client versioned.Interface
|
||||
namespace string
|
||||
tweakListOptions internalinterfaces.TweakListOptionsFunc
|
||||
lock sync.Mutex
|
||||
defaultResync time.Duration
|
||||
customResync map[reflect.Type]time.Duration
|
||||
|
||||
informers map[reflect.Type]cache.SharedIndexInformer
|
||||
// startedInformers is used for tracking which informers have been started.
|
||||
@@ -31,62 +27,23 @@ type sharedInformerFactory struct {
|
||||
startedInformers map[reflect.Type]bool
|
||||
}
|
||||
|
||||
// WithCustomResyncConfig sets a custom resync period for the specified informer types.
|
||||
func WithCustomResyncConfig(resyncConfig map[v1.Object]time.Duration) SharedInformerOption {
|
||||
return func(factory *sharedInformerFactory) *sharedInformerFactory {
|
||||
for k, v := range resyncConfig {
|
||||
factory.customResync[reflect.TypeOf(k)] = v
|
||||
}
|
||||
return factory
|
||||
}
|
||||
}
|
||||
|
||||
// WithTweakListOptions sets a custom filter on all listers of the configured SharedInformerFactory.
|
||||
func WithTweakListOptions(tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerOption {
|
||||
return func(factory *sharedInformerFactory) *sharedInformerFactory {
|
||||
factory.tweakListOptions = tweakListOptions
|
||||
return factory
|
||||
}
|
||||
}
|
||||
|
||||
// WithNamespace limits the SharedInformerFactory to the specified namespace.
|
||||
func WithNamespace(namespace string) SharedInformerOption {
|
||||
return func(factory *sharedInformerFactory) *sharedInformerFactory {
|
||||
factory.namespace = namespace
|
||||
return factory
|
||||
}
|
||||
}
|
||||
|
||||
// NewSharedInformerFactory constructs a new instance of sharedInformerFactory for all namespaces.
|
||||
// NewSharedInformerFactory constructs a new instance of sharedInformerFactory
|
||||
func NewSharedInformerFactory(client versioned.Interface, defaultResync time.Duration) SharedInformerFactory {
|
||||
return NewSharedInformerFactoryWithOptions(client, defaultResync)
|
||||
return NewFilteredSharedInformerFactory(client, defaultResync, v1.NamespaceAll, nil)
|
||||
}
|
||||
|
||||
// NewFilteredSharedInformerFactory constructs a new instance of sharedInformerFactory.
|
||||
// Listers obtained via this SharedInformerFactory will be subject to the same filters
|
||||
// as specified here.
|
||||
// Deprecated: Please use NewSharedInformerFactoryWithOptions instead
|
||||
func NewFilteredSharedInformerFactory(client versioned.Interface, defaultResync time.Duration, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerFactory {
|
||||
return NewSharedInformerFactoryWithOptions(client, defaultResync, WithNamespace(namespace), WithTweakListOptions(tweakListOptions))
|
||||
}
|
||||
|
||||
// NewSharedInformerFactoryWithOptions constructs a new instance of a SharedInformerFactory with additional options.
|
||||
func NewSharedInformerFactoryWithOptions(client versioned.Interface, defaultResync time.Duration, options ...SharedInformerOption) SharedInformerFactory {
|
||||
factory := &sharedInformerFactory{
|
||||
return &sharedInformerFactory{
|
||||
client: client,
|
||||
namespace: v1.NamespaceAll,
|
||||
namespace: namespace,
|
||||
tweakListOptions: tweakListOptions,
|
||||
defaultResync: defaultResync,
|
||||
informers: make(map[reflect.Type]cache.SharedIndexInformer),
|
||||
startedInformers: make(map[reflect.Type]bool),
|
||||
customResync: make(map[reflect.Type]time.Duration),
|
||||
}
|
||||
|
||||
// Apply all options
|
||||
for _, opt := range options {
|
||||
factory = opt(factory)
|
||||
}
|
||||
|
||||
return factory
|
||||
}
|
||||
|
||||
// Start initializes all requested informers.
|
||||
@@ -135,13 +92,7 @@ func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internal
|
||||
if exists {
|
||||
return informer
|
||||
}
|
||||
|
||||
resyncPeriod, exists := f.customResync[informerType]
|
||||
if !exists {
|
||||
resyncPeriod = f.defaultResync
|
||||
}
|
||||
|
||||
informer = newFunc(f.client, resyncPeriod)
|
||||
informer = newFunc(f.client, f.defaultResync)
|
||||
f.informers[informerType] = informer
|
||||
|
||||
return informer
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
package reposerver
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
|
||||
"github.com/argoproj/argo-cd/reposerver/repository"
|
||||
"github.com/argoproj/argo-cd/util"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials"
|
||||
)
|
||||
|
||||
// Clientset represets repository server api clients
|
||||
@@ -20,7 +17,7 @@ type clientSet struct {
|
||||
}
|
||||
|
||||
func (c *clientSet) NewRepositoryClient() (util.Closer, repository.RepositoryServiceClient, error) {
|
||||
conn, err := grpc.Dial(c.address, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{InsecureSkipVerify: true})))
|
||||
conn, err := grpc.Dial(c.address, grpc.WithInsecure())
|
||||
if err != nil {
|
||||
log.Errorf("Unable to connect to repository service with address %s", c.address)
|
||||
return nil, nil, err
|
||||
|
||||
@@ -11,12 +11,9 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/go-jsonnet"
|
||||
"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"
|
||||
@@ -24,9 +21,8 @@ import (
|
||||
"github.com/argoproj/argo-cd/util/cache"
|
||||
"github.com/argoproj/argo-cd/util/git"
|
||||
"github.com/argoproj/argo-cd/util/helm"
|
||||
"github.com/argoproj/argo-cd/util/ksonnet"
|
||||
ksutil "github.com/argoproj/argo-cd/util/ksonnet"
|
||||
"github.com/argoproj/argo-cd/util/kube"
|
||||
"github.com/argoproj/argo-cd/util/kustomize"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -39,7 +35,6 @@ type AppSourceType string
|
||||
const (
|
||||
AppSourceKsonnet AppSourceType = "ksonnet"
|
||||
AppSourceHelm AppSourceType = "helm"
|
||||
AppSourceKustomize AppSourceType = "kustomize"
|
||||
AppSourceDirectory AppSourceType = "directory"
|
||||
)
|
||||
|
||||
@@ -61,7 +56,17 @@ func NewService(gitFactory git.ClientFactory, cache cache.Cache) *Service {
|
||||
|
||||
// ListDir lists the contents of a GitHub repo
|
||||
func (s *Service) ListDir(ctx context.Context, q *ListDirRequest) (*FileList, error) {
|
||||
gitClient, commitSHA, err := s.newClientResolveRevision(q.Repo, q.Revision)
|
||||
appRepoPath := tempRepoPath(q.Repo.Repo)
|
||||
s.repoLock.Lock(appRepoPath)
|
||||
defer s.repoLock.Unlock(appRepoPath)
|
||||
|
||||
gitClient := s.gitFactory.NewClient(q.Repo.Repo, appRepoPath, q.Repo.Username, q.Repo.Password, q.Repo.SSHPrivateKey)
|
||||
err := gitClient.Init()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
commitSHA, err := gitClient.LsRemote(q.Revision)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -73,9 +78,7 @@ func (s *Service) ListDir(ctx context.Context, q *ListDirRequest) (*FileList, er
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
s.repoLock.Lock(gitClient.Root())
|
||||
defer s.repoLock.Unlock(gitClient.Root())
|
||||
commitSHA, err = checkoutRevision(gitClient, commitSHA)
|
||||
err = checkoutRevision(gitClient, q.Revision)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -89,7 +92,7 @@ func (s *Service) ListDir(ctx context.Context, q *ListDirRequest) (*FileList, er
|
||||
Items: lsFiles,
|
||||
}
|
||||
err = s.cache.Set(&cache.Item{
|
||||
Key: listDirCacheKey(commitSHA, q),
|
||||
Key: cacheKey,
|
||||
Object: &res,
|
||||
Expiration: DefaultRepoCacheExpiration,
|
||||
})
|
||||
@@ -100,21 +103,16 @@ func (s *Service) ListDir(ctx context.Context, q *ListDirRequest) (*FileList, er
|
||||
}
|
||||
|
||||
func (s *Service) GetFile(ctx context.Context, q *GetFileRequest) (*GetFileResponse, error) {
|
||||
gitClient, commitSHA, err := s.newClientResolveRevision(q.Repo, q.Revision)
|
||||
appRepoPath := tempRepoPath(q.Repo.Repo)
|
||||
s.repoLock.Lock(appRepoPath)
|
||||
defer s.repoLock.Unlock(appRepoPath)
|
||||
|
||||
gitClient := s.gitFactory.NewClient(q.Repo.Repo, appRepoPath, q.Repo.Username, q.Repo.Password, q.Repo.SSHPrivateKey)
|
||||
err := gitClient.Init()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cacheKey := getFileCacheKey(commitSHA, q)
|
||||
var res GetFileResponse
|
||||
err = s.cache.Get(cacheKey, &res)
|
||||
if err == nil {
|
||||
log.Infof("getfile cache hit: %s", cacheKey)
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
s.repoLock.Lock(gitClient.Root())
|
||||
defer s.repoLock.Unlock(gitClient.Root())
|
||||
commitSHA, err = checkoutRevision(gitClient, commitSHA)
|
||||
err = checkoutRevision(gitClient, q.Revision)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -122,27 +120,36 @@ func (s *Service) GetFile(ctx context.Context, q *GetFileRequest) (*GetFileRespo
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res = GetFileResponse{
|
||||
res := GetFileResponse{
|
||||
Data: data,
|
||||
}
|
||||
err = s.cache.Set(&cache.Item{
|
||||
Key: getFileCacheKey(commitSHA, q),
|
||||
Object: &res,
|
||||
Expiration: DefaultRepoCacheExpiration,
|
||||
})
|
||||
if err != nil {
|
||||
log.Warnf("getfile cache set error %s: %v", cacheKey, err)
|
||||
}
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
func (s *Service) GenerateManifest(c context.Context, q *ManifestRequest) (*ManifestResponse, error) {
|
||||
gitClient, commitSHA, err := s.newClientResolveRevision(q.Repo, q.Revision)
|
||||
var res ManifestResponse
|
||||
if git.IsCommitSHA(q.Revision) {
|
||||
cacheKey := manifestCacheKey(q.Revision, q)
|
||||
err := s.cache.Get(cacheKey, res)
|
||||
if err == nil {
|
||||
log.Infof("manifest cache hit: %s", cacheKey)
|
||||
return &res, nil
|
||||
}
|
||||
}
|
||||
appRepoPath := tempRepoPath(q.Repo.Repo)
|
||||
s.repoLock.Lock(appRepoPath)
|
||||
defer s.repoLock.Unlock(appRepoPath)
|
||||
|
||||
gitClient := s.gitFactory.NewClient(q.Repo.Repo, appRepoPath, q.Repo.Username, q.Repo.Password, q.Repo.SSHPrivateKey)
|
||||
err := gitClient.Init()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
commitSHA, err := gitClient.LsRemote(q.Revision)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cacheKey := manifestCacheKey(commitSHA, q)
|
||||
var res ManifestResponse
|
||||
err = s.cache.Get(cacheKey, &res)
|
||||
if err == nil {
|
||||
log.Infof("manifest cache hit: %s", cacheKey)
|
||||
@@ -154,13 +161,11 @@ func (s *Service) GenerateManifest(c context.Context, q *ManifestRequest) (*Mani
|
||||
log.Infof("manifest cache miss: %s", cacheKey)
|
||||
}
|
||||
|
||||
s.repoLock.Lock(gitClient.Root())
|
||||
defer s.repoLock.Unlock(gitClient.Root())
|
||||
commitSHA, err = checkoutRevision(gitClient, commitSHA)
|
||||
err = checkoutRevision(gitClient, q.Revision)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
appPath := path.Join(gitClient.Root(), q.Path)
|
||||
appPath := path.Join(appRepoPath, q.Path)
|
||||
|
||||
genRes, err := generateManifests(appPath, q)
|
||||
if err != nil {
|
||||
@@ -169,7 +174,7 @@ func (s *Service) GenerateManifest(c context.Context, q *ManifestRequest) (*Mani
|
||||
res = *genRes
|
||||
res.Revision = commitSHA
|
||||
err = s.cache.Set(&cache.Item{
|
||||
Key: manifestCacheKey(commitSHA, q),
|
||||
Key: cacheKey,
|
||||
Object: res,
|
||||
Expiration: DefaultRepoCacheExpiration,
|
||||
})
|
||||
@@ -183,20 +188,16 @@ func (s *Service) GenerateManifest(c context.Context, q *ManifestRequest) (*Mani
|
||||
func generateManifests(appPath string, q *ManifestRequest) (*ManifestResponse, error) {
|
||||
var targetObjs []*unstructured.Unstructured
|
||||
var params []*v1alpha1.ComponentParameter
|
||||
var dest *v1alpha1.ApplicationDestination
|
||||
var env *app.EnvironmentSpec
|
||||
var err error
|
||||
|
||||
appSourceType := IdentifyAppSourceTypeByAppDir(appPath)
|
||||
switch appSourceType {
|
||||
case AppSourceKsonnet:
|
||||
targetObjs, params, dest, err = ksShow(appPath, q.Environment, q.ComponentParameterOverrides)
|
||||
targetObjs, params, env, err = ksShow(appPath, q.Environment, q.ComponentParameterOverrides)
|
||||
case AppSourceHelm:
|
||||
h := helm.NewHelmApp(appPath)
|
||||
err = h.DependencyBuild()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
targetObjs, err = h.Template(q.AppLabel, q.Namespace, q.ValueFiles, q.ComponentParameterOverrides)
|
||||
targetObjs, err = h.Template(q.AppLabel, q.ValueFiles, q.ComponentParameterOverrides)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -204,58 +205,36 @@ 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, 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")
|
||||
}
|
||||
})
|
||||
manifests := make([]string, len(targetObjs))
|
||||
for i, target := range targetObjs {
|
||||
if q.AppLabel != "" {
|
||||
err = kube.SetLabel(target, common.LabelApplicationName, q.AppLabel)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
targets = []*unstructured.Unstructured{obj}
|
||||
}
|
||||
|
||||
for _, target := range targets {
|
||||
if q.AppLabel != "" && !kube.IsCRD(target) {
|
||||
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))
|
||||
manifestStr, err := json.Marshal(target.Object)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
manifests[i] = string(manifestStr)
|
||||
}
|
||||
|
||||
res := ManifestResponse{
|
||||
Manifests: manifests,
|
||||
Params: params,
|
||||
}
|
||||
if dest != nil {
|
||||
res.Namespace = dest.Namespace
|
||||
res.Server = dest.Server
|
||||
if env != nil {
|
||||
res.Namespace = env.Destination.Namespace
|
||||
res.Server = env.Destination.Server
|
||||
}
|
||||
return &res, nil
|
||||
}
|
||||
@@ -273,9 +252,6 @@ 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
|
||||
}
|
||||
|
||||
@@ -287,53 +263,45 @@ 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
|
||||
// Returns the 40 character commit SHA after the checkout has been performed
|
||||
func checkoutRevision(gitClient git.Client, commitSHA string) (string, error) {
|
||||
err := gitClient.Init()
|
||||
func checkoutRevision(gitClient git.Client, revision string) error {
|
||||
err := gitClient.Fetch()
|
||||
if err != nil {
|
||||
return "", status.Errorf(codes.Internal, "Failed to initialize git repo: %v", err)
|
||||
return err
|
||||
}
|
||||
err = gitClient.Fetch()
|
||||
err = gitClient.Reset()
|
||||
if err != nil {
|
||||
return "", status.Errorf(codes.Internal, "Failed to fetch git repo: %v", err)
|
||||
log.Warn(err)
|
||||
}
|
||||
err = gitClient.Checkout(commitSHA)
|
||||
err = gitClient.Checkout(revision)
|
||||
if err != nil {
|
||||
return "", status.Errorf(codes.Internal, "Failed to checkout %s: %v", commitSHA, err)
|
||||
return err
|
||||
}
|
||||
return gitClient.CommitSHA()
|
||||
return nil
|
||||
}
|
||||
|
||||
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|%s", q.AppLabel, q.Path, q.Environment, commitSHA, string(pStr), valuesFiles, q.Namespace)
|
||||
return fmt.Sprintf("mfst|%s|%s|%s|%s|%s|%s", q.AppLabel, q.Path, q.Environment, commitSHA, string(pStr), valuesFiles)
|
||||
}
|
||||
|
||||
func listDirCacheKey(commitSHA string, q *ListDirRequest) string {
|
||||
return fmt.Sprintf("ldir|%s|%s", q.Path, commitSHA)
|
||||
}
|
||||
|
||||
func getFileCacheKey(commitSHA string, q *GetFileRequest) string {
|
||||
return fmt.Sprintf("gfile|%s|%s", q.Path, commitSHA)
|
||||
}
|
||||
|
||||
// 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, *v1alpha1.ApplicationDestination, error) {
|
||||
ksApp, err := ksonnet.NewKsonnetApp(appPath)
|
||||
func ksShow(appPath, envName string, overrides []*v1alpha1.ComponentParameter) ([]*unstructured.Unstructured, []*v1alpha1.ComponentParameter, *app.EnvironmentSpec, error) {
|
||||
ksApp, err := ksutil.NewKsonnetApp(appPath)
|
||||
if err != nil {
|
||||
return nil, nil, nil, status.Errorf(codes.FailedPrecondition, "unable to load application from %s: %v", appPath, err)
|
||||
return nil, nil, nil, fmt.Errorf("unable to load application from %s: %v", appPath, err)
|
||||
}
|
||||
params, err := ksApp.ListEnvParams(envName)
|
||||
if err != nil {
|
||||
return nil, nil, nil, status.Errorf(codes.InvalidArgument, "Failed to list ksonnet app params: %v", err)
|
||||
return nil, nil, nil, fmt.Errorf("Failed to list ksonnet app params: %v", err)
|
||||
}
|
||||
if overrides != nil {
|
||||
for _, override := range overrides {
|
||||
@@ -343,24 +311,25 @@ func ksShow(appPath, envName string, overrides []*v1alpha1.ComponentParameter) (
|
||||
}
|
||||
}
|
||||
}
|
||||
dest, err := ksApp.Destination(envName)
|
||||
appSpec := ksApp.App()
|
||||
env, err := appSpec.Environment(envName)
|
||||
if err != nil {
|
||||
return nil, nil, nil, status.Errorf(codes.NotFound, "environment %q does not exist in ksonnet app", envName)
|
||||
return nil, nil, nil, fmt.Errorf("environment '%s' does not exist in ksonnet app", envName)
|
||||
}
|
||||
targetObjs, err := ksApp.Show(envName)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
return targetObjs, params, dest, nil
|
||||
return targetObjs, params, env, nil
|
||||
}
|
||||
|
||||
var manifestFile = regexp.MustCompile(`^.*\.(yaml|yml|json|jsonnet)$`)
|
||||
var manifestFile = regexp.MustCompile(`^.*\.(yaml|yml|json)$`)
|
||||
|
||||
// findManifests looks at all yaml files in a directory and unmarshals them into a list of unstructured objects
|
||||
func findManifests(appPath string) ([]*unstructured.Unstructured, error) {
|
||||
files, err := ioutil.ReadDir(appPath)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.FailedPrecondition, "Failed to read dir %s: %v", appPath, err)
|
||||
return nil, fmt.Errorf("Failed to read dir %s: %v", appPath, err)
|
||||
}
|
||||
var objs []*unstructured.Unstructured
|
||||
for _, f := range files {
|
||||
@@ -375,32 +344,9 @@ func findManifests(appPath string) ([]*unstructured.Unstructured, error) {
|
||||
var obj unstructured.Unstructured
|
||||
err = json.Unmarshal(out, &obj)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.FailedPrecondition, "Failed to unmarshal %q: %v", f.Name(), err)
|
||||
return nil, fmt.Errorf("Failed to unmarshal '%s': %v", f.Name(), err)
|
||||
}
|
||||
objs = append(objs, &obj)
|
||||
} else if strings.HasSuffix(f.Name(), ".jsonnet") {
|
||||
vm := jsonnet.MakeVM()
|
||||
vm.Importer(&jsonnet.FileImporter{
|
||||
JPaths: []string{appPath},
|
||||
})
|
||||
jsonStr, err := vm.EvaluateSnippet(f.Name(), string(out))
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.FailedPrecondition, "Failed to evaluate jsonnet %q: %v", f.Name(), err)
|
||||
}
|
||||
|
||||
// attempt to unmarshal either array or single object
|
||||
var jsonObjs []*unstructured.Unstructured
|
||||
err = json.Unmarshal([]byte(jsonStr), &jsonObjs)
|
||||
if err == nil {
|
||||
objs = append(objs, jsonObjs...)
|
||||
} else {
|
||||
var jsonObj unstructured.Unstructured
|
||||
err = json.Unmarshal([]byte(jsonStr), &jsonObj)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.FailedPrecondition, "Failed to unmarshal generated json %q: %v", f.Name(), err)
|
||||
}
|
||||
objs = append(objs, &jsonObj)
|
||||
}
|
||||
} else {
|
||||
yamlObjs, err := kube.SplitYAML(string(out))
|
||||
if err != nil {
|
||||
@@ -408,7 +354,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, status.Errorf(codes.FailedPrecondition, "Failed to unmarshal %q: %v", f.Name(), err)
|
||||
return nil, fmt.Errorf("Failed to unmarshal '%s': %v", f.Name(), err)
|
||||
}
|
||||
// Otherwise, it might be a unrelated YAML file which we will ignore
|
||||
continue
|
||||
@@ -428,18 +374,3 @@ func pathExists(name string) bool {
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// newClientResolveRevision is a helper to perform the common task of instantiating a git client
|
||||
// and resolving a revision to a commit SHA
|
||||
func (s *Service) newClientResolveRevision(repo *v1alpha1.Repository, revision string) (git.Client, string, error) {
|
||||
appRepoPath := tempRepoPath(repo.Repo)
|
||||
gitClient, err := s.gitFactory.NewClient(repo.Repo, appRepoPath, repo.Username, repo.Password, repo.SSHPrivateKey)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
commitSHA, err := gitClient.LsRemote(revision)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
return gitClient, commitSHA, nil
|
||||
}
|
||||
|
||||
@@ -1,15 +1,29 @@
|
||||
// Code generated by protoc-gen-gogo. DO NOT EDIT.
|
||||
// source: reposerver/repository/repository.proto
|
||||
|
||||
package repository // import "github.com/argoproj/argo-cd/reposerver/repository"
|
||||
/*
|
||||
Package repository is a generated protocol buffer package.
|
||||
|
||||
It is generated from these files:
|
||||
reposerver/repository/repository.proto
|
||||
|
||||
It has these top-level messages:
|
||||
ManifestRequest
|
||||
ManifestResponse
|
||||
ListDirRequest
|
||||
FileList
|
||||
GetFileRequest
|
||||
GetFileResponse
|
||||
*/
|
||||
package repository
|
||||
|
||||
import proto "github.com/gogo/protobuf/proto"
|
||||
import fmt "fmt"
|
||||
import math "math"
|
||||
import v1alpha1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
|
||||
import _ "github.com/gogo/protobuf/gogoproto"
|
||||
import _ "google.golang.org/genproto/googleapis/api/annotations"
|
||||
import _ "k8s.io/api/core/v1"
|
||||
import github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
|
||||
|
||||
import context "golang.org/x/net/context"
|
||||
import grpc "google.golang.org/grpc"
|
||||
@@ -29,53 +43,21 @@ const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package
|
||||
|
||||
// ManifestRequest is a query for manifest generation.
|
||||
type ManifestRequest struct {
|
||||
Repo *v1alpha1.Repository `protobuf:"bytes,1,opt,name=repo" json:"repo,omitempty"`
|
||||
Revision string `protobuf:"bytes,2,opt,name=revision,proto3" json:"revision,omitempty"`
|
||||
Path string `protobuf:"bytes,3,opt,name=path,proto3" json:"path,omitempty"`
|
||||
Environment string `protobuf:"bytes,4,opt,name=environment,proto3" json:"environment,omitempty"`
|
||||
AppLabel string `protobuf:"bytes,5,opt,name=appLabel,proto3" json:"appLabel,omitempty"`
|
||||
ComponentParameterOverrides []*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"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
Repo *github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Repository `protobuf:"bytes,1,opt,name=repo" json:"repo,omitempty"`
|
||||
Revision string `protobuf:"bytes,2,opt,name=revision,proto3" json:"revision,omitempty"`
|
||||
Path string `protobuf:"bytes,3,opt,name=path,proto3" json:"path,omitempty"`
|
||||
Environment string `protobuf:"bytes,4,opt,name=environment,proto3" json:"environment,omitempty"`
|
||||
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"`
|
||||
}
|
||||
|
||||
func (m *ManifestRequest) Reset() { *m = ManifestRequest{} }
|
||||
func (m *ManifestRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*ManifestRequest) ProtoMessage() {}
|
||||
func (*ManifestRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_repository_49651600e73b0b40, []int{0}
|
||||
}
|
||||
func (m *ManifestRequest) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
}
|
||||
func (m *ManifestRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
if deterministic {
|
||||
return xxx_messageInfo_ManifestRequest.Marshal(b, m, deterministic)
|
||||
} else {
|
||||
b = b[:cap(b)]
|
||||
n, err := m.MarshalTo(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b[:n], nil
|
||||
}
|
||||
}
|
||||
func (dst *ManifestRequest) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_ManifestRequest.Merge(dst, src)
|
||||
}
|
||||
func (m *ManifestRequest) XXX_Size() int {
|
||||
return m.Size()
|
||||
}
|
||||
func (m *ManifestRequest) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_ManifestRequest.DiscardUnknown(m)
|
||||
}
|
||||
func (m *ManifestRequest) Reset() { *m = ManifestRequest{} }
|
||||
func (m *ManifestRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*ManifestRequest) ProtoMessage() {}
|
||||
func (*ManifestRequest) Descriptor() ([]byte, []int) { return fileDescriptorRepository, []int{0} }
|
||||
|
||||
var xxx_messageInfo_ManifestRequest proto.InternalMessageInfo
|
||||
|
||||
func (m *ManifestRequest) GetRepo() *v1alpha1.Repository {
|
||||
func (m *ManifestRequest) GetRepo() *github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Repository {
|
||||
if m != nil {
|
||||
return m.Repo
|
||||
}
|
||||
@@ -110,7 +92,7 @@ func (m *ManifestRequest) GetAppLabel() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *ManifestRequest) GetComponentParameterOverrides() []*v1alpha1.ComponentParameter {
|
||||
func (m *ManifestRequest) GetComponentParameterOverrides() []*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.ComponentParameter {
|
||||
if m != nil {
|
||||
return m.ComponentParameterOverrides
|
||||
}
|
||||
@@ -124,56 +106,18 @@ 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"`
|
||||
Server string `protobuf:"bytes,3,opt,name=server,proto3" json:"server,omitempty"`
|
||||
Revision string `protobuf:"bytes,4,opt,name=revision,proto3" json:"revision,omitempty"`
|
||||
Params []*v1alpha1.ComponentParameter `protobuf:"bytes,5,rep,name=params" json:"params,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
Manifests []string `protobuf:"bytes,1,rep,name=manifests" json:"manifests,omitempty"`
|
||||
Namespace string `protobuf:"bytes,2,opt,name=namespace,proto3" json:"namespace,omitempty"`
|
||||
Server string `protobuf:"bytes,3,opt,name=server,proto3" json:"server,omitempty"`
|
||||
Revision string `protobuf:"bytes,4,opt,name=revision,proto3" json:"revision,omitempty"`
|
||||
Params []*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.ComponentParameter `protobuf:"bytes,5,rep,name=params" json:"params,omitempty"`
|
||||
}
|
||||
|
||||
func (m *ManifestResponse) Reset() { *m = ManifestResponse{} }
|
||||
func (m *ManifestResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*ManifestResponse) ProtoMessage() {}
|
||||
func (*ManifestResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_repository_49651600e73b0b40, []int{1}
|
||||
}
|
||||
func (m *ManifestResponse) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
}
|
||||
func (m *ManifestResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
if deterministic {
|
||||
return xxx_messageInfo_ManifestResponse.Marshal(b, m, deterministic)
|
||||
} else {
|
||||
b = b[:cap(b)]
|
||||
n, err := m.MarshalTo(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b[:n], nil
|
||||
}
|
||||
}
|
||||
func (dst *ManifestResponse) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_ManifestResponse.Merge(dst, src)
|
||||
}
|
||||
func (m *ManifestResponse) XXX_Size() int {
|
||||
return m.Size()
|
||||
}
|
||||
func (m *ManifestResponse) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_ManifestResponse.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_ManifestResponse proto.InternalMessageInfo
|
||||
func (m *ManifestResponse) Reset() { *m = ManifestResponse{} }
|
||||
func (m *ManifestResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*ManifestResponse) ProtoMessage() {}
|
||||
func (*ManifestResponse) Descriptor() ([]byte, []int) { return fileDescriptorRepository, []int{1} }
|
||||
|
||||
func (m *ManifestResponse) GetManifests() []string {
|
||||
if m != nil {
|
||||
@@ -203,7 +147,7 @@ func (m *ManifestResponse) GetRevision() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *ManifestResponse) GetParams() []*v1alpha1.ComponentParameter {
|
||||
func (m *ManifestResponse) GetParams() []*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.ComponentParameter {
|
||||
if m != nil {
|
||||
return m.Params
|
||||
}
|
||||
@@ -212,48 +156,17 @@ func (m *ManifestResponse) GetParams() []*v1alpha1.ComponentParameter {
|
||||
|
||||
// ListDirRequest requests a repository directory structure
|
||||
type ListDirRequest struct {
|
||||
Repo *v1alpha1.Repository `protobuf:"bytes,1,opt,name=repo" json:"repo,omitempty"`
|
||||
Revision string `protobuf:"bytes,2,opt,name=revision,proto3" json:"revision,omitempty"`
|
||||
Path string `protobuf:"bytes,3,opt,name=path,proto3" json:"path,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
Repo *github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Repository `protobuf:"bytes,1,opt,name=repo" json:"repo,omitempty"`
|
||||
Revision string `protobuf:"bytes,2,opt,name=revision,proto3" json:"revision,omitempty"`
|
||||
Path string `protobuf:"bytes,3,opt,name=path,proto3" json:"path,omitempty"`
|
||||
}
|
||||
|
||||
func (m *ListDirRequest) Reset() { *m = ListDirRequest{} }
|
||||
func (m *ListDirRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*ListDirRequest) ProtoMessage() {}
|
||||
func (*ListDirRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_repository_49651600e73b0b40, []int{2}
|
||||
}
|
||||
func (m *ListDirRequest) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
}
|
||||
func (m *ListDirRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
if deterministic {
|
||||
return xxx_messageInfo_ListDirRequest.Marshal(b, m, deterministic)
|
||||
} else {
|
||||
b = b[:cap(b)]
|
||||
n, err := m.MarshalTo(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b[:n], nil
|
||||
}
|
||||
}
|
||||
func (dst *ListDirRequest) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_ListDirRequest.Merge(dst, src)
|
||||
}
|
||||
func (m *ListDirRequest) XXX_Size() int {
|
||||
return m.Size()
|
||||
}
|
||||
func (m *ListDirRequest) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_ListDirRequest.DiscardUnknown(m)
|
||||
}
|
||||
func (m *ListDirRequest) Reset() { *m = ListDirRequest{} }
|
||||
func (m *ListDirRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*ListDirRequest) ProtoMessage() {}
|
||||
func (*ListDirRequest) Descriptor() ([]byte, []int) { return fileDescriptorRepository, []int{2} }
|
||||
|
||||
var xxx_messageInfo_ListDirRequest proto.InternalMessageInfo
|
||||
|
||||
func (m *ListDirRequest) GetRepo() *v1alpha1.Repository {
|
||||
func (m *ListDirRequest) GetRepo() *github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Repository {
|
||||
if m != nil {
|
||||
return m.Repo
|
||||
}
|
||||
@@ -276,44 +189,13 @@ func (m *ListDirRequest) GetPath() string {
|
||||
|
||||
// FileList returns the contents of the repo of a ListDir request
|
||||
type FileList struct {
|
||||
Items []string `protobuf:"bytes,1,rep,name=items" json:"items,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
Items []string `protobuf:"bytes,1,rep,name=items" json:"items,omitempty"`
|
||||
}
|
||||
|
||||
func (m *FileList) Reset() { *m = FileList{} }
|
||||
func (m *FileList) String() string { return proto.CompactTextString(m) }
|
||||
func (*FileList) ProtoMessage() {}
|
||||
func (*FileList) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_repository_49651600e73b0b40, []int{3}
|
||||
}
|
||||
func (m *FileList) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
}
|
||||
func (m *FileList) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
if deterministic {
|
||||
return xxx_messageInfo_FileList.Marshal(b, m, deterministic)
|
||||
} else {
|
||||
b = b[:cap(b)]
|
||||
n, err := m.MarshalTo(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b[:n], nil
|
||||
}
|
||||
}
|
||||
func (dst *FileList) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_FileList.Merge(dst, src)
|
||||
}
|
||||
func (m *FileList) XXX_Size() int {
|
||||
return m.Size()
|
||||
}
|
||||
func (m *FileList) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_FileList.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_FileList proto.InternalMessageInfo
|
||||
func (m *FileList) Reset() { *m = FileList{} }
|
||||
func (m *FileList) String() string { return proto.CompactTextString(m) }
|
||||
func (*FileList) ProtoMessage() {}
|
||||
func (*FileList) Descriptor() ([]byte, []int) { return fileDescriptorRepository, []int{3} }
|
||||
|
||||
func (m *FileList) GetItems() []string {
|
||||
if m != nil {
|
||||
@@ -324,48 +206,17 @@ func (m *FileList) GetItems() []string {
|
||||
|
||||
// GetFileRequest return
|
||||
type GetFileRequest struct {
|
||||
Repo *v1alpha1.Repository `protobuf:"bytes,1,opt,name=repo" json:"repo,omitempty"`
|
||||
Revision string `protobuf:"bytes,2,opt,name=revision,proto3" json:"revision,omitempty"`
|
||||
Path string `protobuf:"bytes,3,opt,name=path,proto3" json:"path,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
Repo *github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Repository `protobuf:"bytes,1,opt,name=repo" json:"repo,omitempty"`
|
||||
Revision string `protobuf:"bytes,2,opt,name=revision,proto3" json:"revision,omitempty"`
|
||||
Path string `protobuf:"bytes,3,opt,name=path,proto3" json:"path,omitempty"`
|
||||
}
|
||||
|
||||
func (m *GetFileRequest) Reset() { *m = GetFileRequest{} }
|
||||
func (m *GetFileRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*GetFileRequest) ProtoMessage() {}
|
||||
func (*GetFileRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_repository_49651600e73b0b40, []int{4}
|
||||
}
|
||||
func (m *GetFileRequest) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
}
|
||||
func (m *GetFileRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
if deterministic {
|
||||
return xxx_messageInfo_GetFileRequest.Marshal(b, m, deterministic)
|
||||
} else {
|
||||
b = b[:cap(b)]
|
||||
n, err := m.MarshalTo(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b[:n], nil
|
||||
}
|
||||
}
|
||||
func (dst *GetFileRequest) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_GetFileRequest.Merge(dst, src)
|
||||
}
|
||||
func (m *GetFileRequest) XXX_Size() int {
|
||||
return m.Size()
|
||||
}
|
||||
func (m *GetFileRequest) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_GetFileRequest.DiscardUnknown(m)
|
||||
}
|
||||
func (m *GetFileRequest) Reset() { *m = GetFileRequest{} }
|
||||
func (m *GetFileRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*GetFileRequest) ProtoMessage() {}
|
||||
func (*GetFileRequest) Descriptor() ([]byte, []int) { return fileDescriptorRepository, []int{4} }
|
||||
|
||||
var xxx_messageInfo_GetFileRequest proto.InternalMessageInfo
|
||||
|
||||
func (m *GetFileRequest) GetRepo() *v1alpha1.Repository {
|
||||
func (m *GetFileRequest) GetRepo() *github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Repository {
|
||||
if m != nil {
|
||||
return m.Repo
|
||||
}
|
||||
@@ -388,44 +239,13 @@ func (m *GetFileRequest) GetPath() string {
|
||||
|
||||
// GetFileResponse returns the contents of the file of a GetFile request
|
||||
type GetFileResponse struct {
|
||||
Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
|
||||
}
|
||||
|
||||
func (m *GetFileResponse) Reset() { *m = GetFileResponse{} }
|
||||
func (m *GetFileResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*GetFileResponse) ProtoMessage() {}
|
||||
func (*GetFileResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_repository_49651600e73b0b40, []int{5}
|
||||
}
|
||||
func (m *GetFileResponse) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
}
|
||||
func (m *GetFileResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
if deterministic {
|
||||
return xxx_messageInfo_GetFileResponse.Marshal(b, m, deterministic)
|
||||
} else {
|
||||
b = b[:cap(b)]
|
||||
n, err := m.MarshalTo(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b[:n], nil
|
||||
}
|
||||
}
|
||||
func (dst *GetFileResponse) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_GetFileResponse.Merge(dst, src)
|
||||
}
|
||||
func (m *GetFileResponse) XXX_Size() int {
|
||||
return m.Size()
|
||||
}
|
||||
func (m *GetFileResponse) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_GetFileResponse.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_GetFileResponse proto.InternalMessageInfo
|
||||
func (m *GetFileResponse) Reset() { *m = GetFileResponse{} }
|
||||
func (m *GetFileResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*GetFileResponse) ProtoMessage() {}
|
||||
func (*GetFileResponse) Descriptor() ([]byte, []int) { return fileDescriptorRepository, []int{5} }
|
||||
|
||||
func (m *GetFileResponse) GetData() []byte {
|
||||
if m != nil {
|
||||
@@ -472,7 +292,7 @@ func NewRepositoryServiceClient(cc *grpc.ClientConn) RepositoryServiceClient {
|
||||
|
||||
func (c *repositoryServiceClient) GenerateManifest(ctx context.Context, in *ManifestRequest, opts ...grpc.CallOption) (*ManifestResponse, error) {
|
||||
out := new(ManifestResponse)
|
||||
err := c.cc.Invoke(ctx, "/repository.RepositoryService/GenerateManifest", in, out, opts...)
|
||||
err := grpc.Invoke(ctx, "/repository.RepositoryService/GenerateManifest", in, out, c.cc, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -481,7 +301,7 @@ func (c *repositoryServiceClient) GenerateManifest(ctx context.Context, in *Mani
|
||||
|
||||
func (c *repositoryServiceClient) ListDir(ctx context.Context, in *ListDirRequest, opts ...grpc.CallOption) (*FileList, error) {
|
||||
out := new(FileList)
|
||||
err := c.cc.Invoke(ctx, "/repository.RepositoryService/ListDir", in, out, opts...)
|
||||
err := grpc.Invoke(ctx, "/repository.RepositoryService/ListDir", in, out, c.cc, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -490,7 +310,7 @@ func (c *repositoryServiceClient) ListDir(ctx context.Context, in *ListDirReques
|
||||
|
||||
func (c *repositoryServiceClient) GetFile(ctx context.Context, in *GetFileRequest, opts ...grpc.CallOption) (*GetFileResponse, error) {
|
||||
out := new(GetFileResponse)
|
||||
err := c.cc.Invoke(ctx, "/repository.RepositoryService/GetFile", in, out, opts...)
|
||||
err := grpc.Invoke(ctx, "/repository.RepositoryService/GetFile", in, out, c.cc, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -663,15 +483,6 @@ 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)
|
||||
}
|
||||
if m.XXX_unrecognized != nil {
|
||||
i += copy(dAtA[i:], m.XXX_unrecognized)
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
|
||||
@@ -735,9 +546,6 @@ func (m *ManifestResponse) MarshalTo(dAtA []byte) (int, error) {
|
||||
i += n
|
||||
}
|
||||
}
|
||||
if m.XXX_unrecognized != nil {
|
||||
i += copy(dAtA[i:], m.XXX_unrecognized)
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
|
||||
@@ -778,9 +586,6 @@ func (m *ListDirRequest) MarshalTo(dAtA []byte) (int, error) {
|
||||
i = encodeVarintRepository(dAtA, i, uint64(len(m.Path)))
|
||||
i += copy(dAtA[i:], m.Path)
|
||||
}
|
||||
if m.XXX_unrecognized != nil {
|
||||
i += copy(dAtA[i:], m.XXX_unrecognized)
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
|
||||
@@ -814,9 +619,6 @@ func (m *FileList) MarshalTo(dAtA []byte) (int, error) {
|
||||
i += copy(dAtA[i:], s)
|
||||
}
|
||||
}
|
||||
if m.XXX_unrecognized != nil {
|
||||
i += copy(dAtA[i:], m.XXX_unrecognized)
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
|
||||
@@ -857,9 +659,6 @@ func (m *GetFileRequest) MarshalTo(dAtA []byte) (int, error) {
|
||||
i = encodeVarintRepository(dAtA, i, uint64(len(m.Path)))
|
||||
i += copy(dAtA[i:], m.Path)
|
||||
}
|
||||
if m.XXX_unrecognized != nil {
|
||||
i += copy(dAtA[i:], m.XXX_unrecognized)
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
|
||||
@@ -884,9 +683,6 @@ func (m *GetFileResponse) MarshalTo(dAtA []byte) (int, error) {
|
||||
i = encodeVarintRepository(dAtA, i, uint64(len(m.Data)))
|
||||
i += copy(dAtA[i:], m.Data)
|
||||
}
|
||||
if m.XXX_unrecognized != nil {
|
||||
i += copy(dAtA[i:], m.XXX_unrecognized)
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
|
||||
@@ -934,13 +730,6 @@ 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))
|
||||
}
|
||||
if m.XXX_unrecognized != nil {
|
||||
n += len(m.XXX_unrecognized)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
@@ -971,9 +760,6 @@ func (m *ManifestResponse) Size() (n int) {
|
||||
n += 1 + l + sovRepository(uint64(l))
|
||||
}
|
||||
}
|
||||
if m.XXX_unrecognized != nil {
|
||||
n += len(m.XXX_unrecognized)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
@@ -992,9 +778,6 @@ func (m *ListDirRequest) Size() (n int) {
|
||||
if l > 0 {
|
||||
n += 1 + l + sovRepository(uint64(l))
|
||||
}
|
||||
if m.XXX_unrecognized != nil {
|
||||
n += len(m.XXX_unrecognized)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
@@ -1007,9 +790,6 @@ func (m *FileList) Size() (n int) {
|
||||
n += 1 + l + sovRepository(uint64(l))
|
||||
}
|
||||
}
|
||||
if m.XXX_unrecognized != nil {
|
||||
n += len(m.XXX_unrecognized)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
@@ -1028,9 +808,6 @@ func (m *GetFileRequest) Size() (n int) {
|
||||
if l > 0 {
|
||||
n += 1 + l + sovRepository(uint64(l))
|
||||
}
|
||||
if m.XXX_unrecognized != nil {
|
||||
n += len(m.XXX_unrecognized)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
@@ -1041,9 +818,6 @@ func (m *GetFileResponse) Size() (n int) {
|
||||
if l > 0 {
|
||||
n += 1 + l + sovRepository(uint64(l))
|
||||
}
|
||||
if m.XXX_unrecognized != nil {
|
||||
n += len(m.XXX_unrecognized)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
@@ -1116,7 +890,7 @@ func (m *ManifestRequest) Unmarshal(dAtA []byte) error {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
if m.Repo == nil {
|
||||
m.Repo = &v1alpha1.Repository{}
|
||||
m.Repo = &github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Repository{}
|
||||
}
|
||||
if err := m.Repo.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
|
||||
return err
|
||||
@@ -1264,7 +1038,7 @@ func (m *ManifestRequest) Unmarshal(dAtA []byte) error {
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.ComponentParameterOverrides = append(m.ComponentParameterOverrides, &v1alpha1.ComponentParameter{})
|
||||
m.ComponentParameterOverrides = append(m.ComponentParameterOverrides, &github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.ComponentParameter{})
|
||||
if err := m.ComponentParameterOverrides[len(m.ComponentParameterOverrides)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1298,35 +1072,6 @@ 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:])
|
||||
@@ -1339,7 +1084,6 @@ func (m *ManifestRequest) Unmarshal(dAtA []byte) error {
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
@@ -1520,7 +1264,7 @@ func (m *ManifestResponse) Unmarshal(dAtA []byte) error {
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Params = append(m.Params, &v1alpha1.ComponentParameter{})
|
||||
m.Params = append(m.Params, &github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.ComponentParameter{})
|
||||
if err := m.Params[len(m.Params)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1537,7 +1281,6 @@ func (m *ManifestResponse) Unmarshal(dAtA []byte) error {
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
@@ -1603,7 +1346,7 @@ func (m *ListDirRequest) Unmarshal(dAtA []byte) error {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
if m.Repo == nil {
|
||||
m.Repo = &v1alpha1.Repository{}
|
||||
m.Repo = &github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Repository{}
|
||||
}
|
||||
if err := m.Repo.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
|
||||
return err
|
||||
@@ -1679,7 +1422,6 @@ func (m *ListDirRequest) Unmarshal(dAtA []byte) error {
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
@@ -1759,7 +1501,6 @@ func (m *FileList) Unmarshal(dAtA []byte) error {
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
@@ -1825,7 +1566,7 @@ func (m *GetFileRequest) Unmarshal(dAtA []byte) error {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
if m.Repo == nil {
|
||||
m.Repo = &v1alpha1.Repository{}
|
||||
m.Repo = &github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Repository{}
|
||||
}
|
||||
if err := m.Repo.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
|
||||
return err
|
||||
@@ -1901,7 +1642,6 @@ func (m *GetFileRequest) Unmarshal(dAtA []byte) error {
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
@@ -1983,7 +1723,6 @@ func (m *GetFileResponse) Unmarshal(dAtA []byte) error {
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...)
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
@@ -2098,47 +1837,44 @@ var (
|
||||
ErrIntOverflowRepository = fmt.Errorf("proto: integer overflow")
|
||||
)
|
||||
|
||||
func init() {
|
||||
proto.RegisterFile("reposerver/repository/repository.proto", fileDescriptor_repository_49651600e73b0b40)
|
||||
}
|
||||
func init() { proto.RegisterFile("reposerver/repository/repository.proto", fileDescriptorRepository) }
|
||||
|
||||
var fileDescriptor_repository_49651600e73b0b40 = []byte{
|
||||
// 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,
|
||||
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,
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ 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 {
|
||||
|
||||
@@ -6,24 +6,14 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestGenerateYamlManifestInDir(t *testing.T) {
|
||||
// update this value if we add/remove manifests
|
||||
const countOfManifests = 22
|
||||
|
||||
func TestGenerateManifestInDir(t *testing.T) {
|
||||
q := ManifestRequest{}
|
||||
res1, err := generateManifests("../../manifests/base", &q)
|
||||
res1, err := generateManifests("../../manifests/components", &q)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, len(res1.Manifests), countOfManifests)
|
||||
assert.True(t, len(res1.Manifests) == 16) // update this value if we add/remove manifests
|
||||
|
||||
// this will test concatenated manifests to verify we split YAMLs correctly
|
||||
res2, err := generateManifests("./testdata/concatenated", &q)
|
||||
res2, err := generateManifests("../../manifests", &q)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 3, len(res2.Manifests))
|
||||
}
|
||||
|
||||
func TestGenerateJsonnetManifestInDir(t *testing.T) {
|
||||
q := ManifestRequest{}
|
||||
res1, err := generateManifests("./testdata/jsonnet", &q)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, len(res1.Manifests), 2)
|
||||
assert.True(t, len(res2.Manifests) == len(res1.Manifests))
|
||||
}
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: sa1
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: sa2
|
||||
---
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: sa3
|
||||
---
|
||||
@@ -1,58 +0,0 @@
|
||||
local params = import 'params.libsonnet';
|
||||
|
||||
[
|
||||
{
|
||||
"apiVersion": "v1",
|
||||
"kind": "Service",
|
||||
"metadata": {
|
||||
"name": params.name
|
||||
},
|
||||
"spec": {
|
||||
"ports": [
|
||||
{
|
||||
"port": params.servicePort,
|
||||
"targetPort": params.containerPort
|
||||
}
|
||||
],
|
||||
"selector": {
|
||||
"app": params.name
|
||||
},
|
||||
"type": params.type
|
||||
}
|
||||
},
|
||||
{
|
||||
"apiVersion": "apps/v1beta2",
|
||||
"kind": "Deployment",
|
||||
"metadata": {
|
||||
"name": params.name
|
||||
},
|
||||
"spec": {
|
||||
"replicas": params.replicas,
|
||||
"selector": {
|
||||
"matchLabels": {
|
||||
"app": params.name
|
||||
},
|
||||
},
|
||||
"template": {
|
||||
"metadata": {
|
||||
"labels": {
|
||||
"app": params.name
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"containers": [
|
||||
{
|
||||
"image": params.image,
|
||||
"name": params.name,
|
||||
"ports": [
|
||||
{
|
||||
"containerPort": params.containerPort
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
containerPort: 80,
|
||||
image: "gcr.io/heptio-images/ks-guestbook-demo:0.2",
|
||||
name: "guestbook-ui",
|
||||
replicas: 1,
|
||||
servicePort: 80,
|
||||
type: "LoadBalancer",
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user