mirror of
https://github.com/argoproj/argo-cd.git
synced 2026-03-21 07:48:50 +01:00
Compare commits
183 Commits
v0.2.0
...
release-0.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
21b64886ce | ||
|
|
eeb1036dcf | ||
|
|
fa990ab0c9 | ||
|
|
933f3da538 | ||
|
|
a7fa2fd256 | ||
|
|
0de1a3b20a | ||
|
|
bcc114ec60 | ||
|
|
1148fae419 | ||
|
|
d7188c29f8 | ||
|
|
4b97732659 | ||
|
|
8ff98cc6e1 | ||
|
|
cf0c324a74 | ||
|
|
69119a21cd | ||
|
|
16fa41d25b | ||
|
|
4e170c2033 | ||
|
|
3fbbe940a1 | ||
|
|
271b57e5c5 | ||
|
|
df0e2e4015 | ||
|
|
9fa622d63b | ||
|
|
fed2149174 | ||
|
|
aa4291183b | ||
|
|
0d3fc9648f | ||
|
|
339138b576 | ||
|
|
666769f9d9 | ||
|
|
8fc594bd2b | ||
|
|
8cf8ad7e24 | ||
|
|
0818f698e6 | ||
|
|
44a33b0a5f | ||
|
|
85078bdb66 | ||
|
|
30a3dba7ad | ||
|
|
0afc671723 | ||
|
|
12e7447e9f | ||
|
|
b675e79b89 | ||
|
|
febdccfb58 | ||
|
|
54835a0d93 | ||
|
|
423fe3487c | ||
|
|
98cb3f7950 | ||
|
|
371492bf5c | ||
|
|
7df831e96d | ||
|
|
f0be1bd251 | ||
|
|
948341a885 | ||
|
|
1b2bf8ce0e | ||
|
|
4f68a0f634 | ||
|
|
e785abeb8f | ||
|
|
3acca5095e | ||
|
|
5a62286127 | ||
|
|
5452aff0be | ||
|
|
0f4f1262af | ||
|
|
4e7f68ccba | ||
|
|
96c05babe0 | ||
|
|
6b78cddb19 | ||
|
|
12596ff936 | ||
|
|
a240f1b2b9 | ||
|
|
f6da19672e | ||
|
|
e81d30be9b | ||
|
|
13b090e3bd | ||
|
|
d0479e6ddc | ||
|
|
1432827006 | ||
|
|
89bf4eac71 | ||
|
|
07aac0bdae | ||
|
|
61220b8d0d | ||
|
|
4e470aaf09 | ||
|
|
76922b620b | ||
|
|
ac0f623eda | ||
|
|
afd5450882 | ||
|
|
c17266fc21 | ||
|
|
f62c825495 | ||
|
|
45f44dd4be | ||
|
|
9c0daebfe0 | ||
|
|
f2a0ca5609 | ||
|
|
e04d315853 | ||
|
|
daec697658 | ||
|
|
7ad5670710 | ||
|
|
8036423373 | ||
|
|
8039228a9d | ||
|
|
b1103af429 | ||
|
|
d67ad5acfd | ||
|
|
c9df9c17b7 | ||
|
|
8fa46b02b0 | ||
|
|
92c481330d | ||
|
|
2664db3e40 | ||
|
|
6b554e5f4e | ||
|
|
2bc0dff135 | ||
|
|
c61795f71a | ||
|
|
a8a7491bf0 | ||
|
|
d1c7c4fcaf | ||
|
|
3dbbcf8918 | ||
|
|
0cfd1ad05f | ||
|
|
bfa4e233b7 | ||
|
|
dc662da3d6 | ||
|
|
4107d2422b | ||
|
|
b83eac5dc2 | ||
|
|
bb51837c56 | ||
|
|
5bbb4fe1a1 | ||
|
|
b5c20e9b46 | ||
|
|
1e1ab636e0 | ||
|
|
7348553897 | ||
|
|
5f65a5128a | ||
|
|
d9c12e7271 | ||
|
|
fb2d6b4aff | ||
|
|
3f4ec0ab22 | ||
|
|
ac938fe8a3 | ||
|
|
dc1e8796fb | ||
|
|
8c5d59c60c | ||
|
|
13558b7ce8 | ||
|
|
3b2b3dacf5 | ||
|
|
1b2f89995c | ||
|
|
0479fcdf82 | ||
|
|
a04465466d | ||
|
|
670921df90 | ||
|
|
18f7e17d7a | ||
|
|
a2aede0441 | ||
|
|
1d876c7729 | ||
|
|
70465a0520 | ||
|
|
3c9845719f | ||
|
|
a36cc8946c | ||
|
|
9567b539d1 | ||
|
|
fdf9515de2 | ||
|
|
b320238487 | ||
|
|
7872a60499 | ||
|
|
5fea3846d1 | ||
|
|
86a4e0baaa | ||
|
|
917f1df250 | ||
|
|
11260f2476 | ||
|
|
38d20d0f04 | ||
|
|
938f40e817 | ||
|
|
5f9c8b862e | ||
|
|
d96d67bb9a | ||
|
|
19c3b87676 | ||
|
|
7d08ab4e2b | ||
|
|
efea09d216 | ||
|
|
2adaef547b | ||
|
|
d71bbf0d9a | ||
|
|
36b3b2b853 | ||
|
|
63dafa08cc | ||
|
|
afddbbe875 | ||
|
|
34811cafca | ||
|
|
8a2851169c | ||
|
|
1a85a2d805 | ||
|
|
cf2d00e1e0 | ||
|
|
266c948add | ||
|
|
dd564ee9dd | ||
|
|
b9d48cabb9 | ||
|
|
276e0674c3 | ||
|
|
f3c4a69327 | ||
|
|
1c60a69866 | ||
|
|
050f937a24 | ||
|
|
b24e478224 | ||
|
|
e34380ed76 | ||
|
|
338a1b826f | ||
|
|
b87c63c897 | ||
|
|
f6ed150bb7 | ||
|
|
d5c683bc76 | ||
|
|
3ac95f3f84 | ||
|
|
3be872ad32 | ||
|
|
80964a79b2 | ||
|
|
e719035ea5 | ||
|
|
f2bcf63b26 | ||
|
|
2c9843f1a0 | ||
|
|
0560406d81 | ||
|
|
db8083c657 | ||
|
|
fcc9f50b3f | ||
|
|
c1ffbad8d8 | ||
|
|
d7cdb1a5af | ||
|
|
6c41ce5e08 | ||
|
|
685a814f38 | ||
|
|
06b64047a4 | ||
|
|
8a90b32446 | ||
|
|
7e47b1ebae | ||
|
|
150b51a3ac | ||
|
|
0002f8db9e | ||
|
|
59ed50d230 | ||
|
|
820b4bac1a | ||
|
|
19c5ecdbfa | ||
|
|
66b0702c24 | ||
|
|
5b5dc0efc4 | ||
|
|
0febf05160 | ||
|
|
ee924bda6e | ||
|
|
ecfe571e75 | ||
|
|
173ecd9397 | ||
|
|
ba3db35ba0 | ||
|
|
074053dac7 | ||
|
|
6bc98f91b1 |
@@ -21,9 +21,7 @@ spec:
|
||||
- name: cmd
|
||||
value: "{{item}}"
|
||||
withItems:
|
||||
- make controller-image
|
||||
- make server-image
|
||||
- make repo-server-image
|
||||
- make controller-image server-image repo-server-image
|
||||
- name: test
|
||||
template: ci-builder
|
||||
arguments:
|
||||
@@ -31,8 +29,7 @@ spec:
|
||||
- name: cmd
|
||||
value: "{{item}}"
|
||||
withItems:
|
||||
- dep ensure && make lint
|
||||
- dep ensure && make test
|
||||
- dep ensure && make cli lint test test-e2e
|
||||
|
||||
- name: ci-builder
|
||||
inputs:
|
||||
@@ -49,6 +46,10 @@ spec:
|
||||
command: [sh, -c]
|
||||
args: ["{{inputs.parameters.cmd}}"]
|
||||
workingDir: /go/src/github.com/argoproj/argo-cd
|
||||
resources:
|
||||
requests:
|
||||
memory: 1024Mi
|
||||
cpu: 200m
|
||||
|
||||
- name: ci-dind
|
||||
inputs:
|
||||
@@ -68,6 +69,10 @@ spec:
|
||||
env:
|
||||
- name: DOCKER_HOST
|
||||
value: 127.0.0.1
|
||||
resources:
|
||||
requests:
|
||||
memory: 1024Mi
|
||||
cpu: 200m
|
||||
sidecars:
|
||||
- name: dind
|
||||
image: docker:17.10-dind
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
# Prevent vendor directory from being copied to ensure we are not not pulling unexpected cruft from
|
||||
# a user's workspace, and are only building off of what is locked by dep.
|
||||
vendor
|
||||
Dockerfile-argocd
|
||||
dist
|
||||
|
||||
14
CHANGELOG.md
Normal file
14
CHANGELOG.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# Changelog
|
||||
|
||||
## v0.4.0 (2018-05-17)
|
||||
+ SSO Integration
|
||||
+ GitHub Webhook
|
||||
+ Add application health status
|
||||
+ Sync/Rollback/Delete is asynchronously handled by controller
|
||||
* Refactor CRUD operation on clusters and repos
|
||||
* Sync will always perform kubectl apply
|
||||
* Synced Status considers last-applied-configuration annotatoin
|
||||
* Server & namespace are mandatory fields (still inferred from app.yaml)
|
||||
* Manifests are memoized in repo server
|
||||
- Fix connection timeouts to SSH repos
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM debian:9.3 as builder
|
||||
FROM debian:9.4 as builder
|
||||
|
||||
RUN apt-get update && apt-get install -y \
|
||||
git \
|
||||
@@ -10,7 +10,7 @@ RUN apt-get update && apt-get install -y \
|
||||
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
||||
|
||||
# Install go
|
||||
ENV GO_VERSION 1.9.3
|
||||
ENV GO_VERSION 1.10.3
|
||||
ENV GO_ARCH amd64
|
||||
ENV GOPATH /root/go
|
||||
ENV PATH ${GOPATH}/bin:/usr/local/go/bin:${PATH}
|
||||
@@ -25,7 +25,7 @@ RUN cd /usr/local && \
|
||||
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.10.4/packr_1.10.4_linux_amd64.tar.gz && \
|
||||
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
|
||||
|
||||
@@ -39,22 +39,45 @@ RUN cd ${GOPATH}/src/dummy && \
|
||||
mv vendor/* ${GOPATH}/src/ && \
|
||||
rmdir vendor
|
||||
|
||||
ARG MAKE_TARGET
|
||||
|
||||
# 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}
|
||||
RUN wget https://github.com/ksonnet/ksonnet/releases/download/v0.9.1/ks_0.9.1_linux_amd64.tar.gz && tar -C /tmp/ -xf ks_0.9.1_linux_amd64.tar.gz
|
||||
|
||||
|
||||
##############################################################
|
||||
# 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
|
||||
|
||||
|
||||
##############################################################
|
||||
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/*
|
||||
ARG BINARY
|
||||
COPY --from=builder /root/go/src/github.com/argoproj/argo-cd/dist/${BINARY} /${BINARY}
|
||||
COPY --from=builder /tmp/ks_0.9.1_linux_amd64/ks /usr/local/bin/ks
|
||||
|
||||
COPY --from=cli-tooling /ks /usr/local/bin/ks
|
||||
COPY --from=cli-tooling /kubectl /usr/local/bin/kubectl
|
||||
# workaround ksonnet issue https://github.com/ksonnet/ksonnet/issues/298
|
||||
ENV USER=root
|
||||
ENV BINARY=$BINARY
|
||||
CMD /$BINARY
|
||||
|
||||
COPY --from=builder /root/go/src/github.com/argoproj/argo-cd/dist/* /
|
||||
ARG BINARY
|
||||
CMD /${BINARY}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM golang:1.9.2
|
||||
FROM golang:1.10.3
|
||||
|
||||
WORKDIR /tmp
|
||||
|
||||
@@ -10,7 +10,13 @@ RUN curl -O https://get.docker.com/builds/Linux/x86_64/docker-1.13.1.tgz && \
|
||||
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
|
||||
# TODO(jessesuen): pin this once we decide on a stable version
|
||||
RUN go get -v -u github.com/ksonnet/ksonnet && \
|
||||
mv ${GOPATH}/bin/ksonnet /usr/local/bin/ks
|
||||
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}
|
||||
|
||||
389
Gopkg.lock
generated
389
Gopkg.lock
generated
@@ -7,6 +7,20 @@
|
||||
revision = "767c40d6a2e058483c25fa193e963a22da17236d"
|
||||
version = "v0.18.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/GeertJohan/go.rice"
|
||||
packages = [
|
||||
".",
|
||||
"embedded"
|
||||
]
|
||||
revision = "c02ca9a983da5807ddf7d796784928f5be4afd09"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/Knetic/govaluate"
|
||||
packages = ["."]
|
||||
revision = "d216395917cc49052c7c7094cf57f09657ca08a8"
|
||||
version = "v3.0.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/PuerkitoBio/purell"
|
||||
packages = ["."]
|
||||
@@ -24,6 +38,40 @@
|
||||
revision = "2ee87856327ba09384cabd113bc6b5d174e9ec0f"
|
||||
version = "v3.5.1"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/casbin/casbin"
|
||||
packages = [
|
||||
".",
|
||||
"config",
|
||||
"effect",
|
||||
"model",
|
||||
"persist",
|
||||
"persist/file-adapter",
|
||||
"rbac",
|
||||
"rbac/default-role-manager",
|
||||
"util"
|
||||
]
|
||||
revision = "d71629e497929858300c38cd442098c178121c30"
|
||||
version = "v1.5.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/coreos/dex"
|
||||
packages = ["api"]
|
||||
revision = "218d671a96865df2a4cf7f310efb99b8bfc5a5e2"
|
||||
version = "v2.10.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "v2"
|
||||
name = "github.com/coreos/go-oidc"
|
||||
packages = ["."]
|
||||
revision = "1180514eaf4d9f38d0d19eef639a1d695e066e72"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/daaku/go.zipexe"
|
||||
packages = ["."]
|
||||
revision = "a5fe2436ffcb3236e175e5149162b41cd28bd27d"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/davecgh/go-spew"
|
||||
packages = ["spew"]
|
||||
@@ -31,24 +79,15 @@
|
||||
version = "v1.1.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/emicklei/go-restful"
|
||||
packages = [
|
||||
".",
|
||||
"log"
|
||||
]
|
||||
revision = "26b41036311f2da8242db402557a0dbd09dc83da"
|
||||
version = "v2.6.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/fatih/color"
|
||||
name = "github.com/dgrijalva/jwt-go"
|
||||
packages = ["."]
|
||||
revision = "5df930a27be2502f99b292b7cc09ebad4d0891f4"
|
||||
revision = "06ea1031745cb8b3dab3f6a236daf2b0aa468b7e"
|
||||
version = "v3.2.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/ghodss/yaml"
|
||||
packages = ["."]
|
||||
revision = "0ca9ea5df5451ffdf184b4428c902747c2c11cd7"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
@@ -74,11 +113,36 @@
|
||||
packages = ["."]
|
||||
revision = "84f4bee7c0a6db40e3166044c7983c1c32125429"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/go-redis/cache"
|
||||
packages = [
|
||||
".",
|
||||
"internal/lrucache",
|
||||
"internal/singleflight"
|
||||
]
|
||||
revision = "c58ada1e23a3b66593f81c70572c20a0bb805a90"
|
||||
version = "v6.3.5"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/go-redis/redis"
|
||||
packages = [
|
||||
".",
|
||||
"internal",
|
||||
"internal/consistenthash",
|
||||
"internal/hashtag",
|
||||
"internal/pool",
|
||||
"internal/proto",
|
||||
"internal/singleflight",
|
||||
"internal/util"
|
||||
]
|
||||
revision = "877867d2845fbaf86798befe410b6ceb6f5c29a3"
|
||||
version = "v6.10.2"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/gobuffalo/packr"
|
||||
packages = ["."]
|
||||
revision = "6434a292ac52e6964adebfdce3f9ce6d9f16be01"
|
||||
version = "v1.10.4"
|
||||
revision = "7f4074995d431987caaa35088199f13c44b24440"
|
||||
version = "v1.11.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/gogo/protobuf"
|
||||
@@ -106,6 +170,7 @@
|
||||
"protoc-gen-gogo/generator",
|
||||
"protoc-gen-gogo/grpc",
|
||||
"protoc-gen-gogo/plugin",
|
||||
"protoc-gen-gogofast",
|
||||
"sortkeys",
|
||||
"vanity",
|
||||
"vanity/command"
|
||||
@@ -120,6 +185,7 @@
|
||||
revision = "23def4e6c14b4da8ac2ed8007337bc5eb5007998"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/golang/protobuf"
|
||||
packages = [
|
||||
"jsonpb",
|
||||
@@ -132,33 +198,16 @@
|
||||
"ptypes/struct",
|
||||
"ptypes/timestamp"
|
||||
]
|
||||
revision = "925541529c1fa6821df4e44ce2723319eb2be768"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/google/btree"
|
||||
packages = ["."]
|
||||
revision = "e89373fe6b4a7413d7acd6da1725b83ef713e6e4"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/google/go-github"
|
||||
packages = ["github"]
|
||||
revision = "996760c56486beb81e91bb7bdb816f8c6f29284e"
|
||||
revision = "e09c5db296004fbe3f74490e84dcd62c3c5ddb1b"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/google/go-jsonnet"
|
||||
packages = [
|
||||
".",
|
||||
"ast",
|
||||
"parser"
|
||||
]
|
||||
revision = "405726fae23ace72b22c410a77b7bd825608f2c8"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/google/go-querystring"
|
||||
packages = ["query"]
|
||||
revision = "53e6ce116135b80d037921a7fdd5138cf32d7a8a"
|
||||
revision = "dfddf2b4e3aec377b0dcdf247ff92e7d078b8179"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
@@ -178,23 +227,18 @@
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/gregjones/httpcache"
|
||||
packages = [
|
||||
".",
|
||||
"diskcache"
|
||||
]
|
||||
revision = "2bcd89a1743fd4b373f7370ce8ddc14dfbd18229"
|
||||
|
||||
[[projects]]
|
||||
branch = "bugfix/37-panic-on-err"
|
||||
name = "github.com/grpc-ecosystem/go-grpc-middleware"
|
||||
packages = [
|
||||
".",
|
||||
"auth",
|
||||
"logging",
|
||||
"logging/logrus",
|
||||
"tags"
|
||||
"logging/logrus/ctxlogrus",
|
||||
"tags",
|
||||
"tags/logrus",
|
||||
"util/metautils"
|
||||
]
|
||||
revision = "b9814e2370c8552db05c796c139b76a6ca45b34f"
|
||||
revision = "bc372cc64f55abd91995ba3f219b380ffbc59e9d"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/grpc-ecosystem/grpc-gateway"
|
||||
@@ -240,28 +284,30 @@
|
||||
version = "1.0.6"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/juju/ratelimit"
|
||||
branch = "master"
|
||||
name = "github.com/kardianos/osext"
|
||||
packages = ["."]
|
||||
revision = "59fac5042749a5afb9af70e813da1dd5474f0167"
|
||||
version = "1.0.1"
|
||||
revision = "ae77be60afb1dcacde03767a8c37337fad28ac14"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/ksonnet/ksonnet"
|
||||
packages = [
|
||||
"component",
|
||||
"env",
|
||||
"generator",
|
||||
"metadata",
|
||||
"metadata/app",
|
||||
"metadata/lib",
|
||||
"metadata/params",
|
||||
"metadata/parts",
|
||||
"metadata/registry",
|
||||
"prototype",
|
||||
"strings"
|
||||
"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"
|
||||
]
|
||||
revision = "e570bff822d88b12f1841aa6e0069713d7e066c5"
|
||||
revision = "e943ae55d4fe256c8330a047ce8426ad9dac110c"
|
||||
version = "v0.11.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/ksonnet/ksonnet-lib"
|
||||
@@ -274,7 +320,8 @@
|
||||
"ksonnet-gen/nodemaker",
|
||||
"ksonnet-gen/printer"
|
||||
]
|
||||
revision = "9f27c242ff65da0620f8324cc0cd50c8ef00bf5b"
|
||||
revision = "dfcaa3d01d0c4948cb596403c35e966c774f2678"
|
||||
version = "v0.1.8"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
@@ -287,34 +334,10 @@
|
||||
revision = "32fa128f234d041f196a9f3e0fea5ac9772c08e1"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/mattn/go-colorable"
|
||||
name = "github.com/patrickmn/go-cache"
|
||||
packages = ["."]
|
||||
revision = "167de6bfdfba052fa6b2d3664c8f5272e23c9072"
|
||||
version = "v0.0.9"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/mattn/go-isatty"
|
||||
packages = ["."]
|
||||
revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39"
|
||||
version = "v0.0.3"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/pborman/uuid"
|
||||
packages = ["."]
|
||||
revision = "e790cca94e6cc75c7064b1332e63811d4aae1a53"
|
||||
version = "v1.1"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/petar/GoLLRB"
|
||||
packages = ["llrb"]
|
||||
revision = "53be0d36a84c2a886ca057d34b6aa4468df9ccb4"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/peterbourgon/diskv"
|
||||
packages = ["."]
|
||||
revision = "5f041e8faa004a95c88a202771f4cc3e991971e6"
|
||||
version = "v2.0.1"
|
||||
revision = "a3647f8e31d79543b2d0f0ae2fe5c379d72cedc0"
|
||||
version = "v2.1.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/pkg/errors"
|
||||
@@ -328,6 +351,21 @@
|
||||
revision = "792786c7400a136282c1664665ae0a8db921c6c2"
|
||||
version = "v1.0.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/pquerna/cachecontrol"
|
||||
packages = [
|
||||
".",
|
||||
"cacheobject"
|
||||
]
|
||||
revision = "525d0eb5f91d30e3b1548de401b7ef9ea6898520"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/qiangmzsx/string-adapter"
|
||||
packages = ["."]
|
||||
revision = "38f25303bb0cd40e674a6fac01e0171ab905f5a1"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/sergi/go-diff"
|
||||
packages = ["diffmatchpatch"]
|
||||
@@ -337,7 +375,13 @@
|
||||
[[projects]]
|
||||
name = "github.com/sirupsen/logrus"
|
||||
packages = ["."]
|
||||
revision = "3d4380f53a34dcdc95f0c1db702615992b38d9a4"
|
||||
revision = "ea8897e79973357ba785ac2533559a6297e83c44"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/skratchdot/open-golang"
|
||||
packages = ["open"]
|
||||
revision = "75fb7ed4208cf72d323d7d02fd1a5964a7a9073c"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/soheilhy/cmux"
|
||||
@@ -380,6 +424,15 @@
|
||||
revision = "12b6f73e6084dad08a7c6e575284b177ecafbc71"
|
||||
version = "v1.2.1"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/vmihailenco/msgpack"
|
||||
packages = [
|
||||
".",
|
||||
"codes"
|
||||
]
|
||||
revision = "a053f3dac71df214bfe8b367f34220f0029c9c02"
|
||||
version = "v3.3.1"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/yudai/gojsondiff"
|
||||
packages = [
|
||||
@@ -398,7 +451,13 @@
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/crypto"
|
||||
packages = ["ssh/terminal"]
|
||||
packages = [
|
||||
"bcrypt",
|
||||
"blowfish",
|
||||
"ed25519",
|
||||
"ed25519/internal/edwards25519",
|
||||
"ssh/terminal"
|
||||
]
|
||||
revision = "432090b8f568c018896cd8a0fb0345872bbac6ce"
|
||||
|
||||
[[projects]]
|
||||
@@ -464,6 +523,12 @@
|
||||
]
|
||||
revision = "4e4a3210bb54bb31f6ab2cdca2edcc0b50c420c1"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/time"
|
||||
packages = ["rate"]
|
||||
revision = "fbb02b2291d28baffd63558aa44b4b56f178d650"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/tools"
|
||||
@@ -477,6 +542,7 @@
|
||||
name = "google.golang.org/appengine"
|
||||
packages = [
|
||||
".",
|
||||
"datastore",
|
||||
"internal",
|
||||
"internal/app_identity",
|
||||
"internal/base",
|
||||
@@ -518,6 +584,8 @@
|
||||
"metadata",
|
||||
"naming",
|
||||
"peer",
|
||||
"reflection",
|
||||
"reflection/grpc_reflection_v1alpha",
|
||||
"resolver",
|
||||
"resolver/dns",
|
||||
"resolver/passthrough",
|
||||
@@ -529,6 +597,17 @@
|
||||
revision = "8e4536a86ab602859c20df5ebfd0bd4228d08655"
|
||||
version = "v1.10.0"
|
||||
|
||||
[[projects]]
|
||||
name = "gopkg.in/go-playground/webhooks.v3"
|
||||
packages = [
|
||||
".",
|
||||
"bitbucket",
|
||||
"github",
|
||||
"gitlab"
|
||||
]
|
||||
revision = "5580947e3ec83427ef5f6f2392eddca8dde5d99a"
|
||||
version = "v3.11.0"
|
||||
|
||||
[[projects]]
|
||||
name = "gopkg.in/inf.v0"
|
||||
packages = ["."]
|
||||
@@ -536,15 +615,25 @@
|
||||
version = "v0.9.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "v2"
|
||||
name = "gopkg.in/yaml.v2"
|
||||
packages = ["."]
|
||||
revision = "d670f9405373e636a5a2765eea47fac0c9bc91a4"
|
||||
name = "gopkg.in/square/go-jose.v2"
|
||||
packages = [
|
||||
".",
|
||||
"cipher",
|
||||
"json"
|
||||
]
|
||||
revision = "76dd09796242edb5b897103a75df2645c028c960"
|
||||
version = "v2.1.6"
|
||||
|
||||
[[projects]]
|
||||
branch = "release-1.9"
|
||||
name = "gopkg.in/yaml.v2"
|
||||
packages = ["."]
|
||||
revision = "eb3733d160e74a9c7e442f435eb3bea458e1d19f"
|
||||
|
||||
[[projects]]
|
||||
branch = "release-1.10"
|
||||
name = "k8s.io/api"
|
||||
packages = [
|
||||
"admission/v1beta1",
|
||||
"admissionregistration/v1alpha1",
|
||||
"admissionregistration/v1beta1",
|
||||
"apps/v1",
|
||||
@@ -563,6 +652,7 @@
|
||||
"core/v1",
|
||||
"events/v1beta1",
|
||||
"extensions/v1beta1",
|
||||
"imagepolicy/v1alpha1",
|
||||
"networking/v1",
|
||||
"policy/v1beta1",
|
||||
"rbac/v1",
|
||||
@@ -574,10 +664,10 @@
|
||||
"storage/v1alpha1",
|
||||
"storage/v1beta1"
|
||||
]
|
||||
revision = "acf347b865f29325eb61f4cd2df11e86e073a5ee"
|
||||
revision = "8b7507fac302640dd5f1efbf9643199952cc58db"
|
||||
|
||||
[[projects]]
|
||||
branch = "release-1.9"
|
||||
branch = "release-1.10"
|
||||
name = "k8s.io/apiextensions-apiserver"
|
||||
packages = [
|
||||
"pkg/apis/apiextensions",
|
||||
@@ -586,20 +676,23 @@
|
||||
"pkg/client/clientset/clientset/scheme",
|
||||
"pkg/client/clientset/clientset/typed/apiextensions/v1beta1"
|
||||
]
|
||||
revision = "b89f5ce12ce6e022fc3e9d7586d61346e694d56e"
|
||||
revision = "b13a681559816a9c14f93086bbeeed1c7baf2bcb"
|
||||
|
||||
[[projects]]
|
||||
branch = "release-1.9"
|
||||
branch = "release-1.10"
|
||||
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",
|
||||
"pkg/apis/meta/v1alpha1",
|
||||
"pkg/apis/meta/v1beta1",
|
||||
"pkg/conversion",
|
||||
"pkg/conversion/queryparams",
|
||||
"pkg/fields",
|
||||
@@ -621,28 +714,70 @@
|
||||
"pkg/util/framer",
|
||||
"pkg/util/intstr",
|
||||
"pkg/util/json",
|
||||
"pkg/util/mergepatch",
|
||||
"pkg/util/net",
|
||||
"pkg/util/runtime",
|
||||
"pkg/util/sets",
|
||||
"pkg/util/uuid",
|
||||
"pkg/util/strategicpatch",
|
||||
"pkg/util/validation",
|
||||
"pkg/util/validation/field",
|
||||
"pkg/util/wait",
|
||||
"pkg/util/yaml",
|
||||
"pkg/version",
|
||||
"pkg/watch",
|
||||
"third_party/forked/golang/json",
|
||||
"third_party/forked/golang/reflect"
|
||||
]
|
||||
revision = "19e3f5aa3adca672c153d324e6b7d82ff8935f03"
|
||||
revision = "f6313580a4d36c7c74a3d845dda6e116642c4f90"
|
||||
|
||||
[[projects]]
|
||||
branch = "release-6.0"
|
||||
branch = "release-7.0"
|
||||
name = "k8s.io/client-go"
|
||||
packages = [
|
||||
"discovery",
|
||||
"discovery/fake",
|
||||
"dynamic",
|
||||
"dynamic/fake",
|
||||
"informers",
|
||||
"informers/admissionregistration",
|
||||
"informers/admissionregistration/v1alpha1",
|
||||
"informers/admissionregistration/v1beta1",
|
||||
"informers/apps",
|
||||
"informers/apps/v1",
|
||||
"informers/apps/v1beta1",
|
||||
"informers/apps/v1beta2",
|
||||
"informers/autoscaling",
|
||||
"informers/autoscaling/v1",
|
||||
"informers/autoscaling/v2beta1",
|
||||
"informers/batch",
|
||||
"informers/batch/v1",
|
||||
"informers/batch/v1beta1",
|
||||
"informers/batch/v2alpha1",
|
||||
"informers/certificates",
|
||||
"informers/certificates/v1beta1",
|
||||
"informers/core",
|
||||
"informers/core/v1",
|
||||
"informers/events",
|
||||
"informers/events/v1beta1",
|
||||
"informers/extensions",
|
||||
"informers/extensions/v1beta1",
|
||||
"informers/internalinterfaces",
|
||||
"informers/networking",
|
||||
"informers/networking/v1",
|
||||
"informers/policy",
|
||||
"informers/policy/v1beta1",
|
||||
"informers/rbac",
|
||||
"informers/rbac/v1",
|
||||
"informers/rbac/v1alpha1",
|
||||
"informers/rbac/v1beta1",
|
||||
"informers/scheduling",
|
||||
"informers/scheduling/v1alpha1",
|
||||
"informers/settings",
|
||||
"informers/settings/v1alpha1",
|
||||
"informers/storage",
|
||||
"informers/storage/v1",
|
||||
"informers/storage/v1alpha1",
|
||||
"informers/storage/v1beta1",
|
||||
"kubernetes",
|
||||
"kubernetes/fake",
|
||||
"kubernetes/scheme",
|
||||
@@ -702,7 +837,34 @@
|
||||
"kubernetes/typed/storage/v1alpha1/fake",
|
||||
"kubernetes/typed/storage/v1beta1",
|
||||
"kubernetes/typed/storage/v1beta1/fake",
|
||||
"listers/admissionregistration/v1alpha1",
|
||||
"listers/admissionregistration/v1beta1",
|
||||
"listers/apps/v1",
|
||||
"listers/apps/v1beta1",
|
||||
"listers/apps/v1beta2",
|
||||
"listers/autoscaling/v1",
|
||||
"listers/autoscaling/v2beta1",
|
||||
"listers/batch/v1",
|
||||
"listers/batch/v1beta1",
|
||||
"listers/batch/v2alpha1",
|
||||
"listers/certificates/v1beta1",
|
||||
"listers/core/v1",
|
||||
"listers/events/v1beta1",
|
||||
"listers/extensions/v1beta1",
|
||||
"listers/networking/v1",
|
||||
"listers/policy/v1beta1",
|
||||
"listers/rbac/v1",
|
||||
"listers/rbac/v1alpha1",
|
||||
"listers/rbac/v1beta1",
|
||||
"listers/scheduling/v1alpha1",
|
||||
"listers/settings/v1alpha1",
|
||||
"listers/storage/v1",
|
||||
"listers/storage/v1alpha1",
|
||||
"listers/storage/v1beta1",
|
||||
"pkg/apis/clientauthentication",
|
||||
"pkg/apis/clientauthentication/v1alpha1",
|
||||
"pkg/version",
|
||||
"plugin/pkg/client/auth/exec",
|
||||
"plugin/pkg/client/auth/gcp",
|
||||
"plugin/pkg/client/auth/oidc",
|
||||
"rest",
|
||||
@@ -725,19 +887,21 @@
|
||||
"util/homedir",
|
||||
"util/integer",
|
||||
"util/jsonpath",
|
||||
"util/retry",
|
||||
"util/workqueue"
|
||||
]
|
||||
revision = "9389c055a838d4f208b699b3c7c51b70f2368861"
|
||||
revision = "26a26f55b28aa1b338fbaf6fbbe0bcd76aed05e0"
|
||||
|
||||
[[projects]]
|
||||
branch = "release-1.9"
|
||||
branch = "release-1.10"
|
||||
name = "k8s.io/code-generator"
|
||||
packages = [
|
||||
"cmd/go-to-protobuf",
|
||||
"cmd/go-to-protobuf/protobuf",
|
||||
"pkg/util",
|
||||
"third_party/forked/golang/reflect"
|
||||
]
|
||||
revision = "91d3f6a57905178524105a085085901bb73bd3dc"
|
||||
revision = "9de8e796a74d16d2a285165727d04c185ebca6dc"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
@@ -754,12 +918,21 @@
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "k8s.io/kube-openapi"
|
||||
packages = ["pkg/common"]
|
||||
packages = ["pkg/util/proto"]
|
||||
revision = "50ae88d24ede7b8bad68e23c805b5d3da5c8abaf"
|
||||
|
||||
[[projects]]
|
||||
name = "k8s.io/kubernetes"
|
||||
packages = [
|
||||
"pkg/apis/core",
|
||||
"pkg/kubectl/scheme"
|
||||
]
|
||||
revision = "81753b10df112992bf51bbc2c2f85208aad78335"
|
||||
version = "v1.10.2"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "683981f86c65c4c2871048e1305c2468fb7dea01ec6de3dbff52c932d8c2f803"
|
||||
inputs-digest = "f2d179e0bbae6ede81f78cf6b0b16cb09fbeb5e97add78bdd97e3051238b86da"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
|
||||
24
Gopkg.toml
24
Gopkg.toml
@@ -1,5 +1,6 @@
|
||||
required = [
|
||||
"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",
|
||||
]
|
||||
@@ -13,23 +14,19 @@ required = [
|
||||
version = "v1.3.1"
|
||||
|
||||
[[constraint]]
|
||||
branch = "release-1.9"
|
||||
name = "k8s.io/apimachinery"
|
||||
|
||||
[[constraint]]
|
||||
branch = "release-1.9"
|
||||
branch = "release-1.10"
|
||||
name = "k8s.io/api"
|
||||
|
||||
[[constraint]]
|
||||
name = "k8s.io/apiextensions-apiserver"
|
||||
branch = "release-1.9"
|
||||
branch = "release-1.10"
|
||||
|
||||
[[constraint]]
|
||||
branch = "release-1.9"
|
||||
branch = "release-1.10"
|
||||
name = "k8s.io/code-generator"
|
||||
|
||||
[[constraint]]
|
||||
branch = "release-6.0"
|
||||
branch = "release-7.0"
|
||||
name = "k8s.io/client-go"
|
||||
|
||||
[[constraint]]
|
||||
@@ -38,8 +35,13 @@ required = [
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/ksonnet/ksonnet"
|
||||
branch = "master"
|
||||
version = "v0.11.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/pborman/uuid"
|
||||
version = "1.1.0"
|
||||
name = "github.com/gobuffalo/packr"
|
||||
version = "v1.11.0"
|
||||
|
||||
# override ksonnet's logrus dependency
|
||||
[[override]]
|
||||
name = "github.com/sirupsen/logrus"
|
||||
revision = "ea8897e79973357ba785ac2533559a6297e83c44"
|
||||
|
||||
60
Makefile
60
Makefile
@@ -1,6 +1,7 @@
|
||||
PACKAGE=github.com/argoproj/argo-cd
|
||||
CURRENT_DIR=$(shell pwd)
|
||||
DIST_DIR=${CURRENT_DIR}/dist
|
||||
CLI_NAME=argocd
|
||||
|
||||
VERSION=$(shell cat ${CURRENT_DIR}/VERSION)
|
||||
BUILD_DATE=$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')
|
||||
@@ -40,7 +41,7 @@ IMAGE_PREFIX=${IMAGE_NAMESPACE}/
|
||||
endif
|
||||
|
||||
.PHONY: all
|
||||
all: cli server-image controller-image repo-server-image
|
||||
all: cli server-image controller-image repo-server-image argocd-util
|
||||
|
||||
.PHONY: protogen
|
||||
protogen:
|
||||
@@ -56,16 +57,34 @@ codegen: protogen clientgen
|
||||
# NOTE: we use packr to do the build instead of go, since we embed .yaml files into the go binary.
|
||||
# This enables ease of maintenance of the yaml files.
|
||||
.PHONY: cli
|
||||
cli:
|
||||
CGO_ENABLED=0 ${PACKR_CMD} build -v -i -ldflags '${LDFLAGS} -extldflags "-static"' -o ${DIST_DIR}/argocd ./cmd/argocd
|
||||
cli: clean-debug
|
||||
CGO_ENABLED=0 ${PACKR_CMD} build -v -i -ldflags '${LDFLAGS} -extldflags "-static"' -o ${DIST_DIR}/${CLI_NAME} ./cmd/argocd
|
||||
|
||||
.PHONY: cli-linux
|
||||
cli-linux: clean-debug
|
||||
docker build --iidfile /tmp/argocd-linux-id --target builder --build-arg MAKE_TARGET="cli IMAGE_TAG=$(IMAGE_TAG) IMAGE_NAMESPACE=$(IMAGE_NAMESPACE) CLI_NAME=argocd-linux-amd64" -f Dockerfile-argocd .
|
||||
docker create --name tmp-argocd-linux `cat /tmp/argocd-linux-id`
|
||||
docker cp tmp-argocd-linux:/root/go/src/github.com/argoproj/argo-cd/dist/argocd-linux-amd64 dist/
|
||||
docker rm tmp-argocd-linux
|
||||
|
||||
.PHONY: cli-darwin
|
||||
cli-darwin: clean-debug
|
||||
docker build --iidfile /tmp/argocd-darwin-id --target builder --build-arg MAKE_TARGET="cli GOOS=darwin IMAGE_TAG=$(IMAGE_TAG) IMAGE_NAMESPACE=$(IMAGE_NAMESPACE) CLI_NAME=argocd-darwin-amd64" -f Dockerfile-argocd .
|
||||
docker create --name tmp-argocd-darwin `cat /tmp/argocd-darwin-id`
|
||||
docker cp tmp-argocd-darwin:/root/go/src/github.com/argoproj/argo-cd/dist/argocd-darwin-amd64 dist/
|
||||
docker 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: server
|
||||
server:
|
||||
CGO_ENABLED=0 go build -v -i -ldflags '${LDFLAGS}' -o ${DIST_DIR}/argocd-server ./cmd/argocd-server
|
||||
server: clean-debug
|
||||
CGO_ENABLED=0 ${PACKR_CMD} build -v -i -ldflags '${LDFLAGS}' -o ${DIST_DIR}/argocd-server ./cmd/argocd-server
|
||||
|
||||
.PHONY: server-image
|
||||
server-image:
|
||||
docker build --build-arg BINARY=argocd-server --build-arg MAKE_TARGET=server -t $(IMAGE_PREFIX)argocd-server:$(IMAGE_TAG) -f Dockerfile-argocd .
|
||||
docker build --build-arg BINARY=argocd-server -t $(IMAGE_PREFIX)argocd-server:$(IMAGE_TAG) -f Dockerfile-argocd .
|
||||
@if [ "$(DOCKER_PUSH)" = "true" ] ; then docker push $(IMAGE_PREFIX)argocd-server:$(IMAGE_TAG) ; fi
|
||||
|
||||
.PHONY: repo-server
|
||||
@@ -74,7 +93,7 @@ repo-server:
|
||||
|
||||
.PHONY: repo-server-image
|
||||
repo-server-image:
|
||||
docker build --build-arg BINARY=argocd-repo-server --build-arg MAKE_TARGET=repo-server -t $(IMAGE_PREFIX)argocd-repo-server:$(IMAGE_TAG) -f Dockerfile-argocd .
|
||||
docker build --build-arg BINARY=argocd-repo-server -t $(IMAGE_PREFIX)argocd-repo-server:$(IMAGE_TAG) -f Dockerfile-argocd .
|
||||
@if [ "$(DOCKER_PUSH)" = "true" ] ; then docker push $(IMAGE_PREFIX)argocd-repo-server:$(IMAGE_TAG) ; fi
|
||||
|
||||
.PHONY: controller
|
||||
@@ -83,9 +102,14 @@ controller:
|
||||
|
||||
.PHONY: controller-image
|
||||
controller-image:
|
||||
docker build --build-arg BINARY=argocd-application-controller --build-arg MAKE_TARGET=controller -t $(IMAGE_PREFIX)argocd-application-controller:$(IMAGE_TAG) -f Dockerfile-argocd .
|
||||
docker build --build-arg BINARY=argocd-application-controller -t $(IMAGE_PREFIX)argocd-application-controller:$(IMAGE_TAG) -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) -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) -f Dockerfile-ci-builder .
|
||||
@@ -96,12 +120,28 @@ lint:
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
go test ./...
|
||||
go test `go list ./... | grep -v "github.com/argoproj/argo-cd/test/e2e"`
|
||||
|
||||
.PHONY: test-e2e
|
||||
test-e2e:
|
||||
go test ./test/e2e
|
||||
|
||||
# Cleans VSCode debug.test files from sub-dirs to prevent them from being included in packr boxes
|
||||
.PHONY: clean-debug
|
||||
clean-debug:
|
||||
-find ${CURRENT_DIR} -name debug.test | xargs rm -f
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
clean: clean-debug
|
||||
-rm -rf ${CURRENT_DIR}/dist
|
||||
|
||||
.PHONY: precheckin
|
||||
precheckin: test lint
|
||||
|
||||
.PHONY: release-precheck
|
||||
release-precheck:
|
||||
@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
|
||||
|
||||
.PHONY: release
|
||||
release: release-precheck precheckin cli-darwin cli-linux server-image controller-image repo-server-image cli-image
|
||||
|
||||
8
OWNERS
Normal file
8
OWNERS
Normal file
@@ -0,0 +1,8 @@
|
||||
owners:
|
||||
- alexmt
|
||||
- jessesuen
|
||||
|
||||
approvers:
|
||||
- alexmt
|
||||
- jessesuen
|
||||
- merenbach
|
||||
8
Procfile
8
Procfile
@@ -1,3 +1,5 @@
|
||||
controller: go run ./cmd/argocd-application-controller/main.go --app-resync 10
|
||||
api-server: go run ./cmd/argocd-server/main.go
|
||||
repo-server: go run ./cmd/argocd-repo-server/main.go
|
||||
controller: go run ./cmd/argocd-application-controller/main.go --app-resync 60
|
||||
api-server: go run ./cmd/argocd-server/main.go --insecure --disable-auth
|
||||
repo-server: go run ./cmd/argocd-repo-server/main.go --loglevel debug
|
||||
dex: sh -c "go run ./cmd/argocd-util/main.go gendexcfg -o `pwd`/dist/dex.yaml && docker run --rm -p 5556:5556 -p 5557:5557 -v `pwd`/dist/dex.yaml:/dex.yaml quay.io/coreos/dex:v2.10.0 serve /dex.yaml"
|
||||
redis: docker run --rm -p 6379:6379 redis:3.2.11
|
||||
|
||||
12
README.md
12
README.md
@@ -12,7 +12,7 @@ Application deployment and lifecycle management should be automated, auditable,
|
||||
|
||||
## Getting Started
|
||||
|
||||
Follow our [getting started guide](docs/GETTING_STARTED.md).
|
||||
Follow our [getting started guide](docs/getting_started.md).
|
||||
|
||||
## How it works
|
||||
|
||||
@@ -23,6 +23,10 @@ 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.
|
||||
|
||||
Argo CD is implemented as a kubernetes controller which continuously monitors running applications
|
||||
and compares the current, live state against the desired target state (as specified in the git repo).
|
||||
A deployed application whose live state deviates from the target state is considered out-of-sync.
|
||||
@@ -31,7 +35,7 @@ manually sync the live state back to the desired target state. Any modifications
|
||||
target state in the git repo can be automatically applied and reflected in the specified target
|
||||
environments.
|
||||
|
||||
For additional details, see [architecture overview](docs/ARCHITECTURE.md).
|
||||
For additional details, see [architecture overview](docs/architecture.md).
|
||||
|
||||
## Features
|
||||
|
||||
@@ -40,6 +44,8 @@ For additional details, see [architecture overview](docs/ARCHITECTURE.md).
|
||||
* Automated or manual syncing of applications to its target state
|
||||
* Web and CLI based visualization of applications and differences between live vs. target state
|
||||
* Rollback/Roll-anywhere to any application state committed in the git repository
|
||||
* SSO Integration (OIDC, LDAP, SAML 2.0, GitLab, Microsoft, LinkedIn)
|
||||
* Webhook Integration (GitHub, BitBucket, GitLab)
|
||||
|
||||
## What is ksonnet?
|
||||
|
||||
@@ -83,5 +89,3 @@ concise definition of kubernetes manifests
|
||||
* PreSync, PostSync, OutOfSync hooks
|
||||
* Customized application actions as Argo workflows
|
||||
* Blue/Green & canary upgrades
|
||||
* SSO Integration
|
||||
* GitHub & Docker webhooks
|
||||
|
||||
@@ -2,17 +2,18 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
argocd "github.com/argoproj/argo-cd"
|
||||
"github.com/argoproj/argo-cd"
|
||||
"github.com/argoproj/argo-cd/controller"
|
||||
"github.com/argoproj/argo-cd/errors"
|
||||
appclientset "github.com/argoproj/argo-cd/pkg/client/clientset/versioned"
|
||||
"github.com/argoproj/argo-cd/server/cluster"
|
||||
apirepository "github.com/argoproj/argo-cd/server/repository"
|
||||
"github.com/argoproj/argo-cd/util/cli"
|
||||
"github.com/argoproj/argo-cd/util/db"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
@@ -21,6 +22,7 @@ import (
|
||||
// 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).
|
||||
|
||||
"github.com/argoproj/argo-cd/reposerver"
|
||||
_ "k8s.io/client-go/plugin/pkg/client/auth/oidc"
|
||||
)
|
||||
@@ -29,19 +31,32 @@ const (
|
||||
// CLIName is the name of the CLI
|
||||
cliName = "argocd-application-controller"
|
||||
// Default time in seconds for application resync period
|
||||
defaultAppResyncPeriod = 600
|
||||
defaultAppResyncPeriod = 180
|
||||
)
|
||||
|
||||
func newCommand() *cobra.Command {
|
||||
var (
|
||||
clientConfig clientcmd.ClientConfig
|
||||
appResyncPeriod int64
|
||||
repoServerAddress string
|
||||
clientConfig clientcmd.ClientConfig
|
||||
appResyncPeriod int64
|
||||
repoServerAddress string
|
||||
statusProcessors int
|
||||
operationProcessors int
|
||||
logLevel string
|
||||
glogLevel int
|
||||
)
|
||||
var command = cobra.Command{
|
||||
Use: cliName,
|
||||
Short: "application-controller is a controller to operate on applications CRD",
|
||||
RunE: func(c *cobra.Command, args []string) error {
|
||||
level, err := log.ParseLevel(logLevel)
|
||||
errors.CheckError(err)
|
||||
log.SetLevel(level)
|
||||
|
||||
// Set the glog level for the k8s go-client
|
||||
_ = flag.CommandLine.Parse([]string{})
|
||||
_ = flag.Lookup("logtostderr").Value.Set("true")
|
||||
_ = flag.Lookup("v").Value.Set(strconv.Itoa(glogLevel))
|
||||
|
||||
config, err := clientConfig.ClientConfig()
|
||||
errors.CheckError(err)
|
||||
|
||||
@@ -56,25 +71,30 @@ func newCommand() *cobra.Command {
|
||||
Namespace: namespace,
|
||||
InstanceID: "",
|
||||
}
|
||||
db := db.NewDB(namespace, kubeClient)
|
||||
resyncDuration := time.Duration(appResyncPeriod) * time.Second
|
||||
apiRepoServer := apirepository.NewServer(namespace, kubeClient, appClient)
|
||||
clusterService := cluster.NewServer(namespace, kubeClient, appClient)
|
||||
appComparator := controller.NewKsonnetAppComparator(clusterService)
|
||||
repoClientset := reposerver.NewRepositoryServerClientset(repoServerAddress)
|
||||
appStateManager := controller.NewAppStateManager(db, appClient, repoClientset, namespace)
|
||||
appHealthManager := controller.NewAppHealthManager(db, namespace)
|
||||
|
||||
appController := controller.NewApplicationController(
|
||||
namespace,
|
||||
kubeClient,
|
||||
appClient,
|
||||
reposerver.NewRepositoryServerClientset(repoServerAddress),
|
||||
apiRepoServer,
|
||||
appComparator,
|
||||
db,
|
||||
appStateManager,
|
||||
appHealthManager,
|
||||
resyncDuration,
|
||||
&controllerConfig)
|
||||
secretController := controller.NewSecretController(kubeClient, repoClientset, resyncDuration, namespace)
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
log.Infof("Application Controller (version: %s) starting (namespace: %s)", argocd.GetVersion(), namespace)
|
||||
go appController.Run(ctx, 1)
|
||||
|
||||
go secretController.Run(ctx)
|
||||
go appController.Run(ctx, statusProcessors, operationProcessors)
|
||||
// Wait forever
|
||||
select {}
|
||||
},
|
||||
@@ -83,6 +103,10 @@ func newCommand() *cobra.Command {
|
||||
clientConfig = cli.AddKubectlFlagsToCmd(&command)
|
||||
command.Flags().Int64Var(&appResyncPeriod, "app-resync", defaultAppResyncPeriod, "Time period in seconds for application resync.")
|
||||
command.Flags().StringVar(&repoServerAddress, "repo-server", "localhost:8081", "Repo server address.")
|
||||
command.Flags().IntVar(&statusProcessors, "status-processors", 1, "Number of application status processors")
|
||||
command.Flags().IntVar(&operationProcessors, "operation-processors", 1, "Number of application operation processors")
|
||||
command.Flags().StringVar(&logLevel, "loglevel", "info", "Set the logging level. One of: debug|info|warn|error")
|
||||
command.Flags().IntVar(&glogLevel, "gloglevel", 0, "Set the glog logging level")
|
||||
return &command
|
||||
}
|
||||
|
||||
|
||||
@@ -5,20 +5,16 @@ import (
|
||||
"net"
|
||||
"os"
|
||||
|
||||
"github.com/argoproj/argo-cd"
|
||||
"github.com/argoproj/argo-cd/errors"
|
||||
"github.com/argoproj/argo-cd/util/cli"
|
||||
"github.com/argoproj/argo-cd/reposerver"
|
||||
"github.com/argoproj/argo-cd/reposerver/repository"
|
||||
"github.com/argoproj/argo-cd/util/cache"
|
||||
"github.com/argoproj/argo-cd/util/git"
|
||||
"github.com/argoproj/argo-cd/util/ksonnet"
|
||||
"github.com/go-redis/redis"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"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).
|
||||
"github.com/argoproj/argo-cd"
|
||||
"github.com/argoproj/argo-cd/reposerver"
|
||||
_ "k8s.io/client-go/plugin/pkg/client/auth/oidc"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -29,8 +25,7 @@ const (
|
||||
|
||||
func newCommand() *cobra.Command {
|
||||
var (
|
||||
clientConfig clientcmd.ClientConfig
|
||||
logLevel string
|
||||
logLevel string
|
||||
)
|
||||
var command = cobra.Command{
|
||||
Use: cliName,
|
||||
@@ -40,33 +35,36 @@ func newCommand() *cobra.Command {
|
||||
errors.CheckError(err)
|
||||
log.SetLevel(level)
|
||||
|
||||
config, err := clientConfig.ClientConfig()
|
||||
errors.CheckError(err)
|
||||
|
||||
namespace, _, err := clientConfig.Namespace()
|
||||
errors.CheckError(err)
|
||||
|
||||
kubeClientset := kubernetes.NewForConfigOrDie(config)
|
||||
|
||||
server := reposerver.NewServer(kubeClientset, namespace)
|
||||
nativeGitClient, err := git.NewNativeGitClient()
|
||||
errors.CheckError(err)
|
||||
grpc := server.CreateGRPC(nativeGitClient)
|
||||
server := reposerver.NewServer(git.NewFactory(), newCache())
|
||||
grpc := server.CreateGRPC()
|
||||
listener, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
|
||||
errors.CheckError(err)
|
||||
|
||||
log.Infof("argocd-repo-server %s serving on %s (namespace: %s)", argocd.GetVersion(), listener.Addr(), namespace)
|
||||
ksVers, err := ksonnet.KsonnetVersion()
|
||||
errors.CheckError(err)
|
||||
|
||||
log.Infof("argocd-repo-server %s serving on %s", argocd.GetVersion(), listener.Addr())
|
||||
log.Infof("ksonnet version: %s", ksVers)
|
||||
err = grpc.Serve(listener)
|
||||
errors.CheckError(err)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
clientConfig = cli.AddKubectlFlagsToCmd(&command)
|
||||
command.Flags().StringVar(&logLevel, "loglevel", "info", "Set the logging level. One of: debug|info|warn|error")
|
||||
return &command
|
||||
}
|
||||
|
||||
func newCache() cache.Cache {
|
||||
//return cache.NewInMemoryCache(repository.DefaultRepoCacheExpiration)
|
||||
client := redis.NewClient(&redis.Options{
|
||||
Addr: "localhost:6379",
|
||||
Password: "",
|
||||
DB: 0,
|
||||
})
|
||||
return cache.NewRedisCache(client, repository.DefaultRepoCacheExpiration)
|
||||
}
|
||||
|
||||
func main() {
|
||||
if err := newCommand().Execute(); err != nil {
|
||||
fmt.Println(err)
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"strconv"
|
||||
|
||||
"github.com/argoproj/argo-cd/errors"
|
||||
appclientset "github.com/argoproj/argo-cd/pkg/client/clientset/versioned"
|
||||
"github.com/argoproj/argo-cd/reposerver"
|
||||
@@ -15,11 +19,13 @@ import (
|
||||
// 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
|
||||
configMapName string
|
||||
disableAuth bool
|
||||
)
|
||||
var command = &cobra.Command{
|
||||
Use: cliName,
|
||||
@@ -30,6 +36,11 @@ func NewCommand() *cobra.Command {
|
||||
errors.CheckError(err)
|
||||
log.SetLevel(level)
|
||||
|
||||
// Set the glog level for the k8s go-client
|
||||
_ = flag.CommandLine.Parse([]string{})
|
||||
_ = flag.Lookup("logtostderr").Value.Set("true")
|
||||
_ = flag.Lookup("v").Value.Set(strconv.Itoa(glogLevel))
|
||||
|
||||
config, err := clientConfig.ClientConfig()
|
||||
errors.CheckError(err)
|
||||
|
||||
@@ -40,16 +51,33 @@ func NewCommand() *cobra.Command {
|
||||
appclientset := appclientset.NewForConfigOrDie(config)
|
||||
repoclientset := reposerver.NewRepositoryServerClientset(repoServerAddress)
|
||||
|
||||
argocd := server.NewServer(kubeclientset, appclientset, repoclientset, namespace, staticAssetsDir, configMapName)
|
||||
argocd.Run()
|
||||
argoCDOpts := server.ArgoCDServerOpts{
|
||||
Insecure: insecure,
|
||||
Namespace: namespace,
|
||||
StaticAssetsDir: staticAssetsDir,
|
||||
KubeClientset: kubeclientset,
|
||||
AppClientset: appclientset,
|
||||
RepoClientset: repoclientset,
|
||||
DisableAuth: disableAuth,
|
||||
}
|
||||
|
||||
for {
|
||||
argocd := server.NewServer(argoCDOpts)
|
||||
ctx := context.Background()
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
argocd.Run(ctx, 8080)
|
||||
cancel()
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
clientConfig = cli.AddKubectlFlagsToCmd(command)
|
||||
command.Flags().BoolVar(&insecure, "insecure", false, "Run server without TLS")
|
||||
command.Flags().StringVar(&staticAssetsDir, "staticassets", "", "Static assets directory path")
|
||||
command.Flags().StringVar(&logLevel, "loglevel", "info", "Set the logging level. One of: debug|info|warn|error")
|
||||
command.Flags().IntVar(&glogLevel, "gloglevel", 0, "Set the glog logging level")
|
||||
command.Flags().StringVar(&repoServerAddress, "repo-server", "localhost:8081", "Repo server address.")
|
||||
command.Flags().StringVar(&configMapName, "config-map", "", "Name of a Kubernetes config map to use.")
|
||||
command.Flags().BoolVar(&disableAuth, "disable-auth", false, "Disable client authentication")
|
||||
command.AddCommand(cli.NewVersionCmd(cliName))
|
||||
return command
|
||||
}
|
||||
|
||||
335
cmd/argocd-util/main.go
Normal file
335
cmd/argocd-util/main.go
Normal file
@@ -0,0 +1,335 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/argoproj/argo-cd/errors"
|
||||
"github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
|
||||
appclientset "github.com/argoproj/argo-cd/pkg/client/clientset/versioned"
|
||||
"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/settings"
|
||||
"github.com/ghodss/yaml"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"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).
|
||||
_ "k8s.io/client-go/plugin/pkg/client/auth/oidc"
|
||||
)
|
||||
|
||||
const (
|
||||
// CLIName is the name of the CLI
|
||||
cliName = "argocd-util"
|
||||
|
||||
// YamlSeparator separates sections of a YAML file
|
||||
yamlSeparator = "\n---\n"
|
||||
)
|
||||
|
||||
// NewCommand returns a new instance of an argocd command
|
||||
func NewCommand() *cobra.Command {
|
||||
var (
|
||||
logLevel string
|
||||
)
|
||||
|
||||
var command = &cobra.Command{
|
||||
Use: cliName,
|
||||
Short: "argocd-util has internal tools used by ArgoCD",
|
||||
Run: func(c *cobra.Command, args []string) {
|
||||
c.HelpFunc()(c, args)
|
||||
},
|
||||
}
|
||||
|
||||
command.AddCommand(cli.NewVersionCmd(cliName))
|
||||
command.AddCommand(NewRunDexCommand())
|
||||
command.AddCommand(NewGenDexConfigCommand())
|
||||
command.AddCommand(NewImportCommand())
|
||||
command.AddCommand(NewExportCommand())
|
||||
|
||||
command.Flags().StringVar(&logLevel, "loglevel", "info", "Set the logging level. One of: debug|info|warn|error")
|
||||
return command
|
||||
}
|
||||
|
||||
func NewRunDexCommand() *cobra.Command {
|
||||
var (
|
||||
clientConfig clientcmd.ClientConfig
|
||||
)
|
||||
var command = cobra.Command{
|
||||
Use: "rundex",
|
||||
Short: "Runs dex generating a config using settings from the ArgoCD configmap and secret",
|
||||
RunE: func(c *cobra.Command, args []string) error {
|
||||
_, err := exec.LookPath("dex")
|
||||
errors.CheckError(err)
|
||||
config, err := clientConfig.ClientConfig()
|
||||
errors.CheckError(err)
|
||||
namespace, _, err := clientConfig.Namespace()
|
||||
errors.CheckError(err)
|
||||
kubeClientset := kubernetes.NewForConfigOrDie(config)
|
||||
settingsMgr := settings.NewSettingsManager(kubeClientset, namespace)
|
||||
settings, err := settingsMgr.GetSettings()
|
||||
errors.CheckError(err)
|
||||
ctx := context.Background()
|
||||
settingsMgr.StartNotifier(ctx, settings)
|
||||
updateCh := make(chan struct{}, 1)
|
||||
settingsMgr.Subscribe(updateCh)
|
||||
|
||||
for {
|
||||
var cmd *exec.Cmd
|
||||
dexCfgBytes, err := dex.GenerateDexConfigYAML(settings)
|
||||
errors.CheckError(err)
|
||||
if len(dexCfgBytes) == 0 {
|
||||
log.Infof("dex is not configured")
|
||||
} else {
|
||||
err = ioutil.WriteFile("/tmp/dex.yaml", dexCfgBytes, 0644)
|
||||
errors.CheckError(err)
|
||||
log.Info(string(dexCfgBytes))
|
||||
cmd = exec.Command("dex", "serve", "/tmp/dex.yaml")
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
err = cmd.Start()
|
||||
errors.CheckError(err)
|
||||
}
|
||||
|
||||
// loop until the dex config changes
|
||||
for {
|
||||
<-updateCh
|
||||
newDexCfgBytes, err := dex.GenerateDexConfigYAML(settings)
|
||||
errors.CheckError(err)
|
||||
if string(newDexCfgBytes) != string(dexCfgBytes) {
|
||||
log.Infof("dex config modified. restarting dex")
|
||||
if cmd != nil && cmd.Process != nil {
|
||||
err = cmd.Process.Signal(syscall.SIGTERM)
|
||||
errors.CheckError(err)
|
||||
_, err = cmd.Process.Wait()
|
||||
errors.CheckError(err)
|
||||
}
|
||||
break
|
||||
} else {
|
||||
log.Infof("dex config unmodified")
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
clientConfig = cli.AddKubectlFlagsToCmd(&command)
|
||||
return &command
|
||||
}
|
||||
|
||||
func NewGenDexConfigCommand() *cobra.Command {
|
||||
var (
|
||||
clientConfig clientcmd.ClientConfig
|
||||
out string
|
||||
)
|
||||
var command = cobra.Command{
|
||||
Use: "gendexcfg",
|
||||
Short: "Generates a dex config from ArgoCD settings",
|
||||
RunE: func(c *cobra.Command, args []string) error {
|
||||
config, err := clientConfig.ClientConfig()
|
||||
errors.CheckError(err)
|
||||
namespace, _, err := clientConfig.Namespace()
|
||||
errors.CheckError(err)
|
||||
kubeClientset := kubernetes.NewForConfigOrDie(config)
|
||||
settingsMgr := settings.NewSettingsManager(kubeClientset, namespace)
|
||||
settings, err := settingsMgr.GetSettings()
|
||||
errors.CheckError(err)
|
||||
dexCfgBytes, err := dex.GenerateDexConfigYAML(settings)
|
||||
errors.CheckError(err)
|
||||
if len(dexCfgBytes) == 0 {
|
||||
log.Infof("dex is not configured")
|
||||
return nil
|
||||
}
|
||||
if out == "" {
|
||||
fmt.Printf(string(dexCfgBytes))
|
||||
} else {
|
||||
err = ioutil.WriteFile(out, dexCfgBytes, 0644)
|
||||
errors.CheckError(err)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
clientConfig = cli.AddKubectlFlagsToCmd(&command)
|
||||
command.Flags().StringVarP(&out, "out", "o", "", "Output to the specified file instead of stdout")
|
||||
return &command
|
||||
}
|
||||
|
||||
// NewImportCommand defines a new command for exporting Kubernetes and Argo CD resources.
|
||||
func NewImportCommand() *cobra.Command {
|
||||
var (
|
||||
clientConfig clientcmd.ClientConfig
|
||||
)
|
||||
var command = cobra.Command{
|
||||
Use: "import SOURCE",
|
||||
Short: "Import Argo CD data from stdin (specify `-') or a file",
|
||||
RunE: func(c *cobra.Command, args []string) error {
|
||||
if len(args) != 1 {
|
||||
c.HelpFunc()(c, args)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
var (
|
||||
input []byte
|
||||
err error
|
||||
newSettings *settings.ArgoCDSettings
|
||||
newRepos []*v1alpha1.Repository
|
||||
newClusters []*v1alpha1.Cluster
|
||||
newApps []*v1alpha1.Application
|
||||
)
|
||||
|
||||
if in := args[0]; in == "-" {
|
||||
input, err = ioutil.ReadAll(os.Stdin)
|
||||
errors.CheckError(err)
|
||||
} else {
|
||||
input, err = ioutil.ReadFile(in)
|
||||
errors.CheckError(err)
|
||||
}
|
||||
inputStrings := strings.Split(string(input), yamlSeparator)
|
||||
|
||||
err = yaml.Unmarshal([]byte(inputStrings[0]), &newSettings)
|
||||
errors.CheckError(err)
|
||||
|
||||
err = yaml.Unmarshal([]byte(inputStrings[1]), &newRepos)
|
||||
errors.CheckError(err)
|
||||
|
||||
err = yaml.Unmarshal([]byte(inputStrings[2]), &newClusters)
|
||||
errors.CheckError(err)
|
||||
|
||||
err = yaml.Unmarshal([]byte(inputStrings[3]), &newApps)
|
||||
errors.CheckError(err)
|
||||
|
||||
config, err := clientConfig.ClientConfig()
|
||||
errors.CheckError(err)
|
||||
namespace, _, err := clientConfig.Namespace()
|
||||
errors.CheckError(err)
|
||||
kubeClientset := kubernetes.NewForConfigOrDie(config)
|
||||
|
||||
settingsMgr := settings.NewSettingsManager(kubeClientset, namespace)
|
||||
err = settingsMgr.SaveSettings(newSettings)
|
||||
errors.CheckError(err)
|
||||
db := db.NewDB(namespace, kubeClientset)
|
||||
|
||||
for _, repo := range newRepos {
|
||||
_, err := db.CreateRepository(context.Background(), repo)
|
||||
if err != nil {
|
||||
log.Warn(err)
|
||||
}
|
||||
}
|
||||
|
||||
for _, cluster := range newClusters {
|
||||
_, err := db.CreateCluster(context.Background(), cluster)
|
||||
if err != nil {
|
||||
log.Warn(err)
|
||||
}
|
||||
}
|
||||
|
||||
appClientset := appclientset.NewForConfigOrDie(config)
|
||||
for _, app := range newApps {
|
||||
out, err := appClientset.ArgoprojV1alpha1().Applications(namespace).Create(app)
|
||||
errors.CheckError(err)
|
||||
log.Println(out)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
clientConfig = cli.AddKubectlFlagsToCmd(&command)
|
||||
|
||||
return &command
|
||||
}
|
||||
|
||||
// NewExportCommand defines a new command for exporting Kubernetes and Argo CD resources.
|
||||
func NewExportCommand() *cobra.Command {
|
||||
var (
|
||||
clientConfig clientcmd.ClientConfig
|
||||
out string
|
||||
)
|
||||
var command = cobra.Command{
|
||||
Use: "export",
|
||||
Short: "Export all Argo CD data to stdout (default) or a file",
|
||||
RunE: func(c *cobra.Command, args []string) error {
|
||||
config, err := clientConfig.ClientConfig()
|
||||
errors.CheckError(err)
|
||||
namespace, _, err := clientConfig.Namespace()
|
||||
errors.CheckError(err)
|
||||
kubeClientset := kubernetes.NewForConfigOrDie(config)
|
||||
|
||||
settingsMgr := settings.NewSettingsManager(kubeClientset, namespace)
|
||||
settings, err := settingsMgr.GetSettings()
|
||||
errors.CheckError(err)
|
||||
// certificate data is included in secrets that are exported alongside
|
||||
settings.Certificate = nil
|
||||
settingsData, err := yaml.Marshal(settings)
|
||||
errors.CheckError(err)
|
||||
|
||||
db := db.NewDB(namespace, kubeClientset)
|
||||
clusters, err := db.ListClusters(context.Background())
|
||||
errors.CheckError(err)
|
||||
clusterData, err := yaml.Marshal(clusters.Items)
|
||||
errors.CheckError(err)
|
||||
|
||||
repos, err := db.ListRepositories(context.Background())
|
||||
errors.CheckError(err)
|
||||
repoData, err := yaml.Marshal(repos.Items)
|
||||
errors.CheckError(err)
|
||||
|
||||
appClientset := appclientset.NewForConfigOrDie(config)
|
||||
apps, err := appClientset.ArgoprojV1alpha1().Applications(namespace).List(metav1.ListOptions{})
|
||||
errors.CheckError(err)
|
||||
|
||||
// remove extraneous cruft from output
|
||||
for idx, app := range apps.Items {
|
||||
apps.Items[idx].ObjectMeta = metav1.ObjectMeta{
|
||||
Name: app.ObjectMeta.Name,
|
||||
Finalizers: app.ObjectMeta.Finalizers,
|
||||
}
|
||||
apps.Items[idx].Status = v1alpha1.ApplicationStatus{
|
||||
History: app.Status.History,
|
||||
}
|
||||
apps.Items[idx].Operation = nil
|
||||
}
|
||||
appsData, err := yaml.Marshal(apps.Items)
|
||||
errors.CheckError(err)
|
||||
|
||||
outputStrings := []string{
|
||||
string(settingsData),
|
||||
string(repoData),
|
||||
string(clusterData),
|
||||
string(appsData),
|
||||
}
|
||||
output := strings.Join(outputStrings, yamlSeparator)
|
||||
|
||||
if out == "-" {
|
||||
fmt.Println(output)
|
||||
} else {
|
||||
err = ioutil.WriteFile(out, []byte(output), 0644)
|
||||
errors.CheckError(err)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
clientConfig = cli.AddKubectlFlagsToCmd(&command)
|
||||
command.Flags().StringVarP(&out, "out", "o", "-", "Output to the specified file instead of stdout")
|
||||
|
||||
return &command
|
||||
}
|
||||
|
||||
func main() {
|
||||
if err := NewCommand().Execute(); err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -26,7 +26,7 @@ import (
|
||||
func NewClusterCommand(clientOpts *argocdclient.ClientOptions, pathOpts *clientcmd.PathOptions) *cobra.Command {
|
||||
var command = &cobra.Command{
|
||||
Use: "cluster",
|
||||
Short: fmt.Sprintf("%s cluster COMMAND", cliName),
|
||||
Short: "Manage cluster credentials",
|
||||
Run: func(c *cobra.Command, args []string) {
|
||||
c.HelpFunc()(c, args)
|
||||
os.Exit(1)
|
||||
@@ -42,6 +42,9 @@ 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
|
||||
)
|
||||
var command = &cobra.Command{
|
||||
Use: "add",
|
||||
Short: fmt.Sprintf("%s cluster add CONTEXT", cliName),
|
||||
@@ -49,7 +52,7 @@ func NewClusterAddCommand(clientOpts *argocdclient.ClientOptions, pathOpts *clie
|
||||
var configAccess clientcmd.ConfigAccess = pathOpts
|
||||
if len(args) == 0 {
|
||||
log.Error("Choose a context name from:")
|
||||
printContexts(configAccess)
|
||||
printKubeContexts(configAccess)
|
||||
os.Exit(1)
|
||||
}
|
||||
config, err := configAccess.GetStartingConfig()
|
||||
@@ -65,29 +68,32 @@ func NewClusterAddCommand(clientOpts *argocdclient.ClientOptions, pathOpts *clie
|
||||
conf, err := clientConfig.ClientConfig()
|
||||
errors.CheckError(err)
|
||||
|
||||
if conf.Username == "" || conf.Password == "" {
|
||||
// Install RBAC resources for managing the cluster if username and password are not specified
|
||||
conf.BearerToken = common.InstallClusterManagerRBAC(conf)
|
||||
}
|
||||
// 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)
|
||||
clst, err = clusterIf.Create(context.Background(), clst)
|
||||
clst := NewCluster(args[0], conf, managerBearerToken)
|
||||
if inCluster {
|
||||
clst.Server = common.KubernetesInternalAPIServerAddr
|
||||
}
|
||||
clstCreateReq := cluster.ClusterCreateRequest{Cluster: clst}
|
||||
clst, err = clusterIf.Create(context.Background(), &clstCreateReq)
|
||||
errors.CheckError(err)
|
||||
fmt.Printf("Cluster '%s' added\n", clst.Name)
|
||||
},
|
||||
}
|
||||
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)")
|
||||
return command
|
||||
}
|
||||
|
||||
func printContexts(ca clientcmd.ConfigAccess) {
|
||||
func printKubeContexts(ca clientcmd.ConfigAccess) {
|
||||
config, err := ca.GetStartingConfig()
|
||||
errors.CheckError(err)
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
||||
defer func() { _ = w.Flush() }()
|
||||
columnNames := []string{"CURRENT", "NAME", "CLUSTER", "AUTHINFO", "NAMESPACE"}
|
||||
columnNames := []string{"CURRENT", "NAME", "CLUSTER", "SERVER"}
|
||||
_, err = fmt.Fprintf(w, "%s\n", strings.Join(columnNames, "\t"))
|
||||
errors.CheckError(err)
|
||||
|
||||
@@ -100,16 +106,17 @@ func printContexts(ca clientcmd.ConfigAccess) {
|
||||
|
||||
for _, name := range contextNames {
|
||||
context := config.Contexts[name]
|
||||
cluster := config.Clusters[context.Cluster]
|
||||
prefix := " "
|
||||
if config.CurrentContext == name {
|
||||
prefix = "*"
|
||||
}
|
||||
_, err := fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\n", prefix, name, context.Cluster, context.AuthInfo, context.Namespace)
|
||||
_, err := fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", prefix, name, context.Cluster, cluster.Server)
|
||||
errors.CheckError(err)
|
||||
}
|
||||
}
|
||||
|
||||
func NewCluster(name string, conf *rest.Config) *argoappv1.Cluster {
|
||||
func NewCluster(name string, conf *rest.Config, managerBearerToken string) *argoappv1.Cluster {
|
||||
tlsClientConfig := argoappv1.TLSClientConfig{
|
||||
Insecure: conf.TLSClientConfig.Insecure,
|
||||
ServerName: conf.TLSClientConfig.ServerName,
|
||||
@@ -136,9 +143,7 @@ func NewCluster(name string, conf *rest.Config) *argoappv1.Cluster {
|
||||
Server: conf.Host,
|
||||
Name: name,
|
||||
Config: argoappv1.ClusterConfig{
|
||||
Username: conf.Username,
|
||||
Password: conf.Password,
|
||||
BearerToken: conf.BearerToken,
|
||||
BearerToken: managerBearerToken,
|
||||
TLSClientConfig: tlsClientConfig,
|
||||
},
|
||||
}
|
||||
@@ -149,7 +154,7 @@ func NewCluster(name string, conf *rest.Config) *argoappv1.Cluster {
|
||||
func NewClusterGetCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
|
||||
var command = &cobra.Command{
|
||||
Use: "get",
|
||||
Short: fmt.Sprintf("%s cluster get SERVER", cliName),
|
||||
Short: "Get cluster information",
|
||||
Run: func(c *cobra.Command, args []string) {
|
||||
if len(args) == 0 {
|
||||
c.HelpFunc()(c, args)
|
||||
@@ -173,7 +178,7 @@ func NewClusterGetCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command
|
||||
func NewClusterRemoveCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
|
||||
var command = &cobra.Command{
|
||||
Use: "rm",
|
||||
Short: fmt.Sprintf("%s cluster rm SERVER", cliName),
|
||||
Short: "Remove cluster credentials",
|
||||
Run: func(c *cobra.Command, args []string) {
|
||||
if len(args) == 0 {
|
||||
c.HelpFunc()(c, args)
|
||||
@@ -196,16 +201,16 @@ func NewClusterRemoveCommand(clientOpts *argocdclient.ClientOptions) *cobra.Comm
|
||||
func NewClusterListCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
|
||||
var command = &cobra.Command{
|
||||
Use: "list",
|
||||
Short: fmt.Sprintf("%s cluster list", cliName),
|
||||
Short: "List configured clusters",
|
||||
Run: func(c *cobra.Command, args []string) {
|
||||
conn, clusterIf := argocdclient.NewClientOrDie(clientOpts).NewClusterClientOrDie()
|
||||
defer util.Close(conn)
|
||||
clusters, err := clusterIf.List(context.Background(), &cluster.ClusterQuery{})
|
||||
errors.CheckError(err)
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
||||
fmt.Fprintf(w, "SERVER\tNAME\n")
|
||||
fmt.Fprintf(w, "SERVER\tNAME\tSTATUS\tMESSAGE\n")
|
||||
for _, c := range clusters.Items {
|
||||
fmt.Fprintf(w, "%s\t%s\n", c.Server, c.Name)
|
||||
fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", c.Server, c.Name, c.ConnectionState.Status, c.ConnectionState.Message)
|
||||
}
|
||||
_ = w.Flush()
|
||||
},
|
||||
|
||||
84
cmd/argocd/commands/context.go
Normal file
84
cmd/argocd/commands/context.go
Normal file
@@ -0,0 +1,84 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/argoproj/argo-cd/errors"
|
||||
argocdclient "github.com/argoproj/argo-cd/pkg/apiclient"
|
||||
"github.com/argoproj/argo-cd/util/localconfig"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// NewContextCommand returns a new instance of an `argocd ctx` command
|
||||
func NewContextCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
|
||||
var command = &cobra.Command{
|
||||
Use: "context",
|
||||
Aliases: []string{"ctx"},
|
||||
Short: "Switch between contexts",
|
||||
Run: func(c *cobra.Command, args []string) {
|
||||
if len(args) == 0 {
|
||||
printArgoCDContexts(clientOpts.ConfigPath)
|
||||
return
|
||||
}
|
||||
ctxName := args[0]
|
||||
argoCDDir, err := localconfig.DefaultConfigDir()
|
||||
errors.CheckError(err)
|
||||
prevCtxFile := path.Join(argoCDDir, ".prev-ctx")
|
||||
|
||||
if ctxName == "-" {
|
||||
prevCtxBytes, err := ioutil.ReadFile(prevCtxFile)
|
||||
errors.CheckError(err)
|
||||
ctxName = string(prevCtxBytes)
|
||||
}
|
||||
localCfg, err := localconfig.ReadLocalConfig(clientOpts.ConfigPath)
|
||||
errors.CheckError(err)
|
||||
if localCfg.CurrentContext == ctxName {
|
||||
fmt.Printf("Already at context '%s'\n", localCfg.CurrentContext)
|
||||
return
|
||||
}
|
||||
if _, err = localCfg.ResolveContext(ctxName); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
prevCtx := localCfg.CurrentContext
|
||||
localCfg.CurrentContext = ctxName
|
||||
err = localconfig.WriteLocalConfig(*localCfg, clientOpts.ConfigPath)
|
||||
errors.CheckError(err)
|
||||
err = ioutil.WriteFile(prevCtxFile, []byte(prevCtx), 0644)
|
||||
errors.CheckError(err)
|
||||
fmt.Printf("Switched to context '%s'\n", localCfg.CurrentContext)
|
||||
},
|
||||
}
|
||||
return command
|
||||
}
|
||||
|
||||
func printArgoCDContexts(configPath string) {
|
||||
localCfg, err := localconfig.ReadLocalConfig(configPath)
|
||||
errors.CheckError(err)
|
||||
if localCfg == nil {
|
||||
log.Fatalf("No contexts defined in %s", configPath)
|
||||
}
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
||||
defer func() { _ = w.Flush() }()
|
||||
columnNames := []string{"CURRENT", "NAME", "SERVER"}
|
||||
_, err = fmt.Fprintf(w, "%s\n", strings.Join(columnNames, "\t"))
|
||||
errors.CheckError(err)
|
||||
|
||||
for _, contextRef := range localCfg.Contexts {
|
||||
context, err := localCfg.ResolveContext(contextRef.Name)
|
||||
if err != nil {
|
||||
log.Warnf("Context '%s' had error: %v", contextRef.Name, err)
|
||||
}
|
||||
prefix := " "
|
||||
if localCfg.CurrentContext == context.Name {
|
||||
prefix = "*"
|
||||
}
|
||||
_, err = fmt.Fprintf(w, "%s\t%s\t%s\n", prefix, context.Name, context.Server.Server)
|
||||
errors.CheckError(err)
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,11 @@ func NewInstallCommand() *cobra.Command {
|
||||
Run: func(c *cobra.Command, args []string) {
|
||||
conf, err := clientConfig.ClientConfig()
|
||||
errors.CheckError(err)
|
||||
namespace, wasSpecified, err := clientConfig.Namespace()
|
||||
errors.CheckError(err)
|
||||
if wasSpecified {
|
||||
installOpts.Namespace = namespace
|
||||
}
|
||||
installer, err := install.NewInstaller(conf, installOpts)
|
||||
errors.CheckError(err)
|
||||
installer.Install()
|
||||
@@ -28,14 +33,43 @@ func NewInstallCommand() *cobra.Command {
|
||||
}
|
||||
command.Flags().BoolVar(&installOpts.Upgrade, "upgrade", false, "upgrade controller/ui deployments and configmap if already installed")
|
||||
command.Flags().BoolVar(&installOpts.DryRun, "dry-run", false, "print the kubernetes manifests to stdout instead of installing")
|
||||
command.Flags().BoolVar(&installOpts.ConfigSuperuser, "config-superuser", false, "create or update a superuser username and password")
|
||||
command.Flags().StringVar(&installOpts.ConfigMap, "config-map", "", "apply settings from a Kubernetes config map")
|
||||
command.Flags().StringVar(&installOpts.Namespace, "install-namespace", install.DefaultInstallNamespace, "install into a specific namespace")
|
||||
command.Flags().StringVar(&installOpts.SuperuserPassword, "superuser-password", "", "password for super user")
|
||||
command.Flags().StringVar(&installOpts.ControllerImage, "controller-image", install.DefaultControllerImage, "use a specified controller image")
|
||||
command.Flags().StringVar(&installOpts.ServerImage, "server-image", install.DefaultServerImage, "use a specified api server image")
|
||||
command.Flags().StringVar(&installOpts.UIImage, "ui-image", install.DefaultUIImage, "use a specified ui image")
|
||||
command.Flags().StringVar(&installOpts.RepoServerImage, "repo-server-image", install.DefaultRepoServerImage, "use a specified repo server image")
|
||||
command.Flags().StringVar(&installOpts.ImagePullPolicy, "image-pull-policy", "", "set the image pull policy of the pod specs")
|
||||
clientConfig = cli.AddKubectlFlagsToCmd(command)
|
||||
command.AddCommand(newSettingsCommand())
|
||||
return command
|
||||
}
|
||||
|
||||
// newSettingsCommand returns a new instance of `argocd install settings` command
|
||||
func newSettingsCommand() *cobra.Command {
|
||||
var (
|
||||
clientConfig clientcmd.ClientConfig
|
||||
installOpts install.InstallOptions
|
||||
)
|
||||
var command = &cobra.Command{
|
||||
Use: "settings",
|
||||
Short: "Creates or updates ArgoCD settings",
|
||||
Long: "Creates or updates ArgoCD settings",
|
||||
Run: func(c *cobra.Command, args []string) {
|
||||
conf, err := clientConfig.ClientConfig()
|
||||
errors.CheckError(err)
|
||||
namespace, wasSpecified, err := clientConfig.Namespace()
|
||||
errors.CheckError(err)
|
||||
if wasSpecified {
|
||||
installOpts.Namespace = namespace
|
||||
}
|
||||
installer, err := install.NewInstaller(conf, installOpts)
|
||||
errors.CheckError(err)
|
||||
installer.InstallSettings()
|
||||
},
|
||||
}
|
||||
command.Flags().BoolVar(&installOpts.UpdateSuperuser, "update-superuser", false, "force updating the superuser password")
|
||||
command.Flags().StringVar(&installOpts.SuperuserPassword, "superuser-password", "", "password for super user")
|
||||
command.Flags().BoolVar(&installOpts.UpdateSignature, "update-signature", false, "force updating the server-side token signing signature")
|
||||
clientConfig = cli.AddKubectlFlagsToCmd(command)
|
||||
return command
|
||||
}
|
||||
|
||||
276
cmd/argocd/commands/login.go
Normal file
276
cmd/argocd/commands/login.go
Normal file
@@ -0,0 +1,276 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/argoproj/argo-cd/common"
|
||||
"github.com/argoproj/argo-cd/errors"
|
||||
argocdclient "github.com/argoproj/argo-cd/pkg/apiclient"
|
||||
"github.com/argoproj/argo-cd/server/session"
|
||||
"github.com/argoproj/argo-cd/server/settings"
|
||||
"github.com/argoproj/argo-cd/util"
|
||||
"github.com/argoproj/argo-cd/util/cli"
|
||||
grpc_util "github.com/argoproj/argo-cd/util/grpc"
|
||||
"github.com/argoproj/argo-cd/util/localconfig"
|
||||
jwt "github.com/dgrijalva/jwt-go"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/skratchdot/open-golang/open"
|
||||
"github.com/spf13/cobra"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
// NewLoginCommand returns a new instance of `argocd login` command
|
||||
func NewLoginCommand(globalClientOpts *argocdclient.ClientOptions) *cobra.Command {
|
||||
var (
|
||||
ctxName string
|
||||
username string
|
||||
password string
|
||||
sso bool
|
||||
)
|
||||
var command = &cobra.Command{
|
||||
Use: "login SERVER",
|
||||
Short: "Log in to Argo CD",
|
||||
Long: "Log in to Argo CD",
|
||||
Run: func(c *cobra.Command, args []string) {
|
||||
if len(args) == 0 {
|
||||
c.HelpFunc()(c, args)
|
||||
os.Exit(1)
|
||||
}
|
||||
server := args[0]
|
||||
tlsTestResult, err := grpc_util.TestTLS(server)
|
||||
errors.CheckError(err)
|
||||
if !tlsTestResult.TLS {
|
||||
if !globalClientOpts.PlainText {
|
||||
if !cli.AskToProceed("WARNING: server is not configured with TLS. Proceed (y/n)? ") {
|
||||
os.Exit(1)
|
||||
}
|
||||
globalClientOpts.PlainText = true
|
||||
}
|
||||
} else if tlsTestResult.InsecureErr != nil {
|
||||
if !globalClientOpts.Insecure {
|
||||
if !cli.AskToProceed(fmt.Sprintf("WARNING: server certificate had error: %s. Proceed insecurely (y/n)? ", tlsTestResult.InsecureErr)) {
|
||||
os.Exit(1)
|
||||
}
|
||||
globalClientOpts.Insecure = true
|
||||
}
|
||||
}
|
||||
clientOpts := argocdclient.ClientOptions{
|
||||
ConfigPath: "",
|
||||
ServerAddr: server,
|
||||
Insecure: globalClientOpts.Insecure,
|
||||
PlainText: globalClientOpts.PlainText,
|
||||
}
|
||||
acdClient := argocdclient.NewClientOrDie(&clientOpts)
|
||||
setConn, setIf := acdClient.NewSettingsClientOrDie()
|
||||
defer util.Close(setConn)
|
||||
|
||||
if ctxName == "" {
|
||||
ctxName = server
|
||||
}
|
||||
|
||||
// Perform the login
|
||||
var tokenString string
|
||||
if !sso {
|
||||
tokenString = passwordLogin(acdClient, username, password)
|
||||
} else {
|
||||
acdSet, err := setIf.Get(context.Background(), &settings.SettingsQuery{})
|
||||
errors.CheckError(err)
|
||||
if !ssoConfigured(acdSet) {
|
||||
log.Fatalf("ArgoCD instance is not configured with SSO")
|
||||
}
|
||||
tokenString = oauth2Login(server, clientOpts.PlainText)
|
||||
// The token which we just received from the OAuth2 flow, was from dex. ArgoCD
|
||||
// currently does not back dex with any kind of persistent storage (it is run
|
||||
// in-memory). As a result, this token cannot be used in any permanent capacity.
|
||||
// Restarts of dex will result in a different signing key, and sessions becoming
|
||||
// invalid. Instead we turn-around and ask ArgoCD to re-sign the token (who *does*
|
||||
// have persistence of signing keys), and is what we store in the config. Should we
|
||||
// ever decide to have a database layer for dex, the next line can be removed.
|
||||
tokenString = tokenLogin(acdClient, tokenString)
|
||||
}
|
||||
|
||||
parser := &jwt.Parser{
|
||||
SkipClaimsValidation: true,
|
||||
}
|
||||
claims := jwt.MapClaims{}
|
||||
_, _, err = parser.ParseUnverified(tokenString, &claims)
|
||||
errors.CheckError(err)
|
||||
|
||||
fmt.Printf("'%s' logged in successfully\n", userDisplayName(claims))
|
||||
// login successful. Persist the config
|
||||
localCfg, err := localconfig.ReadLocalConfig(globalClientOpts.ConfigPath)
|
||||
errors.CheckError(err)
|
||||
if localCfg == nil {
|
||||
localCfg = &localconfig.LocalConfig{}
|
||||
}
|
||||
localCfg.UpsertServer(localconfig.Server{
|
||||
Server: server,
|
||||
PlainText: globalClientOpts.PlainText,
|
||||
Insecure: globalClientOpts.Insecure,
|
||||
})
|
||||
localCfg.UpsertUser(localconfig.User{
|
||||
Name: ctxName,
|
||||
AuthToken: tokenString,
|
||||
})
|
||||
if ctxName == "" {
|
||||
ctxName = server
|
||||
}
|
||||
localCfg.CurrentContext = ctxName
|
||||
localCfg.UpsertContext(localconfig.ContextRef{
|
||||
Name: ctxName,
|
||||
User: ctxName,
|
||||
Server: server,
|
||||
})
|
||||
err = localconfig.WriteLocalConfig(*localCfg, globalClientOpts.ConfigPath)
|
||||
errors.CheckError(err)
|
||||
fmt.Printf("Context '%s' updated\n", ctxName)
|
||||
},
|
||||
}
|
||||
command.Flags().StringVar(&ctxName, "name", "", "name to use for the context")
|
||||
command.Flags().StringVar(&username, "username", "", "the username of an account to authenticate")
|
||||
command.Flags().StringVar(&password, "password", "", "the password of an account to authenticate")
|
||||
command.Flags().BoolVar(&sso, "sso", false, "Perform SSO login")
|
||||
return command
|
||||
}
|
||||
|
||||
func userDisplayName(claims jwt.MapClaims) string {
|
||||
if email, ok := claims["email"]; ok && email != nil {
|
||||
return email.(string)
|
||||
}
|
||||
if name, ok := claims["name"]; ok && name != nil {
|
||||
return name.(string)
|
||||
}
|
||||
return claims["sub"].(string)
|
||||
}
|
||||
|
||||
func ssoConfigured(set *settings.Settings) bool {
|
||||
return set.DexConfig != nil && len(set.DexConfig.Connectors) > 0
|
||||
}
|
||||
|
||||
// getFreePort asks the kernel for a free open port that is ready to use.
|
||||
func getFreePort() (int, error) {
|
||||
ln, err := net.Listen("tcp", "[::]:0")
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return ln.Addr().(*net.TCPAddr).Port, ln.Close()
|
||||
}
|
||||
|
||||
// oauth2Login opens a browser, runs a temporary HTTP server to delegate OAuth2 login flow and returns the JWT token
|
||||
func oauth2Login(host string, plaintext bool) string {
|
||||
ctx := context.Background()
|
||||
port, err := getFreePort()
|
||||
errors.CheckError(err)
|
||||
var scheme = "https"
|
||||
if plaintext {
|
||||
scheme = "http"
|
||||
}
|
||||
conf := &oauth2.Config{
|
||||
ClientID: common.ArgoCDCLIClientAppID,
|
||||
Scopes: []string{"openid", "profile", "email", "groups", "offline_access"},
|
||||
Endpoint: oauth2.Endpoint{
|
||||
AuthURL: fmt.Sprintf("%s://%s%s/auth", scheme, host, common.DexAPIEndpoint),
|
||||
TokenURL: fmt.Sprintf("%s://%s%s/token", scheme, host, common.DexAPIEndpoint),
|
||||
},
|
||||
RedirectURL: fmt.Sprintf("http://localhost:%d/auth/callback", port),
|
||||
}
|
||||
srv := &http.Server{Addr: ":" + strconv.Itoa(port)}
|
||||
var tokenString string
|
||||
loginCompleted := make(chan struct{})
|
||||
|
||||
callbackHandler := func(w http.ResponseWriter, r *http.Request) {
|
||||
defer func() {
|
||||
loginCompleted <- struct{}{}
|
||||
}()
|
||||
|
||||
// Authorization redirect callback from OAuth2 auth flow.
|
||||
if errMsg := r.FormValue("error"); errMsg != "" {
|
||||
http.Error(w, errMsg+": "+r.FormValue("error_description"), http.StatusBadRequest)
|
||||
log.Fatal(errMsg)
|
||||
return
|
||||
}
|
||||
code := r.FormValue("code")
|
||||
if code == "" {
|
||||
errMsg := fmt.Sprintf("no code in request: %q", r.Form)
|
||||
http.Error(w, errMsg, http.StatusBadRequest)
|
||||
log.Fatal(errMsg)
|
||||
return
|
||||
}
|
||||
tok, err := conf.Exchange(ctx, code)
|
||||
errors.CheckError(err)
|
||||
log.Info("Authentication successful")
|
||||
|
||||
var ok bool
|
||||
tokenString, ok = tok.Extra("id_token").(string)
|
||||
if !ok {
|
||||
errMsg := "no id_token in token response"
|
||||
http.Error(w, errMsg, http.StatusInternalServerError)
|
||||
log.Fatal(errMsg)
|
||||
return
|
||||
}
|
||||
|
||||
log.Debugf("Token: %s", tokenString)
|
||||
successPage := `
|
||||
<div style="height:100px; width:100%!; display:flex; flex-direction: column; justify-content: center; align-items:center; background-color:#2ecc71; color:white; font-size:22"><div>Authentication successful!</div></div>
|
||||
<p style="margin-top:20px; font-size:18; text-align:center">Authentication was successful, you can now return to CLI. This page will close automatically</p>
|
||||
<script>window.onload=function(){setTimeout(this.close, 4000)}</script>
|
||||
`
|
||||
fmt.Fprintf(w, successPage)
|
||||
}
|
||||
http.HandleFunc("/auth/callback", callbackHandler)
|
||||
|
||||
// add transport for self-signed certificate to context
|
||||
sslcli := &http.Client{
|
||||
Transport: &http.Transport{
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||
},
|
||||
}
|
||||
ctx = context.WithValue(ctx, oauth2.HTTPClient, sslcli)
|
||||
|
||||
// Redirect user to login & consent page to ask for permission for the scopes specified above.
|
||||
log.Info("Opening browser for authentication")
|
||||
url := conf.AuthCodeURL("state", oauth2.AccessTypeOffline)
|
||||
log.Infof("Authentication URL: %s", url)
|
||||
time.Sleep(1 * time.Second)
|
||||
err = open.Run(url)
|
||||
errors.CheckError(err)
|
||||
go func() {
|
||||
if err := srv.ListenAndServe(); err != http.ErrServerClosed {
|
||||
log.Fatalf("listen: %s\n", err)
|
||||
}
|
||||
}()
|
||||
<-loginCompleted
|
||||
_ = srv.Shutdown(ctx)
|
||||
return tokenString
|
||||
}
|
||||
|
||||
func passwordLogin(acdClient argocdclient.Client, username, password string) string {
|
||||
username, password = cli.PromptCredentials(username, password)
|
||||
sessConn, sessionIf := acdClient.NewSessionClientOrDie()
|
||||
defer util.Close(sessConn)
|
||||
sessionRequest := session.SessionCreateRequest{
|
||||
Username: username,
|
||||
Password: password,
|
||||
}
|
||||
createdSession, err := sessionIf.Create(context.Background(), &sessionRequest)
|
||||
errors.CheckError(err)
|
||||
return createdSession.Token
|
||||
}
|
||||
|
||||
func tokenLogin(acdClient argocdclient.Client, token string) string {
|
||||
sessConn, sessionIf := acdClient.NewSessionClientOrDie()
|
||||
defer util.Close(sessConn)
|
||||
sessionRequest := session.SessionCreateRequest{
|
||||
Token: token,
|
||||
}
|
||||
createdSession, err := sessionIf.Create(context.Background(), &sessionRequest)
|
||||
errors.CheckError(err)
|
||||
return createdSession.Token
|
||||
}
|
||||
@@ -1,12 +1,10 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"syscall"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/argoproj/argo-cd/errors"
|
||||
@@ -14,17 +12,17 @@ import (
|
||||
appsv1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/server/repository"
|
||||
"github.com/argoproj/argo-cd/util"
|
||||
"github.com/argoproj/argo-cd/util/cli"
|
||||
"github.com/argoproj/argo-cd/util/git"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"golang.org/x/crypto/ssh/terminal"
|
||||
)
|
||||
|
||||
// NewRepoCommand returns a new instance of an `argocd repo` command
|
||||
func NewRepoCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
|
||||
var command = &cobra.Command{
|
||||
Use: "repo",
|
||||
Short: fmt.Sprintf("%s repo COMMAND", cliName),
|
||||
Short: "Manage git repository credentials",
|
||||
Run: func(c *cobra.Command, args []string) {
|
||||
c.HelpFunc()(c, args)
|
||||
os.Exit(1)
|
||||
@@ -44,8 +42,8 @@ func NewRepoAddCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
|
||||
sshPrivateKeyPath string
|
||||
)
|
||||
var command = &cobra.Command{
|
||||
Use: "add",
|
||||
Short: fmt.Sprintf("%s repo add REPO", cliName),
|
||||
Use: "add REPO",
|
||||
Short: "Add git repository credentials",
|
||||
Run: func(c *cobra.Command, args []string) {
|
||||
if len(args) != 1 {
|
||||
c.HelpFunc()(c, args)
|
||||
@@ -61,18 +59,19 @@ func NewRepoAddCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
|
||||
}
|
||||
err := git.TestRepo(repo.Repo, repo.Username, repo.Password, repo.SSHPrivateKey)
|
||||
if err != nil {
|
||||
if repo.Username != "" && repo.Password != "" || git.IsSshURL(repo.Repo) {
|
||||
if repo.Username != "" && repo.Password != "" || git.IsSSHURL(repo.Repo) {
|
||||
// if everything was supplied or repo URL is SSH url, one of the inputs was definitely bad
|
||||
log.Fatal(err)
|
||||
}
|
||||
// If we can't test the repo, it's probably private. Prompt for credentials and try again.
|
||||
promptCredentials(&repo)
|
||||
repo.Username, repo.Password = cli.PromptCredentials(repo.Username, repo.Password)
|
||||
err = git.TestRepo(repo.Repo, repo.Username, repo.Password, repo.SSHPrivateKey)
|
||||
}
|
||||
errors.CheckError(err)
|
||||
conn, repoIf := argocdclient.NewClientOrDie(clientOpts).NewRepoClientOrDie()
|
||||
defer util.Close(conn)
|
||||
createdRepo, err := repoIf.Create(context.Background(), &repo)
|
||||
repoCreateReq := repository.RepoCreateRequest{Repo: &repo}
|
||||
createdRepo, err := repoIf.Create(context.Background(), &repoCreateReq)
|
||||
errors.CheckError(err)
|
||||
fmt.Printf("repository '%s' added\n", createdRepo.Repo)
|
||||
},
|
||||
@@ -83,25 +82,11 @@ func NewRepoAddCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
|
||||
return command
|
||||
}
|
||||
|
||||
func promptCredentials(repo *appsv1.Repository) {
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
if repo.Username == "" {
|
||||
fmt.Print("Username: ")
|
||||
username, _ := reader.ReadString('\n')
|
||||
repo.Username = username
|
||||
}
|
||||
if repo.Password == "" {
|
||||
fmt.Print("Password: ")
|
||||
bytePassword, _ := terminal.ReadPassword(syscall.Stdin)
|
||||
repo.Password = string(bytePassword)
|
||||
}
|
||||
}
|
||||
|
||||
// NewRepoRemoveCommand returns a new instance of an `argocd repo list` command
|
||||
func NewRepoRemoveCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
|
||||
var command = &cobra.Command{
|
||||
Use: "rm",
|
||||
Short: fmt.Sprintf("%s repo rm REPO", cliName),
|
||||
Use: "rm REPO",
|
||||
Short: "Remove git repository credentials",
|
||||
Run: func(c *cobra.Command, args []string) {
|
||||
if len(args) == 0 {
|
||||
c.HelpFunc()(c, args)
|
||||
@@ -122,16 +107,16 @@ func NewRepoRemoveCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command
|
||||
func NewRepoListCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
|
||||
var command = &cobra.Command{
|
||||
Use: "list",
|
||||
Short: fmt.Sprintf("%s repo list", cliName),
|
||||
Short: "List configured repositories",
|
||||
Run: func(c *cobra.Command, args []string) {
|
||||
conn, repoIf := argocdclient.NewClientOrDie(clientOpts).NewRepoClientOrDie()
|
||||
defer util.Close(conn)
|
||||
repos, err := repoIf.List(context.Background(), &repository.RepoQuery{})
|
||||
errors.CheckError(err)
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
||||
fmt.Fprintf(w, "REPO\tUSER\n")
|
||||
fmt.Fprintf(w, "REPO\tUSER\tSTATUS\tMESSAGE\n")
|
||||
for _, r := range repos.Items {
|
||||
fmt.Fprintf(w, "%s\t%s\n", r.Repo, r.Username)
|
||||
fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", r.Repo, r.Username, r.ConnectionState.Status, r.ConnectionState.Message)
|
||||
}
|
||||
_ = w.Flush()
|
||||
},
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"github.com/argoproj/argo-cd/errors"
|
||||
argocdclient "github.com/argoproj/argo-cd/pkg/apiclient"
|
||||
"github.com/argoproj/argo-cd/util/cli"
|
||||
"github.com/argoproj/argo-cd/util/localconfig"
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
)
|
||||
@@ -22,15 +23,23 @@ func NewCommand() *cobra.Command {
|
||||
},
|
||||
}
|
||||
|
||||
command.AddCommand(cli.NewVersionCmd(cliName))
|
||||
command.AddCommand(NewVersionCmd(&clientOpts))
|
||||
command.AddCommand(NewClusterCommand(&clientOpts, pathOpts))
|
||||
command.AddCommand(NewApplicationCommand(&clientOpts))
|
||||
command.AddCommand(NewLoginCommand(&clientOpts))
|
||||
command.AddCommand(NewRepoCommand(&clientOpts))
|
||||
command.AddCommand(NewInstallCommand())
|
||||
command.AddCommand(NewUninstallCommand())
|
||||
command.AddCommand(NewContextCommand(&clientOpts))
|
||||
|
||||
defaultLocalConfigPath, err := localconfig.DefaultLocalConfigPath()
|
||||
errors.CheckError(err)
|
||||
command.PersistentFlags().StringVar(&clientOpts.ConfigPath, "config", defaultLocalConfigPath, "Path to ArgoCD config")
|
||||
command.PersistentFlags().StringVar(&clientOpts.ServerAddr, "server", "", "ArgoCD server address")
|
||||
command.PersistentFlags().BoolVar(&clientOpts.Insecure, "insecure", true, "Disable transport security for the client connection")
|
||||
command.PersistentFlags().BoolVar(&clientOpts.PlainText, "plaintext", false, "Disable TLS")
|
||||
command.PersistentFlags().BoolVar(&clientOpts.Insecure, "insecure", false, "Skip server certificate and domain verification")
|
||||
command.PersistentFlags().StringVar(&clientOpts.CertFile, "server-crt", "", "Server certificate file")
|
||||
command.PersistentFlags().StringVar(&clientOpts.AuthToken, "auth-token", "", "Authentication token")
|
||||
|
||||
return command
|
||||
}
|
||||
|
||||
@@ -11,8 +11,10 @@ import (
|
||||
// NewUninstallCommand returns a new instance of `argocd install` command
|
||||
func NewUninstallCommand() *cobra.Command {
|
||||
var (
|
||||
clientConfig clientcmd.ClientConfig
|
||||
installOpts install.InstallOptions
|
||||
clientConfig clientcmd.ClientConfig
|
||||
installOpts install.InstallOptions
|
||||
deleteNamespace bool
|
||||
deleteCRD bool
|
||||
)
|
||||
var command = &cobra.Command{
|
||||
Use: "uninstall",
|
||||
@@ -21,12 +23,18 @@ func NewUninstallCommand() *cobra.Command {
|
||||
Run: func(c *cobra.Command, args []string) {
|
||||
conf, err := clientConfig.ClientConfig()
|
||||
errors.CheckError(err)
|
||||
namespace, wasSpecified, err := clientConfig.Namespace()
|
||||
errors.CheckError(err)
|
||||
if wasSpecified {
|
||||
installOpts.Namespace = namespace
|
||||
}
|
||||
installer, err := install.NewInstaller(conf, installOpts)
|
||||
errors.CheckError(err)
|
||||
installer.Uninstall()
|
||||
installer.Uninstall(deleteNamespace, deleteCRD)
|
||||
},
|
||||
}
|
||||
command.Flags().StringVar(&installOpts.Namespace, "install-namespace", install.DefaultInstallNamespace, "uninstall from a specific namespace")
|
||||
clientConfig = cli.AddKubectlFlagsToCmd(command)
|
||||
command.Flags().BoolVar(&deleteNamespace, "delete-namespace", false, "Also delete the namespace during uninstall")
|
||||
command.Flags().BoolVar(&deleteCRD, "delete-crd", false, "Also delete the Application CRD during uninstall")
|
||||
return command
|
||||
}
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
argoappv1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
|
||||
"github.com/ghodss/yaml"
|
||||
)
|
||||
|
||||
// unmarshalApplication tries to convert a YAML or JSON byte array into an Application struct.
|
||||
func unmarshalApplication(data []byte, app *argoappv1.Application) {
|
||||
// first, try unmarshaling as JSON
|
||||
// Based on technique from Kubectl, which supports both YAML and JSON:
|
||||
// https://mlafeldt.github.io/blog/teaching-go-programs-to-love-json-and-yaml/
|
||||
// http://ghodss.com/2014/the-right-way-to-handle-yaml-in-golang/
|
||||
// Short version: JSON unmarshaling won't zero out null fields; YAML unmarshaling will.
|
||||
// This may have unintended effects or hard-to-catch issues when populating our application object.
|
||||
data, err := yaml.YAMLToJSON(data)
|
||||
if err != nil {
|
||||
log.Fatal("Could not decode valid JSON or YAML Kubernetes manifest")
|
||||
}
|
||||
err = json.Unmarshal(data, &app)
|
||||
if err != nil {
|
||||
log.Fatalf("Could not unmarshal Kubernetes manifest: %s", string(data))
|
||||
}
|
||||
}
|
||||
|
||||
// readLocalFile reads a file from disk and returns its contents as a byte array.
|
||||
// The caller is responsible for checking error return values.
|
||||
func readLocalFile(path string) (data []byte, err error) {
|
||||
data, err = ioutil.ReadFile(path)
|
||||
return
|
||||
}
|
||||
|
||||
// readRemoteFile issues a GET request to retrieve the contents of the specified URL as a byte array.
|
||||
// The caller is responsible for checking error return values.
|
||||
func readRemoteFile(url string) (data []byte, err error) {
|
||||
resp, err := http.Get(url)
|
||||
if err == nil {
|
||||
defer func() {
|
||||
_ = resp.Body.Close()
|
||||
}()
|
||||
data, err = ioutil.ReadAll(resp.Body)
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestReadLocalFile(t *testing.T) {
|
||||
sentinel := "Hello, world!"
|
||||
|
||||
file, err := ioutil.TempFile(os.TempDir(), "")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer func() {
|
||||
_ = os.Remove(file.Name())
|
||||
}()
|
||||
|
||||
_, _ = file.WriteString(sentinel)
|
||||
_ = file.Sync()
|
||||
|
||||
data, err := readLocalFile(file.Name())
|
||||
if string(data) != sentinel {
|
||||
t.Errorf("Test data did not match (err = %v)! Expected \"%s\" and received \"%s\"", err, sentinel, string(data))
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadRemoteFile(t *testing.T) {
|
||||
sentinel := "Hello, world!"
|
||||
|
||||
serve := func(c chan<- string) {
|
||||
// listen on first available dynamic (unprivileged) port
|
||||
listener, err := net.Listen("tcp", ":0")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// send back the address so that it can be used
|
||||
c <- listener.Addr().String()
|
||||
|
||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
// return the sentinel text at root URL
|
||||
fmt.Fprint(w, sentinel)
|
||||
})
|
||||
|
||||
panic(http.Serve(listener, nil))
|
||||
}
|
||||
|
||||
c := make(chan string, 1)
|
||||
|
||||
// run a local webserver to test data retrieval
|
||||
go serve(c)
|
||||
|
||||
address := <-c
|
||||
data, err := readRemoteFile("http://" + address)
|
||||
t.Logf("Listening at address: %s", address)
|
||||
if string(data) != sentinel {
|
||||
t.Errorf("Test data did not match (err = %v)! Expected \"%s\" and received \"%s\"", err, sentinel, string(data))
|
||||
}
|
||||
}
|
||||
64
cmd/argocd/commands/version.go
Normal file
64
cmd/argocd/commands/version.go
Normal file
@@ -0,0 +1,64 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
argocd "github.com/argoproj/argo-cd"
|
||||
"github.com/argoproj/argo-cd/errors"
|
||||
argocdclient "github.com/argoproj/argo-cd/pkg/apiclient"
|
||||
"github.com/argoproj/argo-cd/util"
|
||||
"github.com/golang/protobuf/ptypes/empty"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// NewVersionCmd returns a new `version` command to be used as a sub-command to root
|
||||
func NewVersionCmd(clientOpts *argocdclient.ClientOptions) *cobra.Command {
|
||||
var short bool
|
||||
var client bool
|
||||
|
||||
versionCmd := cobra.Command{
|
||||
Use: "version",
|
||||
Short: fmt.Sprintf("Print version information"),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
version := argocd.GetVersion()
|
||||
fmt.Printf("%s: %s\n", cliName, version)
|
||||
if !short {
|
||||
fmt.Printf(" BuildDate: %s\n", version.BuildDate)
|
||||
fmt.Printf(" GitCommit: %s\n", version.GitCommit)
|
||||
fmt.Printf(" GitTreeState: %s\n", version.GitTreeState)
|
||||
if version.GitTag != "" {
|
||||
fmt.Printf(" GitTag: %s\n", version.GitTag)
|
||||
}
|
||||
fmt.Printf(" GoVersion: %s\n", version.GoVersion)
|
||||
fmt.Printf(" Compiler: %s\n", version.Compiler)
|
||||
fmt.Printf(" Platform: %s\n", version.Platform)
|
||||
}
|
||||
if client {
|
||||
return
|
||||
}
|
||||
|
||||
// Get Server version
|
||||
conn, versionIf := argocdclient.NewClientOrDie(clientOpts).NewVersionClientOrDie()
|
||||
defer util.Close(conn)
|
||||
serverVers, err := versionIf.Version(context.Background(), &empty.Empty{})
|
||||
errors.CheckError(err)
|
||||
fmt.Printf("%s: %s\n", "argocd-server", serverVers.Version)
|
||||
if !short {
|
||||
fmt.Printf(" BuildDate: %s\n", serverVers.BuildDate)
|
||||
fmt.Printf(" GitCommit: %s\n", serverVers.GitCommit)
|
||||
fmt.Printf(" GitTreeState: %s\n", serverVers.GitTreeState)
|
||||
if version.GitTag != "" {
|
||||
fmt.Printf(" GitTag: %s\n", serverVers.GitTag)
|
||||
}
|
||||
fmt.Printf(" GoVersion: %s\n", serverVers.GoVersion)
|
||||
fmt.Printf(" Compiler: %s\n", serverVers.Compiler)
|
||||
fmt.Printf(" Platform: %s\n", serverVers.Platform)
|
||||
}
|
||||
|
||||
},
|
||||
}
|
||||
versionCmd.Flags().BoolVar(&short, "short", false, "print just the version number")
|
||||
versionCmd.Flags().BoolVar(&client, "client", false, "client version only (no server required)")
|
||||
return &versionCmd
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"github.com/argoproj/argo-cd/pkg/apis/application"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
|
||||
"github.com/argoproj/argo-cd/pkg/apis/application"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -14,6 +15,42 @@ const (
|
||||
|
||||
// SecretTypeCluster indicates a secret type of cluster
|
||||
SecretTypeCluster = "cluster"
|
||||
|
||||
// AuthCookieName is the HTTP cookie name where we store our auth token
|
||||
AuthCookieName = "argocd.token"
|
||||
// ResourcesFinalizerName is a number of application CRD finalizer
|
||||
ResourcesFinalizerName = "resources-finalizer." + MetadataPrefix
|
||||
|
||||
// KubernetesInternalAPIServerAddr is address of the k8s API server when accessing internal to the cluster
|
||||
KubernetesInternalAPIServerAddr = "https://kubernetes.default.svc"
|
||||
)
|
||||
|
||||
const (
|
||||
ArgoCDAdminUsername = "admin"
|
||||
ArgoCDSecretName = "argocd-secret"
|
||||
ArgoCDConfigMapName = "argocd-cm"
|
||||
ArgoCDRBACConfigMapName = "argocd-rbac-cm"
|
||||
)
|
||||
|
||||
const (
|
||||
// DexAPIEndpoint is the endpoint where we serve the Dex API server
|
||||
DexAPIEndpoint = "/api/dex"
|
||||
// LoginEndpoint is ArgoCD's shorthand login endpoint which redirects to dex's OAuth 2.0 provider's consent page
|
||||
LoginEndpoint = "/auth/login"
|
||||
// CallbackEndpoint is ArgoCD's final callback endpoint we reach after OAuth 2.0 login flow has been completed
|
||||
CallbackEndpoint = "/auth/callback"
|
||||
// ArgoCDClientAppName is name of the Oauth client app used when registering our web app to dex
|
||||
ArgoCDClientAppName = "ArgoCD"
|
||||
// ArgoCDClientAppID is the Oauth client ID we will use when registering our app to dex
|
||||
ArgoCDClientAppID = "argo-cd"
|
||||
// ArgoCDCLIClientAppName is name of the Oauth client app used when registering our CLI to dex
|
||||
ArgoCDCLIClientAppName = "ArgoCD CLI"
|
||||
// ArgoCDCLIClientAppID is the Oauth client ID we will use when registering our CLI to dex
|
||||
ArgoCDCLIClientAppID = "argo-cd-cli"
|
||||
// EnvVarSSODebug is an environment variable to enable additional OAuth debugging in the API server
|
||||
EnvVarSSODebug = "ARGOCD_SSO_DEBUG"
|
||||
// EnvVarRBACDebug is an environment variable to enable additional RBAC debugging in the API server
|
||||
EnvVarRBACDebug = "ARGOCD_RBAC_DEBUG"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -23,10 +60,23 @@ var (
|
||||
// LabelKeySecretType contains the type of argocd secret (either 'cluster' or 'repo')
|
||||
LabelKeySecretType = MetadataPrefix + "/secret-type"
|
||||
|
||||
// AnnotationConnectionStatus contains connection state status
|
||||
AnnotationConnectionStatus = MetadataPrefix + "/connection-status"
|
||||
// AnnotationConnectionMessage contains additional information about connection status
|
||||
AnnotationConnectionMessage = MetadataPrefix + "/connection-message"
|
||||
// AnnotationConnectionModifiedAt contains timestamp when connection state had been modified
|
||||
AnnotationConnectionModifiedAt = MetadataPrefix + "/connection-modified-at"
|
||||
|
||||
// LabelKeyApplicationControllerInstanceID is the label which allows to separate application among multiple running application controllers.
|
||||
LabelKeyApplicationControllerInstanceID = application.ApplicationFullName + "/controller-instanceid"
|
||||
|
||||
// LabelApplicationName is the label which indicates that resource belongs to application with the specified name
|
||||
LabelApplicationName = application.ApplicationFullName + "/app-name"
|
||||
|
||||
// AnnotationKeyRefresh is the annotation key in the application which is updated with an
|
||||
// arbitrary value (i.e. timestamp) on a git event, to force the controller to wake up and
|
||||
// re-evaluate the application
|
||||
AnnotationKeyRefresh = application.ApplicationFullName + "/refresh"
|
||||
)
|
||||
|
||||
// ArgoCDManagerServiceAccount is the name of the service account for managing a cluster
|
||||
@@ -44,46 +94,3 @@ var ArgoCDManagerPolicyRules = []rbacv1.PolicyRule{
|
||||
Verbs: []string{"*"},
|
||||
},
|
||||
}
|
||||
|
||||
const (
|
||||
ArgoCDServerServiceAccount = "argocd-server"
|
||||
ArgoCDServerRole = "argocd-server-role"
|
||||
ArgoCDServerRoleBinding = "argocd-server-role-binding"
|
||||
)
|
||||
|
||||
var ArgoCDServerPolicyRules = []rbacv1.PolicyRule{
|
||||
{
|
||||
APIGroups: []string{""},
|
||||
Resources: []string{"pods", "pods/exec", "pods/log"},
|
||||
Verbs: []string{"get", "list", "watch"},
|
||||
},
|
||||
{
|
||||
APIGroups: []string{""},
|
||||
Resources: []string{"secrets"},
|
||||
Verbs: []string{"create", "get", "list", "watch", "update", "patch", "delete"},
|
||||
},
|
||||
{
|
||||
APIGroups: []string{"argoproj.io"},
|
||||
Resources: []string{"applications"},
|
||||
Verbs: []string{"create", "get", "list", "watch", "update", "patch", "delete"},
|
||||
},
|
||||
}
|
||||
|
||||
const (
|
||||
ApplicationControllerServiceAccount = "application-controller"
|
||||
ApplicationControllerRole = "application-controller-role"
|
||||
ApplicationControllerRoleBinding = "application-controller-role-binding"
|
||||
)
|
||||
|
||||
var ApplicationControllerPolicyRules = []rbacv1.PolicyRule{
|
||||
{
|
||||
APIGroups: []string{""},
|
||||
Resources: []string{"secrets"},
|
||||
Verbs: []string{"get"},
|
||||
},
|
||||
{
|
||||
APIGroups: []string{"argoproj.io"},
|
||||
Resources: []string{"applications"},
|
||||
Verbs: []string{"create", "get", "list", "watch", "update", "patch", "delete"},
|
||||
},
|
||||
}
|
||||
|
||||
560
controller/appcontroller.go
Normal file
560
controller/appcontroller.go
Normal file
@@ -0,0 +1,560 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"runtime/debug"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/argoproj/argo-cd/common"
|
||||
appv1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
|
||||
appclientset "github.com/argoproj/argo-cd/pkg/client/clientset/versioned"
|
||||
appinformers "github.com/argoproj/argo-cd/pkg/client/informers/externalversions"
|
||||
"github.com/argoproj/argo-cd/util/db"
|
||||
"github.com/argoproj/argo-cd/util/kube"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/selection"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
"k8s.io/client-go/util/workqueue"
|
||||
)
|
||||
|
||||
const (
|
||||
watchResourcesRetryTimeout = 10 * time.Second
|
||||
updateOperationStateTimeout = 1 * time.Second
|
||||
)
|
||||
|
||||
// ApplicationController is the controller for application resources.
|
||||
type ApplicationController struct {
|
||||
namespace string
|
||||
kubeClientset kubernetes.Interface
|
||||
applicationClientset appclientset.Interface
|
||||
appRefreshQueue workqueue.RateLimitingInterface
|
||||
appOperationQueue workqueue.RateLimitingInterface
|
||||
appInformer cache.SharedIndexInformer
|
||||
appStateManager AppStateManager
|
||||
appHealthManager AppHealthManager
|
||||
statusRefreshTimeout time.Duration
|
||||
db db.ArgoDB
|
||||
forceRefreshApps map[string]bool
|
||||
forceRefreshAppsMutex *sync.Mutex
|
||||
}
|
||||
|
||||
type ApplicationControllerConfig struct {
|
||||
InstanceID string
|
||||
Namespace string
|
||||
}
|
||||
|
||||
// NewApplicationController creates new instance of ApplicationController.
|
||||
func NewApplicationController(
|
||||
namespace string,
|
||||
kubeClientset kubernetes.Interface,
|
||||
applicationClientset appclientset.Interface,
|
||||
db db.ArgoDB,
|
||||
appStateManager AppStateManager,
|
||||
appHealthManager AppHealthManager,
|
||||
appResyncPeriod time.Duration,
|
||||
config *ApplicationControllerConfig,
|
||||
) *ApplicationController {
|
||||
appRefreshQueue := workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter())
|
||||
appOperationQueue := workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter())
|
||||
return &ApplicationController{
|
||||
namespace: namespace,
|
||||
kubeClientset: kubeClientset,
|
||||
applicationClientset: applicationClientset,
|
||||
appRefreshQueue: appRefreshQueue,
|
||||
appOperationQueue: appOperationQueue,
|
||||
appStateManager: appStateManager,
|
||||
appHealthManager: appHealthManager,
|
||||
appInformer: newApplicationInformer(applicationClientset, appRefreshQueue, appOperationQueue, appResyncPeriod, config),
|
||||
db: db,
|
||||
statusRefreshTimeout: appResyncPeriod,
|
||||
forceRefreshApps: make(map[string]bool),
|
||||
forceRefreshAppsMutex: &sync.Mutex{},
|
||||
}
|
||||
}
|
||||
|
||||
// Run starts the Application CRD controller.
|
||||
func (ctrl *ApplicationController) Run(ctx context.Context, statusProcessors int, operationProcessors int) {
|
||||
defer runtime.HandleCrash()
|
||||
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
|
||||
}
|
||||
|
||||
for i := 0; i < statusProcessors; i++ {
|
||||
go wait.Until(func() {
|
||||
for ctrl.processAppRefreshQueueItem() {
|
||||
}
|
||||
}, time.Second, ctx.Done())
|
||||
}
|
||||
|
||||
for i := 0; i < operationProcessors; i++ {
|
||||
go wait.Until(func() {
|
||||
for ctrl.processAppOperationQueueItem() {
|
||||
}
|
||||
}, time.Second, ctx.Done())
|
||||
}
|
||||
|
||||
<-ctx.Done()
|
||||
}
|
||||
|
||||
func (ctrl *ApplicationController) forceAppRefresh(appName string) {
|
||||
ctrl.forceRefreshAppsMutex.Lock()
|
||||
defer ctrl.forceRefreshAppsMutex.Unlock()
|
||||
ctrl.forceRefreshApps[appName] = true
|
||||
}
|
||||
|
||||
func (ctrl *ApplicationController) isRefreshForced(appName string) bool {
|
||||
ctrl.forceRefreshAppsMutex.Lock()
|
||||
defer ctrl.forceRefreshAppsMutex.Unlock()
|
||||
_, ok := ctrl.forceRefreshApps[appName]
|
||||
if ok {
|
||||
delete(ctrl.forceRefreshApps, appName)
|
||||
}
|
||||
return ok
|
||||
}
|
||||
|
||||
// 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) {
|
||||
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)
|
||||
objLabels := eventObj.GetLabels()
|
||||
if objLabels == nil {
|
||||
objLabels = make(map[string]string)
|
||||
}
|
||||
if appName, ok := objLabels[common.LabelApplicationName]; ok {
|
||||
ctrl.forceAppRefresh(appName)
|
||||
ctrl.appRefreshQueue.Add(ctrl.namespace + "/" + appName)
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("resource updates channel has closed")
|
||||
}, fmt.Sprintf("watch app resources on %s", config.Host), ctx, watchResourcesRetryTimeout)
|
||||
|
||||
}
|
||||
|
||||
// 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]context.CancelFunc)
|
||||
|
||||
retryUntilSucceed(func() error {
|
||||
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 {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
watchingClusters[event.Cluster.Server] = cancel
|
||||
go ctrl.watchClusterResources(ctx, *event.Cluster)
|
||||
}
|
||||
})
|
||||
}, "watch clusters", context.Background(), watchResourcesRetryTimeout)
|
||||
|
||||
<-context.Background().Done()
|
||||
}
|
||||
|
||||
// retryUntilSucceed keep retrying given action with specified timeout until action succeed or specified context is done.
|
||||
func retryUntilSucceed(action func() error, desc string, ctx context.Context, timeout time.Duration) {
|
||||
ctxCompleted := false
|
||||
go func() {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
ctxCompleted = true
|
||||
}
|
||||
}()
|
||||
for {
|
||||
err := action()
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
if ctxCompleted {
|
||||
log.Infof("Stop retrying %s", desc)
|
||||
return
|
||||
} else {
|
||||
log.Warnf("Failed to %s: %v, retrying in %v", desc, err, timeout)
|
||||
time.Sleep(timeout)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func (ctrl *ApplicationController) processAppOperationQueueItem() (processNext bool) {
|
||||
appKey, shutdown := ctrl.appOperationQueue.Get()
|
||||
if shutdown {
|
||||
processNext = false
|
||||
return
|
||||
} else {
|
||||
processNext = true
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
log.Errorf("Recovered from panic: %+v\n%s", r, debug.Stack())
|
||||
}
|
||||
ctrl.appOperationQueue.Done(appKey)
|
||||
}()
|
||||
|
||||
obj, exists, err := ctrl.appInformer.GetIndexer().GetByKey(appKey.(string))
|
||||
if err != nil {
|
||||
log.Errorf("Failed to get application '%s' from informer index: %+v", appKey, err)
|
||||
return
|
||||
}
|
||||
if !exists {
|
||||
// This happens after app was deleted, but the work queue still had an entry for it.
|
||||
return
|
||||
}
|
||||
app, ok := obj.(*appv1.Application)
|
||||
if !ok {
|
||||
log.Warnf("Key '%s' in index is not an application", appKey)
|
||||
return
|
||||
}
|
||||
if app.Operation != nil {
|
||||
ctrl.processRequestedAppOperation(app)
|
||||
} else if app.DeletionTimestamp != nil && app.CascadedDeletion() {
|
||||
ctrl.finalizeApplicationDeletion(app)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (ctrl *ApplicationController) finalizeApplicationDeletion(app *appv1.Application) {
|
||||
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) {
|
||||
log.Errorf("Unable to get refreshed application info prior deleting resources: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
clst, err := ctrl.db.GetCluster(context.Background(), app.Spec.Destination.Server)
|
||||
|
||||
if err == nil {
|
||||
config := clst.RESTConfig()
|
||||
err = kube.DeleteResourceWithLabel(config, app.Spec.Destination.Namespace, common.LabelApplicationName, app.Name)
|
||||
if err == nil {
|
||||
app.SetCascadedDeletion(false)
|
||||
var patch []byte
|
||||
patch, err = json.Marshal(map[string]interface{}{
|
||||
"metadata": map[string]interface{}{
|
||||
"finalizers": app.Finalizers,
|
||||
},
|
||||
})
|
||||
if err == nil {
|
||||
_, err = ctrl.applicationClientset.ArgoprojV1alpha1().Applications(app.Namespace).Patch(app.Name, types.MergePatchType, patch)
|
||||
}
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
log.Errorf("Unable to delete application resources: %v", err)
|
||||
ctrl.setAppCondition(app, appv1.ApplicationCondition{
|
||||
Type: appv1.ApplicationConditionDeletionError,
|
||||
Message: err.Error(),
|
||||
})
|
||||
} else {
|
||||
log.Infof("Successfully deleted resources for application %s", app.Name)
|
||||
}
|
||||
}
|
||||
|
||||
func (ctrl *ApplicationController) setAppCondition(app *appv1.Application, condition appv1.ApplicationCondition) {
|
||||
index := -1
|
||||
for i, exiting := range app.Status.Conditions {
|
||||
if exiting.Type == condition.Type {
|
||||
index = i
|
||||
break
|
||||
}
|
||||
}
|
||||
if index > -1 {
|
||||
app.Status.Conditions[index] = condition
|
||||
} else {
|
||||
app.Status.Conditions = append(app.Status.Conditions, condition)
|
||||
}
|
||||
var patch []byte
|
||||
patch, err := json.Marshal(map[string]interface{}{
|
||||
"status": map[string]interface{}{
|
||||
"conditions": app.Status.Conditions,
|
||||
},
|
||||
})
|
||||
if err == nil {
|
||||
_, err = ctrl.applicationClientset.ArgoprojV1alpha1().Applications(app.Namespace).Patch(app.Name, types.MergePatchType, patch)
|
||||
}
|
||||
if err != nil {
|
||||
log.Errorf("Unable to set application condition: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (ctrl *ApplicationController) processRequestedAppOperation(app *appv1.Application) {
|
||||
state := appv1.OperationState{Phase: appv1.OperationRunning, Operation: *app.Operation, StartedAt: metav1.Now()}
|
||||
// Recover from any unexpected panics and automatically set the status to be failed
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
log.Errorf("Recovered from panic: %+v\n%s", r, debug.Stack())
|
||||
// TODO: consider adding Error OperationStatus in addition to Failed
|
||||
state.Phase = appv1.OperationError
|
||||
if rerr, ok := r.(error); ok {
|
||||
state.Message = rerr.Error()
|
||||
} else {
|
||||
state.Message = fmt.Sprintf("%v", r)
|
||||
}
|
||||
ctrl.setOperationState(app.Name, state, app.Operation)
|
||||
}
|
||||
}()
|
||||
if app.Status.OperationState != nil && !app.Status.OperationState.Phase.Completed() {
|
||||
// If we get here, we are about process an operation but we notice it is already Running.
|
||||
// We need to detect if the controller crashed before completing the operation, or if the
|
||||
// the app object we pulled off the informer is simply stale and doesn't reflect the fact
|
||||
// that the operation is completed. We don't want to perform the operation 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 {
|
||||
log.Errorf("Failed to retrieve latest application state: %v", err)
|
||||
return
|
||||
}
|
||||
if freshApp.Status.OperationState == nil || freshApp.Status.OperationState.Phase.Completed() {
|
||||
log.Infof("Skipping operation on stale application state (%s)", app.ObjectMeta.Name)
|
||||
return
|
||||
}
|
||||
log.Warnf("Found interrupted application operation %s %v", app.ObjectMeta.Name, app.Status.OperationState)
|
||||
} else {
|
||||
ctrl.setOperationState(app.Name, state, app.Operation)
|
||||
}
|
||||
|
||||
if app.Operation.Sync != nil {
|
||||
opRes := ctrl.appStateManager.SyncAppState(app, app.Operation.Sync.Revision, nil, app.Operation.Sync.DryRun, app.Operation.Sync.Prune)
|
||||
state.Phase = opRes.Phase
|
||||
state.Message = opRes.Message
|
||||
state.SyncResult = opRes.SyncResult
|
||||
} else if app.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)
|
||||
} else {
|
||||
opRes := ctrl.appStateManager.SyncAppState(app, deploymentInfo.Revision, &deploymentInfo.ComponentParameterOverrides, app.Operation.Rollback.DryRun, app.Operation.Rollback.Prune)
|
||||
state.Phase = opRes.Phase
|
||||
state.Message = opRes.Message
|
||||
state.RollbackResult = opRes.SyncResult
|
||||
}
|
||||
} else {
|
||||
state.Phase = appv1.OperationFailed
|
||||
state.Message = "Invalid operation request"
|
||||
}
|
||||
ctrl.setOperationState(app.Name, state, app.Operation)
|
||||
}
|
||||
|
||||
func (ctrl *ApplicationController) setOperationState(appName string, state appv1.OperationState, operation *appv1.Operation) {
|
||||
retryUntilSucceed(func() error {
|
||||
var inProgressOpValue *appv1.Operation
|
||||
if state.Phase == "" {
|
||||
// expose any bugs where we neglect to set phase
|
||||
panic("no phase was set")
|
||||
}
|
||||
if !state.Phase.Completed() {
|
||||
// If operation is still running, we populate the app.operation field, which prevents
|
||||
// any other operation from running at the same time. Otherwise, it is cleared by setting
|
||||
// it to nil which indicates no operation is in progress.
|
||||
inProgressOpValue = operation
|
||||
} else {
|
||||
nowTime := metav1.Now()
|
||||
state.FinishedAt = &nowTime
|
||||
}
|
||||
|
||||
patch, err := json.Marshal(map[string]interface{}{
|
||||
"status": map[string]interface{}{
|
||||
"operationState": state,
|
||||
},
|
||||
"operation": inProgressOpValue,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
appClient := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(ctrl.namespace)
|
||||
_, err = appClient.Patch(appName, types.MergePatchType, patch)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Infof("updated '%s' operation (phase: %s)", appName, state.Phase)
|
||||
return nil
|
||||
}, "Update application operation state", context.Background(), updateOperationStateTimeout)
|
||||
}
|
||||
|
||||
func (ctrl *ApplicationController) processAppRefreshQueueItem() (processNext bool) {
|
||||
appKey, shutdown := ctrl.appRefreshQueue.Get()
|
||||
if shutdown {
|
||||
processNext = false
|
||||
return
|
||||
} else {
|
||||
processNext = true
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
log.Errorf("Recovered from panic: %+v\n%s", r, debug.Stack())
|
||||
}
|
||||
ctrl.appRefreshQueue.Done(appKey)
|
||||
}()
|
||||
|
||||
obj, exists, err := ctrl.appInformer.GetIndexer().GetByKey(appKey.(string))
|
||||
if err != nil {
|
||||
log.Errorf("Failed to get application '%s' from informer index: %+v", appKey, err)
|
||||
return
|
||||
}
|
||||
if !exists {
|
||||
// This happens after app was deleted, but the work queue still had an entry for it.
|
||||
return
|
||||
}
|
||||
app, ok := obj.(*appv1.Application)
|
||||
if !ok {
|
||||
log.Warnf("Key '%s' in index is not an application", appKey)
|
||||
return
|
||||
}
|
||||
|
||||
isForceRefreshed := ctrl.isRefreshForced(app.Name)
|
||||
if isForceRefreshed || app.NeedRefreshAppStatus(ctrl.statusRefreshTimeout) {
|
||||
log.Infof("Refreshing application '%s' status (force refreshed: %v)", app.Name, isForceRefreshed)
|
||||
|
||||
comparisonResult, parameters, healthState, err := ctrl.tryRefreshAppStatus(app.DeepCopy())
|
||||
if err != nil {
|
||||
comparisonResult = &appv1.ComparisonResult{
|
||||
Status: appv1.ComparisonStatusError,
|
||||
Error: fmt.Sprintf("Failed to get application status for application '%s': %v", app.Name, err),
|
||||
ComparedTo: app.Spec.Source,
|
||||
ComparedAt: metav1.Time{Time: time.Now().UTC()},
|
||||
}
|
||||
parameters = nil
|
||||
healthState = &appv1.HealthStatus{Status: appv1.HealthStatusUnknown}
|
||||
}
|
||||
ctrl.updateAppStatus(app.Name, app.Namespace, comparisonResult, parameters, *healthState)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (ctrl *ApplicationController) tryRefreshAppStatus(app *appv1.Application) (*appv1.ComparisonResult, *[]appv1.ComponentParameter, *appv1.HealthStatus, error) {
|
||||
comparisonResult, manifestInfo, err := ctrl.appStateManager.CompareAppState(app)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
log.Infof("App %s comparison result: prev: %s. current: %s", app.Name, app.Status.ComparisonResult.Status, comparisonResult.Status)
|
||||
|
||||
parameters := make([]appv1.ComponentParameter, len(manifestInfo.Params))
|
||||
for i := range manifestInfo.Params {
|
||||
parameters[i] = *manifestInfo.Params[i]
|
||||
}
|
||||
healthState, err := ctrl.appHealthManager.GetAppHealth(app.Spec.Destination.Server, app.Spec.Destination.Namespace, comparisonResult)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
return comparisonResult, ¶meters, healthState, nil
|
||||
}
|
||||
|
||||
func (ctrl *ApplicationController) updateAppStatus(
|
||||
appName string, namespace string, comparisonResult *appv1.ComparisonResult, parameters *[]appv1.ComponentParameter, healthState appv1.HealthStatus) {
|
||||
statusPatch := make(map[string]interface{})
|
||||
statusPatch["comparisonResult"] = comparisonResult
|
||||
statusPatch["parameters"] = parameters
|
||||
statusPatch["health"] = healthState
|
||||
patch, err := json.Marshal(map[string]interface{}{
|
||||
"status": statusPatch,
|
||||
})
|
||||
|
||||
if err == nil {
|
||||
appClient := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(namespace)
|
||||
_, err = appClient.Patch(appName, types.MergePatchType, patch)
|
||||
}
|
||||
if err != nil {
|
||||
log.Warnf("Error updating application: %v", err)
|
||||
} else {
|
||||
log.Info("Application update successful")
|
||||
}
|
||||
}
|
||||
|
||||
func newApplicationInformer(
|
||||
appClientset appclientset.Interface,
|
||||
appQueue workqueue.RateLimitingInterface,
|
||||
appOperationQueue workqueue.RateLimitingInterface,
|
||||
appResyncPeriod time.Duration,
|
||||
config *ApplicationControllerConfig) cache.SharedIndexInformer {
|
||||
|
||||
appInformerFactory := appinformers.NewFilteredSharedInformerFactory(
|
||||
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(
|
||||
cache.ResourceEventHandlerFuncs{
|
||||
AddFunc: func(obj interface{}) {
|
||||
key, err := cache.MetaNamespaceKeyFunc(obj)
|
||||
if err == nil {
|
||||
appQueue.Add(key)
|
||||
appOperationQueue.Add(key)
|
||||
}
|
||||
},
|
||||
UpdateFunc: func(old, new interface{}) {
|
||||
key, err := cache.MetaNamespaceKeyFunc(new)
|
||||
if err == nil {
|
||||
appQueue.Add(key)
|
||||
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 {
|
||||
appQueue.Add(key)
|
||||
}
|
||||
},
|
||||
},
|
||||
)
|
||||
return informer
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/server/cluster"
|
||||
"github.com/argoproj/argo-cd/util/diff"
|
||||
kubeutil "github.com/argoproj/argo-cd/util/kube"
|
||||
log "github.com/sirupsen/logrus"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
|
||||
// AppComparator defines methods which allow to compare application spec and actual application state.
|
||||
type AppComparator interface {
|
||||
CompareAppState(server string, namespace string, targetObjs []*unstructured.Unstructured, app *v1alpha1.Application) (*v1alpha1.ComparisonResult, error)
|
||||
}
|
||||
|
||||
// KsonnetAppComparator allows to compare application using KSonnet CLI
|
||||
type KsonnetAppComparator struct {
|
||||
clusterService cluster.ClusterServiceServer
|
||||
}
|
||||
|
||||
// CompareAppState compares application spec and real app state using KSonnet
|
||||
func (ks *KsonnetAppComparator) CompareAppState(
|
||||
server string,
|
||||
namespace string,
|
||||
targetObjs []*unstructured.Unstructured,
|
||||
app *v1alpha1.Application) (*v1alpha1.ComparisonResult, error) {
|
||||
|
||||
log.Infof("Comparing app %s state in cluster %s (namespace: %s)", app.ObjectMeta.Name, server, namespace)
|
||||
// Get the REST config for the cluster corresponding to the environment
|
||||
clst, err := ks.clusterService.Get(context.Background(), &cluster.ClusterQuery{Server: server})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Retrieve the live versions of the objects
|
||||
liveObjs, err := kubeutil.GetLiveResources(clst.RESTConfig(), targetObjs, namespace)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Do the actual comparison
|
||||
diffResults, err := diff.DiffArray(targetObjs, liveObjs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resources := make([]v1alpha1.ResourceState, len(targetObjs))
|
||||
for i := 0; i < len(targetObjs); i++ {
|
||||
resState := v1alpha1.ResourceState{}
|
||||
targetObjBytes, err := json.Marshal(targetObjs[i].Object)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resState.TargetState = string(targetObjBytes)
|
||||
if liveObjs[i] == nil {
|
||||
resState.LiveState = "null"
|
||||
} else {
|
||||
liveObjBytes, err := json.Marshal(liveObjs[i].Object)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resState.LiveState = string(liveObjBytes)
|
||||
}
|
||||
diffResult := diffResults.Diffs[i]
|
||||
if diffResult.Modified {
|
||||
resState.Status = v1alpha1.ComparisonStatusOutOfSync
|
||||
} else {
|
||||
resState.Status = v1alpha1.ComparisonStatusSynced
|
||||
}
|
||||
resources[i] = resState
|
||||
}
|
||||
compResult := v1alpha1.ComparisonResult{
|
||||
ComparedTo: app.Spec.Source,
|
||||
ComparedAt: metav1.Time{Time: time.Now().UTC()},
|
||||
Server: clst.Server,
|
||||
Namespace: namespace,
|
||||
Resources: resources,
|
||||
}
|
||||
if diffResults.Modified {
|
||||
compResult.Status = v1alpha1.ComparisonStatusOutOfSync
|
||||
} else {
|
||||
compResult.Status = v1alpha1.ComparisonStatusSynced
|
||||
}
|
||||
return &compResult, nil
|
||||
}
|
||||
|
||||
// NewKsonnetAppComparator creates new instance of Ksonnet app comparator
|
||||
func NewKsonnetAppComparator(clusterService cluster.ClusterServiceServer) AppComparator {
|
||||
return &KsonnetAppComparator{
|
||||
clusterService: clusterService,
|
||||
}
|
||||
}
|
||||
@@ -1,253 +0,0 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/argoproj/argo-cd/common"
|
||||
appv1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
|
||||
appclientset "github.com/argoproj/argo-cd/pkg/client/clientset/versioned"
|
||||
appinformers "github.com/argoproj/argo-cd/pkg/client/informers/externalversions"
|
||||
"github.com/argoproj/argo-cd/reposerver"
|
||||
"github.com/argoproj/argo-cd/reposerver/repository"
|
||||
apireposerver "github.com/argoproj/argo-cd/server/repository"
|
||||
"github.com/argoproj/argo-cd/util"
|
||||
argoutil "github.com/argoproj/argo-cd/util/argo"
|
||||
log "github.com/sirupsen/logrus"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/selection"
|
||||
"k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
"k8s.io/client-go/util/workqueue"
|
||||
)
|
||||
|
||||
// ApplicationController is the controller for application resources.
|
||||
type ApplicationController struct {
|
||||
repoClientset reposerver.Clientset
|
||||
kubeClientset kubernetes.Interface
|
||||
applicationClientset appclientset.Interface
|
||||
appQueue workqueue.RateLimitingInterface
|
||||
appInformer cache.SharedIndexInformer
|
||||
appComparator AppComparator
|
||||
statusRefreshTimeout time.Duration
|
||||
apiRepoService apireposerver.RepositoryServiceServer
|
||||
}
|
||||
|
||||
type ApplicationControllerConfig struct {
|
||||
InstanceID string
|
||||
Namespace string
|
||||
}
|
||||
|
||||
// NewApplicationController creates new instance of ApplicationController.
|
||||
func NewApplicationController(
|
||||
kubeClientset kubernetes.Interface,
|
||||
applicationClientset appclientset.Interface,
|
||||
repoClientset reposerver.Clientset,
|
||||
apiRepoService apireposerver.RepositoryServiceServer,
|
||||
appComparator AppComparator,
|
||||
appResyncPeriod time.Duration,
|
||||
config *ApplicationControllerConfig,
|
||||
) *ApplicationController {
|
||||
appQueue := workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter())
|
||||
return &ApplicationController{
|
||||
kubeClientset: kubeClientset,
|
||||
applicationClientset: applicationClientset,
|
||||
repoClientset: repoClientset,
|
||||
appQueue: appQueue,
|
||||
apiRepoService: apiRepoService,
|
||||
appComparator: appComparator,
|
||||
appInformer: newApplicationInformer(applicationClientset, appQueue, appResyncPeriod, config),
|
||||
statusRefreshTimeout: appResyncPeriod,
|
||||
}
|
||||
}
|
||||
|
||||
// Run starts the Application CRD controller.
|
||||
func (ctrl *ApplicationController) Run(ctx context.Context, appWorkers int) {
|
||||
defer runtime.HandleCrash()
|
||||
defer ctrl.appQueue.ShutDown()
|
||||
|
||||
go ctrl.appInformer.Run(ctx.Done())
|
||||
|
||||
if !cache.WaitForCacheSync(ctx.Done(), ctrl.appInformer.HasSynced) {
|
||||
log.Error("Timed out waiting for caches to sync")
|
||||
return
|
||||
}
|
||||
|
||||
for i := 0; i < appWorkers; i++ {
|
||||
go wait.Until(ctrl.runWorker, time.Second, ctx.Done())
|
||||
}
|
||||
|
||||
<-ctx.Done()
|
||||
}
|
||||
|
||||
func (ctrl *ApplicationController) processNextItem() bool {
|
||||
appKey, shutdown := ctrl.appQueue.Get()
|
||||
if shutdown {
|
||||
return false
|
||||
}
|
||||
|
||||
defer ctrl.appQueue.Done(appKey)
|
||||
|
||||
obj, exists, err := ctrl.appInformer.GetIndexer().GetByKey(appKey.(string))
|
||||
if err != nil {
|
||||
log.Errorf("Failed to get application '%s' from informer index: %+v", appKey, err)
|
||||
return true
|
||||
}
|
||||
if !exists {
|
||||
// This happens after app was deleted, but the work queue still had an entry for it.
|
||||
return true
|
||||
}
|
||||
app, ok := obj.(*appv1.Application)
|
||||
if !ok {
|
||||
log.Warnf("Key '%s' in index is not an application", appKey)
|
||||
return true
|
||||
}
|
||||
|
||||
if app.NeedRefreshAppStatus(ctrl.statusRefreshTimeout) {
|
||||
updatedApp := app.DeepCopy()
|
||||
status, err := ctrl.tryRefreshAppStatus(updatedApp)
|
||||
if err != nil {
|
||||
updatedApp.Status.ComparisonResult = appv1.ComparisonResult{
|
||||
Status: appv1.ComparisonStatusError,
|
||||
Error: fmt.Sprintf("Failed to get application status for application '%s': %v", app.Name, err),
|
||||
ComparedTo: app.Spec.Source,
|
||||
ComparedAt: metav1.Time{Time: time.Now().UTC()},
|
||||
}
|
||||
} else {
|
||||
updatedApp.Status = *status
|
||||
}
|
||||
ctrl.persistApp(updatedApp)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (ctrl *ApplicationController) tryRefreshAppStatus(app *appv1.Application) (*appv1.ApplicationStatus, error) {
|
||||
conn, client, err := ctrl.repoClientset.NewRepositoryClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer util.Close(conn)
|
||||
repo, err := ctrl.apiRepoService.Get(context.Background(), &apireposerver.RepoQuery{Repo: app.Spec.Source.RepoURL})
|
||||
if err != nil {
|
||||
// If we couldn't retrieve from the repo service, assume public repositories
|
||||
repo = &appv1.Repository{
|
||||
Repo: app.Spec.Source.RepoURL,
|
||||
Username: "",
|
||||
Password: "",
|
||||
}
|
||||
}
|
||||
overrides := make([]*appv1.ComponentParameter, len(app.Spec.Source.ComponentParameterOverrides))
|
||||
if app.Spec.Source.ComponentParameterOverrides != nil {
|
||||
for i := range app.Spec.Source.ComponentParameterOverrides {
|
||||
item := app.Spec.Source.ComponentParameterOverrides[i]
|
||||
overrides[i] = &item
|
||||
}
|
||||
}
|
||||
revision := app.Spec.Source.TargetRevision
|
||||
manifestInfo, err := client.GenerateManifest(context.Background(), &repository.ManifestRequest{
|
||||
Repo: repo,
|
||||
Revision: revision,
|
||||
Path: app.Spec.Source.Path,
|
||||
Environment: app.Spec.Source.Environment,
|
||||
AppLabel: app.Name,
|
||||
ComponentParameterOverrides: overrides,
|
||||
})
|
||||
if err != nil {
|
||||
log.Errorf("Failed to load application manifest %v", err)
|
||||
return nil, err
|
||||
}
|
||||
targetObjs := make([]*unstructured.Unstructured, len(manifestInfo.Manifests))
|
||||
for i, manifestStr := range manifestInfo.Manifests {
|
||||
var obj unstructured.Unstructured
|
||||
if err := json.Unmarshal([]byte(manifestStr), &obj); err != nil {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
targetObjs[i] = &obj
|
||||
}
|
||||
|
||||
server, namespace := argoutil.ResolveServerNamespace(app.Spec.Destination, manifestInfo)
|
||||
comparisonResult, err := ctrl.appComparator.CompareAppState(server, namespace, targetObjs, app)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
log.Infof("App %s comparison result: prev: %s. current: %s", app.Name, app.Status.ComparisonResult.Status, comparisonResult.Status)
|
||||
newStatus := app.Status
|
||||
newStatus.ComparisonResult = *comparisonResult
|
||||
return &newStatus, nil
|
||||
}
|
||||
|
||||
func (ctrl *ApplicationController) runWorker() {
|
||||
for ctrl.processNextItem() {
|
||||
}
|
||||
}
|
||||
|
||||
func (ctrl *ApplicationController) persistApp(app *appv1.Application) {
|
||||
appClient := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(app.ObjectMeta.Namespace)
|
||||
_, err := appClient.Update(app)
|
||||
if err != nil {
|
||||
log.Warnf("Error updating application: %v", err)
|
||||
}
|
||||
log.Info("Application update successful")
|
||||
}
|
||||
|
||||
func newApplicationInformer(
|
||||
appClientset appclientset.Interface, appQueue workqueue.RateLimitingInterface, appResyncPeriod time.Duration, config *ApplicationControllerConfig) cache.SharedIndexInformer {
|
||||
|
||||
appInformerFactory := appinformers.NewFilteredSharedInformerFactory(
|
||||
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(
|
||||
cache.ResourceEventHandlerFuncs{
|
||||
AddFunc: func(obj interface{}) {
|
||||
key, err := cache.MetaNamespaceKeyFunc(obj)
|
||||
if err == nil {
|
||||
appQueue.Add(key)
|
||||
}
|
||||
},
|
||||
UpdateFunc: func(old, new interface{}) {
|
||||
key, err := cache.MetaNamespaceKeyFunc(new)
|
||||
if err == nil {
|
||||
appQueue.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 {
|
||||
appQueue.Add(key)
|
||||
}
|
||||
},
|
||||
},
|
||||
)
|
||||
return informer
|
||||
}
|
||||
161
controller/health.go
Normal file
161
controller/health.go
Normal file
@@ -0,0 +1,161 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
appv1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/util/db"
|
||||
"github.com/argoproj/argo-cd/util/kube"
|
||||
"k8s.io/api/apps/v1"
|
||||
coreV1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
const (
|
||||
maxHistoryCnt = 5
|
||||
)
|
||||
|
||||
type AppHealthManager interface {
|
||||
GetAppHealth(server string, namespace string, comparisonResult *appv1.ComparisonResult) (*appv1.HealthStatus, error)
|
||||
}
|
||||
|
||||
type kubeAppHealthManager struct {
|
||||
db db.ArgoDB
|
||||
namespace string
|
||||
}
|
||||
|
||||
func NewAppHealthManager(db db.ArgoDB, namespace string) AppHealthManager {
|
||||
return &kubeAppHealthManager{db: db, namespace: namespace}
|
||||
}
|
||||
|
||||
func (ctrl *kubeAppHealthManager) getServiceHealth(config *rest.Config, namespace string, name string) (*appv1.HealthStatus, error) {
|
||||
clientSet, err := kubernetes.NewForConfig(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
service, err := clientSet.CoreV1().Services(namespace).Get(name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
health := appv1.HealthStatus{Status: appv1.HealthStatusHealthy}
|
||||
if service.Spec.Type == coreV1.ServiceTypeLoadBalancer {
|
||||
health.Status = appv1.HealthStatusProgressing
|
||||
for _, ingress := range service.Status.LoadBalancer.Ingress {
|
||||
if ingress.Hostname != "" || ingress.IP != "" {
|
||||
health.Status = appv1.HealthStatusHealthy
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return &health, nil
|
||||
}
|
||||
|
||||
func (ctrl *kubeAppHealthManager) getDeploymentHealth(config *rest.Config, namespace string, name string) (*appv1.HealthStatus, error) {
|
||||
clientSet, err := kubernetes.NewForConfig(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
deployment, err := clientSet.AppsV1().Deployments(namespace).Get(name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if deployment.Generation <= deployment.Status.ObservedGeneration {
|
||||
cond := getDeploymentCondition(deployment.Status, v1.DeploymentProgressing)
|
||||
if cond != nil && cond.Reason == "ProgressDeadlineExceeded" {
|
||||
return &appv1.HealthStatus{
|
||||
Status: appv1.HealthStatusDegraded,
|
||||
StatusDetails: fmt.Sprintf("Deployment %q exceeded its progress deadline", name),
|
||||
}, nil
|
||||
} else if deployment.Spec.Replicas != nil && deployment.Status.UpdatedReplicas < *deployment.Spec.Replicas {
|
||||
return &appv1.HealthStatus{
|
||||
Status: appv1.HealthStatusProgressing,
|
||||
StatusDetails: fmt.Sprintf("Waiting for rollout to finish: %d out of %d new replicas have been updated...\n", deployment.Status.UpdatedReplicas, *deployment.Spec.Replicas),
|
||||
}, nil
|
||||
} else if deployment.Status.Replicas > deployment.Status.UpdatedReplicas {
|
||||
return &appv1.HealthStatus{
|
||||
Status: appv1.HealthStatusProgressing,
|
||||
StatusDetails: fmt.Sprintf("Waiting for rollout to finish: %d old replicas are pending termination...\n", deployment.Status.Replicas-deployment.Status.UpdatedReplicas),
|
||||
}, nil
|
||||
} else if deployment.Status.AvailableReplicas < deployment.Status.UpdatedReplicas {
|
||||
return &appv1.HealthStatus{
|
||||
Status: appv1.HealthStatusProgressing,
|
||||
StatusDetails: fmt.Sprintf("Waiting for rollout to finish: %d of %d updated replicas are available...\n", deployment.Status.AvailableReplicas, deployment.Status.UpdatedReplicas),
|
||||
}, nil
|
||||
}
|
||||
} else {
|
||||
return &appv1.HealthStatus{
|
||||
Status: appv1.HealthStatusProgressing,
|
||||
StatusDetails: "Waiting for rollout to finish: observed deployment generation less then desired generation",
|
||||
}, nil
|
||||
}
|
||||
|
||||
return &appv1.HealthStatus{
|
||||
Status: appv1.HealthStatusHealthy,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func getDeploymentCondition(status v1.DeploymentStatus, condType v1.DeploymentConditionType) *v1.DeploymentCondition {
|
||||
for i := range status.Conditions {
|
||||
c := status.Conditions[i]
|
||||
if c.Type == condType {
|
||||
return &c
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ctrl *kubeAppHealthManager) GetAppHealth(server string, namespace string, comparisonResult *appv1.ComparisonResult) (*appv1.HealthStatus, error) {
|
||||
clst, err := ctrl.db.GetCluster(context.Background(), server)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
restConfig := clst.RESTConfig()
|
||||
|
||||
appHealth := appv1.HealthStatus{Status: appv1.HealthStatusHealthy}
|
||||
for i := range comparisonResult.Resources {
|
||||
resource := comparisonResult.Resources[i]
|
||||
if resource.LiveState == "null" {
|
||||
resource.Health = appv1.HealthStatus{Status: appv1.HealthStatusUnknown}
|
||||
} else {
|
||||
var obj unstructured.Unstructured
|
||||
err := json.Unmarshal([]byte(resource.LiveState), &obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch obj.GetKind() {
|
||||
case kube.DeploymentKind:
|
||||
state, err := ctrl.getDeploymentHealth(restConfig, namespace, obj.GetName())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resource.Health = *state
|
||||
case kube.ServiceKind:
|
||||
state, err := ctrl.getServiceHealth(restConfig, namespace, obj.GetName())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resource.Health = *state
|
||||
default:
|
||||
resource.Health = appv1.HealthStatus{Status: appv1.HealthStatusHealthy}
|
||||
}
|
||||
|
||||
if resource.Health.Status == appv1.HealthStatusProgressing {
|
||||
if appHealth.Status == appv1.HealthStatusHealthy {
|
||||
appHealth.Status = appv1.HealthStatusProgressing
|
||||
}
|
||||
} else if resource.Health.Status == appv1.HealthStatusDegraded {
|
||||
if appHealth.Status == appv1.HealthStatusHealthy || appHealth.Status == appv1.HealthStatusProgressing {
|
||||
appHealth.Status = appv1.HealthStatusDegraded
|
||||
}
|
||||
}
|
||||
}
|
||||
comparisonResult.Resources[i] = resource
|
||||
}
|
||||
return &appHealth, nil
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
// Code generated by mockery v1.0.0
|
||||
package mocks
|
||||
|
||||
import mock "github.com/stretchr/testify/mock"
|
||||
import v1alpha1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
|
||||
|
||||
// AppComparator is an autogenerated mock type for the AppComparator type
|
||||
type AppComparator struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// CompareAppState provides a mock function with given fields: appRepoPath, app
|
||||
func (_m *AppComparator) CompareAppState(appRepoPath string, app *v1alpha1.Application) (*v1alpha1.ComparisonResult, error) {
|
||||
ret := _m.Called(appRepoPath, app)
|
||||
|
||||
var r0 *v1alpha1.ComparisonResult
|
||||
if rf, ok := ret.Get(0).(func(string, *v1alpha1.Application) *v1alpha1.ComparisonResult); ok {
|
||||
r0 = rf(appRepoPath, app)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*v1alpha1.ComparisonResult)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(string, *v1alpha1.Application) error); ok {
|
||||
r1 = rf(appRepoPath, app)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
205
controller/secretcontroller.go
Normal file
205
controller/secretcontroller.go
Normal file
@@ -0,0 +1,205 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"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"
|
||||
"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/wait"
|
||||
"k8s.io/client-go/informers"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
"k8s.io/client-go/util/workqueue"
|
||||
)
|
||||
|
||||
type SecretController struct {
|
||||
kubeClient kubernetes.Interface
|
||||
secretQueue workqueue.RateLimitingInterface
|
||||
secretInformer cache.SharedIndexInformer
|
||||
repoClientset reposerver.Clientset
|
||||
namespace string
|
||||
}
|
||||
|
||||
func (ctrl *SecretController) Run(ctx context.Context) {
|
||||
go ctrl.secretInformer.Run(ctx.Done())
|
||||
if !cache.WaitForCacheSync(ctx.Done(), ctrl.secretInformer.HasSynced) {
|
||||
log.Error("Timed out waiting for caches to sync")
|
||||
return
|
||||
}
|
||||
go wait.Until(func() {
|
||||
for ctrl.processSecret() {
|
||||
}
|
||||
}, time.Second, ctx.Done())
|
||||
}
|
||||
|
||||
func (ctrl *SecretController) processSecret() (processNext bool) {
|
||||
secretKey, shutdown := ctrl.secretQueue.Get()
|
||||
if shutdown {
|
||||
processNext = false
|
||||
return
|
||||
} else {
|
||||
processNext = true
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
log.Errorf("Recovered from panic: %+v\n%s", r, debug.Stack())
|
||||
}
|
||||
ctrl.secretQueue.Done(secretKey)
|
||||
}()
|
||||
obj, exists, err := ctrl.secretInformer.GetIndexer().GetByKey(secretKey.(string))
|
||||
if err != nil {
|
||||
log.Errorf("Failed to get secret '%s' from informer index: %+v", secretKey, err)
|
||||
return
|
||||
}
|
||||
if !exists {
|
||||
// This happens after secret was deleted, but the work queue still had an entry for it.
|
||||
return
|
||||
}
|
||||
secret, ok := obj.(*corev1.Secret)
|
||||
if !ok {
|
||||
log.Warnf("Key '%s' in index is not an secret", secretKey)
|
||||
return
|
||||
}
|
||||
|
||||
if secret.Labels[common.LabelKeySecretType] == common.SecretTypeCluster {
|
||||
cluster := db.SecretToCluster(secret)
|
||||
ctrl.updateState(secret, ctrl.getClusterState(cluster))
|
||||
} else if secret.Labels[common.LabelKeySecretType] == common.SecretTypeRepository {
|
||||
repo := db.SecretToRepo(secret)
|
||||
ctrl.updateState(secret, ctrl.getRepoConnectionState(repo))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (ctrl *SecretController) getRepoConnectionState(repo *v1alpha1.Repository) v1alpha1.ConnectionState {
|
||||
state := v1alpha1.ConnectionState{
|
||||
ModifiedAt: repo.ConnectionState.ModifiedAt,
|
||||
Status: v1alpha1.ConnectionStatusUnknown,
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
func (ctrl *SecretController) getClusterState(cluster *v1alpha1.Cluster) v1alpha1.ConnectionState {
|
||||
state := v1alpha1.ConnectionState{
|
||||
ModifiedAt: cluster.ConnectionState.ModifiedAt,
|
||||
Status: v1alpha1.ConnectionStatusUnknown,
|
||||
}
|
||||
kubeClientset, err := kubernetes.NewForConfig(cluster.RESTConfig())
|
||||
if err == nil {
|
||||
_, err = kubeClientset.Discovery().ServerVersion()
|
||||
}
|
||||
if err == nil {
|
||||
state.Status = v1alpha1.ConnectionStatusSuccessful
|
||||
} else {
|
||||
state.Status = v1alpha1.ConnectionStatusFailed
|
||||
state.Message = err.Error()
|
||||
}
|
||||
|
||||
return state
|
||||
}
|
||||
|
||||
func (ctrl *SecretController) updateState(secret *corev1.Secret, state v1alpha1.ConnectionState) {
|
||||
annotationsPatch := make(map[string]string)
|
||||
for key, value := range db.AnnotationsFromConnectionState(&state) {
|
||||
if secret.Annotations[key] != value {
|
||||
annotationsPatch[key] = value
|
||||
}
|
||||
}
|
||||
if len(annotationsPatch) > 0 {
|
||||
annotationsPatch[common.AnnotationConnectionModifiedAt] = metav1.Now().Format(time.RFC3339)
|
||||
patchData, err := json.Marshal(map[string]interface{}{
|
||||
"metadata": map[string]interface{}{
|
||||
"annotations": annotationsPatch,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
log.Warnf("Unable to prepare secret state annotation patch: %v", err)
|
||||
} else {
|
||||
_, err := ctrl.kubeClient.CoreV1().Secrets(secret.Namespace).Patch(secret.Name, types.MergePatchType, patchData)
|
||||
if err != nil {
|
||||
log.Warnf("Unable to patch secret state annotation: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func newSecretInformer(client kubernetes.Interface, resyncPeriod time.Duration, namespace string, secretQueue workqueue.RateLimitingInterface) cache.SharedIndexInformer {
|
||||
informerFactory := informers.NewFilteredSharedInformerFactory(
|
||||
client,
|
||||
resyncPeriod,
|
||||
namespace,
|
||||
func(options *metav1.ListOptions) {
|
||||
var req *labels.Requirement
|
||||
req, err := labels.NewRequirement(common.LabelKeySecretType, selection.In, []string{common.SecretTypeCluster, common.SecretTypeRepository})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
options.FieldSelector = fields.Everything().String()
|
||||
labelSelector := labels.NewSelector().Add(*req)
|
||||
options.LabelSelector = labelSelector.String()
|
||||
},
|
||||
)
|
||||
informer := informerFactory.Core().V1().Secrets().Informer()
|
||||
informer.AddEventHandler(
|
||||
cache.ResourceEventHandlerFuncs{
|
||||
AddFunc: func(obj interface{}) {
|
||||
key, err := cache.MetaNamespaceKeyFunc(obj)
|
||||
if err == nil {
|
||||
secretQueue.Add(key)
|
||||
}
|
||||
},
|
||||
UpdateFunc: func(old, new interface{}) {
|
||||
key, err := cache.MetaNamespaceKeyFunc(new)
|
||||
if err == nil {
|
||||
secretQueue.Add(key)
|
||||
}
|
||||
},
|
||||
},
|
||||
)
|
||||
return informer
|
||||
}
|
||||
|
||||
func NewSecretController(kubeClient kubernetes.Interface, repoClientset reposerver.Clientset, resyncPeriod time.Duration, namespace string) *SecretController {
|
||||
secretQueue := workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter())
|
||||
return &SecretController{
|
||||
kubeClient: kubeClient,
|
||||
secretQueue: secretQueue,
|
||||
secretInformer: newSecretInformer(kubeClient, resyncPeriod, namespace, secretQueue),
|
||||
namespace: namespace,
|
||||
repoClientset: repoClientset,
|
||||
}
|
||||
}
|
||||
500
controller/state.go
Normal file
500
controller/state.go
Normal file
@@ -0,0 +1,500 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/argoproj/argo-cd/common"
|
||||
"github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
|
||||
appclientset "github.com/argoproj/argo-cd/pkg/client/clientset/versioned"
|
||||
"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"
|
||||
"github.com/argoproj/argo-cd/util/diff"
|
||||
"github.com/argoproj/argo-cd/util/kube"
|
||||
kubeutil "github.com/argoproj/argo-cd/util/kube"
|
||||
log "github.com/sirupsen/logrus"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/client-go/discovery"
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
// AppStateManager defines methods which allow to compare application spec and actual application state.
|
||||
type AppStateManager interface {
|
||||
CompareAppState(app *v1alpha1.Application) (*v1alpha1.ComparisonResult, *repository.ManifestResponse, error)
|
||||
SyncAppState(app *v1alpha1.Application, revision string, overrides *[]v1alpha1.ComponentParameter, dryRun bool, prune bool) *v1alpha1.OperationState
|
||||
}
|
||||
|
||||
// KsonnetAppStateManager allows to compare application using KSonnet CLI
|
||||
type KsonnetAppStateManager struct {
|
||||
db db.ArgoDB
|
||||
appclientset appclientset.Interface
|
||||
repoClientset reposerver.Clientset
|
||||
namespace string
|
||||
}
|
||||
|
||||
// groupLiveObjects deduplicate list of kubernetes resources and choose correct version of resource: if resource has corresponding expected application resource then method pick
|
||||
// kubernetes resource with matching version, otherwise chooses single kubernetes resource with any version
|
||||
func (ks *KsonnetAppStateManager) groupLiveObjects(liveObjs []*unstructured.Unstructured, targetObjs []*unstructured.Unstructured) map[string]*unstructured.Unstructured {
|
||||
targetByFullName := make(map[string]*unstructured.Unstructured)
|
||||
for _, obj := range targetObjs {
|
||||
targetByFullName[getResourceFullName(obj)] = obj
|
||||
}
|
||||
|
||||
liveListByFullName := make(map[string][]*unstructured.Unstructured)
|
||||
for _, obj := range liveObjs {
|
||||
list := liveListByFullName[getResourceFullName(obj)]
|
||||
if list == nil {
|
||||
list = make([]*unstructured.Unstructured, 0)
|
||||
}
|
||||
list = append(list, obj)
|
||||
liveListByFullName[getResourceFullName(obj)] = list
|
||||
}
|
||||
|
||||
liveByFullName := make(map[string]*unstructured.Unstructured)
|
||||
|
||||
for fullName, list := range liveListByFullName {
|
||||
targetObj := targetByFullName[fullName]
|
||||
var liveObj *unstructured.Unstructured
|
||||
if targetObj != nil {
|
||||
for i := range list {
|
||||
if list[i].GetAPIVersion() == targetObj.GetAPIVersion() {
|
||||
liveObj = list[i]
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
liveObj = list[0]
|
||||
}
|
||||
if liveObj != nil {
|
||||
liveByFullName[getResourceFullName(liveObj)] = liveObj
|
||||
}
|
||||
}
|
||||
return liveByFullName
|
||||
}
|
||||
|
||||
// CompareAppState compares application spec and real app state using KSonnet
|
||||
func (ks *KsonnetAppStateManager) CompareAppState(app *v1alpha1.Application) (*v1alpha1.ComparisonResult, *repository.ManifestResponse, error) {
|
||||
repo := ks.getRepo(app.Spec.Source.RepoURL)
|
||||
conn, repoClient, err := ks.repoClientset.NewRepositoryClient()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer util.Close(conn)
|
||||
overrides := make([]*v1alpha1.ComponentParameter, len(app.Spec.Source.ComponentParameterOverrides))
|
||||
if app.Spec.Source.ComponentParameterOverrides != nil {
|
||||
for i := range app.Spec.Source.ComponentParameterOverrides {
|
||||
item := app.Spec.Source.ComponentParameterOverrides[i]
|
||||
overrides[i] = &item
|
||||
}
|
||||
}
|
||||
|
||||
manifestInfo, err := repoClient.GenerateManifest(context.Background(), &repository.ManifestRequest{
|
||||
Repo: repo,
|
||||
Environment: app.Spec.Source.Environment,
|
||||
Path: app.Spec.Source.Path,
|
||||
Revision: app.Spec.Source.TargetRevision,
|
||||
ComponentParameterOverrides: overrides,
|
||||
AppLabel: app.Name,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
targetObjs := make([]*unstructured.Unstructured, len(manifestInfo.Manifests))
|
||||
for i, manifest := range manifestInfo.Manifests {
|
||||
obj, err := v1alpha1.UnmarshalToUnstructured(manifest)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
targetObjs[i] = obj
|
||||
}
|
||||
|
||||
server, namespace := app.Spec.Destination.Server, app.Spec.Destination.Namespace
|
||||
|
||||
log.Infof("Comparing app %s state in cluster %s (namespace: %s)", app.ObjectMeta.Name, server, namespace)
|
||||
// Get the REST config for the cluster corresponding to the environment
|
||||
clst, err := ks.db.GetCluster(context.Background(), server)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
restConfig := clst.RESTConfig()
|
||||
|
||||
// Retrieve the live versions of the objects
|
||||
liveObjs, err := kubeutil.GetResourcesWithLabel(restConfig, namespace, common.LabelApplicationName, app.Name)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
liveObjByFullName := ks.groupLiveObjects(liveObjs, targetObjs)
|
||||
|
||||
controlledLiveObj := make([]*unstructured.Unstructured, len(targetObjs))
|
||||
|
||||
// Move live resources which have corresponding target object to controlledLiveObj
|
||||
dynClientPool := dynamic.NewDynamicClientPool(restConfig)
|
||||
disco, err := discovery.NewDiscoveryClientForConfig(restConfig)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
for i, targetObj := range targetObjs {
|
||||
fullName := getResourceFullName(targetObj)
|
||||
liveObj := liveObjByFullName[fullName]
|
||||
if liveObj == nil && targetObj.GetName() != "" {
|
||||
// If we get here, it indicates we did not find the live resource when querying using
|
||||
// our app label. However, it is possible that the resource was created/modified outside
|
||||
// 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 {
|
||||
return nil, nil, err
|
||||
}
|
||||
liveObj, err = kubeutil.GetLiveResource(dclient, targetObj, apiResource, namespace)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
controlledLiveObj[i] = liveObj
|
||||
delete(liveObjByFullName, fullName)
|
||||
}
|
||||
|
||||
// Move root level live resources to controlledLiveObj and add nil to targetObjs to indicate that target object is missing
|
||||
for fullName := range liveObjByFullName {
|
||||
liveObj := liveObjByFullName[fullName]
|
||||
if !hasParent(liveObj) {
|
||||
targetObjs = append(targetObjs, nil)
|
||||
controlledLiveObj = append(controlledLiveObj, liveObj)
|
||||
}
|
||||
}
|
||||
|
||||
// Do the actual comparison
|
||||
diffResults, err := diff.DiffArray(targetObjs, controlledLiveObj)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
comparisonStatus := v1alpha1.ComparisonStatusSynced
|
||||
|
||||
resources := make([]v1alpha1.ResourceState, len(targetObjs))
|
||||
for i := 0; i < len(targetObjs); i++ {
|
||||
resState := v1alpha1.ResourceState{
|
||||
ChildLiveResources: make([]v1alpha1.ResourceNode, 0),
|
||||
}
|
||||
diffResult := diffResults.Diffs[i]
|
||||
if diffResult.Modified {
|
||||
// Set resource state to 'OutOfSync' since target and corresponding live resource are different
|
||||
resState.Status = v1alpha1.ComparisonStatusOutOfSync
|
||||
comparisonStatus = v1alpha1.ComparisonStatusOutOfSync
|
||||
} else {
|
||||
resState.Status = v1alpha1.ComparisonStatusSynced
|
||||
}
|
||||
|
||||
if targetObjs[i] == nil {
|
||||
resState.TargetState = "null"
|
||||
// Set resource state to 'OutOfSync' since target resource is missing and live resource is unexpected
|
||||
resState.Status = v1alpha1.ComparisonStatusOutOfSync
|
||||
comparisonStatus = v1alpha1.ComparisonStatusOutOfSync
|
||||
} else {
|
||||
targetObjBytes, err := json.Marshal(targetObjs[i].Object)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
resState.TargetState = string(targetObjBytes)
|
||||
}
|
||||
|
||||
if controlledLiveObj[i] == nil {
|
||||
resState.LiveState = "null"
|
||||
// Set resource state to 'OutOfSync' since target resource present but corresponding live resource is missing
|
||||
resState.Status = v1alpha1.ComparisonStatusOutOfSync
|
||||
comparisonStatus = v1alpha1.ComparisonStatusOutOfSync
|
||||
} else {
|
||||
liveObjBytes, err := json.Marshal(controlledLiveObj[i].Object)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
resState.LiveState = string(liveObjBytes)
|
||||
}
|
||||
|
||||
resources[i] = resState
|
||||
}
|
||||
|
||||
for i, resource := range resources {
|
||||
liveResource := controlledLiveObj[i]
|
||||
if liveResource != nil {
|
||||
childResources, err := getChildren(liveResource, liveObjByFullName)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
resource.ChildLiveResources = childResources
|
||||
resources[i] = resource
|
||||
}
|
||||
}
|
||||
compResult := v1alpha1.ComparisonResult{
|
||||
ComparedTo: app.Spec.Source,
|
||||
ComparedAt: metav1.Time{Time: time.Now().UTC()},
|
||||
Resources: resources,
|
||||
Status: comparisonStatus,
|
||||
}
|
||||
return &compResult, manifestInfo, nil
|
||||
}
|
||||
|
||||
func hasParent(obj *unstructured.Unstructured) bool {
|
||||
// TODO: remove special case after Service and Endpoint get explicit relationship ( https://github.com/kubernetes/kubernetes/issues/28483 )
|
||||
return obj.GetKind() == kubeutil.EndpointsKind || metav1.GetControllerOf(obj) != nil
|
||||
}
|
||||
|
||||
func isControlledBy(obj *unstructured.Unstructured, parent *unstructured.Unstructured) bool {
|
||||
// TODO: remove special case after Service and Endpoint get explicit relationship ( https://github.com/kubernetes/kubernetes/issues/28483 )
|
||||
if obj.GetKind() == kubeutil.EndpointsKind && parent.GetKind() == kubeutil.ServiceKind {
|
||||
return obj.GetName() == parent.GetName()
|
||||
}
|
||||
return metav1.IsControlledBy(obj, parent)
|
||||
}
|
||||
|
||||
func getChildren(parent *unstructured.Unstructured, liveObjByFullName map[string]*unstructured.Unstructured) ([]v1alpha1.ResourceNode, error) {
|
||||
children := make([]v1alpha1.ResourceNode, 0)
|
||||
for fullName, obj := range liveObjByFullName {
|
||||
if isControlledBy(obj, parent) {
|
||||
delete(liveObjByFullName, fullName)
|
||||
childResource := v1alpha1.ResourceNode{}
|
||||
json, err := json.Marshal(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
childResource.State = string(json)
|
||||
childResourceChildren, err := getChildren(obj, liveObjByFullName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
childResource.Children = childResourceChildren
|
||||
children = append(children, childResource)
|
||||
}
|
||||
}
|
||||
return children, nil
|
||||
}
|
||||
|
||||
func getResourceFullName(obj *unstructured.Unstructured) string {
|
||||
return fmt.Sprintf("%s:%s", obj.GetKind(), obj.GetName())
|
||||
}
|
||||
|
||||
func (s *KsonnetAppStateManager) SyncAppState(
|
||||
app *v1alpha1.Application, revision string, overrides *[]v1alpha1.ComponentParameter, dryRun bool, prune bool) *v1alpha1.OperationState {
|
||||
|
||||
if revision != "" {
|
||||
app.Spec.Source.TargetRevision = revision
|
||||
}
|
||||
|
||||
if overrides != nil {
|
||||
app.Spec.Source.ComponentParameterOverrides = *overrides
|
||||
}
|
||||
|
||||
opRes, manifest := s.syncAppResources(app, dryRun, prune)
|
||||
if !dryRun && opRes.Phase.Successful() {
|
||||
err := s.persistDeploymentInfo(app, manifest.Revision, manifest.Params, nil)
|
||||
if err != nil {
|
||||
opRes.Phase = v1alpha1.OperationError
|
||||
opRes.Message = fmt.Sprintf("failed to record sync to history: %v", err)
|
||||
}
|
||||
}
|
||||
return opRes
|
||||
}
|
||||
|
||||
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
|
||||
repo = &v1alpha1.Repository{Repo: repoURL}
|
||||
}
|
||||
return repo
|
||||
}
|
||||
|
||||
func (s *KsonnetAppStateManager) persistDeploymentInfo(
|
||||
app *v1alpha1.Application, revision string, envParams []*v1alpha1.ComponentParameter, overrides *[]v1alpha1.ComponentParameter) error {
|
||||
|
||||
params := make([]v1alpha1.ComponentParameter, len(envParams))
|
||||
for i := range envParams {
|
||||
param := *envParams[i]
|
||||
params[i] = param
|
||||
}
|
||||
var nextId int64 = 0
|
||||
if len(app.Status.History) > 0 {
|
||||
nextId = app.Status.History[len(app.Status.History)-1].ID + 1
|
||||
}
|
||||
history := append(app.Status.History, v1alpha1.DeploymentInfo{
|
||||
ComponentParameterOverrides: app.Spec.Source.ComponentParameterOverrides,
|
||||
Revision: revision,
|
||||
Params: params,
|
||||
DeployedAt: metav1.NewTime(time.Now()),
|
||||
ID: nextId,
|
||||
})
|
||||
|
||||
if len(history) > maxHistoryCnt {
|
||||
history = history[1 : maxHistoryCnt+1]
|
||||
}
|
||||
|
||||
patch, err := json.Marshal(map[string]map[string][]v1alpha1.DeploymentInfo{
|
||||
"status": {
|
||||
"history": history,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = s.appclientset.ArgoprojV1alpha1().Applications(s.namespace).Patch(app.Name, types.MergePatchType, patch)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *KsonnetAppStateManager) syncAppResources(
|
||||
app *v1alpha1.Application,
|
||||
dryRun bool,
|
||||
prune bool) (*v1alpha1.OperationState, *repository.ManifestResponse) {
|
||||
|
||||
opRes := v1alpha1.OperationState{
|
||||
SyncResult: &v1alpha1.SyncOperationResult{},
|
||||
}
|
||||
|
||||
comparison, manifestInfo, err := s.CompareAppState(app)
|
||||
if err != nil {
|
||||
opRes.Phase = v1alpha1.OperationError
|
||||
opRes.Message = err.Error()
|
||||
return &opRes, manifestInfo
|
||||
}
|
||||
|
||||
clst, err := s.db.GetCluster(context.Background(), app.Spec.Destination.Server)
|
||||
if err != nil {
|
||||
opRes.Phase = v1alpha1.OperationError
|
||||
opRes.Message = err.Error()
|
||||
return &opRes, manifestInfo
|
||||
}
|
||||
config := clst.RESTConfig()
|
||||
|
||||
opRes.SyncResult.Resources = make([]*v1alpha1.ResourceDetails, len(comparison.Resources))
|
||||
liveObjs := make([]*unstructured.Unstructured, len(comparison.Resources))
|
||||
targetObjs := make([]*unstructured.Unstructured, len(comparison.Resources))
|
||||
|
||||
// First perform a `kubectl apply --dry-run` against all the manifests. This will detect most
|
||||
// (but not all) validation issues with the users' manifests (e.g. will detect syntax issues,
|
||||
// but will not not detect if they are mutating immutable fields). If anything fails, we will
|
||||
// refuse to perform the sync.
|
||||
dryRunSuccessful := true
|
||||
for i, resourceState := range comparison.Resources {
|
||||
liveObj, err := resourceState.LiveObject()
|
||||
if err != nil {
|
||||
opRes.Phase = v1alpha1.OperationError
|
||||
opRes.Message = fmt.Sprintf("Failed to unmarshal live object: %v", err)
|
||||
return &opRes, manifestInfo
|
||||
}
|
||||
targetObj, err := resourceState.TargetObject()
|
||||
if err != nil {
|
||||
opRes.Phase = v1alpha1.OperationError
|
||||
opRes.Message = fmt.Sprintf("Failed to unmarshal target object: %v", err)
|
||||
return &opRes, manifestInfo
|
||||
}
|
||||
liveObjs[i] = liveObj
|
||||
targetObjs[i] = targetObj
|
||||
resDetails, successful := syncObject(config, app.Spec.Destination.Namespace, targetObj, liveObj, prune, true)
|
||||
if !successful {
|
||||
dryRunSuccessful = false
|
||||
}
|
||||
opRes.SyncResult.Resources[i] = &resDetails
|
||||
}
|
||||
if !dryRunSuccessful {
|
||||
opRes.Phase = v1alpha1.OperationFailed
|
||||
opRes.Message = "one or more objects failed to apply (dry run)"
|
||||
return &opRes, manifestInfo
|
||||
}
|
||||
if dryRun {
|
||||
opRes.Phase = v1alpha1.OperationSucceeded
|
||||
opRes.Message = "successfully synced (dry run)"
|
||||
return &opRes, manifestInfo
|
||||
}
|
||||
// If we get here, all objects passed their dry-run, so we are now ready to actually perform the
|
||||
// `kubectl apply`. Loop through the resources again, this time without dry-run.
|
||||
syncSuccessful := true
|
||||
for i := range comparison.Resources {
|
||||
resDetails, successful := syncObject(config, app.Spec.Destination.Namespace, targetObjs[i], liveObjs[i], prune, false)
|
||||
if !successful {
|
||||
syncSuccessful = false
|
||||
}
|
||||
opRes.SyncResult.Resources[i] = &resDetails
|
||||
}
|
||||
if !syncSuccessful {
|
||||
opRes.Message = "one or more objects failed to apply"
|
||||
opRes.Phase = v1alpha1.OperationFailed
|
||||
} else {
|
||||
opRes.Message = "successfully synced"
|
||||
opRes.Phase = v1alpha1.OperationSucceeded
|
||||
}
|
||||
return &opRes, manifestInfo
|
||||
}
|
||||
|
||||
// syncObject performs a sync of a single resource
|
||||
func syncObject(config *rest.Config, namespace string, targetObj, liveObj *unstructured.Unstructured, prune, dryRun bool) (v1alpha1.ResourceDetails, bool) {
|
||||
obj := targetObj
|
||||
if obj == nil {
|
||||
obj = liveObj
|
||||
}
|
||||
resDetails := v1alpha1.ResourceDetails{
|
||||
Name: obj.GetName(),
|
||||
Kind: obj.GetKind(),
|
||||
Namespace: namespace,
|
||||
}
|
||||
needsDelete := targetObj == nil
|
||||
successful := true
|
||||
if needsDelete {
|
||||
if prune {
|
||||
if dryRun {
|
||||
resDetails.Message = "pruned (dry run)"
|
||||
resDetails.Status = v1alpha1.ResourceDetailsSyncedAndPruned
|
||||
} else {
|
||||
err := kubeutil.DeleteResource(config, liveObj, namespace)
|
||||
if err != nil {
|
||||
resDetails.Message = err.Error()
|
||||
resDetails.Status = v1alpha1.ResourceDetailsSyncFailed
|
||||
successful = false
|
||||
} else {
|
||||
resDetails.Message = "pruned"
|
||||
resDetails.Status = v1alpha1.ResourceDetailsSyncedAndPruned
|
||||
}
|
||||
}
|
||||
} else {
|
||||
resDetails.Message = "ignored (requires pruning)"
|
||||
resDetails.Status = v1alpha1.ResourceDetailsPruningRequired
|
||||
}
|
||||
} else {
|
||||
message, err := kube.ApplyResource(config, targetObj, namespace, dryRun)
|
||||
if err != nil {
|
||||
resDetails.Message = err.Error()
|
||||
resDetails.Status = v1alpha1.ResourceDetailsSyncFailed
|
||||
successful = false
|
||||
} else {
|
||||
resDetails.Message = message
|
||||
resDetails.Status = v1alpha1.ResourceDetailsSynced
|
||||
}
|
||||
}
|
||||
return resDetails, successful
|
||||
}
|
||||
|
||||
// NewAppStateManager creates new instance of Ksonnet app comparator
|
||||
func NewAppStateManager(
|
||||
db db.ArgoDB,
|
||||
appclientset appclientset.Interface,
|
||||
repoClientset reposerver.Clientset,
|
||||
namespace string,
|
||||
) AppStateManager {
|
||||
return &KsonnetAppStateManager{
|
||||
db: db,
|
||||
appclientset: appclientset,
|
||||
repoClientset: repoClientset,
|
||||
namespace: namespace,
|
||||
}
|
||||
}
|
||||
@@ -9,9 +9,10 @@
|
||||
The API server is a gRPC/REST server which exposes the API consumed by the Web UI, CLI, and CI/CD
|
||||
systems. It has the following responsibilities:
|
||||
* application management and status reporting
|
||||
* invoking of application actions (e.g. manual sync, user-defined actions)
|
||||
* invoking of application operations (e.g. sync, rollback, user-defined actions)
|
||||
* repository and cluster credential management (stored as K8s secrets)
|
||||
* authentication and RBAC enforcement, with eventual integration with external identity providers
|
||||
* authentication and auth delegation to external identity providers
|
||||
* RBAC enforcement
|
||||
* listener/forwarder for git webhook events
|
||||
|
||||
### Repository Server
|
||||
BIN
docs/assets/oauth2-config.png
Normal file
BIN
docs/assets/oauth2-config.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 60 KiB |
BIN
docs/assets/register-app.png
Normal file
BIN
docs/assets/register-app.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 70 KiB |
BIN
docs/assets/webhook-config.png
Normal file
BIN
docs/assets/webhook-config.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 92 KiB |
@@ -9,11 +9,16 @@ An example Ksonnet guestbook application is provided to demonstrates how Argo CD
|
||||
|
||||
## 1. Download Argo CD
|
||||
|
||||
Download the latest Argo CD version from the [releases](https://github.com/argoproj/argo-cd/releases) page.
|
||||
|
||||
## 2. Install the Argo CD components
|
||||
Download the latest Argo CD version
|
||||
```
|
||||
$ argocd install
|
||||
curl -sSL -o /usr/local/bin/argocd https://github.com/argoproj/argo-cd/releases/download/v0.5.1/argocd-darwin-amd64
|
||||
chmod +x /usr/local/bin/argocd
|
||||
```
|
||||
|
||||
|
||||
## 2. Install Argo CD
|
||||
```
|
||||
argocd install
|
||||
```
|
||||
This will create a new namespace, `argocd`, where Argo CD services and application resources will live.
|
||||
|
||||
@@ -23,24 +28,23 @@ By default, the Argo CD API server is not exposed with an external IP. To expose
|
||||
change service type to `LoadBalancer`:
|
||||
|
||||
```
|
||||
$ kubectl patch svc argocd-server -n argocd -p '{"spec": {"type": "LoadBalancer"}}'
|
||||
kubectl patch svc argocd-server -n argocd -p '{"spec": {"type": "LoadBalancer"}}'
|
||||
```
|
||||
|
||||
Export API server URL into `ARGOCD_SERVER` environment variable, which the CLI looks to for
|
||||
connection information:
|
||||
## 4. Login to the server from the CLI
|
||||
|
||||
```
|
||||
$ export ARGOCD_SERVER=$(minikube service argocd-server -n argocd --url | cut -d'/' -f 3)
|
||||
argocd login $(minikube service argocd-server -n argocd --url | cut -d'/' -f 3)
|
||||
```
|
||||
|
||||
Now, Argo CD is able to talk to API server and you can deploy your first application.
|
||||
Now, the Argo CD cli is configured to talk to API server and you can deploy your first application.
|
||||
|
||||
## 4. Connect and deploy the Guestbook application
|
||||
## 5. Connect and deploy the Guestbook application
|
||||
|
||||
1. Register the minikube cluster to Argo CD:
|
||||
|
||||
```
|
||||
$ argocd cluster add minikube
|
||||
argocd cluster add minikube
|
||||
```
|
||||
The `argocd cluster add CONTEXT` command installs an `argocd-manager` ServiceAccount and ClusterRole into
|
||||
the cluster associated with the supplied kubectl context. Argo CD then uses the associated service account
|
||||
@@ -49,21 +53,21 @@ token to perform its required management tasks (i.e. deploy/monitoring).
|
||||
2. Add the guestbook application and github repository containing the Guestbook application
|
||||
|
||||
```
|
||||
$ argocd app add --name guestbook --repo https://github.com/argoproj/argo-cd.git --path examples/guestbook --env minikube --dest-server https://$(minikube ip):8443
|
||||
argocd app create --name guestbook --repo https://github.com/argoproj/argo-cd.git --path examples/guestbook --env minikube --dest-server https://$(minikube ip):8443
|
||||
```
|
||||
|
||||
Once the application is added, you can now see its status:
|
||||
|
||||
```
|
||||
$ argocd app list
|
||||
$ argocd app sync guestbook
|
||||
argocd app list
|
||||
argocd app get guestbook
|
||||
```
|
||||
|
||||
The application status is initially in an `OutOfSync` state, since the application has yet to be
|
||||
deployed, and no Kubernetes resouces have been created. To sync (deploy) the application, run:
|
||||
deployed, and no Kubernetes resources have been created. To sync (deploy) the application, run:
|
||||
|
||||
```
|
||||
$ argocd app sync guestbook
|
||||
argocd app sync guestbook
|
||||
```
|
||||
|
||||
[](https://asciinema.org/a/uYnbFMy5WI2rc9S49oEAyGLb0)
|
||||
@@ -71,7 +75,7 @@ $ argocd app sync guestbook
|
||||
Argo CD also allows to view and manager applications using web UI. Get the web UI URL by running:
|
||||
|
||||
```
|
||||
$ minikube service argocd-server -n argocd --url
|
||||
minikube service argocd-server -n argocd --url
|
||||
```
|
||||
|
||||

|
||||
72
docs/sso.md
Normal file
72
docs/sso.md
Normal file
@@ -0,0 +1,72 @@
|
||||
# SSO Configuration
|
||||
|
||||
## Overview
|
||||
|
||||
ArgoCD embeds and bundles [Dex](https://github.com/coreos/dex) as part of its installation, for the
|
||||
purposes of delegating authentication to an external identity provider. Multiple types of identity
|
||||
providers are supported (OIDC, SAML, LDAP, GitHub, etc...). SSO configuration of ArgoCD requires
|
||||
editing the `argocd-cm` ConfigMap with a
|
||||
[Dex connector](https://github.com/coreos/dex/tree/master/Documentation/connectors) settings.
|
||||
|
||||
This document describes how to configure ArgoCD SSO using GitHub (OAuth2) as an example, but the
|
||||
steps should be similar for other identity providers.
|
||||
|
||||
### 1. Register the application in the identity provider
|
||||
|
||||
In GitHub, register a new application. The callback address should be the `/api/dex/callback`
|
||||
endpoint of your ArgoCD URL (e.g. https://argocd.example.com/api/dex/callback).
|
||||
|
||||

|
||||
|
||||
After registering the app, you will receive an OAuth2 client ID and secret. These values will be
|
||||
inputted into the ArgoCD configmap.
|
||||
|
||||

|
||||
|
||||
### 2. Configure ArgoCD for SSO
|
||||
|
||||
Edit the argocd-cm configmap:
|
||||
```
|
||||
kubectl edit configmap argocd-cm
|
||||
```
|
||||
|
||||
* In the `url` key, input the base URL of ArgoCD. In this example, it is https://argocd.example.com
|
||||
* In the `dex.config` key, add the `github` connector to the `connectors` sub field. See Dex's
|
||||
[GitHub connector](https://github.com/coreos/dex/blob/master/Documentation/connectors/github.md)
|
||||
documentation for explanation of the fields. A minimal config should populate the clientID,
|
||||
clientSecret generated in Step 1.
|
||||
* You will very likely want to restrict logins to one ore more GitHub organization. In the
|
||||
`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.
|
||||
|
||||
```
|
||||
data:
|
||||
url: https://argocd.example.com
|
||||
|
||||
dex.config: |
|
||||
connectors:
|
||||
- type: github
|
||||
id: github
|
||||
name: GitHub
|
||||
config:
|
||||
clientID: 5aae0fcec2c11634be8c
|
||||
clientSecret: c6fcb18177869174bd09be2c51259fb049c9d4e5
|
||||
orgs:
|
||||
- name: your-github-org
|
||||
```
|
||||
|
||||
NOTES:
|
||||
* Any values which start with '$' will look to a key in argocd-secret of the same name (minus the $),
|
||||
to obtain the actual value. This allows you to store the `clientSecret` as a kubernetes secret.
|
||||
* There is no need to set `redirectURI` in the `connectors.config` as shown in the dex documentation.
|
||||
ArgoCD will automatically use the correct `redirectURI` for any OAuth2 connectors, to match the
|
||||
correct external callback URL (e.g. https://argocd.example.com/api/dex/callback)
|
||||
|
||||
### 3. Restart ArgoCD for changes to take effect
|
||||
Any changes to the `argocd-cm` ConfigMap or `argocd-secret` Secret, currently require a restart of
|
||||
the ArgoCD API server for the settings to take effect. Delete the `argocd-server` pod to force a
|
||||
restart. [Issue #174](https://github.com/argoproj/argo-cd/issues/174) will address this limitation.
|
||||
|
||||
```
|
||||
kubectl delete pod -l app=argocd-server
|
||||
```
|
||||
41
docs/tracking_strategies.md
Normal file
41
docs/tracking_strategies.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# Tracking and Deployment Strategies
|
||||
|
||||
An ArgoCD application spec provides several different ways of track kubernetes resource manifests in git. This document describes the different techniques and the means of deploying those manifests to the target environment.
|
||||
|
||||
## Branch Tracking
|
||||
|
||||
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, which will then be detected by ArgoCD controller.
|
||||
|
||||
## Tag Tracking
|
||||
|
||||
If a tag is specified, the manifests at the specified git tag will be used to perform the sync comparison. This provides some advantages over branch tracking in that a tag is generally considered more stable, and less frequently updated, with some manual judgement of what constitutes a tag.
|
||||
|
||||
To redeploy an application, the user uses git to change the meaning of a tag by retagging it to a different commit SHA. ArgoCD will detect the new meaning of the tag when performing the comparison/sync.
|
||||
|
||||
## Commit Pinning
|
||||
|
||||
If a git commit SHA is specified, the application is effectively pinned to the manifests defined at the specified commit. This is the most restrictive of the techniques and is typically used to control production environments.
|
||||
|
||||
Since commit SHAs cannot change meaning, the only way to change the live state of an application which is pinned to a commit, is by updating the tracking revision in the application to a different commit containing the new manifests.
|
||||
Note that parameter overrides can still be made against a application which is pinned to a revision.
|
||||
|
||||
## Parameter Overrides
|
||||
|
||||
ArgoCD provides means to override the parameters of a ksonnet app. This gives some extra flexibility in having *some* parts of the k8s manifests determined dynamically. It also serves as an alternative way of redeploying an application by changing application parameters via ArgoCD, instead of making the changes to the manifests in git.
|
||||
|
||||
The following is an example of where this would be useful: A team maintains a "dev" environment, which needs to be continually updated with the latest version of their guestbook application after every build in the tip of master. To address this use case, the ksonnet application should expose an parameter named `image`, whose value used in the `dev` environment contains a placeholder value (e.g. `example/guestbook:replaceme`), intended to be set externally (outside of git) such as a build systems. As part of the build pipeline, the parameter value of the `image` would be continually updated to the freshly built image (e.g. `example/guestbook:abcd123`). A sync operation would result in the application being redeployed with the new image.
|
||||
|
||||
ArgoCD provides these operations conveniently via the CLI, or alternatively via the gRPC/REST API.
|
||||
```
|
||||
$ argocd app set guestbook -p guestbook=image=example/guestbook:abcd123
|
||||
$ argocd app sync guestbook
|
||||
```
|
||||
|
||||
Note that in all tracking strategies, any parameter overrides set in the application instance will be honored.
|
||||
|
||||
|
||||
## [Auto-Sync](https://github.com/argoproj/argo-cd/issues/79) (Not Yet Implemented)
|
||||
|
||||
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.
|
||||
70
docs/webhook.md
Normal file
70
docs/webhook.md
Normal file
@@ -0,0 +1,70 @@
|
||||
# Git Webhook Configuration
|
||||
|
||||
## Overview
|
||||
|
||||
ArgoCD will poll git repositories every three minutes for changes to the manifests. To eliminate
|
||||
this delay from polling, the API server can be configured to receive webhook events. ArgoCD supports
|
||||
git webhook notifications from GitHub, GitLab, and BitBucket. The following explains how to configure
|
||||
a git webhook for GitHub, but the same process should be applicable to other providers.
|
||||
|
||||
### 1. Create the webhook in the git provider
|
||||
|
||||
In your git provider, navigate to the settings page where webhooks can be configured. 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). Input an arbitrary value in the secret. The same
|
||||
value will be used when configuring the webhook in step 2.
|
||||
|
||||

|
||||
|
||||
### 2. Configure ArgoCD with the webhook secret
|
||||
|
||||
In the `argocd-secret` kubernetes secret, configure one of the following keys with the git provider
|
||||
webhook secret configured in step 1.
|
||||
|
||||
| Provider | K8s Secret Key |
|
||||
|---------- | ------------------------ |
|
||||
| GitHub | `github.webhook.secret` |
|
||||
| GitLab | `gitlab.webhook.secret` |
|
||||
| BitBucket | `bitbucket.webhook.uuid` |
|
||||
|
||||
Edit the ArgoCD kubernetes secret:
|
||||
```
|
||||
kubectl edit secret argocd-secret
|
||||
```
|
||||
|
||||
TIP: for ease of entering secrets, kubernetes supports inputting secrets in the `stringData` field,
|
||||
which saves you the trouble of base64 encoding the values and copying it to the `data` field.
|
||||
Simply copy the shared webhook secret created in step 1, to the corresponding
|
||||
GitHub/GitLab/BitBucket key under the `stringData` field:
|
||||
|
||||
|
||||
```
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: argocd-secret
|
||||
namespace: argocd
|
||||
type: Opaque
|
||||
data:
|
||||
...
|
||||
|
||||
stringData:
|
||||
# github webhook secret
|
||||
github.webhook.secret: shhhh! it's a github secret
|
||||
|
||||
# gitlab webhook secret
|
||||
gitlab.webhook.secret: shhhh! it's a gitlab secret
|
||||
|
||||
# bitbucket webhook secret
|
||||
bitbucket.webhook.uuid: your-bitbucket-uuid
|
||||
|
||||
```
|
||||
|
||||
### 3. Restart ArgoCD for changes to take effect
|
||||
Any changes to the `argocd-cm` ConfigMap or `argocd-secret` Secret, currently require a restart of
|
||||
the ArgoCD API server for the settings to take effect. Delete the `argocd-server` pod to force a
|
||||
restart. [Issue #174](https://github.com/argoproj/argo-cd/issues/174) will address this limitation.
|
||||
|
||||
```
|
||||
kubectl delete pod -l app=argocd-server
|
||||
```
|
||||
@@ -23,7 +23,7 @@ local appDeployment = deployment
|
||||
params.replicas,
|
||||
container
|
||||
.new(params.name, params.image)
|
||||
.withPorts(containerPort.new(targetPort)),
|
||||
labels);
|
||||
.withPorts(containerPort.new(targetPort)) + if params.command != null then { command: [ params.command ] } else {},
|
||||
labels).withProgressDeadlineSeconds(5);
|
||||
|
||||
k.core.v1.list.new([appService, appDeployment])
|
||||
@@ -12,7 +12,8 @@
|
||||
name: "guestbook-ui",
|
||||
replicas: 1,
|
||||
servicePort: 80,
|
||||
type: "LoadBalancer",
|
||||
type: "ClusterIP",
|
||||
command: null,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"Vendor": true,
|
||||
"DisableAll": true,
|
||||
"Deadline": "3m",
|
||||
"Deadline": "8m",
|
||||
"Enable": [
|
||||
"vet",
|
||||
"gofmt",
|
||||
|
||||
@@ -39,10 +39,19 @@ go-to-protobuf \
|
||||
--apimachinery-packages=$(IFS=, ; echo "${APIMACHINERY_PKGS[*]}") \
|
||||
--proto-import=./vendor
|
||||
|
||||
# protoc-gen-go or protoc-gen-gofast is used to build server/*/<service>.pb.go from .proto files
|
||||
# NOTE: it is possible to use golang/protobuf or gogo/protobuf interchangeably
|
||||
go build -i -o dist/protoc-gen-gofast ./vendor/github.com/gogo/protobuf/protoc-gen-gofast
|
||||
# Either protoc-gen-go, protoc-gen-gofast, or protoc-gen-gogofast can be used to build
|
||||
# server/*/<service>.pb.go from .proto files. golang/protobuf and gogo/protobuf can be used
|
||||
# interchangeably. The difference in the options are:
|
||||
# 1. protoc-gen-go - official golang/protobuf
|
||||
#go build -i -o dist/protoc-gen-go ./vendor/github.com/golang/protobuf/protoc-gen-go
|
||||
#GOPROTOBINARY=go
|
||||
# 2. protoc-gen-gofast - fork of golang golang/protobuf. Faster code generation
|
||||
#go build -i -o dist/protoc-gen-gofast ./vendor/github.com/gogo/protobuf/protoc-gen-gofast
|
||||
#GOPROTOBINARY=gofast
|
||||
# 3. protoc-gen-gogofast - faster code generation and gogo extensions and flexibility in controlling
|
||||
# the generated go code (e.g. customizing field names, nullable fields)
|
||||
go build -i -o dist/protoc-gen-gogofast ./vendor/github.com/gogo/protobuf/protoc-gen-gogofast
|
||||
GOPROTOBINARY=gogofast
|
||||
|
||||
# protoc-gen-grpc-gateway is used to build <service>.pb.gw.go files from from .proto files
|
||||
go build -i -o dist/protoc-gen-grpc-gateway ./vendor/github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway
|
||||
@@ -50,7 +59,6 @@ go build -i -o dist/protoc-gen-grpc-gateway ./vendor/github.com/grpc-ecosystem/g
|
||||
# Generate server/<service>/(<service>.pb.go|<service>.pb.gw.go)
|
||||
PROTO_FILES=$(find $PROJECT_ROOT \( -name "*.proto" -and -path '*/server/*' -or -path '*/reposerver/*' -and -name "*.proto" \))
|
||||
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
|
||||
@@ -67,7 +75,7 @@ for i in ${PROTO_FILES}; do
|
||||
-I$GOPATH/src \
|
||||
-I${GOOGLE_PROTO_API_PATH} \
|
||||
-I${GOGO_PROTOBUF_PATH} \
|
||||
--go_out=plugins=grpc:$GOPATH/src \
|
||||
--${GOPROTOBINARY}_out=plugins=grpc:$GOPATH/src \
|
||||
--grpc-gateway_out=logtostderr=true:$GOPATH/src \
|
||||
$i
|
||||
done
|
||||
|
||||
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,25 +1,17 @@
|
||||
package install
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/argoproj/argo-cd/errors"
|
||||
"github.com/argoproj/argo-cd/util"
|
||||
"github.com/argoproj/argo-cd/util/diff"
|
||||
"github.com/argoproj/argo-cd/util/kube"
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/gobuffalo/packr"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/yudai/gojsondiff/formatter"
|
||||
"golang.org/x/crypto/ssh/terminal"
|
||||
appsv1beta2 "k8s.io/api/apps/v1beta2"
|
||||
apiv1 "k8s.io/api/core/v1"
|
||||
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
|
||||
apierr "k8s.io/apimachinery/pkg/api/errors"
|
||||
@@ -29,6 +21,15 @@ import (
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
|
||||
"github.com/argoproj/argo-cd/common"
|
||||
"github.com/argoproj/argo-cd/errors"
|
||||
"github.com/argoproj/argo-cd/util/diff"
|
||||
"github.com/argoproj/argo-cd/util/kube"
|
||||
"github.com/argoproj/argo-cd/util/password"
|
||||
"github.com/argoproj/argo-cd/util/session"
|
||||
"github.com/argoproj/argo-cd/util/settings"
|
||||
tlsutil "github.com/argoproj/argo-cd/util/tls"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -47,16 +48,17 @@ var (
|
||||
|
||||
// InstallOptions stores a collection of installation settings.
|
||||
type InstallOptions struct {
|
||||
DryRun bool
|
||||
Upgrade bool
|
||||
ConfigSuperuser bool
|
||||
ConfigMap string
|
||||
Namespace string
|
||||
ControllerImage string
|
||||
UIImage string
|
||||
ServerImage string
|
||||
RepoServerImage string
|
||||
ImagePullPolicy string
|
||||
DryRun bool
|
||||
Upgrade bool
|
||||
UpdateSuperuser bool
|
||||
UpdateSignature bool
|
||||
SuperuserPassword string
|
||||
Namespace string
|
||||
ControllerImage string
|
||||
UIImage string
|
||||
ServerImage string
|
||||
RepoServerImage string
|
||||
ImagePullPolicy string
|
||||
}
|
||||
|
||||
type Installer struct {
|
||||
@@ -74,6 +76,9 @@ func NewInstaller(config *rest.Config, opts InstallOptions) (*Installer, error)
|
||||
box: packr.NewBox("./manifests"),
|
||||
config: &shallowCopy,
|
||||
}
|
||||
if opts.Namespace == "" {
|
||||
inst.Namespace = DefaultInstallNamespace
|
||||
}
|
||||
var err error
|
||||
inst.dynClientPool = dynamic.NewDynamicClientPool(inst.config)
|
||||
inst.disco, err = discovery.NewDiscoveryClientForConfig(inst.config)
|
||||
@@ -86,30 +91,34 @@ func NewInstaller(config *rest.Config, opts InstallOptions) (*Installer, error)
|
||||
func (i *Installer) Install() {
|
||||
i.InstallNamespace()
|
||||
i.InstallApplicationCRD()
|
||||
i.InstallSettings()
|
||||
i.InstallRBACConfigMap()
|
||||
i.InstallApplicationController()
|
||||
i.InstallArgoCDServer()
|
||||
i.InstallArgoCDRepoServer()
|
||||
}
|
||||
|
||||
func (i *Installer) Uninstall() {
|
||||
func (i *Installer) Uninstall(deleteNamespace, deleteCRD bool) {
|
||||
manifests := i.box.List()
|
||||
for _, manifestPath := range manifests {
|
||||
if strings.HasSuffix(manifestPath, ".yaml") || strings.HasSuffix(manifestPath, ".yml") {
|
||||
var obj unstructured.Unstructured
|
||||
i.unmarshalManifest(manifestPath, &obj)
|
||||
if obj.GetKind() == "Namespace" {
|
||||
// Don't delete namespaces
|
||||
continue
|
||||
switch strings.ToLower(obj.GetKind()) {
|
||||
case "namespace":
|
||||
if !deleteNamespace {
|
||||
log.Infof("Skipped deletion of Namespace: '%s'", obj.GetName())
|
||||
continue
|
||||
}
|
||||
case "customresourcedefinition":
|
||||
if !deleteCRD {
|
||||
log.Infof("Skipped deletion of CustomResourceDefinition: '%s'", obj.GetName())
|
||||
continue
|
||||
}
|
||||
}
|
||||
i.MustUninstallResource(&obj)
|
||||
}
|
||||
}
|
||||
|
||||
// i.InstallNamespace()
|
||||
// i.InstallApplicationCRD()
|
||||
// i.InstallApplicationController()
|
||||
// i.InstallArgoCDServer()
|
||||
// i.InstallArgoCDRepoServer()
|
||||
}
|
||||
|
||||
func (i *Installer) InstallNamespace() {
|
||||
@@ -129,15 +138,99 @@ func (i *Installer) InstallApplicationCRD() {
|
||||
i.MustInstallResource(kube.MustToUnstructured(&applicationCRD))
|
||||
}
|
||||
|
||||
func (i *Installer) InstallSettings() {
|
||||
kubeclientset, err := kubernetes.NewForConfig(i.config)
|
||||
errors.CheckError(err)
|
||||
settingsMgr := settings.NewSettingsManager(kubeclientset, i.Namespace)
|
||||
cdSettings, err := settingsMgr.GetSettings()
|
||||
if err != nil {
|
||||
if apierr.IsNotFound(err) {
|
||||
cdSettings = &settings.ArgoCDSettings{}
|
||||
} else {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
if cdSettings.ServerSignature == nil || i.UpdateSignature {
|
||||
// set JWT signature
|
||||
signature, err := session.MakeSignature(32)
|
||||
errors.CheckError(err)
|
||||
cdSettings.ServerSignature = signature
|
||||
}
|
||||
|
||||
if cdSettings.LocalUsers == nil {
|
||||
cdSettings.LocalUsers = make(map[string]string)
|
||||
}
|
||||
if _, ok := cdSettings.LocalUsers[common.ArgoCDAdminUsername]; !ok || i.UpdateSuperuser {
|
||||
passwordRaw := i.SuperuserPassword
|
||||
if passwordRaw == "" {
|
||||
passwordRaw = readAndConfirmPassword()
|
||||
}
|
||||
hashedPassword, err := password.HashPassword(passwordRaw)
|
||||
errors.CheckError(err)
|
||||
cdSettings.LocalUsers = map[string]string{
|
||||
common.ArgoCDAdminUsername: hashedPassword,
|
||||
}
|
||||
}
|
||||
|
||||
if cdSettings.Certificate == nil {
|
||||
// generate TLS cert
|
||||
hosts := []string{
|
||||
"localhost",
|
||||
"argocd-server",
|
||||
fmt.Sprintf("argocd-server.%s", i.Namespace),
|
||||
fmt.Sprintf("argocd-server.%s.svc", i.Namespace),
|
||||
fmt.Sprintf("argocd-server.%s.svc.cluster.local", i.Namespace),
|
||||
}
|
||||
certOpts := tlsutil.CertOptions{
|
||||
Hosts: hosts,
|
||||
Organization: "Argo CD",
|
||||
IsCA: true,
|
||||
}
|
||||
cert, err := tlsutil.GenerateX509KeyPair(certOpts)
|
||||
errors.CheckError(err)
|
||||
cdSettings.Certificate = cert
|
||||
}
|
||||
|
||||
err = settingsMgr.SaveSettings(cdSettings)
|
||||
errors.CheckError(err)
|
||||
}
|
||||
|
||||
func (i *Installer) InstallRBACConfigMap() {
|
||||
var rbacCM apiv1.ConfigMap
|
||||
i.unmarshalManifest("02c_argocd-rbac-cm.yaml", &rbacCM)
|
||||
_, err := i.InstallResource(kube.MustToUnstructured(&rbacCM))
|
||||
if err != nil && !apierr.IsAlreadyExists(err) {
|
||||
errors.CheckError(err)
|
||||
}
|
||||
}
|
||||
|
||||
func readAndConfirmPassword() string {
|
||||
for {
|
||||
fmt.Print("*** Enter an admin password: ")
|
||||
password, err := terminal.ReadPassword(syscall.Stdin)
|
||||
errors.CheckError(err)
|
||||
fmt.Print("\n")
|
||||
fmt.Print("*** Confirm the admin password: ")
|
||||
confirmPassword, err := terminal.ReadPassword(syscall.Stdin)
|
||||
errors.CheckError(err)
|
||||
fmt.Print("\n")
|
||||
if string(password) == string(confirmPassword) {
|
||||
return string(password)
|
||||
}
|
||||
log.Error("Passwords do not match")
|
||||
}
|
||||
}
|
||||
|
||||
func (i *Installer) InstallApplicationController() {
|
||||
var applicationControllerServiceAccount apiv1.ServiceAccount
|
||||
var applicationControllerRole rbacv1.Role
|
||||
var applicationControllerRoleBinding rbacv1.RoleBinding
|
||||
var applicationControllerDeployment appsv1beta2.Deployment
|
||||
i.unmarshalManifest("02a_application-controller-sa.yaml", &applicationControllerServiceAccount)
|
||||
i.unmarshalManifest("02b_application-controller-role.yaml", &applicationControllerRole)
|
||||
i.unmarshalManifest("02c_application-controller-rolebinding.yaml", &applicationControllerRoleBinding)
|
||||
i.unmarshalManifest("02d_application-controller-deployment.yaml", &applicationControllerDeployment)
|
||||
i.unmarshalManifest("03a_application-controller-sa.yaml", &applicationControllerServiceAccount)
|
||||
i.unmarshalManifest("03b_application-controller-role.yaml", &applicationControllerRole)
|
||||
i.unmarshalManifest("03c_application-controller-rolebinding.yaml", &applicationControllerRoleBinding)
|
||||
i.unmarshalManifest("03d_application-controller-deployment.yaml", &applicationControllerDeployment)
|
||||
applicationControllerDeployment.Spec.Template.Spec.Containers[0].Image = i.ControllerImage
|
||||
applicationControllerDeployment.Spec.Template.Spec.Containers[0].ImagePullPolicy = apiv1.PullPolicy(i.ImagePullPolicy)
|
||||
i.MustInstallResource(kube.MustToUnstructured(&applicationControllerServiceAccount))
|
||||
@@ -152,57 +245,30 @@ func (i *Installer) InstallArgoCDServer() {
|
||||
var argoCDServerControllerRoleBinding rbacv1.RoleBinding
|
||||
var argoCDServerControllerDeployment appsv1beta2.Deployment
|
||||
var argoCDServerService apiv1.Service
|
||||
i.unmarshalManifest("03a_argocd-server-sa.yaml", &argoCDServerServiceAccount)
|
||||
i.unmarshalManifest("03b_argocd-server-role.yaml", &argoCDServerControllerRole)
|
||||
i.unmarshalManifest("03c_argocd-server-rolebinding.yaml", &argoCDServerControllerRoleBinding)
|
||||
i.unmarshalManifest("03d_argocd-server-deployment.yaml", &argoCDServerControllerDeployment)
|
||||
i.unmarshalManifest("03e_argocd-server-service.yaml", &argoCDServerService)
|
||||
argoCDServerControllerDeployment.Spec.Template.Spec.InitContainers[0].Image = i.UIImage
|
||||
i.unmarshalManifest("04a_argocd-server-sa.yaml", &argoCDServerServiceAccount)
|
||||
i.unmarshalManifest("04b_argocd-server-role.yaml", &argoCDServerControllerRole)
|
||||
i.unmarshalManifest("04c_argocd-server-rolebinding.yaml", &argoCDServerControllerRoleBinding)
|
||||
i.unmarshalManifest("04d_argocd-server-deployment.yaml", &argoCDServerControllerDeployment)
|
||||
i.unmarshalManifest("04e_argocd-server-service.yaml", &argoCDServerService)
|
||||
argoCDServerControllerDeployment.Spec.Template.Spec.InitContainers[0].Image = i.ServerImage
|
||||
argoCDServerControllerDeployment.Spec.Template.Spec.InitContainers[0].ImagePullPolicy = apiv1.PullPolicy(i.ImagePullPolicy)
|
||||
argoCDServerControllerDeployment.Spec.Template.Spec.InitContainers[1].Image = i.UIImage
|
||||
argoCDServerControllerDeployment.Spec.Template.Spec.InitContainers[1].ImagePullPolicy = apiv1.PullPolicy(i.ImagePullPolicy)
|
||||
argoCDServerControllerDeployment.Spec.Template.Spec.Containers[0].Image = i.ServerImage
|
||||
argoCDServerControllerDeployment.Spec.Template.Spec.Containers[0].ImagePullPolicy = apiv1.PullPolicy(i.ImagePullPolicy)
|
||||
|
||||
kubeclientset, err := kubernetes.NewForConfig(i.config)
|
||||
errors.CheckError(err)
|
||||
|
||||
configManager := util.NewConfigManager(kubeclientset, i.Namespace, i.ConfigMap)
|
||||
errors.CheckError(err)
|
||||
|
||||
if i.InstallOptions.ConfigMap != "" {
|
||||
quotedConfigMapName := strconv.Quote(i.InstallOptions.ConfigMap)
|
||||
container := &argoCDServerControllerDeployment.Spec.Template.Spec.Containers[0]
|
||||
container.Command = append(container.Command, "--config-map", quotedConfigMapName)
|
||||
}
|
||||
|
||||
i.MustInstallResource(kube.MustToUnstructured(&argoCDServerServiceAccount))
|
||||
i.MustInstallResource(kube.MustToUnstructured(&argoCDServerControllerRole))
|
||||
i.MustInstallResource(kube.MustToUnstructured(&argoCDServerControllerRoleBinding))
|
||||
i.MustInstallResource(kube.MustToUnstructured(&argoCDServerControllerDeployment))
|
||||
i.MustInstallResource(kube.MustToUnstructured(&argoCDServerService))
|
||||
|
||||
if i.InstallOptions.ConfigSuperuser {
|
||||
inputReader := bufio.NewReader(os.Stdin)
|
||||
|
||||
fmt.Print("*** Please enter a superuser username: ")
|
||||
rootUsername, err := inputReader.ReadString('\n')
|
||||
errors.CheckError(err)
|
||||
rootUsername = strings.Trim(rootUsername, "\n")
|
||||
|
||||
fmt.Print("*** Please enter a superuser password: ")
|
||||
rawPassword, err := terminal.ReadPassword(syscall.Stdin)
|
||||
errors.CheckError(err)
|
||||
fmt.Print("\n")
|
||||
|
||||
err = configManager.SetRootUserCredentials(rootUsername, string(rawPassword))
|
||||
errors.CheckError(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (i *Installer) InstallArgoCDRepoServer() {
|
||||
var argoCDRepoServerControllerDeployment appsv1beta2.Deployment
|
||||
var argoCDRepoServerService apiv1.Service
|
||||
i.unmarshalManifest("04a_argocd-repo-server-deployment.yaml", &argoCDRepoServerControllerDeployment)
|
||||
i.unmarshalManifest("04b_argocd-repo-server-service.yaml", &argoCDRepoServerService)
|
||||
i.unmarshalManifest("05a_argocd-repo-server-deployment.yaml", &argoCDRepoServerControllerDeployment)
|
||||
i.unmarshalManifest("05b_argocd-repo-server-service.yaml", &argoCDRepoServerService)
|
||||
argoCDRepoServerControllerDeployment.Spec.Template.Spec.Containers[0].Image = i.RepoServerImage
|
||||
argoCDRepoServerControllerDeployment.Spec.Template.Spec.Containers[0].ImagePullPolicy = apiv1.PullPolicy(i.ImagePullPolicy)
|
||||
i.MustInstallResource(kube.MustToUnstructured(&argoCDRepoServerControllerDeployment))
|
||||
|
||||
56
install/manifests/02a_argocd-cm.yaml
Normal file
56
install/manifests/02a_argocd-cm.yaml
Normal file
@@ -0,0 +1,56 @@
|
||||
# NOTE: the values here are just a example and are not the values used during an install.
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: argocd-cm
|
||||
data:
|
||||
# url is the externally facing base URL of ArgoCD.
|
||||
# This field is required when configuring SSO, which ArgoCD uses as part the redirectURI for the
|
||||
# dex connectors. When configuring the application in the SSO provider (e.g. github, okta), the
|
||||
# authorization callback URL will be url + /api/dex/callback. For example, if ArgoCD's url is
|
||||
# https://example.com, then the auth callback to set in the SSO provider should be:
|
||||
# https://example.com/api/dex/callback
|
||||
url: http://localhost:8080
|
||||
|
||||
# dex.config holds the contents of the configuration yaml for the dex OIDC/Oauth2 provider sidecar.
|
||||
# Only a subset of a full dex config is required, namely the connectors list. ArgoCD will generate
|
||||
# the complete dex config based on the configured URL, and the known callback endpoint which the
|
||||
# ArgoCD API server exposes (i.e. /api/dex/callback).
|
||||
dex.config: |
|
||||
# connectors is a list of dex connector configurations. For details on available connectors and
|
||||
# how to configure them, see: https://github.com/coreos/dex/tree/master/Documentation/connectors
|
||||
# NOTE:
|
||||
# * Any values which start with '$' will look to a key in argocd-secret of the same name, to
|
||||
# obtain the actual value.
|
||||
# * ArgoCD will automatically set the 'redirectURI' field in any OAuth2 connectors, to match the
|
||||
# external callback URL (e.g. https://example.com/api/dex/callback)
|
||||
connectors:
|
||||
# GitHub example
|
||||
- type: github
|
||||
id: github
|
||||
name: GitHub
|
||||
config:
|
||||
clientID: aabbccddeeff00112233
|
||||
clientSecret: $dex.github.clientSecret
|
||||
orgs:
|
||||
- name: your-github-org
|
||||
|
||||
# GitHub enterprise example
|
||||
- type: github
|
||||
id: acme-github
|
||||
name: Acme GitHub
|
||||
config:
|
||||
hostName: github.acme.com
|
||||
clientID: abcdefghijklmnopqrst
|
||||
clientSecret: $dex.acme.clientSecret
|
||||
orgs:
|
||||
- name: your-github-org
|
||||
|
||||
# OIDC example (e.g. Okta)
|
||||
- type: oidc
|
||||
id: okta
|
||||
name: Okta
|
||||
config:
|
||||
issuer: https://dev-123456.oktapreview.com
|
||||
clientID: aaaabbbbccccddddeee
|
||||
clientSecret: $dex.okta.clientSecret
|
||||
26
install/manifests/02b_argocd-secret.yaml
Normal file
26
install/manifests/02b_argocd-secret.yaml
Normal file
@@ -0,0 +1,26 @@
|
||||
# NOTE: the values in this secret are provided as working manifest example and are not the values
|
||||
# used during an install. New values will be generated as part of `argocd install`
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: argocd-secret
|
||||
type: Opaque
|
||||
stringData:
|
||||
# bcrypt hash of the string "password"
|
||||
admin.password: $2a$10$2b2cU8CPhOTaGrs1HRQuAueS7JTT5ZHsHSzYiFPm1leZck7Mc8T4W
|
||||
# random server signature key for session validation
|
||||
server.secretkey: aEDvv73vv70F77+9CRBSNu+/vTYQ77+9EUFh77+9LzFyJ++/vXfLsO+/vWRbeu+/ve+/vQ==
|
||||
|
||||
# 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: shhhh! it's a github secret
|
||||
gitlab.webhook.secret: shhhh! it's a gitlab secret
|
||||
bitbucket.webhook.uuid: your-bitbucket-uuid
|
||||
|
||||
# the following of user defined keys which are referenced in the example argocd-cm configmap
|
||||
# as pat of SSO configuration.
|
||||
dex.github.clientSecret: nv1vx8w4gw5byrflujfkxww6ykh85yq818aorvwy
|
||||
dex.acme.clientSecret: 5pp7dyre3d5nyk0ree1tr0gd68k18xn94x8lfae9
|
||||
dex.okta.clientSecret: x41ztv6ufyf07oyoopc6f62p222c00mox2ciquvt
|
||||
26
install/manifests/02c_argocd-rbac-cm.yaml
Normal file
26
install/manifests/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
|
||||
#
|
||||
# The policy definition format is:
|
||||
# p, <user/group>, <resource>, <action>, <project>/<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/*
|
||||
#
|
||||
# The role definition format is:
|
||||
# g, <user/group>, <group>
|
||||
# For example, the following rule makes all members of 'my-org:team2' have the role:admin role:
|
||||
# g, my-org:team2, role:admin
|
||||
policy.csv: ""
|
||||
|
||||
# policy.default holds the default policy which will ArgoCD will fall back to, when authorizing
|
||||
# a user for API requests.
|
||||
policy.default: role:readonly
|
||||
@@ -2,4 +2,3 @@ apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: application-controller
|
||||
namespace: argocd
|
||||
@@ -2,7 +2,6 @@ apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: application-controller-role
|
||||
namespace: argocd
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
@@ -10,6 +9,10 @@ rules:
|
||||
- secrets
|
||||
verbs:
|
||||
- get
|
||||
- watch
|
||||
- list
|
||||
- patch
|
||||
- update
|
||||
- apiGroups:
|
||||
- argoproj.io
|
||||
resources:
|
||||
@@ -2,7 +2,6 @@ apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: application-controller-role-binding
|
||||
namespace: argocd
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
@@ -10,4 +9,3 @@ roleRef:
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: application-controller
|
||||
namespace: argocd
|
||||
@@ -2,7 +2,6 @@ apiVersion: apps/v1beta2
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: application-controller
|
||||
namespace: argocd
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
@@ -2,4 +2,3 @@ apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: argocd-server
|
||||
namespace: argocd
|
||||
@@ -2,7 +2,6 @@ apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: argocd-server-role
|
||||
namespace: argocd
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
@@ -2,7 +2,6 @@ apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: argocd-server-role-binding
|
||||
namespace: argocd
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
@@ -10,4 +9,3 @@ roleRef:
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: argocd-server
|
||||
namespace: argocd
|
||||
@@ -2,7 +2,6 @@ apiVersion: apps/v1beta2
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: argocd-server
|
||||
namespace: argocd
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
@@ -14,16 +13,28 @@ spec:
|
||||
spec:
|
||||
serviceAccountName: argocd-server
|
||||
initContainers:
|
||||
- command: [cp, -r, /app, /shared]
|
||||
- name: copyutil
|
||||
image: argoproj/argocd-server:latest
|
||||
command: [cp, /argocd-util, /shared]
|
||||
volumeMounts:
|
||||
- mountPath: /shared
|
||||
name: static-files
|
||||
- name: ui
|
||||
image: argoproj/argocd-ui:latest
|
||||
name: argocd-server-ui
|
||||
command: [cp, -r, /app, /shared]
|
||||
volumeMounts:
|
||||
- mountPath: /shared
|
||||
name: static-files
|
||||
containers:
|
||||
- command: [/argocd-server, --staticassets, /shared/app, --repo-server, 'argocd-repo-server:8081']
|
||||
- name: argocd-server
|
||||
image: argoproj/argocd-server:latest
|
||||
name: argocd-server
|
||||
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
|
||||
@@ -2,10 +2,15 @@ apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: argocd-server
|
||||
namespace: argocd
|
||||
spec:
|
||||
ports:
|
||||
- port: 80
|
||||
- name: http
|
||||
protocol: TCP
|
||||
port: 80
|
||||
targetPort: 8080
|
||||
- name: https
|
||||
protocol: TCP
|
||||
port: 443
|
||||
targetPort: 8080
|
||||
selector:
|
||||
app: argocd-server
|
||||
@@ -2,7 +2,6 @@ apiVersion: apps/v1beta2
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: argocd-repo-server
|
||||
namespace: argocd
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
@@ -13,8 +12,12 @@ spec:
|
||||
app: argocd-repo-server
|
||||
spec:
|
||||
containers:
|
||||
- command: [/argocd-repo-server]
|
||||
- name: argocd-repo-server
|
||||
image: argoproj/argocd-repo-server:latest
|
||||
name: argocd-repo-server
|
||||
command: [/argocd-repo-server]
|
||||
ports:
|
||||
- containerPort: 8081
|
||||
- name: redis
|
||||
image: redis:3.2.11
|
||||
ports:
|
||||
- containerPort: 6379
|
||||
@@ -2,9 +2,9 @@ apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: argocd-repo-server
|
||||
namespace: argocd
|
||||
spec:
|
||||
ports:
|
||||
- port: 8081
|
||||
targetPort: 8081
|
||||
selector:
|
||||
app: argocd-repo-server
|
||||
@@ -1,22 +1,40 @@
|
||||
package apiclient
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/argoproj/argo-cd/server/application"
|
||||
"github.com/argoproj/argo-cd/server/cluster"
|
||||
"github.com/argoproj/argo-cd/server/repository"
|
||||
"github.com/argoproj/argo-cd/server/session"
|
||||
"github.com/argoproj/argo-cd/server/settings"
|
||||
"github.com/argoproj/argo-cd/server/version"
|
||||
grpc_util "github.com/argoproj/argo-cd/util/grpc"
|
||||
"github.com/argoproj/argo-cd/util/localconfig"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials"
|
||||
)
|
||||
|
||||
const (
|
||||
MetaDataTokenKey = "token"
|
||||
// EnvArgoCDServer is the environment variable to look for an ArgoCD server address
|
||||
EnvArgoCDServer = "ARGOCD_SERVER"
|
||||
// EnvArgoCDAuthToken is the environment variable to look for an ArgoCD auth token
|
||||
EnvArgoCDAuthToken = "ARGOCD_AUTH_TOKEN"
|
||||
)
|
||||
|
||||
type ServerClient interface {
|
||||
// Client defines an interface for interaction with an Argo CD server.
|
||||
type Client interface {
|
||||
ClientOptions() ClientOptions
|
||||
NewConn() (*grpc.ClientConn, error)
|
||||
NewRepoClient() (*grpc.ClientConn, repository.RepositoryServiceClient, error)
|
||||
NewRepoClientOrDie() (*grpc.ClientConn, repository.RepositoryServiceClient)
|
||||
@@ -24,31 +42,100 @@ type ServerClient interface {
|
||||
NewClusterClientOrDie() (*grpc.ClientConn, cluster.ClusterServiceClient)
|
||||
NewApplicationClient() (*grpc.ClientConn, application.ApplicationServiceClient, error)
|
||||
NewApplicationClientOrDie() (*grpc.ClientConn, application.ApplicationServiceClient)
|
||||
NewSessionClient() (*grpc.ClientConn, session.SessionServiceClient, error)
|
||||
NewSessionClientOrDie() (*grpc.ClientConn, session.SessionServiceClient)
|
||||
NewSettingsClient() (*grpc.ClientConn, settings.SettingsServiceClient, error)
|
||||
NewSettingsClientOrDie() (*grpc.ClientConn, settings.SettingsServiceClient)
|
||||
NewVersionClient() (*grpc.ClientConn, version.VersionServiceClient, error)
|
||||
NewVersionClientOrDie() (*grpc.ClientConn, version.VersionServiceClient)
|
||||
}
|
||||
|
||||
// ClientOptions hold address, security, and other settings for the API client.
|
||||
type ClientOptions struct {
|
||||
ServerAddr string
|
||||
PlainText bool
|
||||
Insecure bool
|
||||
CertFile string
|
||||
AuthToken string
|
||||
ConfigPath string
|
||||
Context string
|
||||
}
|
||||
|
||||
type client struct {
|
||||
ClientOptions
|
||||
ServerAddr string
|
||||
PlainText bool
|
||||
Insecure bool
|
||||
CertPEMData []byte
|
||||
AuthToken string
|
||||
}
|
||||
|
||||
func NewClient(opts *ClientOptions) (ServerClient, error) {
|
||||
clientOpts := *opts
|
||||
if clientOpts.ServerAddr == "" {
|
||||
clientOpts.ServerAddr = os.Getenv(EnvArgoCDServer)
|
||||
// NewClient creates a new API client from a set of config options.
|
||||
func NewClient(opts *ClientOptions) (Client, error) {
|
||||
var c client
|
||||
localCfg, err := localconfig.ReadLocalConfig(opts.ConfigPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if clientOpts.ServerAddr == "" {
|
||||
return nil, errors.New("Argo CD server address not supplied")
|
||||
if localCfg != nil {
|
||||
configCtx, err := localCfg.ResolveContext(opts.Context)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if configCtx != nil {
|
||||
c.ServerAddr = configCtx.Server.Server
|
||||
if configCtx.Server.CACertificateAuthorityData != "" {
|
||||
c.CertPEMData, err = base64.StdEncoding.DecodeString(configCtx.Server.CACertificateAuthorityData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
c.PlainText = configCtx.Server.PlainText
|
||||
c.Insecure = configCtx.Server.Insecure
|
||||
c.AuthToken = configCtx.User.AuthToken
|
||||
}
|
||||
}
|
||||
return &client{
|
||||
ClientOptions: clientOpts,
|
||||
}, nil
|
||||
// Override server address if specified in env or CLI flag
|
||||
if serverFromEnv := os.Getenv(EnvArgoCDServer); serverFromEnv != "" {
|
||||
c.ServerAddr = serverFromEnv
|
||||
}
|
||||
if opts.ServerAddr != "" {
|
||||
c.ServerAddr = opts.ServerAddr
|
||||
}
|
||||
// Make sure we got the server address and auth token from somewhere
|
||||
if c.ServerAddr == "" {
|
||||
return nil, errors.New("ArgoCD server address unspecified")
|
||||
}
|
||||
if parts := strings.Split(c.ServerAddr, ":"); len(parts) == 1 {
|
||||
// If port is unspecified, assume the most likely port
|
||||
c.ServerAddr += ":443"
|
||||
}
|
||||
// Override auth-token if specified in env variable or CLI flag
|
||||
if authFromEnv := os.Getenv(EnvArgoCDAuthToken); authFromEnv != "" {
|
||||
c.AuthToken = authFromEnv
|
||||
}
|
||||
if opts.AuthToken != "" {
|
||||
c.AuthToken = opts.AuthToken
|
||||
}
|
||||
// Override certificate data if specified from CLI flag
|
||||
if opts.CertFile != "" {
|
||||
b, err := ioutil.ReadFile(opts.CertFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.CertPEMData = b
|
||||
}
|
||||
// Override insecure/plaintext options if specified from CLI
|
||||
if opts.PlainText {
|
||||
c.PlainText = true
|
||||
}
|
||||
if opts.Insecure {
|
||||
c.Insecure = true
|
||||
}
|
||||
return &c, nil
|
||||
}
|
||||
|
||||
func NewClientOrDie(opts *ClientOptions) ServerClient {
|
||||
// NewClientOrDie creates a new API client from a set of config options, or fails fatally if the new client creation fails.
|
||||
func NewClientOrDie(opts *ClientOptions) Client {
|
||||
client, err := NewClient(opts)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
@@ -56,16 +143,52 @@ func NewClientOrDie(opts *ClientOptions) ServerClient {
|
||||
return client
|
||||
}
|
||||
|
||||
// JwtCredentials implements the gRPC credentials.Credentials interface which we is used to do
|
||||
// grpc.WithPerRPCCredentials(), for authentication
|
||||
type jwtCredentials struct {
|
||||
Token string
|
||||
}
|
||||
|
||||
func (c jwtCredentials) RequireTransportSecurity() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (c jwtCredentials) GetRequestMetadata(context.Context, ...string) (map[string]string, error) {
|
||||
return map[string]string{
|
||||
MetaDataTokenKey: c.Token,
|
||||
"tokens": c.Token, // legacy key. delete eventually
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *client) NewConn() (*grpc.ClientConn, error) {
|
||||
var dialOpts []grpc.DialOption
|
||||
if c.Insecure {
|
||||
dialOpts = append(dialOpts, grpc.WithInsecure())
|
||||
} else {
|
||||
return nil, errors.New("secure authentication unsupported")
|
||||
} // else if opts.Credentials != nil {
|
||||
// dialOpts = append(dialOpts, grpc.WithTransportCredentials(opts.Credentials))
|
||||
//}
|
||||
return grpc.Dial(c.ServerAddr, dialOpts...)
|
||||
var creds credentials.TransportCredentials
|
||||
if !c.PlainText {
|
||||
var tlsConfig tls.Config
|
||||
if len(c.CertPEMData) > 0 {
|
||||
cp := x509.NewCertPool()
|
||||
if !cp.AppendCertsFromPEM(c.CertPEMData) {
|
||||
return nil, fmt.Errorf("credentials: failed to append certificates")
|
||||
}
|
||||
tlsConfig.RootCAs = cp
|
||||
}
|
||||
if c.Insecure {
|
||||
tlsConfig.InsecureSkipVerify = true
|
||||
}
|
||||
creds = credentials.NewTLS(&tlsConfig)
|
||||
}
|
||||
endpointCredentials := jwtCredentials{
|
||||
Token: c.AuthToken,
|
||||
}
|
||||
return grpc_util.BlockingDial(context.Background(), "tcp", c.ServerAddr, creds, grpc.WithPerRPCCredentials(endpointCredentials))
|
||||
}
|
||||
|
||||
func (c *client) ClientOptions() ClientOptions {
|
||||
return ClientOptions{
|
||||
ServerAddr: c.ServerAddr,
|
||||
PlainText: c.PlainText,
|
||||
Insecure: c.Insecure,
|
||||
AuthToken: c.AuthToken,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *client) NewRepoClient() (*grpc.ClientConn, repository.RepositoryServiceClient, error) {
|
||||
@@ -118,3 +241,54 @@ func (c *client) NewApplicationClientOrDie() (*grpc.ClientConn, application.Appl
|
||||
}
|
||||
return conn, repoIf
|
||||
}
|
||||
|
||||
func (c *client) NewSessionClient() (*grpc.ClientConn, session.SessionServiceClient, error) {
|
||||
conn, err := c.NewConn()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
sessionIf := session.NewSessionServiceClient(conn)
|
||||
return conn, sessionIf, nil
|
||||
}
|
||||
|
||||
func (c *client) NewSessionClientOrDie() (*grpc.ClientConn, session.SessionServiceClient) {
|
||||
conn, sessionIf, err := c.NewSessionClient()
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to establish connection to %s: %v", c.ServerAddr, err)
|
||||
}
|
||||
return conn, sessionIf
|
||||
}
|
||||
|
||||
func (c *client) NewSettingsClient() (*grpc.ClientConn, settings.SettingsServiceClient, error) {
|
||||
conn, err := c.NewConn()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
setIf := settings.NewSettingsServiceClient(conn)
|
||||
return conn, setIf, nil
|
||||
}
|
||||
|
||||
func (c *client) NewSettingsClientOrDie() (*grpc.ClientConn, settings.SettingsServiceClient) {
|
||||
conn, setIf, err := c.NewSettingsClient()
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to establish connection to %s: %v", c.ServerAddr, err)
|
||||
}
|
||||
return conn, setIf
|
||||
}
|
||||
|
||||
func (c *client) NewVersionClient() (*grpc.ClientConn, version.VersionServiceClient, error) {
|
||||
conn, err := c.NewConn()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
versionIf := version.NewVersionServiceClient(conn)
|
||||
return conn, versionIf, nil
|
||||
}
|
||||
|
||||
func (c *client) NewVersionClientOrDie() (*grpc.ClientConn, version.VersionServiceClient) {
|
||||
conn, versionIf, err := c.NewVersionClient()
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to establish connection to %s: %v", c.ServerAddr, err)
|
||||
}
|
||||
return conn, versionIf
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -23,6 +23,17 @@ message Application {
|
||||
optional ApplicationSpec spec = 2;
|
||||
|
||||
optional ApplicationStatus status = 3;
|
||||
|
||||
optional Operation operation = 4;
|
||||
}
|
||||
|
||||
// ApplicationCondition contains details about current application condition
|
||||
message ApplicationCondition {
|
||||
// Type is an application condition type
|
||||
optional string type = 1;
|
||||
|
||||
// Message contains human-readable message indicating details about condition
|
||||
optional string message = 2;
|
||||
}
|
||||
|
||||
// ApplicationDestination contains deployment destination information
|
||||
@@ -67,7 +78,6 @@ message ApplicationSpec {
|
||||
optional ApplicationSource source = 1;
|
||||
|
||||
// Destination overrides the kubernetes server and namespace defined in the environment ksonnet app.yaml
|
||||
// This field is optional. If omitted, uses the server and namespace defined in the environment
|
||||
optional ApplicationDestination destination = 2;
|
||||
}
|
||||
|
||||
@@ -75,7 +85,15 @@ message ApplicationSpec {
|
||||
message ApplicationStatus {
|
||||
optional ComparisonResult comparisonResult = 1;
|
||||
|
||||
repeated DeploymentInfo recentDeployment = 2;
|
||||
repeated DeploymentInfo history = 2;
|
||||
|
||||
repeated ComponentParameter parameters = 3;
|
||||
|
||||
optional HealthStatus health = 4;
|
||||
|
||||
optional OperationState operationState = 5;
|
||||
|
||||
repeated ApplicationCondition conditions = 6;
|
||||
}
|
||||
|
||||
// ApplicationWatchEvent contains information about application change.
|
||||
@@ -100,6 +118,9 @@ message Cluster {
|
||||
|
||||
// Config holds cluster information for connecting to a cluster
|
||||
optional ClusterConfig config = 3;
|
||||
|
||||
// ConnectionState contains information about cluster connection state
|
||||
optional ConnectionState connectionState = 4;
|
||||
}
|
||||
|
||||
// ClusterConfig is the configuration attributes. This structure is subset of the go-client
|
||||
@@ -132,10 +153,6 @@ message ComparisonResult {
|
||||
|
||||
optional ApplicationSource comparedTo = 2;
|
||||
|
||||
optional string server = 3;
|
||||
|
||||
optional string namespace = 4;
|
||||
|
||||
optional string status = 5;
|
||||
|
||||
repeated ResourceState resources = 6;
|
||||
@@ -152,6 +169,15 @@ message ComponentParameter {
|
||||
optional string value = 3;
|
||||
}
|
||||
|
||||
// ConnectionState contains information about remote resource connection state
|
||||
message ConnectionState {
|
||||
optional string status = 1;
|
||||
|
||||
optional string message = 2;
|
||||
|
||||
optional k8s.io.apimachinery.pkg.apis.meta.v1.Time attemptedAt = 3;
|
||||
}
|
||||
|
||||
// DeploymentInfo contains information relevant to an application deployment
|
||||
message DeploymentInfo {
|
||||
repeated ComponentParameter params = 1;
|
||||
@@ -161,6 +187,45 @@ message DeploymentInfo {
|
||||
repeated ComponentParameter componentParameterOverrides = 3;
|
||||
|
||||
optional k8s.io.apimachinery.pkg.apis.meta.v1.Time deployedAt = 4;
|
||||
|
||||
optional int64 id = 5;
|
||||
}
|
||||
|
||||
message HealthStatus {
|
||||
optional string status = 1;
|
||||
|
||||
optional string statusDetails = 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.
|
||||
message OperationState {
|
||||
// Operation is the original requested operation
|
||||
optional Operation operation = 1;
|
||||
|
||||
// Phase is the current phase of the operation
|
||||
optional string phase = 2;
|
||||
|
||||
// Message hold any pertinent messages when attempting to perform operation (typically errors).
|
||||
optional string message = 3;
|
||||
|
||||
// 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;
|
||||
|
||||
// FinishedAt contains time of operation completion
|
||||
optional k8s.io.apimachinery.pkg.apis.meta.v1.Time finishedAt = 7;
|
||||
}
|
||||
|
||||
// Repository is a Git repository holding application configurations
|
||||
@@ -172,6 +237,8 @@ message Repository {
|
||||
optional string password = 3;
|
||||
|
||||
optional string sshPrivateKey = 4;
|
||||
|
||||
optional ConnectionState connectionState = 5;
|
||||
}
|
||||
|
||||
// RepositoryList is a collection of Repositories.
|
||||
@@ -181,6 +248,25 @@ message RepositoryList {
|
||||
repeated Repository items = 2;
|
||||
}
|
||||
|
||||
message ResourceDetails {
|
||||
optional string name = 1;
|
||||
|
||||
optional string kind = 2;
|
||||
|
||||
optional string namespace = 3;
|
||||
|
||||
optional string message = 4;
|
||||
|
||||
optional string status = 5;
|
||||
}
|
||||
|
||||
// ResourceNode contains information about live resource and its children
|
||||
message ResourceNode {
|
||||
optional string state = 1;
|
||||
|
||||
repeated ResourceNode children = 2;
|
||||
}
|
||||
|
||||
// ResourceState holds the target state of a resource and live state of a resource
|
||||
message ResourceState {
|
||||
optional string targetState = 1;
|
||||
@@ -188,6 +274,32 @@ message ResourceState {
|
||||
optional string liveState = 2;
|
||||
|
||||
optional string status = 3;
|
||||
|
||||
repeated ResourceNode childLiveResources = 4;
|
||||
|
||||
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 {
|
||||
optional string revision = 1;
|
||||
|
||||
optional bool prune = 2;
|
||||
|
||||
optional bool dryRun = 3;
|
||||
}
|
||||
|
||||
// SyncOperationResult represent result of sync operation
|
||||
message SyncOperationResult {
|
||||
repeated ResourceDetails resources = 1;
|
||||
}
|
||||
|
||||
// TLSClientConfig contains settings to enable transport layer security
|
||||
|
||||
@@ -11,7 +11,9 @@ type objectMeta struct {
|
||||
}
|
||||
|
||||
func (a *Application) GetMetadata() *objectMeta {
|
||||
return &objectMeta{
|
||||
Name: &a.Name,
|
||||
var om objectMeta
|
||||
if a != nil {
|
||||
om.Name = &a.Name
|
||||
}
|
||||
return &om
|
||||
}
|
||||
|
||||
@@ -2,21 +2,102 @@ package v1alpha1
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"time"
|
||||
|
||||
"github.com/argoproj/argo-cd/common"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
// SyncOperation contains sync operation details.
|
||||
type SyncOperation struct {
|
||||
Revision string `json:"revision,omitempty" protobuf:"bytes,1,opt,name=revision"`
|
||||
Prune bool `json:"prune,omitempty" protobuf:"bytes,2,opt,name=prune"`
|
||||
DryRun bool `json:"dryRun,omitempty" protobuf:"bytes,3,opt,name=dryRun"`
|
||||
}
|
||||
|
||||
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"`
|
||||
Rollback *RollbackOperation `json:"rollback,omitempty" protobuf:"bytes,2,opt,name=rollback"`
|
||||
}
|
||||
|
||||
type OperationPhase string
|
||||
|
||||
const (
|
||||
OperationRunning OperationPhase = "Running"
|
||||
OperationFailed OperationPhase = "Failed"
|
||||
OperationError OperationPhase = "Error"
|
||||
OperationSucceeded OperationPhase = "Succeeded"
|
||||
)
|
||||
|
||||
func (os OperationPhase) Completed() bool {
|
||||
switch os {
|
||||
case OperationFailed, OperationError, OperationSucceeded:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (os OperationPhase) Successful() bool {
|
||||
return os == OperationSucceeded
|
||||
}
|
||||
|
||||
// OperationState contains information about state of currently performing operation on application.
|
||||
type OperationState struct {
|
||||
// Operation is the original requested operation
|
||||
Operation Operation `json:"operation" protobuf:"bytes,1,opt,name=operation"`
|
||||
// Phase is the current phase of the operation
|
||||
Phase OperationPhase `json:"phase" protobuf:"bytes,2,opt,name=phase"`
|
||||
// Message hold any pertinent messages when attempting to perform operation (typically errors).
|
||||
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"`
|
||||
}
|
||||
|
||||
// SyncOperationResult represent result of sync operation
|
||||
type SyncOperationResult struct {
|
||||
Resources []*ResourceDetails `json:"resources" protobuf:"bytes,1,opt,name=resources"`
|
||||
}
|
||||
|
||||
type ResourceSyncStatus string
|
||||
|
||||
const (
|
||||
ResourceDetailsSynced ResourceSyncStatus = "Synced"
|
||||
ResourceDetailsSyncFailed ResourceSyncStatus = "SyncFailed"
|
||||
ResourceDetailsSyncedAndPruned ResourceSyncStatus = "SyncedAndPruned"
|
||||
ResourceDetailsPruningRequired ResourceSyncStatus = "PruningRequired"
|
||||
)
|
||||
|
||||
type ResourceDetails struct {
|
||||
Name string `json:"name" protobuf:"bytes,1,opt,name=name"`
|
||||
Kind string `json:"kind" protobuf:"bytes,2,opt,name=kind"`
|
||||
Namespace string `json:"namespace" protobuf:"bytes,3,opt,name=namespace"`
|
||||
Message string `json:"message,omitempty" protobuf:"bytes,4,opt,name=message"`
|
||||
Status ResourceSyncStatus `json:"status,omitempty" protobuf:"bytes,5,opt,name=status"`
|
||||
}
|
||||
|
||||
// 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"`
|
||||
ID int64 `json:"id" protobuf:"bytes,5,opt,name=id"`
|
||||
}
|
||||
|
||||
// Application is a definition of Application resource.
|
||||
@@ -28,6 +109,7 @@ type Application struct {
|
||||
metav1.ObjectMeta `json:"metadata" protobuf:"bytes,1,opt,name=metadata"`
|
||||
Spec ApplicationSpec `json:"spec" protobuf:"bytes,2,opt,name=spec"`
|
||||
Status ApplicationStatus `json:"status" protobuf:"bytes,3,opt,name=status"`
|
||||
Operation *Operation `json:"operation,omitempty" protobuf:"bytes,4,opt,name=operation"`
|
||||
}
|
||||
|
||||
// ApplicationWatchEvent contains information about application change.
|
||||
@@ -55,8 +137,7 @@ type ApplicationSpec struct {
|
||||
// Source is a reference to the location ksonnet application definition
|
||||
Source ApplicationSource `json:"source" protobuf:"bytes,1,opt,name=source"`
|
||||
// Destination overrides the kubernetes server and namespace defined in the environment ksonnet app.yaml
|
||||
// This field is optional. If omitted, uses the server and namespace defined in the environment
|
||||
Destination *ApplicationDestination `json:"destination,omitempty" protobuf:"bytes,2,opt,name=destination"`
|
||||
Destination ApplicationDestination `json:"destination" protobuf:"bytes,2,name=destination"`
|
||||
}
|
||||
|
||||
// ComponentParameter contains information about component parameter value
|
||||
@@ -102,26 +183,81 @@ const (
|
||||
|
||||
// ApplicationStatus contains information about application status in target environment.
|
||||
type ApplicationStatus struct {
|
||||
ComparisonResult ComparisonResult `json:"comparisonResult" protobuf:"bytes,1,opt,name=comparisonResult"`
|
||||
RecentDeployments []DeploymentInfo `json:"recentDeployments" protobuf:"bytes,2,opt,name=recentDeployment"`
|
||||
ComparisonResult ComparisonResult `json:"comparisonResult" protobuf:"bytes,1,opt,name=comparisonResult"`
|
||||
History []DeploymentInfo `json:"history" protobuf:"bytes,2,opt,name=history"`
|
||||
Parameters []ComponentParameter `json:"parameters,omitempty" protobuf:"bytes,3,opt,name=parameters"`
|
||||
Health HealthStatus `json:"health,omitempty" protobuf:"bytes,4,opt,name=health"`
|
||||
OperationState *OperationState `json:"operationState,omitempty" protobuf:"bytes,5,opt,name=operationState"`
|
||||
Conditions []ApplicationCondition `json:"conditions,omitempty" protobuf:"bytes,6,opt,name=conditions"`
|
||||
}
|
||||
|
||||
type ApplicationConditionType = string
|
||||
|
||||
const (
|
||||
// ApplicationConditionDeletionError indicates that controller failed to delete application
|
||||
ApplicationConditionDeletionError = "DeletionError"
|
||||
)
|
||||
|
||||
// ApplicationCondition contains details about current application condition
|
||||
type ApplicationCondition struct {
|
||||
// Type is an application condition type
|
||||
Type ApplicationConditionType `json:"type" protobuf:"bytes,1,opt,name=type"`
|
||||
// Message contains human-readable message indicating details about condition
|
||||
Message string `json:"message" protobuf:"bytes,2,opt,name=message"`
|
||||
}
|
||||
|
||||
// ComparisonResult is a comparison result of application spec and deployed application.
|
||||
type ComparisonResult struct {
|
||||
ComparedAt metav1.Time `json:"comparedAt" protobuf:"bytes,1,opt,name=comparedAt"`
|
||||
ComparedTo ApplicationSource `json:"comparedTo" protobuf:"bytes,2,opt,name=comparedTo"`
|
||||
Server string `json:"server" protobuf:"bytes,3,opt,name=server"`
|
||||
Namespace string `json:"namespace" protobuf:"bytes,4,opt,name=namespace"`
|
||||
Status ComparisonStatus `json:"status" protobuf:"bytes,5,opt,name=status,casttype=ComparisonStatus"`
|
||||
Resources []ResourceState `json:"resources" protobuf:"bytes,6,opt,name=resources"`
|
||||
Error string `json:"error,omitempty" protobuf:"bytes,7,opt,name=error"`
|
||||
Error string `json:"error" protobuf:"bytes,7,opt,name=error"`
|
||||
}
|
||||
|
||||
type HealthStatus struct {
|
||||
Status HealthStatusCode `json:"status,omitempty" protobuf:"bytes,1,opt,name=status"`
|
||||
StatusDetails string `json:"statusDetails,omitempty" protobuf:"bytes,2,opt,name=statusDetails"`
|
||||
}
|
||||
|
||||
type HealthStatusCode = string
|
||||
|
||||
const (
|
||||
HealthStatusUnknown = ""
|
||||
HealthStatusProgressing = "Progressing"
|
||||
HealthStatusHealthy = "Healthy"
|
||||
HealthStatusDegraded = "Degraded"
|
||||
)
|
||||
|
||||
// ResourceNode contains information about live resource and its children
|
||||
type ResourceNode struct {
|
||||
State string `json:"state,omitempty" protobuf:"bytes,1,opt,name=state"`
|
||||
Children []ResourceNode `json:"children,omitempty" protobuf:"bytes,2,opt,name=children"`
|
||||
}
|
||||
|
||||
// ResourceState holds the target state of a resource and live state of a resource
|
||||
type ResourceState struct {
|
||||
TargetState string `json:"targetState,omitempty" protobuf:"bytes,1,opt,name=targetState"`
|
||||
LiveState string `json:"liveState,omitempty" protobuf:"bytes,2,opt,name=liveState"`
|
||||
Status ComparisonStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"`
|
||||
TargetState string `json:"targetState,omitempty" protobuf:"bytes,1,opt,name=targetState"`
|
||||
LiveState string `json:"liveState,omitempty" protobuf:"bytes,2,opt,name=liveState"`
|
||||
Status ComparisonStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"`
|
||||
ChildLiveResources []ResourceNode `json:"childLiveResources,omitempty" protobuf:"bytes,4,opt,name=childLiveResources"`
|
||||
Health HealthStatus `json:"health,omitempty" protobuf:"bytes,5,opt,name=health"`
|
||||
}
|
||||
|
||||
// ConnectionStatus represents connection status
|
||||
type ConnectionStatus = string
|
||||
|
||||
const (
|
||||
ConnectionStatusUnknown = "Unknown"
|
||||
ConnectionStatusSuccessful = "Successful"
|
||||
ConnectionStatusFailed = "Failed"
|
||||
)
|
||||
|
||||
// ConnectionState contains information about remote resource connection state
|
||||
type ConnectionState struct {
|
||||
Status ConnectionStatus `json:"status" protobuf:"bytes,1,opt,name=status"`
|
||||
Message string `json:"message" protobuf:"bytes,2,opt,name=message"`
|
||||
ModifiedAt *metav1.Time `json:"attemptedAt" protobuf:"bytes,3,opt,name=attemptedAt"`
|
||||
}
|
||||
|
||||
// Cluster is the definition of a cluster resource
|
||||
@@ -134,6 +270,9 @@ type Cluster struct {
|
||||
|
||||
// Config holds cluster information for connecting to a cluster
|
||||
Config ClusterConfig `json:"config" protobuf:"bytes,3,opt,name=config"`
|
||||
|
||||
// ConnectionState contains information about cluster connection state
|
||||
ConnectionState ConnectionState `json:"connectionState,omitempty" protobuf:"bytes,4,opt,name=connectionState"`
|
||||
}
|
||||
|
||||
// ClusterList is a collection of Clusters.
|
||||
@@ -180,10 +319,11 @@ type TLSClientConfig struct {
|
||||
|
||||
// Repository is a Git repository holding application configurations
|
||||
type Repository struct {
|
||||
Repo string `json:"repo" protobuf:"bytes,1,opt,name=repo"`
|
||||
Username string `json:"username" protobuf:"bytes,2,opt,name=username"`
|
||||
Password string `json:"password" protobuf:"bytes,3,opt,name=password"`
|
||||
SSHPrivateKey string `json:"sshPrivateKey" protobuf:"bytes,4,opt,name=sshPrivateKey"`
|
||||
Repo string `json:"repo" protobuf:"bytes,1,opt,name=repo"`
|
||||
Username string `json:"username,omitempty" protobuf:"bytes,2,opt,name=username"`
|
||||
Password string `json:"password,omitempty" protobuf:"bytes,3,opt,name=password"`
|
||||
SSHPrivateKey string `json:"sshPrivateKey,omitempty" protobuf:"bytes,4,opt,name=sshPrivateKey"`
|
||||
ConnectionState ConnectionState `json:"connectionState,omitempty" protobuf:"bytes,5,opt,name=connectionState"`
|
||||
}
|
||||
|
||||
// RepositoryList is a collection of Repositories.
|
||||
@@ -192,6 +332,33 @@ type RepositoryList struct {
|
||||
Items []Repository `json:"items" protobuf:"bytes,2,rep,name=items"`
|
||||
}
|
||||
|
||||
func (app *Application) getFinalizerIndex(name string) int {
|
||||
for i, finalizer := range app.Finalizers {
|
||||
if finalizer == name {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// CascadedDeletion indicates if resources finalizer is set and controller should delete app resources before deleting app
|
||||
func (app *Application) CascadedDeletion() bool {
|
||||
return app.getFinalizerIndex(common.ResourcesFinalizerName) > -1
|
||||
}
|
||||
|
||||
// SetCascadedDeletion sets or remove resources finalizer
|
||||
func (app *Application) SetCascadedDeletion(prune bool) {
|
||||
index := app.getFinalizerIndex(common.ResourcesFinalizerName)
|
||||
if prune != (index > -1) {
|
||||
if index > -1 {
|
||||
app.Finalizers[index] = app.Finalizers[len(app.Finalizers)-1]
|
||||
app.Finalizers = app.Finalizers[:len(app.Finalizers)-1]
|
||||
} else {
|
||||
app.Finalizers = append(app.Finalizers, common.ResourcesFinalizerName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NeedRefreshAppStatus answers if application status needs to be refreshed. Returns true if application never been compared, has changed or comparison result has expired.
|
||||
func (app *Application) NeedRefreshAppStatus(statusRefreshTimeout time.Duration) bool {
|
||||
return app.Status.ComparisonResult.Status == ComparisonStatusUnknown ||
|
||||
@@ -228,7 +395,7 @@ func (c *Cluster) RESTConfig() *rest.Config {
|
||||
func (cr *ComparisonResult) TargetObjects() ([]*unstructured.Unstructured, error) {
|
||||
objs := make([]*unstructured.Unstructured, len(cr.Resources))
|
||||
for i, resState := range cr.Resources {
|
||||
obj, err := UnmarshalToUnstructured(resState.TargetState)
|
||||
obj, err := resState.TargetObject()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -241,7 +408,7 @@ func (cr *ComparisonResult) TargetObjects() ([]*unstructured.Unstructured, error
|
||||
func (cr *ComparisonResult) LiveObjects() ([]*unstructured.Unstructured, error) {
|
||||
objs := make([]*unstructured.Unstructured, len(cr.Resources))
|
||||
for i, resState := range cr.Resources {
|
||||
obj, err := UnmarshalToUnstructured(resState.LiveState)
|
||||
obj, err := resState.LiveObject()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -261,3 +428,11 @@ func UnmarshalToUnstructured(resource string) (*unstructured.Unstructured, error
|
||||
}
|
||||
return &obj, nil
|
||||
}
|
||||
|
||||
func (r ResourceState) LiveObject() (*unstructured.Unstructured, error) {
|
||||
return UnmarshalToUnstructured(r.LiveState)
|
||||
}
|
||||
|
||||
func (r ResourceState) TargetObject() (*unstructured.Unstructured, error) {
|
||||
return UnmarshalToUnstructured(r.TargetState)
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
@@ -15,6 +16,15 @@ func (in *Application) DeepCopyInto(out *Application) {
|
||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||
in.Spec.DeepCopyInto(&out.Spec)
|
||||
in.Status.DeepCopyInto(&out.Status)
|
||||
if in.Operation != nil {
|
||||
in, out := &in.Operation, &out.Operation
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(Operation)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -36,6 +46,22 @@ func (in *Application) DeepCopyObject() runtime.Object {
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ApplicationCondition) DeepCopyInto(out *ApplicationCondition) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationCondition.
|
||||
func (in *ApplicationCondition) DeepCopy() *ApplicationCondition {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ApplicationCondition)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ApplicationDestination) DeepCopyInto(out *ApplicationDestination) {
|
||||
*out = *in
|
||||
@@ -110,15 +136,7 @@ func (in *ApplicationSource) DeepCopy() *ApplicationSource {
|
||||
func (in *ApplicationSpec) DeepCopyInto(out *ApplicationSpec) {
|
||||
*out = *in
|
||||
in.Source.DeepCopyInto(&out.Source)
|
||||
if in.Destination != nil {
|
||||
in, out := &in.Destination, &out.Destination
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(ApplicationDestination)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
out.Destination = in.Destination
|
||||
return
|
||||
}
|
||||
|
||||
@@ -136,13 +154,33 @@ func (in *ApplicationSpec) DeepCopy() *ApplicationSpec {
|
||||
func (in *ApplicationStatus) DeepCopyInto(out *ApplicationStatus) {
|
||||
*out = *in
|
||||
in.ComparisonResult.DeepCopyInto(&out.ComparisonResult)
|
||||
if in.RecentDeployments != nil {
|
||||
in, out := &in.RecentDeployments, &out.RecentDeployments
|
||||
if in.History != nil {
|
||||
in, out := &in.History, &out.History
|
||||
*out = make([]DeploymentInfo, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.Parameters != nil {
|
||||
in, out := &in.Parameters, &out.Parameters
|
||||
*out = make([]ComponentParameter, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
out.Health = in.Health
|
||||
if in.OperationState != nil {
|
||||
in, out := &in.OperationState, &out.OperationState
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(OperationState)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
if in.Conditions != nil {
|
||||
in, out := &in.Conditions, &out.Conditions
|
||||
*out = make([]ApplicationCondition, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -177,6 +215,7 @@ func (in *ApplicationWatchEvent) DeepCopy() *ApplicationWatchEvent {
|
||||
func (in *Cluster) DeepCopyInto(out *Cluster) {
|
||||
*out = *in
|
||||
in.Config.DeepCopyInto(&out.Config)
|
||||
in.ConnectionState.DeepCopyInto(&out.ConnectionState)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -239,7 +278,9 @@ func (in *ComparisonResult) DeepCopyInto(out *ComparisonResult) {
|
||||
if in.Resources != nil {
|
||||
in, out := &in.Resources, &out.Resources
|
||||
*out = make([]ResourceState, len(*in))
|
||||
copy(*out, *in)
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -270,6 +311,31 @@ func (in *ComponentParameter) DeepCopy() *ComponentParameter {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ConnectionState) DeepCopyInto(out *ConnectionState) {
|
||||
*out = *in
|
||||
if in.ModifiedAt != nil {
|
||||
in, out := &in.ModifiedAt, &out.ModifiedAt
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(v1.Time)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConnectionState.
|
||||
func (in *ConnectionState) DeepCopy() *ConnectionState {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ConnectionState)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// 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
|
||||
@@ -297,9 +363,105 @@ func (in *DeploymentInfo) DeepCopy() *DeploymentInfo {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *HealthStatus) DeepCopyInto(out *HealthStatus) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HealthStatus.
|
||||
func (in *HealthStatus) DeepCopy() *HealthStatus {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(HealthStatus)
|
||||
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
|
||||
if in.Sync != nil {
|
||||
in, out := &in.Sync, &out.Sync
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(SyncOperation)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
if in.Rollback != nil {
|
||||
in, out := &in.Rollback, &out.Rollback
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(RollbackOperation)
|
||||
**out = **in
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Operation.
|
||||
func (in *Operation) DeepCopy() *Operation {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Operation)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *OperationState) DeepCopyInto(out *OperationState) {
|
||||
*out = *in
|
||||
in.Operation.DeepCopyInto(&out.Operation)
|
||||
if in.SyncResult != nil {
|
||||
in, out := &in.SyncResult, &out.SyncResult
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(SyncOperationResult)
|
||||
(*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
|
||||
if *in == nil {
|
||||
*out = nil
|
||||
} else {
|
||||
*out = new(v1.Time)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OperationState.
|
||||
func (in *OperationState) DeepCopy() *OperationState {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(OperationState)
|
||||
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
|
||||
in.ConnectionState.DeepCopyInto(&out.ConnectionState)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -320,7 +482,9 @@ func (in *RepositoryList) DeepCopyInto(out *RepositoryList) {
|
||||
if in.Items != nil {
|
||||
in, out := &in.Items, &out.Items
|
||||
*out = make([]Repository, len(*in))
|
||||
copy(*out, *in)
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -335,9 +499,56 @@ func (in *RepositoryList) DeepCopy() *RepositoryList {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ResourceDetails) DeepCopyInto(out *ResourceDetails) {
|
||||
*out = *in
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceDetails.
|
||||
func (in *ResourceDetails) DeepCopy() *ResourceDetails {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ResourceDetails)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ResourceNode) DeepCopyInto(out *ResourceNode) {
|
||||
*out = *in
|
||||
if in.Children != nil {
|
||||
in, out := &in.Children, &out.Children
|
||||
*out = make([]ResourceNode, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceNode.
|
||||
func (in *ResourceNode) DeepCopy() *ResourceNode {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ResourceNode)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ResourceState) DeepCopyInto(out *ResourceState) {
|
||||
*out = *in
|
||||
if in.ChildLiveResources != nil {
|
||||
in, out := &in.ChildLiveResources, &out.ChildLiveResources
|
||||
*out = make([]ResourceNode, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
out.Health = in.Health
|
||||
return
|
||||
}
|
||||
|
||||
@@ -351,6 +562,66 @@ 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
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SyncOperation.
|
||||
func (in *SyncOperation) DeepCopy() *SyncOperation {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(SyncOperation)
|
||||
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
|
||||
if in.Resources != nil {
|
||||
in, out := &in.Resources, &out.Resources
|
||||
*out = make([]*ResourceDetails, len(*in))
|
||||
for i := range *in {
|
||||
if (*in)[i] == nil {
|
||||
(*out)[i] = nil
|
||||
} else {
|
||||
(*out)[i] = new(ResourceDetails)
|
||||
(*in)[i].DeepCopyInto((*out)[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SyncOperationResult.
|
||||
func (in *SyncOperationResult) DeepCopy() *SyncOperationResult {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(SyncOperationResult)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *TLSClientConfig) DeepCopyInto(out *TLSClientConfig) {
|
||||
*out = *in
|
||||
|
||||
@@ -1,56 +1,146 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/argoproj/argo-cd/common"
|
||||
"github.com/argoproj/argo-cd/util"
|
||||
"github.com/argoproj/argo-cd/util/cache"
|
||||
"github.com/argoproj/argo-cd/util/git"
|
||||
ksutil "github.com/argoproj/argo-cd/util/ksonnet"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"golang.org/x/net/context"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"github.com/argoproj/argo-cd/util/kube"
|
||||
)
|
||||
|
||||
const (
|
||||
// DefaultRepoCacheExpiration is the duration for items to live in the repo cache
|
||||
DefaultRepoCacheExpiration = 24 * time.Hour
|
||||
)
|
||||
|
||||
// Service implements ManifestService interface
|
||||
type Service struct {
|
||||
ns string
|
||||
kubeClient kubernetes.Interface
|
||||
gitClient git.Client
|
||||
repoLock *util.KeyLock
|
||||
gitFactory git.ClientFactory
|
||||
cache cache.Cache
|
||||
}
|
||||
|
||||
// NewService returns a new instance of the Manifest service
|
||||
func NewService(namespace string, kubeClient kubernetes.Interface, gitClient git.Client) *Service {
|
||||
func NewService(gitFactory git.ClientFactory, cache cache.Cache) *Service {
|
||||
return &Service{
|
||||
ns: namespace,
|
||||
kubeClient: kubeClient,
|
||||
gitClient: gitClient,
|
||||
repoLock: util.NewKeyLock(),
|
||||
gitFactory: gitFactory,
|
||||
cache: cache,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Service) GenerateManifest(c context.Context, q *ManifestRequest) (*ManifestResponse, error) {
|
||||
appRepoPath := path.Join(os.TempDir(), strings.Replace(q.Repo.Repo, "/", "_", -1))
|
||||
// ListDir lists the contents of a GitHub repo
|
||||
func (s *Service) ListDir(ctx context.Context, q *ListDirRequest) (*FileList, error) {
|
||||
appRepoPath := tempRepoPath(q.Repo.Repo)
|
||||
s.repoLock.Lock(appRepoPath)
|
||||
defer func() {
|
||||
err := s.gitClient.Reset(appRepoPath)
|
||||
if err != nil {
|
||||
log.Warn(err)
|
||||
}
|
||||
s.repoLock.Unlock(appRepoPath)
|
||||
}()
|
||||
defer s.repoLock.Unlock(appRepoPath)
|
||||
|
||||
err := s.gitClient.CloneOrFetch(q.Repo.Repo, q.Repo.Username, q.Repo.Password, q.Repo.SSHPrivateKey, 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
|
||||
}
|
||||
|
||||
revision, err := s.gitClient.Checkout(appRepoPath, q.Revision)
|
||||
commitSHA, err := gitClient.LsRemote(q.Revision)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cacheKey := listDirCacheKey(commitSHA, q)
|
||||
var res FileList
|
||||
err = s.cache.Get(cacheKey, &res)
|
||||
if err == nil {
|
||||
log.Infof("manifest cache hit: %s", cacheKey)
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
err = checkoutRevision(gitClient, q.Revision)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
lsFiles, err := gitClient.LsFiles(q.Path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res = FileList{
|
||||
Items: lsFiles,
|
||||
}
|
||||
err = s.cache.Set(&cache.Item{
|
||||
Key: cacheKey,
|
||||
Object: &res,
|
||||
Expiration: DefaultRepoCacheExpiration,
|
||||
})
|
||||
if err != nil {
|
||||
log.Warnf("manifest cache set error %s: %v", cacheKey, err)
|
||||
}
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
func (s *Service) GetFile(ctx context.Context, q *GetFileRequest) (*GetFileResponse, error) {
|
||||
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
|
||||
}
|
||||
err = checkoutRevision(gitClient, q.Revision)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
data, err := ioutil.ReadFile(path.Join(gitClient.Root(), q.Path))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res := GetFileResponse{
|
||||
Data: data,
|
||||
}
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
func (s *Service) GenerateManifest(c context.Context, q *ManifestRequest) (*ManifestResponse, error) {
|
||||
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)
|
||||
return &res, nil
|
||||
}
|
||||
if err != cache.ErrCacheMiss {
|
||||
log.Warnf("manifest cache error %s: %v", cacheKey, err)
|
||||
} else {
|
||||
log.Infof("manifest cache miss: %s", cacheKey)
|
||||
}
|
||||
|
||||
err = checkoutRevision(gitClient, q.Revision)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -60,6 +150,11 @@ func (s *Service) GenerateManifest(c context.Context, q *ManifestRequest) (*Mani
|
||||
return nil, fmt.Errorf("unable to load application from %s: %v", appPath, err)
|
||||
}
|
||||
|
||||
params, err := ksApp.ListEnvParams(q.Environment)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if q.ComponentParameterOverrides != nil {
|
||||
for _, override := range q.ComponentParameterOverrides {
|
||||
err = ksApp.SetComponentParams(q.Environment, override.Component, override.Name, override.Value)
|
||||
@@ -82,12 +177,10 @@ func (s *Service) GenerateManifest(c context.Context, q *ManifestRequest) (*Mani
|
||||
manifests := make([]string, len(targetObjs))
|
||||
for i, target := range targetObjs {
|
||||
if q.AppLabel != "" {
|
||||
labels := target.GetLabels()
|
||||
if labels == nil {
|
||||
labels = make(map[string]string)
|
||||
err = kube.SetLabel(target, common.LabelApplicationName, q.AppLabel)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
labels[common.LabelApplicationName] = q.AppLabel
|
||||
target.SetLabels(labels)
|
||||
}
|
||||
manifestStr, err := json.Marshal(target.Object)
|
||||
if err != nil {
|
||||
@@ -95,41 +188,51 @@ func (s *Service) GenerateManifest(c context.Context, q *ManifestRequest) (*Mani
|
||||
}
|
||||
manifests[i] = string(manifestStr)
|
||||
}
|
||||
return &ManifestResponse{
|
||||
Revision: revision,
|
||||
res = ManifestResponse{
|
||||
Revision: commitSHA,
|
||||
Manifests: manifests,
|
||||
Namespace: env.Destination.Namespace,
|
||||
Server: env.Destination.Server,
|
||||
}, nil
|
||||
Params: params,
|
||||
}
|
||||
err = s.cache.Set(&cache.Item{
|
||||
Key: cacheKey,
|
||||
Object: &res,
|
||||
Expiration: DefaultRepoCacheExpiration,
|
||||
})
|
||||
if err != nil {
|
||||
log.Warnf("manifest cache set error %s: %v", cacheKey, err)
|
||||
}
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
// GetEnvParams retrieves Ksonnet environment params in specified repo name and revision
|
||||
func (s *Service) GetEnvParams(c context.Context, q *EnvParamsRequest) (*EnvParamsResponse, error) {
|
||||
appRepoPath := path.Join(os.TempDir(), strings.Replace(q.Repo.Repo, "/", "_", -1))
|
||||
s.repoLock.Lock(appRepoPath)
|
||||
defer s.repoLock.Unlock(appRepoPath)
|
||||
|
||||
err := s.gitClient.CloneOrFetch(q.Repo.Repo, q.Repo.Username, q.Repo.Password, q.Repo.SSHPrivateKey, appRepoPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, err = s.gitClient.Checkout(appRepoPath, q.Revision)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
appPath := path.Join(appRepoPath, q.Path)
|
||||
ksApp, err := ksutil.NewKsonnetApp(appPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
target, err := ksApp.ListEnvParams(q.Environment)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &EnvParamsResponse{
|
||||
Params: target,
|
||||
}, nil
|
||||
// tempRepoPath returns a formulated temporary directory location to clone a repository
|
||||
func tempRepoPath(repo string) string {
|
||||
return path.Join(os.TempDir(), strings.Replace(repo, "/", "_", -1))
|
||||
}
|
||||
|
||||
// checkoutRevision is a convenience function to initialize a repo, fetch, and checkout a revision
|
||||
func checkoutRevision(gitClient git.Client, revision string) error {
|
||||
err := gitClient.Fetch()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = gitClient.Reset()
|
||||
if err != nil {
|
||||
log.Warn(err)
|
||||
}
|
||||
err = gitClient.Checkout(revision)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func manifestCacheKey(commitSHA string, q *ManifestRequest) string {
|
||||
pStr, _ := json.Marshal(q.ComponentParameterOverrides)
|
||||
return fmt.Sprintf("mfst|%s|%s|%s|%s", q.Path, q.Environment, commitSHA, string(pStr))
|
||||
}
|
||||
|
||||
func listDirCacheKey(commitSHA string, q *ListDirRequest) string {
|
||||
return fmt.Sprintf("ldir|%s|%s", q.Path, commitSHA)
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -23,17 +23,32 @@ message ManifestResponse {
|
||||
string namespace = 2;
|
||||
string server = 3;
|
||||
string revision = 4;
|
||||
repeated github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.ComponentParameter params = 5;
|
||||
}
|
||||
|
||||
message EnvParamsRequest {
|
||||
// ListDirRequest requests a repository directory structure
|
||||
message ListDirRequest {
|
||||
github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.Repository repo = 1;
|
||||
string revision = 2;
|
||||
string path = 3;
|
||||
string environment = 4;
|
||||
}
|
||||
|
||||
message EnvParamsResponse {
|
||||
repeated github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.ComponentParameter params = 1;
|
||||
// FileList returns the contents of the repo of a ListDir request
|
||||
message FileList {
|
||||
repeated string items = 1;
|
||||
}
|
||||
|
||||
// GetFileRequest return
|
||||
message GetFileRequest {
|
||||
github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.Repository repo = 1;
|
||||
string revision = 2;
|
||||
string path = 3;
|
||||
}
|
||||
|
||||
|
||||
// GetFileResponse returns the contents of the file of a GetFile request
|
||||
message GetFileResponse {
|
||||
bytes data = 1;
|
||||
}
|
||||
|
||||
// ManifestService
|
||||
@@ -43,7 +58,12 @@ service RepositoryService {
|
||||
rpc GenerateManifest(ManifestRequest) returns (ManifestResponse) {
|
||||
}
|
||||
|
||||
// Retrieve Ksonnet environment params in specified repo name and revision
|
||||
rpc GetEnvParams(EnvParamsRequest) returns (EnvParamsResponse) {
|
||||
// ListDir returns the file contents at the specified repo and path
|
||||
rpc ListDir(ListDirRequest) returns (FileList) {
|
||||
}
|
||||
|
||||
// GetFile returns the file contents at the specified repo and path
|
||||
rpc GetFile(GetFileRequest) returns (GetFileResponse) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,33 +3,34 @@ package reposerver
|
||||
import (
|
||||
"github.com/argoproj/argo-cd/reposerver/repository"
|
||||
"github.com/argoproj/argo-cd/server/version"
|
||||
"github.com/argoproj/argo-cd/util/cache"
|
||||
"github.com/argoproj/argo-cd/util/git"
|
||||
grpc_util "github.com/argoproj/argo-cd/util/grpc"
|
||||
"github.com/grpc-ecosystem/go-grpc-middleware"
|
||||
"github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"google.golang.org/grpc"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"google.golang.org/grpc/reflection"
|
||||
)
|
||||
|
||||
// ArgoCDRepoServer is the repo server implementation
|
||||
type ArgoCDRepoServer struct {
|
||||
ns string
|
||||
kubeclientset kubernetes.Interface
|
||||
log *log.Entry
|
||||
log *log.Entry
|
||||
gitFactory git.ClientFactory
|
||||
cache cache.Cache
|
||||
}
|
||||
|
||||
// NewServer returns a new instance of the ArgoCD Repo server
|
||||
func NewServer(kubeclientset kubernetes.Interface, namespace string) *ArgoCDRepoServer {
|
||||
func NewServer(gitFactory git.ClientFactory, cache cache.Cache) *ArgoCDRepoServer {
|
||||
return &ArgoCDRepoServer{
|
||||
ns: namespace,
|
||||
kubeclientset: kubeclientset,
|
||||
log: log.NewEntry(log.New()),
|
||||
log: log.NewEntry(log.New()),
|
||||
gitFactory: gitFactory,
|
||||
cache: cache,
|
||||
}
|
||||
}
|
||||
|
||||
// CreateGRPC creates new configured grpc server
|
||||
func (a *ArgoCDRepoServer) CreateGRPC(gitClient git.Client) *grpc.Server {
|
||||
func (a *ArgoCDRepoServer) CreateGRPC() *grpc.Server {
|
||||
server := grpc.NewServer(
|
||||
grpc.StreamInterceptor(grpc_middleware.ChainStreamServer(
|
||||
grpc_logrus.StreamServerInterceptor(a.log),
|
||||
@@ -41,8 +42,11 @@ func (a *ArgoCDRepoServer) CreateGRPC(gitClient git.Client) *grpc.Server {
|
||||
)),
|
||||
)
|
||||
version.RegisterVersionServiceServer(server, &version.Server{})
|
||||
manifestService := repository.NewService(a.ns, a.kubeclientset, gitClient)
|
||||
manifestService := repository.NewService(a.gitFactory, a.cache)
|
||||
repository.RegisterRepositoryServiceServer(server, manifestService)
|
||||
|
||||
// Register reflection service on gRPC server.
|
||||
reflection.Register(server)
|
||||
|
||||
return server
|
||||
}
|
||||
|
||||
@@ -1,32 +1,40 @@
|
||||
package application
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"path"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/ksonnet/ksonnet/pkg/app"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"golang.org/x/net/context"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"k8s.io/api/core/v1"
|
||||
apierr "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
|
||||
"github.com/argoproj/argo-cd/common"
|
||||
"github.com/argoproj/argo-cd/controller"
|
||||
appv1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
|
||||
appclientset "github.com/argoproj/argo-cd/pkg/client/clientset/versioned"
|
||||
"github.com/argoproj/argo-cd/reposerver"
|
||||
"github.com/argoproj/argo-cd/reposerver/repository"
|
||||
"github.com/argoproj/argo-cd/server/cluster"
|
||||
apirepository "github.com/argoproj/argo-cd/server/repository"
|
||||
"github.com/argoproj/argo-cd/util"
|
||||
argoutil "github.com/argoproj/argo-cd/util/argo"
|
||||
"github.com/argoproj/argo-cd/util/diff"
|
||||
"github.com/argoproj/argo-cd/util/kube"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"golang.org/x/net/context"
|
||||
apiv1 "k8s.io/api/core/v1"
|
||||
apierr "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
)
|
||||
|
||||
const (
|
||||
maxRecentDeploymentsCnt = 5
|
||||
"github.com/argoproj/argo-cd/util/db"
|
||||
"github.com/argoproj/argo-cd/util/git"
|
||||
"github.com/argoproj/argo-cd/util/grpc"
|
||||
"github.com/argoproj/argo-cd/util/rbac"
|
||||
)
|
||||
|
||||
// Server provides a Application service
|
||||
@@ -35,9 +43,9 @@ type Server struct {
|
||||
kubeclientset kubernetes.Interface
|
||||
appclientset appclientset.Interface
|
||||
repoClientset reposerver.Clientset
|
||||
// TODO(jessesuen): move common cluster code to shared libraries
|
||||
clusterService cluster.ClusterServiceServer
|
||||
repoService apirepository.RepositoryServiceServer
|
||||
db db.ArgoDB
|
||||
appComparator controller.AppStateManager
|
||||
enf *rbac.Enforcer
|
||||
}
|
||||
|
||||
// NewServer returns a new instance of the Application service
|
||||
@@ -46,64 +54,242 @@ func NewServer(
|
||||
kubeclientset kubernetes.Interface,
|
||||
appclientset appclientset.Interface,
|
||||
repoClientset reposerver.Clientset,
|
||||
repoService apirepository.RepositoryServiceServer,
|
||||
clusterService cluster.ClusterServiceServer) ApplicationServiceServer {
|
||||
db db.ArgoDB,
|
||||
enf *rbac.Enforcer,
|
||||
) ApplicationServiceServer {
|
||||
|
||||
return &Server{
|
||||
ns: namespace,
|
||||
appclientset: appclientset,
|
||||
kubeclientset: kubeclientset,
|
||||
clusterService: clusterService,
|
||||
repoClientset: repoClientset,
|
||||
repoService: repoService,
|
||||
ns: namespace,
|
||||
appclientset: appclientset,
|
||||
kubeclientset: kubeclientset,
|
||||
db: db,
|
||||
repoClientset: repoClientset,
|
||||
appComparator: controller.NewAppStateManager(db, appclientset, repoClientset, namespace),
|
||||
enf: enf,
|
||||
}
|
||||
}
|
||||
|
||||
// appRBACName formats fully qualified application name for RBAC check
|
||||
func appRBACName(app appv1.Application) string {
|
||||
return fmt.Sprintf("%s/%s", git.NormalizeGitURL(app.Spec.Source.RepoURL), app.Name)
|
||||
}
|
||||
|
||||
// List returns list of applications
|
||||
func (s *Server) List(ctx context.Context, q *ApplicationQuery) (*appv1.ApplicationList, error) {
|
||||
return s.appclientset.ArgoprojV1alpha1().Applications(s.ns).List(metav1.ListOptions{})
|
||||
appList, err := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
newItems := make([]appv1.Application, 0)
|
||||
for _, a := range appList.Items {
|
||||
if s.enf.EnforceClaims(ctx.Value("claims"), "applications", "get", appRBACName(a)) {
|
||||
newItems = append(newItems, a)
|
||||
}
|
||||
}
|
||||
appList.Items = newItems
|
||||
return appList, nil
|
||||
}
|
||||
|
||||
// Create creates a application
|
||||
func (s *Server) Create(ctx context.Context, a *appv1.Application) (*appv1.Application, error) {
|
||||
return s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Create(a)
|
||||
// Create creates an application
|
||||
func (s *Server) Create(ctx context.Context, q *ApplicationCreateRequest) (*appv1.Application, error) {
|
||||
if !s.enf.EnforceClaims(ctx.Value("claims"), "applications", "create", appRBACName(q.Application)) {
|
||||
return nil, grpc.ErrPermissionDenied
|
||||
}
|
||||
a := q.Application
|
||||
err := s.validateApp(ctx, &a.Spec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
a.SetCascadedDeletion(true)
|
||||
out, err := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Create(&a)
|
||||
if apierr.IsAlreadyExists(err) {
|
||||
// act idempotent if existing spec matches new spec
|
||||
existing, getErr := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Get(a.Name, metav1.GetOptions{})
|
||||
if getErr != nil {
|
||||
return nil, status.Errorf(codes.Internal, "unable to check existing application details: %v", err)
|
||||
}
|
||||
if q.Upsert != nil && *q.Upsert {
|
||||
if !s.enf.EnforceClaims(ctx.Value("claims"), "applications", "update", appRBACName(a)) {
|
||||
return nil, grpc.ErrPermissionDenied
|
||||
}
|
||||
existing.Spec = a.Spec
|
||||
out, err = s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Update(existing)
|
||||
} else {
|
||||
if reflect.DeepEqual(existing.Spec, a.Spec) {
|
||||
return existing, nil
|
||||
} else {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "existing application spec is different, use upsert flag to force update")
|
||||
}
|
||||
}
|
||||
}
|
||||
return out, err
|
||||
}
|
||||
|
||||
// Get returns a application by name
|
||||
// GetManifests returns application manifests
|
||||
func (s *Server) GetManifests(ctx context.Context, q *ApplicationManifestQuery) (*repository.ManifestResponse, error) {
|
||||
a, err := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Get(*q.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !s.enf.EnforceClaims(ctx.Value("claims"), "applications/manifests", "get", appRBACName(*a)) {
|
||||
return nil, grpc.ErrPermissionDenied
|
||||
}
|
||||
repo := s.getRepo(ctx, a.Spec.Source.RepoURL)
|
||||
|
||||
conn, repoClient, err := s.repoClientset.NewRepositoryClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer util.Close(conn)
|
||||
overrides := make([]*appv1.ComponentParameter, len(a.Spec.Source.ComponentParameterOverrides))
|
||||
if a.Spec.Source.ComponentParameterOverrides != nil {
|
||||
for i := range a.Spec.Source.ComponentParameterOverrides {
|
||||
item := a.Spec.Source.ComponentParameterOverrides[i]
|
||||
overrides[i] = &item
|
||||
}
|
||||
}
|
||||
|
||||
revision := a.Spec.Source.TargetRevision
|
||||
if q.Revision != "" {
|
||||
revision = q.Revision
|
||||
}
|
||||
manifestInfo, err := repoClient.GenerateManifest(context.Background(), &repository.ManifestRequest{
|
||||
Repo: repo,
|
||||
Environment: a.Spec.Source.Environment,
|
||||
Path: a.Spec.Source.Path,
|
||||
Revision: revision,
|
||||
ComponentParameterOverrides: overrides,
|
||||
AppLabel: a.Name,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return manifestInfo, nil
|
||||
}
|
||||
|
||||
// Get returns an application by name
|
||||
func (s *Server) Get(ctx context.Context, q *ApplicationQuery) (*appv1.Application, error) {
|
||||
return s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Get(q.Name, metav1.GetOptions{})
|
||||
appIf := s.appclientset.ArgoprojV1alpha1().Applications(s.ns)
|
||||
a, err := appIf.Get(*q.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !s.enf.EnforceClaims(ctx.Value("claims"), "applications", "get", appRBACName(*a)) {
|
||||
return nil, grpc.ErrPermissionDenied
|
||||
}
|
||||
if q.Refresh {
|
||||
_, err = argoutil.RefreshApp(appIf, *q.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
a, err = argoutil.WaitForRefresh(appIf, *q.Name, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
// Update updates a application
|
||||
func (s *Server) Update(ctx context.Context, a *appv1.Application) (*appv1.Application, error) {
|
||||
// ListResourceEvents returns a list of event resources
|
||||
func (s *Server) ListResourceEvents(ctx context.Context, q *ApplicationResourceEventsQuery) (*v1.EventList, error) {
|
||||
a, err := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Get(*q.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !s.enf.EnforceClaims(ctx.Value("claims"), "applications/events", "get", appRBACName(*a)) {
|
||||
return nil, grpc.ErrPermissionDenied
|
||||
}
|
||||
config, namespace, err := s.getApplicationClusterConfig(*q.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
kubeClientset, err := kubernetes.NewForConfig(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fieldSelector := fields.SelectorFromSet(map[string]string{
|
||||
"involvedObject.name": q.ResourceName,
|
||||
"involvedObject.uid": q.ResourceUID,
|
||||
"involvedObject.namespace": namespace,
|
||||
}).String()
|
||||
|
||||
log.Infof("Querying for resource events with field selector: %s", fieldSelector)
|
||||
opts := metav1.ListOptions{FieldSelector: fieldSelector}
|
||||
|
||||
return kubeClientset.CoreV1().Events(namespace).List(opts)
|
||||
}
|
||||
|
||||
// Update updates an application
|
||||
func (s *Server) Update(ctx context.Context, q *ApplicationUpdateRequest) (*appv1.Application, error) {
|
||||
if !s.enf.EnforceClaims(ctx.Value("claims"), "applications", "update", appRBACName(*q.Application)) {
|
||||
return nil, grpc.ErrPermissionDenied
|
||||
}
|
||||
a := q.Application
|
||||
err := s.validateApp(ctx, &a.Spec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Update(a)
|
||||
}
|
||||
|
||||
// UpdateSpec updates an application spec
|
||||
func (s *Server) UpdateSpec(ctx context.Context, q *ApplicationUpdateSpecRequest) (*appv1.ApplicationSpec, error) {
|
||||
a, err := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Get(*q.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !s.enf.EnforceClaims(ctx.Value("claims"), "applications", "update", appRBACName(*a)) {
|
||||
return nil, grpc.ErrPermissionDenied
|
||||
}
|
||||
err = s.validateApp(ctx, &q.Spec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
patch, err := json.Marshal(map[string]appv1.ApplicationSpec{
|
||||
"spec": q.Spec,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Patch(*q.Name, types.MergePatchType, patch)
|
||||
return &q.Spec, err
|
||||
}
|
||||
|
||||
// Delete removes an application and all associated resources
|
||||
func (s *Server) Delete(ctx context.Context, q *DeleteApplicationRequest) (*ApplicationResponse, error) {
|
||||
err := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Delete(q.Name, &metav1.DeleteOptions{})
|
||||
func (s *Server) Delete(ctx context.Context, q *ApplicationDeleteRequest) (*ApplicationResponse, error) {
|
||||
a, err := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Get(*q.Name, metav1.GetOptions{})
|
||||
if err != nil && !apierr.IsNotFound(err) {
|
||||
return nil, err
|
||||
}
|
||||
if q.Server != "" && q.Namespace != "" {
|
||||
clst, err := s.clusterService.Get(ctx, &cluster.ClusterQuery{Server: q.Server})
|
||||
|
||||
if !s.enf.EnforceClaims(ctx.Value("claims"), "applications", "delete", appRBACName(*a)) {
|
||||
return nil, grpc.ErrPermissionDenied
|
||||
}
|
||||
|
||||
if q.Cascade != nil && *q.Cascade != a.CascadedDeletion() {
|
||||
a.SetCascadedDeletion(*q.Cascade)
|
||||
patch, err := json.Marshal(map[string]interface{}{
|
||||
"metadata": map[string]interface{}{
|
||||
"finalizers": a.Finalizers,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config := clst.RESTConfig()
|
||||
err = kube.DeleteResourceWithLabel(config, q.Namespace, fmt.Sprintf("%s=%s", common.LabelApplicationName, q.Name))
|
||||
_, err = s.appclientset.ArgoprojV1alpha1().Applications(a.Namespace).Patch(a.Name, types.MergePatchType, patch)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return &ApplicationResponse{}, nil
|
||||
}
|
||||
err = s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Delete(*q.Name, &metav1.DeleteOptions{})
|
||||
if err != nil && !apierr.IsNotFound(err) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// ListPods returns pods in a application
|
||||
func (s *Server) ListPods(ctx context.Context, q *ApplicationQuery) (*apiv1.PodList, error) {
|
||||
// TODO: filter by the app label
|
||||
return s.kubeclientset.CoreV1().Pods(s.ns).List(metav1.ListOptions{})
|
||||
return &ApplicationResponse{}, nil
|
||||
}
|
||||
|
||||
func (s *Server) Watch(q *ApplicationQuery, ws ApplicationService_WatchServer) error {
|
||||
@@ -111,14 +297,19 @@ func (s *Server) Watch(q *ApplicationQuery, ws ApplicationService_WatchServer) e
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
claims := ws.Context().Value("claims")
|
||||
done := make(chan bool)
|
||||
go func() {
|
||||
for next := range w.ResultChan() {
|
||||
app := *next.Object.(*appv1.Application)
|
||||
if q.Name == "" || q.Name == app.Name {
|
||||
a := *next.Object.(*appv1.Application)
|
||||
if q.Name == nil || *q.Name == "" || *q.Name == a.Name {
|
||||
if !s.enf.EnforceClaims(claims, "applications", "get", appRBACName(a)) {
|
||||
// do not emit apps user does not have accessing
|
||||
continue
|
||||
}
|
||||
err = ws.Send(&appv1.ApplicationWatchEvent{
|
||||
Type: next.Type,
|
||||
Application: app,
|
||||
Application: a,
|
||||
})
|
||||
if err != nil {
|
||||
log.Warnf("Unable to send stream message: %v", err)
|
||||
@@ -135,69 +326,227 @@ func (s *Server) Watch(q *ApplicationQuery, ws ApplicationService_WatchServer) e
|
||||
return nil
|
||||
}
|
||||
|
||||
// Sync syncs an application to its target state
|
||||
func (s *Server) Sync(ctx context.Context, syncReq *ApplicationSyncRequest) (*ApplicationSyncResult, error) {
|
||||
log.Infof("Syncing application %s", syncReq.Name)
|
||||
app, err := s.Get(ctx, &ApplicationQuery{Name: syncReq.Name})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
revision := syncReq.Revision
|
||||
if revision == "" {
|
||||
app.Spec.Source.TargetRevision = revision
|
||||
}
|
||||
|
||||
repo := s.getRepo(ctx, app.Spec.Source.RepoURL)
|
||||
// validateApp will ensure:
|
||||
// * the git repository is accessible
|
||||
// * the git path contains a valid app.yaml
|
||||
// * the specified environment exists
|
||||
// * the referenced cluster has been added to ArgoCD
|
||||
func (s *Server) validateApp(ctx context.Context, spec *appv1.ApplicationSpec) error {
|
||||
// Test the repo
|
||||
conn, repoClient, err := s.repoClientset.NewRepositoryClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
defer util.Close(conn)
|
||||
// set fields in v1alpha/types.go
|
||||
log.Infof("Retrieving deployment params for application %s", syncReq.Name)
|
||||
envParams, err := repoClient.GetEnvParams(ctx, &repository.EnvParamsRequest{
|
||||
Repo: repo,
|
||||
Environment: app.Spec.Source.Environment,
|
||||
Path: app.Spec.Source.Path,
|
||||
Revision: revision,
|
||||
})
|
||||
repoRes, err := s.db.GetRepository(ctx, spec.Source.RepoURL)
|
||||
if err != nil {
|
||||
if errStatus, ok := status.FromError(err); ok && errStatus.Code() == codes.NotFound {
|
||||
// The repo has not been added to ArgoCD so we do not have credentials to access it.
|
||||
// We support the mode where apps can be created from public repositories. Test the
|
||||
// repo to make sure it is publicly accessible
|
||||
err = git.TestRepo(spec.Source.RepoURL, "", "", "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Verify app.yaml is functional
|
||||
req := repository.GetFileRequest{
|
||||
Repo: &appv1.Repository{
|
||||
Repo: spec.Source.RepoURL,
|
||||
},
|
||||
Revision: spec.Source.TargetRevision,
|
||||
Path: path.Join(spec.Source.Path, "app.yaml"),
|
||||
}
|
||||
if repoRes != nil {
|
||||
req.Repo.Username = repoRes.Username
|
||||
req.Repo.Password = repoRes.Password
|
||||
req.Repo.SSHPrivateKey = repoRes.SSHPrivateKey
|
||||
}
|
||||
getRes, err := repoClient.GetFile(ctx, &req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var appSpec app.Spec
|
||||
err = yaml.Unmarshal(getRes.Data, &appSpec)
|
||||
if err != nil {
|
||||
return status.Errorf(codes.InvalidArgument, "app.yaml is not a valid ksonnet app spec")
|
||||
}
|
||||
|
||||
// Default revision to HEAD if unspecified
|
||||
if spec.Source.TargetRevision == "" {
|
||||
spec.Source.TargetRevision = "HEAD"
|
||||
}
|
||||
|
||||
// Verify the specified environment is defined in it
|
||||
envSpec, ok := appSpec.Environments[spec.Source.Environment]
|
||||
if !ok || envSpec == nil {
|
||||
return status.Errorf(codes.InvalidArgument, "environment '%s' does not exist in ksonnet app", spec.Source.Environment)
|
||||
}
|
||||
|
||||
// If server and namespace are not supplied, pull it from the app.yaml
|
||||
if spec.Destination.Server == "" {
|
||||
spec.Destination.Server = envSpec.Destination.Server
|
||||
}
|
||||
if spec.Destination.Namespace == "" {
|
||||
spec.Destination.Namespace = envSpec.Destination.Namespace
|
||||
}
|
||||
|
||||
// Ensure the k8s cluster the app is referencing, is configured in ArgoCD
|
||||
_, err = s.db.GetCluster(ctx, spec.Destination.Server)
|
||||
if err != nil {
|
||||
if apierr.IsNotFound(err) {
|
||||
return status.Errorf(codes.InvalidArgument, "cluster '%s' has not been configured", spec.Destination.Server)
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) getApplicationClusterConfig(applicationName string) (*rest.Config, string, error) {
|
||||
server, namespace, err := s.getApplicationDestination(context.Background(), applicationName)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
clst, err := s.db.GetCluster(context.Background(), server)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
config := clst.RESTConfig()
|
||||
return config, namespace, err
|
||||
}
|
||||
|
||||
func (s *Server) ensurePodBelongsToApp(applicationName string, podName, namespace string, kubeClientset *kubernetes.Clientset) error {
|
||||
pod, err := kubeClientset.CoreV1().Pods(namespace).Get(podName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
wrongPodError := status.Errorf(codes.InvalidArgument, "pod %s does not belong to application %s", podName, applicationName)
|
||||
if pod.Labels == nil {
|
||||
return wrongPodError
|
||||
}
|
||||
if value, ok := pod.Labels[common.LabelApplicationName]; !ok || value != applicationName {
|
||||
return wrongPodError
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) DeletePod(ctx context.Context, q *ApplicationDeletePodRequest) (*ApplicationResponse, error) {
|
||||
a, err := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Get(*q.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
log.Infof("Received deployment params: %s", envParams.Params)
|
||||
|
||||
res, manifest, err := s.deploy(ctx, app.Spec.Source, app.Spec.Destination, app.Name, syncReq.DryRun)
|
||||
if err == nil {
|
||||
// Persist app deployment info
|
||||
params := make([]appv1.ComponentParameter, len(envParams.Params))
|
||||
for i := range envParams.Params {
|
||||
param := *envParams.Params[i]
|
||||
params[i] = param
|
||||
}
|
||||
app, err = s.Get(ctx, &ApplicationQuery{Name: syncReq.Name})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
app.Status.RecentDeployments = append(app.Status.RecentDeployments, appv1.DeploymentInfo{
|
||||
ComponentParameterOverrides: app.Spec.Source.ComponentParameterOverrides,
|
||||
Revision: manifest.Revision,
|
||||
Params: params,
|
||||
DeployedAt: metav1.NewTime(time.Now()),
|
||||
})
|
||||
if len(app.Status.RecentDeployments) > maxRecentDeploymentsCnt {
|
||||
app.Status.RecentDeployments = app.Status.RecentDeployments[:maxRecentDeploymentsCnt]
|
||||
}
|
||||
_, err = s.Update(ctx, app)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !s.enf.EnforceClaims(ctx.Value("claims"), "applications/pods", "delete", appRBACName(*a)) {
|
||||
return nil, grpc.ErrPermissionDenied
|
||||
}
|
||||
return res, err
|
||||
|
||||
config, namespace, err := s.getApplicationClusterConfig(*q.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
kubeClientset, err := kubernetes.NewForConfig(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = s.ensurePodBelongsToApp(*q.Name, *q.PodName, namespace, kubeClientset)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = kubeClientset.CoreV1().Pods(namespace).Delete(*q.PodName, &metav1.DeleteOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &ApplicationResponse{}, nil
|
||||
}
|
||||
|
||||
func (s *Server) PodLogs(q *ApplicationPodLogsQuery, ws ApplicationService_PodLogsServer) error {
|
||||
a, err := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Get(*q.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !s.enf.EnforceClaims(ws.Context().Value("claims"), "applications/logs", "get", appRBACName(*a)) {
|
||||
return grpc.ErrPermissionDenied
|
||||
}
|
||||
config, namespace, err := s.getApplicationClusterConfig(*q.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
kubeClientset, err := kubernetes.NewForConfig(config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = s.ensurePodBelongsToApp(*q.Name, *q.PodName, namespace, kubeClientset)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var sinceSeconds, tailLines *int64
|
||||
if q.SinceSeconds > 0 {
|
||||
sinceSeconds = &q.SinceSeconds
|
||||
}
|
||||
if q.TailLines > 0 {
|
||||
tailLines = &q.TailLines
|
||||
}
|
||||
stream, err := kubeClientset.CoreV1().Pods(namespace).GetLogs(*q.PodName, &v1.PodLogOptions{
|
||||
Container: q.Container,
|
||||
Follow: q.Follow,
|
||||
Timestamps: true,
|
||||
SinceSeconds: sinceSeconds,
|
||||
SinceTime: q.SinceTime,
|
||||
TailLines: tailLines,
|
||||
}).Stream()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
done := make(chan bool)
|
||||
go func() {
|
||||
scanner := bufio.NewScanner(stream)
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
parts := strings.Split(line, " ")
|
||||
logTime, err := time.Parse(time.RFC3339, parts[0])
|
||||
metaLogTime := metav1.NewTime(logTime)
|
||||
if err == nil {
|
||||
lines := strings.Join(parts[1:], " ")
|
||||
for _, line := range strings.Split(lines, "\r") {
|
||||
if line != "" {
|
||||
err = ws.Send(&LogEntry{
|
||||
Content: line,
|
||||
TimeStamp: metaLogTime,
|
||||
})
|
||||
if err != nil {
|
||||
log.Warnf("Unable to send stream message: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
done <- true
|
||||
}()
|
||||
select {
|
||||
case <-ws.Context().Done():
|
||||
util.Close(stream)
|
||||
case <-done:
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) getApplicationDestination(ctx context.Context, name string) (string, string, error) {
|
||||
a, err := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Get(name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
server, namespace := a.Spec.Destination.Server, a.Spec.Destination.Namespace
|
||||
return server, namespace, nil
|
||||
}
|
||||
|
||||
func (s *Server) getRepo(ctx context.Context, repoURL string) *appv1.Repository {
|
||||
repo, err := s.repoService.Get(ctx, &apirepository.RepoQuery{Repo: repoURL})
|
||||
repo, err := s.db.GetRepository(ctx, repoURL)
|
||||
if err != nil {
|
||||
// If we couldn't retrieve from the repo service, assume public repositories
|
||||
repo = &appv1.Repository{Repo: repoURL}
|
||||
@@ -205,93 +554,65 @@ func (s *Server) getRepo(ctx context.Context, repoURL string) *appv1.Repository
|
||||
return repo
|
||||
}
|
||||
|
||||
func (s *Server) deploy(
|
||||
ctx context.Context,
|
||||
source appv1.ApplicationSource,
|
||||
destination *appv1.ApplicationDestination,
|
||||
appLabel string,
|
||||
dryRun bool) (*ApplicationSyncResult, *repository.ManifestResponse, error) {
|
||||
|
||||
repo := s.getRepo(ctx, source.RepoURL)
|
||||
conn, repoClient, err := s.repoClientset.NewRepositoryClient()
|
||||
// Sync syncs an application to its target state
|
||||
func (s *Server) Sync(ctx context.Context, syncReq *ApplicationSyncRequest) (*appv1.Application, error) {
|
||||
a, err := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Get(*syncReq.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
defer util.Close(conn)
|
||||
overrides := make([]*appv1.ComponentParameter, len(source.ComponentParameterOverrides))
|
||||
if source.ComponentParameterOverrides != nil {
|
||||
for i := range source.ComponentParameterOverrides {
|
||||
item := source.ComponentParameterOverrides[i]
|
||||
overrides[i] = &item
|
||||
}
|
||||
if !s.enf.EnforceClaims(ctx.Value("claims"), "applications", "sync", appRBACName(*a)) {
|
||||
return nil, grpc.ErrPermissionDenied
|
||||
}
|
||||
|
||||
manifestInfo, err := repoClient.GenerateManifest(ctx, &repository.ManifestRequest{
|
||||
Repo: repo,
|
||||
Environment: source.Environment,
|
||||
Path: source.Path,
|
||||
Revision: source.TargetRevision,
|
||||
ComponentParameterOverrides: overrides,
|
||||
AppLabel: appLabel,
|
||||
return s.setAppOperation(ctx, *syncReq.Name, func(app *appv1.Application) (*appv1.Operation, error) {
|
||||
return &appv1.Operation{
|
||||
Sync: &appv1.SyncOperation{
|
||||
Revision: syncReq.Revision,
|
||||
Prune: syncReq.Prune,
|
||||
DryRun: syncReq.DryRun,
|
||||
},
|
||||
}, nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
server, namespace := argoutil.ResolveServerNamespace(destination, manifestInfo)
|
||||
|
||||
clst, err := s.clusterService.Get(ctx, &cluster.ClusterQuery{Server: server})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
config := clst.RESTConfig()
|
||||
|
||||
targetObjs := make([]*unstructured.Unstructured, len(manifestInfo.Manifests))
|
||||
for i, manifest := range manifestInfo.Manifests {
|
||||
obj, err := appv1.UnmarshalToUnstructured(manifest)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
targetObjs[i] = obj
|
||||
}
|
||||
|
||||
liveObjs, err := kube.GetLiveResources(config, targetObjs, namespace)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
diffResList, err := diff.DiffArray(targetObjs, liveObjs)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
var syncRes ApplicationSyncResult
|
||||
syncRes.Resources = make([]*ResourceDetails, 0)
|
||||
for i, diffRes := range diffResList.Diffs {
|
||||
resDetails := ResourceDetails{
|
||||
Name: targetObjs[i].GetName(),
|
||||
Kind: targetObjs[i].GetKind(),
|
||||
Namespace: namespace,
|
||||
}
|
||||
needsCreate := bool(liveObjs[i] == nil)
|
||||
if !diffRes.Modified {
|
||||
resDetails.Message = fmt.Sprintf("already synced")
|
||||
} else if dryRun {
|
||||
if needsCreate {
|
||||
resDetails.Message = fmt.Sprintf("will create")
|
||||
} else {
|
||||
resDetails.Message = fmt.Sprintf("will update")
|
||||
}
|
||||
} else {
|
||||
_, err := kube.ApplyResource(config, targetObjs[i], namespace)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if needsCreate {
|
||||
resDetails.Message = fmt.Sprintf("created")
|
||||
} else {
|
||||
resDetails.Message = fmt.Sprintf("updated")
|
||||
}
|
||||
}
|
||||
syncRes.Resources = append(syncRes.Resources, &resDetails)
|
||||
}
|
||||
syncRes.Message = "successfully synced"
|
||||
return &syncRes, manifestInfo, nil
|
||||
}
|
||||
|
||||
func (s *Server) Rollback(ctx context.Context, rollbackReq *ApplicationRollbackRequest) (*appv1.Application, error) {
|
||||
a, err := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Get(*rollbackReq.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !s.enf.EnforceClaims(ctx.Value("claims"), "applications", "rollback", appRBACName(*a)) {
|
||||
return nil, grpc.ErrPermissionDenied
|
||||
}
|
||||
return s.setAppOperation(ctx, *rollbackReq.Name, func(app *appv1.Application) (*appv1.Operation, error) {
|
||||
return &appv1.Operation{
|
||||
Rollback: &appv1.RollbackOperation{
|
||||
ID: rollbackReq.ID,
|
||||
Prune: rollbackReq.Prune,
|
||||
DryRun: rollbackReq.DryRun,
|
||||
},
|
||||
}, nil
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Server) setAppOperation(ctx context.Context, appName string, operationCreator func(app *appv1.Application) (*appv1.Operation, error)) (*appv1.Application, error) {
|
||||
for {
|
||||
a, err := s.Get(ctx, &ApplicationQuery{Name: &appName})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if a.Operation != nil {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "another operation is already in progress")
|
||||
}
|
||||
op, err := operationCreator(a)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
a.Operation = op
|
||||
a.Status.OperationState = nil
|
||||
_, err = s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Update(a)
|
||||
if err != nil && apierr.IsConflict(err) {
|
||||
log.Warnf("Failed to set operation for app '%s' due to update conflict. Retrying again...", appName)
|
||||
} else {
|
||||
return a, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -12,7 +12,6 @@ import (
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/grpc-ecosystem/grpc-gateway/runtime"
|
||||
"github.com/grpc-ecosystem/grpc-gateway/utilities"
|
||||
@@ -46,6 +45,41 @@ func request_ApplicationService_List_0(ctx context.Context, marshaler runtime.Ma
|
||||
|
||||
}
|
||||
|
||||
var (
|
||||
filter_ApplicationService_ListResourceEvents_0 = &utilities.DoubleArray{Encoding: map[string]int{"name": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}}
|
||||
)
|
||||
|
||||
func request_ApplicationService_ListResourceEvents_0(ctx context.Context, marshaler runtime.Marshaler, client ApplicationServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq ApplicationResourceEventsQuery
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
var (
|
||||
val string
|
||||
ok bool
|
||||
err error
|
||||
_ = err
|
||||
)
|
||||
|
||||
val, ok = pathParams["name"]
|
||||
if !ok {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "name")
|
||||
}
|
||||
|
||||
protoReq.Name, err = runtime.StringP(val)
|
||||
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err)
|
||||
}
|
||||
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_ApplicationService_ListResourceEvents_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := client.ListResourceEvents(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
var (
|
||||
filter_ApplicationService_Watch_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
|
||||
)
|
||||
@@ -71,11 +105,19 @@ func request_ApplicationService_Watch_0(ctx context.Context, marshaler runtime.M
|
||||
|
||||
}
|
||||
|
||||
var (
|
||||
filter_ApplicationService_Create_0 = &utilities.DoubleArray{Encoding: map[string]int{"application": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}}
|
||||
)
|
||||
|
||||
func request_ApplicationService_Create_0(ctx context.Context, marshaler runtime.Marshaler, client ApplicationServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq v1alpha1.Application
|
||||
var protoReq ApplicationCreateRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil {
|
||||
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq.Application); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_ApplicationService_Create_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
@@ -84,6 +126,10 @@ func request_ApplicationService_Create_0(ctx context.Context, marshaler runtime.
|
||||
|
||||
}
|
||||
|
||||
var (
|
||||
filter_ApplicationService_Get_0 = &utilities.DoubleArray{Encoding: map[string]int{"name": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}}
|
||||
)
|
||||
|
||||
func request_ApplicationService_Get_0(ctx context.Context, marshaler runtime.Marshaler, client ApplicationServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq ApplicationQuery
|
||||
var metadata runtime.ServerMetadata
|
||||
@@ -100,54 +146,27 @@ func request_ApplicationService_Get_0(ctx context.Context, marshaler runtime.Mar
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "name")
|
||||
}
|
||||
|
||||
protoReq.Name, err = runtime.String(val)
|
||||
protoReq.Name, err = runtime.StringP(val)
|
||||
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err)
|
||||
}
|
||||
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_ApplicationService_Get_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := client.Get(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func request_ApplicationService_Update_0(ctx context.Context, marshaler runtime.Marshaler, client ApplicationServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq v1alpha1.Application
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
var (
|
||||
val string
|
||||
ok bool
|
||||
err error
|
||||
_ = err
|
||||
)
|
||||
|
||||
val, ok = pathParams["metadata.name"]
|
||||
if !ok {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "metadata.name")
|
||||
}
|
||||
|
||||
protoReq.GetMetadata().Name, err = runtime.StringP(val)
|
||||
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "metadata.name", err)
|
||||
}
|
||||
|
||||
msg, err := client.Update(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
var (
|
||||
filter_ApplicationService_Delete_0 = &utilities.DoubleArray{Encoding: map[string]int{"name": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}}
|
||||
filter_ApplicationService_GetManifests_0 = &utilities.DoubleArray{Encoding: map[string]int{"name": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}}
|
||||
)
|
||||
|
||||
func request_ApplicationService_Delete_0(ctx context.Context, marshaler runtime.Marshaler, client ApplicationServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq DeleteApplicationRequest
|
||||
func request_ApplicationService_GetManifests_0(ctx context.Context, marshaler runtime.Marshaler, client ApplicationServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq ApplicationManifestQuery
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
var (
|
||||
@@ -162,7 +181,104 @@ func request_ApplicationService_Delete_0(ctx context.Context, marshaler runtime.
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "name")
|
||||
}
|
||||
|
||||
protoReq.Name, err = runtime.String(val)
|
||||
protoReq.Name, err = runtime.StringP(val)
|
||||
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err)
|
||||
}
|
||||
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_ApplicationService_GetManifests_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := client.GetManifests(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func request_ApplicationService_Update_0(ctx context.Context, marshaler runtime.Marshaler, client ApplicationServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq ApplicationUpdateRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq.Application); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
var (
|
||||
val string
|
||||
ok bool
|
||||
err error
|
||||
_ = err
|
||||
)
|
||||
|
||||
val, ok = pathParams["application.metadata.name"]
|
||||
if !ok {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "application.metadata.name")
|
||||
}
|
||||
|
||||
protoReq.GetApplication().GetMetadata().Name, err = runtime.StringP(val)
|
||||
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "application.metadata.name", err)
|
||||
}
|
||||
|
||||
msg, err := client.Update(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func request_ApplicationService_UpdateSpec_0(ctx context.Context, marshaler runtime.Marshaler, client ApplicationServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq ApplicationUpdateSpecRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq.Spec); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
var (
|
||||
val string
|
||||
ok bool
|
||||
err error
|
||||
_ = err
|
||||
)
|
||||
|
||||
val, ok = pathParams["name"]
|
||||
if !ok {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "name")
|
||||
}
|
||||
|
||||
protoReq.Name, err = runtime.StringP(val)
|
||||
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err)
|
||||
}
|
||||
|
||||
msg, err := client.UpdateSpec(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
var (
|
||||
filter_ApplicationService_Delete_0 = &utilities.DoubleArray{Encoding: map[string]int{"name": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}}
|
||||
)
|
||||
|
||||
func request_ApplicationService_Delete_0(ctx context.Context, marshaler runtime.Marshaler, client ApplicationServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq ApplicationDeleteRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
var (
|
||||
val string
|
||||
ok bool
|
||||
err error
|
||||
_ = err
|
||||
)
|
||||
|
||||
val, ok = pathParams["name"]
|
||||
if !ok {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "name")
|
||||
}
|
||||
|
||||
protoReq.Name, err = runtime.StringP(val)
|
||||
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err)
|
||||
@@ -177,33 +293,6 @@ func request_ApplicationService_Delete_0(ctx context.Context, marshaler runtime.
|
||||
|
||||
}
|
||||
|
||||
func request_ApplicationService_ListPods_0(ctx context.Context, marshaler runtime.Marshaler, client ApplicationServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq ApplicationQuery
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
var (
|
||||
val string
|
||||
ok bool
|
||||
err error
|
||||
_ = err
|
||||
)
|
||||
|
||||
val, ok = pathParams["name"]
|
||||
if !ok {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "name")
|
||||
}
|
||||
|
||||
protoReq.Name, err = runtime.String(val)
|
||||
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err)
|
||||
}
|
||||
|
||||
msg, err := client.ListPods(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func request_ApplicationService_Sync_0(ctx context.Context, marshaler runtime.Marshaler, client ApplicationServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq ApplicationSyncRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
@@ -224,7 +313,7 @@ func request_ApplicationService_Sync_0(ctx context.Context, marshaler runtime.Ma
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "name")
|
||||
}
|
||||
|
||||
protoReq.Name, err = runtime.String(val)
|
||||
protoReq.Name, err = runtime.StringP(val)
|
||||
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err)
|
||||
@@ -235,6 +324,129 @@ func request_ApplicationService_Sync_0(ctx context.Context, marshaler runtime.Ma
|
||||
|
||||
}
|
||||
|
||||
func request_ApplicationService_Rollback_0(ctx context.Context, marshaler runtime.Marshaler, client ApplicationServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq ApplicationRollbackRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
var (
|
||||
val string
|
||||
ok bool
|
||||
err error
|
||||
_ = err
|
||||
)
|
||||
|
||||
val, ok = pathParams["name"]
|
||||
if !ok {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "name")
|
||||
}
|
||||
|
||||
protoReq.Name, err = runtime.StringP(val)
|
||||
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err)
|
||||
}
|
||||
|
||||
msg, err := client.Rollback(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func request_ApplicationService_DeletePod_0(ctx context.Context, marshaler runtime.Marshaler, client ApplicationServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq ApplicationDeletePodRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
var (
|
||||
val string
|
||||
ok bool
|
||||
err error
|
||||
_ = err
|
||||
)
|
||||
|
||||
val, ok = pathParams["name"]
|
||||
if !ok {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "name")
|
||||
}
|
||||
|
||||
protoReq.Name, err = runtime.StringP(val)
|
||||
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err)
|
||||
}
|
||||
|
||||
val, ok = pathParams["podName"]
|
||||
if !ok {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "podName")
|
||||
}
|
||||
|
||||
protoReq.PodName, err = runtime.StringP(val)
|
||||
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "podName", err)
|
||||
}
|
||||
|
||||
msg, err := client.DeletePod(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
var (
|
||||
filter_ApplicationService_PodLogs_0 = &utilities.DoubleArray{Encoding: map[string]int{"name": 0, "podName": 1}, Base: []int{1, 1, 2, 0, 0}, Check: []int{0, 1, 1, 2, 3}}
|
||||
)
|
||||
|
||||
func request_ApplicationService_PodLogs_0(ctx context.Context, marshaler runtime.Marshaler, client ApplicationServiceClient, req *http.Request, pathParams map[string]string) (ApplicationService_PodLogsClient, runtime.ServerMetadata, error) {
|
||||
var protoReq ApplicationPodLogsQuery
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
var (
|
||||
val string
|
||||
ok bool
|
||||
err error
|
||||
_ = err
|
||||
)
|
||||
|
||||
val, ok = pathParams["name"]
|
||||
if !ok {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "name")
|
||||
}
|
||||
|
||||
protoReq.Name, err = runtime.StringP(val)
|
||||
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err)
|
||||
}
|
||||
|
||||
val, ok = pathParams["podName"]
|
||||
if !ok {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "podName")
|
||||
}
|
||||
|
||||
protoReq.PodName, err = runtime.StringP(val)
|
||||
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "podName", err)
|
||||
}
|
||||
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_ApplicationService_PodLogs_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
stream, err := client.PodLogs(ctx, &protoReq)
|
||||
if err != nil {
|
||||
return nil, metadata, err
|
||||
}
|
||||
header, err := stream.Header()
|
||||
if err != nil {
|
||||
return nil, metadata, err
|
||||
}
|
||||
metadata.HeaderMD = header
|
||||
return stream, metadata, nil
|
||||
|
||||
}
|
||||
|
||||
// RegisterApplicationServiceHandlerFromEndpoint is same as RegisterApplicationServiceHandler but
|
||||
// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
|
||||
func RegisterApplicationServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
|
||||
@@ -302,6 +514,35 @@ func RegisterApplicationServiceHandlerClient(ctx context.Context, mux *runtime.S
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_ApplicationService_ListResourceEvents_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
if cn, ok := w.(http.CloseNotifier); ok {
|
||||
go func(done <-chan struct{}, closed <-chan bool) {
|
||||
select {
|
||||
case <-done:
|
||||
case <-closed:
|
||||
cancel()
|
||||
}
|
||||
}(ctx.Done(), cn.CloseNotify())
|
||||
}
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_ApplicationService_ListResourceEvents_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_ApplicationService_ListResourceEvents_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_ApplicationService_Watch_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
@@ -389,6 +630,35 @@ func RegisterApplicationServiceHandlerClient(ctx context.Context, mux *runtime.S
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_ApplicationService_GetManifests_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
if cn, ok := w.(http.CloseNotifier); ok {
|
||||
go func(done <-chan struct{}, closed <-chan bool) {
|
||||
select {
|
||||
case <-done:
|
||||
case <-closed:
|
||||
cancel()
|
||||
}
|
||||
}(ctx.Done(), cn.CloseNotify())
|
||||
}
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_ApplicationService_GetManifests_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_ApplicationService_GetManifests_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("PUT", pattern_ApplicationService_Update_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
@@ -418,6 +688,35 @@ func RegisterApplicationServiceHandlerClient(ctx context.Context, mux *runtime.S
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("PUT", pattern_ApplicationService_UpdateSpec_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
if cn, ok := w.(http.CloseNotifier); ok {
|
||||
go func(done <-chan struct{}, closed <-chan bool) {
|
||||
select {
|
||||
case <-done:
|
||||
case <-closed:
|
||||
cancel()
|
||||
}
|
||||
}(ctx.Done(), cn.CloseNotify())
|
||||
}
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_ApplicationService_UpdateSpec_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_ApplicationService_UpdateSpec_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("DELETE", pattern_ApplicationService_Delete_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
@@ -447,35 +746,6 @@ func RegisterApplicationServiceHandlerClient(ctx context.Context, mux *runtime.S
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_ApplicationService_ListPods_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
if cn, ok := w.(http.CloseNotifier); ok {
|
||||
go func(done <-chan struct{}, closed <-chan bool) {
|
||||
select {
|
||||
case <-done:
|
||||
case <-closed:
|
||||
cancel()
|
||||
}
|
||||
}(ctx.Done(), cn.CloseNotify())
|
||||
}
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_ApplicationService_ListPods_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_ApplicationService_ListPods_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_ApplicationService_Sync_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
@@ -505,41 +775,148 @@ func RegisterApplicationServiceHandlerClient(ctx context.Context, mux *runtime.S
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_ApplicationService_Rollback_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
if cn, ok := w.(http.CloseNotifier); ok {
|
||||
go func(done <-chan struct{}, closed <-chan bool) {
|
||||
select {
|
||||
case <-done:
|
||||
case <-closed:
|
||||
cancel()
|
||||
}
|
||||
}(ctx.Done(), cn.CloseNotify())
|
||||
}
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_ApplicationService_Rollback_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_ApplicationService_Rollback_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("DELETE", pattern_ApplicationService_DeletePod_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
if cn, ok := w.(http.CloseNotifier); ok {
|
||||
go func(done <-chan struct{}, closed <-chan bool) {
|
||||
select {
|
||||
case <-done:
|
||||
case <-closed:
|
||||
cancel()
|
||||
}
|
||||
}(ctx.Done(), cn.CloseNotify())
|
||||
}
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_ApplicationService_DeletePod_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_ApplicationService_DeletePod_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_ApplicationService_PodLogs_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
if cn, ok := w.(http.CloseNotifier); ok {
|
||||
go func(done <-chan struct{}, closed <-chan bool) {
|
||||
select {
|
||||
case <-done:
|
||||
case <-closed:
|
||||
cancel()
|
||||
}
|
||||
}(ctx.Done(), cn.CloseNotify())
|
||||
}
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_ApplicationService_PodLogs_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_ApplicationService_PodLogs_0(ctx, mux, outboundMarshaler, w, req, func() (proto.Message, error) { return resp.Recv() }, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
pattern_ApplicationService_List_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "applications"}, ""))
|
||||
|
||||
pattern_ApplicationService_ListResourceEvents_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"api", "v1", "applications", "name", "events"}, ""))
|
||||
|
||||
pattern_ApplicationService_Watch_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"api", "v1", "stream", "applications"}, ""))
|
||||
|
||||
pattern_ApplicationService_Create_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "applications"}, ""))
|
||||
|
||||
pattern_ApplicationService_Get_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v1", "applications", "name"}, ""))
|
||||
|
||||
pattern_ApplicationService_Update_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v1", "applications", "metadata.name"}, ""))
|
||||
pattern_ApplicationService_GetManifests_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"api", "v1", "applications", "name", "manifests"}, ""))
|
||||
|
||||
pattern_ApplicationService_Update_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v1", "applications", "application.metadata.name"}, ""))
|
||||
|
||||
pattern_ApplicationService_UpdateSpec_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"api", "v1", "applications", "name", "spec"}, ""))
|
||||
|
||||
pattern_ApplicationService_Delete_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v1", "applications", "name"}, ""))
|
||||
|
||||
pattern_ApplicationService_ListPods_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"api", "v1", "applications", "name", "pods"}, ""))
|
||||
|
||||
pattern_ApplicationService_Sync_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"api", "v1", "applications", "name", "sync"}, ""))
|
||||
|
||||
pattern_ApplicationService_Rollback_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"api", "v1", "applications", "name", "rollback"}, ""))
|
||||
|
||||
pattern_ApplicationService_DeletePod_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"api", "v1", "applications", "name", "pods", "podName"}, ""))
|
||||
|
||||
pattern_ApplicationService_PodLogs_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4, 1, 0, 4, 1, 5, 5, 2, 6}, []string{"api", "v1", "applications", "name", "pods", "podName", "logs"}, ""))
|
||||
)
|
||||
|
||||
var (
|
||||
forward_ApplicationService_List_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_ApplicationService_ListResourceEvents_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_ApplicationService_Watch_0 = runtime.ForwardResponseStream
|
||||
|
||||
forward_ApplicationService_Create_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_ApplicationService_Get_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_ApplicationService_GetManifests_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_ApplicationService_Update_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_ApplicationService_UpdateSpec_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_ApplicationService_Delete_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_ApplicationService_ListPods_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_ApplicationService_Sync_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_ApplicationService_Rollback_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_ApplicationService_DeletePod_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_ApplicationService_PodLogs_0 = runtime.ForwardResponseStream
|
||||
)
|
||||
|
||||
@@ -1,48 +1,93 @@
|
||||
syntax = "proto3";
|
||||
syntax = "proto2";
|
||||
option go_package = "github.com/argoproj/argo-cd/server/application";
|
||||
|
||||
// Application Service
|
||||
//
|
||||
// Application Service API performs CRUD actions against application resources
|
||||
// Application Service API performs CRUD actions against application resources
|
||||
package application;
|
||||
|
||||
import "gogoproto/gogo.proto";
|
||||
import "google/api/annotations.proto";
|
||||
import "k8s.io/api/core/v1/generated.proto";
|
||||
import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto";
|
||||
import "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1/generated.proto";
|
||||
import "github.com/argoproj/argo-cd/reposerver/repository/repository.proto";
|
||||
|
||||
|
||||
// ApplicationQuery is a query for application resources
|
||||
message ApplicationQuery {
|
||||
string name = 1;
|
||||
optional string name = 1;
|
||||
optional bool refresh = 2 [(gogoproto.nullable) = false];
|
||||
}
|
||||
|
||||
// ApplicationEventsQuery is a query for application resource events
|
||||
message ApplicationResourceEventsQuery {
|
||||
required string name = 1;
|
||||
required string resourceName = 2 [(gogoproto.nullable) = false];
|
||||
required string resourceUID = 3 [(gogoproto.nullable) = false];
|
||||
}
|
||||
|
||||
// ManifestQuery is a query for manifest resources
|
||||
message ApplicationManifestQuery {
|
||||
required string name = 1;
|
||||
optional string revision = 2 [(gogoproto.nullable) = false];
|
||||
}
|
||||
|
||||
message ApplicationResponse {}
|
||||
|
||||
message DeleteApplicationRequest {
|
||||
string name = 1;
|
||||
string namespace = 2;
|
||||
string server = 3;
|
||||
message ApplicationCreateRequest {
|
||||
required github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.Application application = 1 [(gogoproto.nullable) = false];
|
||||
optional bool upsert = 2;
|
||||
}
|
||||
|
||||
message ApplicationUpdateRequest {
|
||||
required github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.Application application = 1;
|
||||
}
|
||||
|
||||
message ApplicationDeleteRequest {
|
||||
required string name = 1;
|
||||
optional bool cascade = 2;
|
||||
}
|
||||
|
||||
// ApplicationSyncRequest is a request to apply the config state to live state
|
||||
message ApplicationSyncRequest {
|
||||
string name = 1;
|
||||
string revision = 2;
|
||||
bool dryRun = 3;
|
||||
required string name = 1;
|
||||
required string revision = 2 [(gogoproto.nullable) = false];
|
||||
required bool dryRun = 3 [(gogoproto.nullable) = false];
|
||||
required bool prune = 4 [(gogoproto.nullable) = false];
|
||||
}
|
||||
|
||||
// ApplicationSyncResult is a result of a sync requeswt
|
||||
message ApplicationSyncResult {
|
||||
string message = 1;
|
||||
repeated ResourceDetails resources = 2;
|
||||
// ApplicationUpdateSpecRequest is a request to update application spec
|
||||
message ApplicationUpdateSpecRequest {
|
||||
required string name = 1;
|
||||
required github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.ApplicationSpec spec = 2 [(gogoproto.nullable) = false];
|
||||
}
|
||||
|
||||
message ResourceDetails {
|
||||
string name = 1;
|
||||
string kind = 2;
|
||||
string namespace = 3;
|
||||
string message = 4;
|
||||
message ApplicationRollbackRequest {
|
||||
required string name = 1;
|
||||
required int64 id = 2 [(gogoproto.customname) = "ID", (gogoproto.nullable) = false];
|
||||
required bool dryRun = 3 [(gogoproto.nullable) = false];
|
||||
required bool prune = 4 [(gogoproto.nullable) = false];
|
||||
}
|
||||
|
||||
message ApplicationDeletePodRequest {
|
||||
required string name = 1;
|
||||
required string podName = 2;
|
||||
}
|
||||
|
||||
message ApplicationPodLogsQuery {
|
||||
required string name = 1;
|
||||
required string podName = 2;
|
||||
required string container = 3 [(gogoproto.nullable) = false];
|
||||
required int64 sinceSeconds = 4 [(gogoproto.nullable) = false];
|
||||
optional k8s.io.apimachinery.pkg.apis.meta.v1.Time sinceTime = 5;
|
||||
required int64 tailLines = 6 [(gogoproto.nullable) = false];
|
||||
required bool follow = 7 [(gogoproto.nullable) = false];
|
||||
}
|
||||
|
||||
message LogEntry {
|
||||
required string content = 1 [(gogoproto.nullable) = false];
|
||||
required k8s.io.apimachinery.pkg.apis.meta.v1.Time timeStamp = 2 [(gogoproto.nullable) = false];
|
||||
}
|
||||
|
||||
// ApplicationService
|
||||
@@ -53,16 +98,21 @@ service ApplicationService {
|
||||
option (google.api.http).get = "/api/v1/applications";
|
||||
}
|
||||
|
||||
// ListResourceEvents returns a list of event resources
|
||||
rpc ListResourceEvents(ApplicationResourceEventsQuery) returns (k8s.io.api.core.v1.EventList) {
|
||||
option (google.api.http).get = "/api/v1/applications/{name}/events";
|
||||
}
|
||||
|
||||
// Watch returns stream of application change events.
|
||||
rpc Watch(ApplicationQuery) returns (stream github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.ApplicationWatchEvent) {
|
||||
option (google.api.http).get = "/api/v1/stream/applications";
|
||||
}
|
||||
|
||||
// Create creates an application
|
||||
rpc Create(github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.Application) returns (github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.Application) {
|
||||
rpc Create(ApplicationCreateRequest) returns (github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.Application) {
|
||||
option (google.api.http) = {
|
||||
post: "/api/v1/applications"
|
||||
body: "*"
|
||||
body: "application"
|
||||
};
|
||||
}
|
||||
|
||||
@@ -71,30 +121,55 @@ service ApplicationService {
|
||||
option (google.api.http).get = "/api/v1/applications/{name}";
|
||||
}
|
||||
|
||||
// GetManifests returns application manifests
|
||||
rpc GetManifests(ApplicationManifestQuery) returns (repository.ManifestResponse) {
|
||||
option (google.api.http).get = "/api/v1/applications/{name}/manifests";
|
||||
}
|
||||
|
||||
// Update updates an application
|
||||
rpc Update(github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.Application) returns (github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.Application) {
|
||||
rpc Update(ApplicationUpdateRequest) returns (github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.Application) {
|
||||
option (google.api.http) = {
|
||||
put: "/api/v1/applications/{metadata.name}"
|
||||
body: "*"
|
||||
put: "/api/v1/applications/{application.metadata.name}"
|
||||
body: "application"
|
||||
};
|
||||
}
|
||||
|
||||
// Update updates an application spec
|
||||
rpc UpdateSpec(ApplicationUpdateSpecRequest) returns (github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.ApplicationSpec) {
|
||||
option (google.api.http) = {
|
||||
put: "/api/v1/applications/{name}/spec"
|
||||
body: "spec"
|
||||
};
|
||||
}
|
||||
|
||||
// Delete deletes an application
|
||||
rpc Delete(DeleteApplicationRequest) returns (ApplicationResponse) {
|
||||
rpc Delete(ApplicationDeleteRequest) returns (ApplicationResponse) {
|
||||
option (google.api.http).delete = "/api/v1/applications/{name}";
|
||||
}
|
||||
|
||||
// ListPods returns pods in an application
|
||||
rpc ListPods(ApplicationQuery) returns (k8s.io.api.core.v1.PodList) {
|
||||
option (google.api.http).get = "/api/v1/applications/{name}/pods";
|
||||
}
|
||||
|
||||
// Sync syncs an application to its target state
|
||||
rpc Sync(ApplicationSyncRequest) returns (ApplicationSyncResult) {
|
||||
rpc Sync(ApplicationSyncRequest) returns (github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.Application) {
|
||||
option (google.api.http) = {
|
||||
post: "/api/v1/applications/{name}/sync"
|
||||
body: "*"
|
||||
};
|
||||
}
|
||||
|
||||
// Sync syncs an application to its target state
|
||||
rpc Rollback(ApplicationRollbackRequest) returns (github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.Application) {
|
||||
option (google.api.http) = {
|
||||
post: "/api/v1/applications/{name}/rollback"
|
||||
body: "*"
|
||||
};
|
||||
}
|
||||
|
||||
// PodLogs returns stream of log entries for the specified pod. Pod
|
||||
rpc DeletePod(ApplicationDeletePodRequest) returns (ApplicationResponse) {
|
||||
option (google.api.http).delete = "/api/v1/applications/{name}/pods/{podName}";
|
||||
}
|
||||
|
||||
// PodLogs returns stream of log entries for the specified pod. Pod
|
||||
rpc PodLogs(ApplicationPodLogsQuery) returns (stream LogEntry) {
|
||||
option (google.api.http).get = "/api/v1/applications/{name}/pods/{podName}/logs";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ var (
|
||||
)
|
||||
|
||||
func init() {
|
||||
forward_ApplicationService_Watch_0 = func(ctx context.Context, mux *runtime.ServeMux, marshaler runtime.Marshaler, w http.ResponseWriter, req *http.Request, recv func() (proto.Message, error), opts ...func(context.Context, http.ResponseWriter, proto.Message) error) {
|
||||
sseOverrider := func(ctx context.Context, mux *runtime.ServeMux, marshaler runtime.Marshaler, w http.ResponseWriter, req *http.Request, recv func() (proto.Message, error), opts ...func(context.Context, http.ResponseWriter, proto.Message) error) {
|
||||
if req.Header.Get("Accept") == "text/event-stream" {
|
||||
w.Header().Set("Content-Type", "text/event-stream")
|
||||
w.Header().Set("Transfer-Encoding", "chunked")
|
||||
@@ -55,4 +55,6 @@ func init() {
|
||||
runtime.ForwardResponseStream(ctx, mux, marshaler, w, req, recv, opts...)
|
||||
}
|
||||
}
|
||||
forward_ApplicationService_Watch_0 = sseOverrider
|
||||
forward_ApplicationService_PodLogs_0 = sseOverrider
|
||||
}
|
||||
|
||||
@@ -1,190 +1,87 @@
|
||||
package cluster
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"hash/fnv"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/argoproj/argo-cd/common"
|
||||
appv1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
|
||||
appclientset "github.com/argoproj/argo-cd/pkg/client/clientset/versioned"
|
||||
"github.com/argoproj/argo-cd/util/kube"
|
||||
"golang.org/x/net/context"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
apiv1 "k8s.io/api/core/v1"
|
||||
apierr "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/selection"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
|
||||
appv1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
|
||||
"github.com/argoproj/argo-cd/util/db"
|
||||
"github.com/argoproj/argo-cd/util/grpc"
|
||||
"github.com/argoproj/argo-cd/util/rbac"
|
||||
)
|
||||
|
||||
// Server provides a Cluster service
|
||||
type Server struct {
|
||||
ns string
|
||||
kubeclientset kubernetes.Interface
|
||||
appclientset appclientset.Interface
|
||||
db db.ArgoDB
|
||||
enf *rbac.Enforcer
|
||||
}
|
||||
|
||||
// NewServer returns a new instance of the Cluster service
|
||||
func NewServer(namespace string, kubeclientset kubernetes.Interface, appclientset appclientset.Interface) ClusterServiceServer {
|
||||
func NewServer(db db.ArgoDB, enf *rbac.Enforcer) *Server {
|
||||
return &Server{
|
||||
ns: namespace,
|
||||
appclientset: appclientset,
|
||||
kubeclientset: kubeclientset,
|
||||
db: db,
|
||||
enf: enf,
|
||||
}
|
||||
}
|
||||
|
||||
// ListPods returns application related pods in a cluster
|
||||
func (s *Server) ListPods(ctx context.Context, q *ClusterQuery) (*apiv1.PodList, error) {
|
||||
// TODO: filter by the app label
|
||||
return s.kubeclientset.CoreV1().Pods(s.ns).List(metav1.ListOptions{})
|
||||
}
|
||||
|
||||
// List returns list of clusters
|
||||
func (s *Server) List(ctx context.Context, q *ClusterQuery) (*appv1.ClusterList, error) {
|
||||
listOpts := metav1.ListOptions{}
|
||||
labelSelector := labels.NewSelector()
|
||||
req, err := labels.NewRequirement(common.LabelKeySecretType, selection.Equals, []string{common.SecretTypeCluster})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
clusterList, err := s.db.ListClusters(ctx)
|
||||
if clusterList != nil {
|
||||
newItems := make([]appv1.Cluster, 0)
|
||||
for _, clust := range clusterList.Items {
|
||||
if s.enf.EnforceClaims(ctx.Value("claims"), "clusters", "get", fmt.Sprintf("*/%s", clust.Server)) {
|
||||
newItems = append(newItems, *redact(&clust))
|
||||
}
|
||||
}
|
||||
clusterList.Items = newItems
|
||||
}
|
||||
labelSelector = labelSelector.Add(*req)
|
||||
listOpts.LabelSelector = labelSelector.String()
|
||||
clusterSecrets, err := s.kubeclientset.CoreV1().Secrets(s.ns).List(listOpts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
clusterList := appv1.ClusterList{
|
||||
Items: make([]appv1.Cluster, len(clusterSecrets.Items)),
|
||||
}
|
||||
for i, clusterSecret := range clusterSecrets.Items {
|
||||
clusterList.Items[i] = *secretToCluster(&clusterSecret)
|
||||
}
|
||||
return &clusterList, nil
|
||||
return clusterList, err
|
||||
}
|
||||
|
||||
// Create creates a cluster
|
||||
func (s *Server) Create(ctx context.Context, c *appv1.Cluster) (*appv1.Cluster, error) {
|
||||
err := kube.TestConfig(c.RESTConfig())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
func (s *Server) Create(ctx context.Context, q *ClusterCreateRequest) (*appv1.Cluster, error) {
|
||||
if !s.enf.EnforceClaims(ctx.Value("claims"), "clusters", "create", fmt.Sprintf("*/%s", q.Cluster.Server)) {
|
||||
return nil, grpc.ErrPermissionDenied
|
||||
}
|
||||
secName := serverToSecretName(c.Server)
|
||||
clusterSecret := &apiv1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: secName,
|
||||
Labels: map[string]string{
|
||||
common.LabelKeySecretType: common.SecretTypeCluster,
|
||||
},
|
||||
},
|
||||
}
|
||||
clusterSecret.StringData = clusterToStringData(c)
|
||||
clusterSecret, err = s.kubeclientset.CoreV1().Secrets(s.ns).Create(clusterSecret)
|
||||
if err != nil {
|
||||
if apierr.IsAlreadyExists(err) {
|
||||
return nil, grpc.Errorf(codes.AlreadyExists, "cluster '%s' already exists", c.Server)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return secretToCluster(clusterSecret), nil
|
||||
}
|
||||
|
||||
func (s *Server) getClusterSecret(server string) (*apiv1.Secret, error) {
|
||||
secName := serverToSecretName(server)
|
||||
clusterSecret, err := s.kubeclientset.CoreV1().Secrets(s.ns).Get(secName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
if apierr.IsNotFound(err) {
|
||||
return nil, grpc.Errorf(codes.NotFound, "cluster '%s' not found", server)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return clusterSecret, nil
|
||||
clust, err := s.db.CreateCluster(ctx, q.Cluster)
|
||||
return redact(clust), err
|
||||
}
|
||||
|
||||
// Get returns a cluster from a query
|
||||
func (s *Server) Get(ctx context.Context, q *ClusterQuery) (*appv1.Cluster, error) {
|
||||
clusterSecret, err := s.getClusterSecret(q.Server)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if !s.enf.EnforceClaims(ctx.Value("claims"), "clusters", "get", fmt.Sprintf("*/%s", q.Server)) {
|
||||
return nil, grpc.ErrPermissionDenied
|
||||
}
|
||||
return secretToCluster(clusterSecret), nil
|
||||
clust, err := s.db.GetCluster(ctx, q.Server)
|
||||
return redact(clust), err
|
||||
}
|
||||
|
||||
// Update updates a cluster
|
||||
func (s *Server) Update(ctx context.Context, c *appv1.Cluster) (*appv1.Cluster, error) {
|
||||
err := kube.TestConfig(c.RESTConfig())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
func (s *Server) Update(ctx context.Context, q *ClusterUpdateRequest) (*appv1.Cluster, error) {
|
||||
if !s.enf.EnforceClaims(ctx.Value("claims"), "clusters", "update", fmt.Sprintf("*/%s", q.Cluster.Server)) {
|
||||
return nil, grpc.ErrPermissionDenied
|
||||
}
|
||||
clusterSecret, err := s.getClusterSecret(c.Server)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
clusterSecret.StringData = clusterToStringData(c)
|
||||
clusterSecret, err = s.kubeclientset.CoreV1().Secrets(s.ns).Update(clusterSecret)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return secretToCluster(clusterSecret), nil
|
||||
}
|
||||
|
||||
// UpdateREST updates a cluster (special handler intended to be used only by the gRPC gateway)
|
||||
func (s *Server) UpdateREST(ctx context.Context, r *ClusterUpdateRequest) (*appv1.Cluster, error) {
|
||||
return s.Update(ctx, r.Cluster)
|
||||
clust, err := s.db.UpdateCluster(ctx, q.Cluster)
|
||||
return redact(clust), err
|
||||
}
|
||||
|
||||
// Delete deletes a cluster by name
|
||||
func (s *Server) Delete(ctx context.Context, q *ClusterQuery) (*ClusterResponse, error) {
|
||||
secName := serverToSecretName(q.Server)
|
||||
err := s.kubeclientset.CoreV1().Secrets(s.ns).Delete(secName, &metav1.DeleteOptions{})
|
||||
if !s.enf.EnforceClaims(ctx.Value("claims"), "clusters", "delete", fmt.Sprintf("*/%s", q.Server)) {
|
||||
return nil, grpc.ErrPermissionDenied
|
||||
}
|
||||
err := s.db.DeleteCluster(ctx, q.Server)
|
||||
return &ClusterResponse{}, err
|
||||
}
|
||||
|
||||
// serverToSecretName hashes server address to the secret name using a formula.
|
||||
// Part of the server address is incorporated for debugging purposes
|
||||
func serverToSecretName(server string) string {
|
||||
serverURL, err := url.ParseRequestURI(server)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
func redact(clust *appv1.Cluster) *appv1.Cluster {
|
||||
if clust == nil {
|
||||
return nil
|
||||
}
|
||||
h := fnv.New32a()
|
||||
_, _ = h.Write([]byte(server))
|
||||
host := strings.Split(serverURL.Host, ":")[0]
|
||||
return fmt.Sprintf("cluster-%s-%v", host, h.Sum32())
|
||||
}
|
||||
|
||||
// clusterToStringData converts a cluster object to string data for serialization to a secret
|
||||
func clusterToStringData(c *appv1.Cluster) map[string]string {
|
||||
stringData := make(map[string]string)
|
||||
stringData["server"] = c.Server
|
||||
if c.Name == "" {
|
||||
stringData["name"] = c.Server
|
||||
} else {
|
||||
stringData["name"] = c.Name
|
||||
}
|
||||
configBytes, err := json.Marshal(c.Config)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
stringData["config"] = string(configBytes)
|
||||
return stringData
|
||||
}
|
||||
|
||||
// secretToRepo converts a secret into a repository object
|
||||
func secretToCluster(s *apiv1.Secret) *appv1.Cluster {
|
||||
var config appv1.ClusterConfig
|
||||
err := json.Unmarshal(s.Data["config"], &config)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
cluster := appv1.Cluster{
|
||||
Server: string(s.Data["server"]),
|
||||
Name: string(s.Data["name"]),
|
||||
Config: config,
|
||||
}
|
||||
return &cluster
|
||||
clust.Config.Password = ""
|
||||
clust.Config.BearerToken = ""
|
||||
clust.Config.TLSClientConfig.KeyData = nil
|
||||
return clust
|
||||
}
|
||||
|
||||
@@ -1,35 +1,36 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// Code generated by protoc-gen-gogo. DO NOT EDIT.
|
||||
// source: server/cluster/cluster.proto
|
||||
|
||||
/*
|
||||
Package cluster is a generated protocol buffer package.
|
||||
Package cluster is a generated protocol buffer package.
|
||||
|
||||
Cluster Service
|
||||
Cluster Service
|
||||
|
||||
Cluster Service API performs CRUD actions against cluster resources
|
||||
Cluster Service API performs CRUD actions against cluster resources
|
||||
|
||||
It is generated from these files:
|
||||
server/cluster/cluster.proto
|
||||
It is generated from these files:
|
||||
server/cluster/cluster.proto
|
||||
|
||||
It has these top-level messages:
|
||||
ClusterQuery
|
||||
ClusterResponse
|
||||
ClusterUpdateRequest
|
||||
It has these top-level messages:
|
||||
ClusterQuery
|
||||
ClusterResponse
|
||||
ClusterCreateRequest
|
||||
ClusterUpdateRequest
|
||||
*/
|
||||
package cluster
|
||||
|
||||
import proto "github.com/golang/protobuf/proto"
|
||||
import proto "github.com/gogo/protobuf/proto"
|
||||
import fmt "fmt"
|
||||
import math "math"
|
||||
import _ "github.com/gogo/protobuf/gogoproto"
|
||||
import _ "google.golang.org/genproto/googleapis/api/annotations"
|
||||
import k8s_io_api_core_v1 "k8s.io/api/core/v1"
|
||||
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"
|
||||
grpc "google.golang.org/grpc"
|
||||
)
|
||||
import context "golang.org/x/net/context"
|
||||
import grpc "google.golang.org/grpc"
|
||||
|
||||
import io "io"
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
@@ -40,17 +41,17 @@ var _ = math.Inf
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
|
||||
const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package
|
||||
|
||||
// ClusterQuery is a query for cluster resources
|
||||
type ClusterQuery struct {
|
||||
Server string `protobuf:"bytes,1,opt,name=server" json:"server,omitempty"`
|
||||
Server string `protobuf:"bytes,1,opt,name=server,proto3" json:"server,omitempty"`
|
||||
}
|
||||
|
||||
func (m *ClusterQuery) Reset() { *m = ClusterQuery{} }
|
||||
func (m *ClusterQuery) String() string { return proto.CompactTextString(m) }
|
||||
func (*ClusterQuery) ProtoMessage() {}
|
||||
func (*ClusterQuery) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
|
||||
func (*ClusterQuery) Descriptor() ([]byte, []int) { return fileDescriptorCluster, []int{0} }
|
||||
|
||||
func (m *ClusterQuery) GetServer() string {
|
||||
if m != nil {
|
||||
@@ -65,24 +66,32 @@ type ClusterResponse struct {
|
||||
func (m *ClusterResponse) Reset() { *m = ClusterResponse{} }
|
||||
func (m *ClusterResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*ClusterResponse) ProtoMessage() {}
|
||||
func (*ClusterResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
|
||||
func (*ClusterResponse) Descriptor() ([]byte, []int) { return fileDescriptorCluster, []int{1} }
|
||||
|
||||
type ClusterCreateRequest struct {
|
||||
Cluster *github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Cluster `protobuf:"bytes,1,opt,name=cluster" json:"cluster,omitempty"`
|
||||
}
|
||||
|
||||
func (m *ClusterCreateRequest) Reset() { *m = ClusterCreateRequest{} }
|
||||
func (m *ClusterCreateRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*ClusterCreateRequest) ProtoMessage() {}
|
||||
func (*ClusterCreateRequest) Descriptor() ([]byte, []int) { return fileDescriptorCluster, []int{2} }
|
||||
|
||||
func (m *ClusterCreateRequest) GetCluster() *github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Cluster {
|
||||
if m != nil {
|
||||
return m.Cluster
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ClusterUpdateRequest struct {
|
||||
Server string `protobuf:"bytes,1,opt,name=server" json:"server,omitempty"`
|
||||
Cluster *github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Cluster `protobuf:"bytes,2,opt,name=cluster" json:"cluster,omitempty"`
|
||||
Cluster *github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Cluster `protobuf:"bytes,1,opt,name=cluster" json:"cluster,omitempty"`
|
||||
}
|
||||
|
||||
func (m *ClusterUpdateRequest) Reset() { *m = ClusterUpdateRequest{} }
|
||||
func (m *ClusterUpdateRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*ClusterUpdateRequest) ProtoMessage() {}
|
||||
func (*ClusterUpdateRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
|
||||
|
||||
func (m *ClusterUpdateRequest) GetServer() string {
|
||||
if m != nil {
|
||||
return m.Server
|
||||
}
|
||||
return ""
|
||||
}
|
||||
func (*ClusterUpdateRequest) Descriptor() ([]byte, []int) { return fileDescriptorCluster, []int{3} }
|
||||
|
||||
func (m *ClusterUpdateRequest) GetCluster() *github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Cluster {
|
||||
if m != nil {
|
||||
@@ -94,6 +103,7 @@ func (m *ClusterUpdateRequest) GetCluster() *github_com_argoproj_argo_cd_pkg_api
|
||||
func init() {
|
||||
proto.RegisterType((*ClusterQuery)(nil), "cluster.ClusterQuery")
|
||||
proto.RegisterType((*ClusterResponse)(nil), "cluster.ClusterResponse")
|
||||
proto.RegisterType((*ClusterCreateRequest)(nil), "cluster.ClusterCreateRequest")
|
||||
proto.RegisterType((*ClusterUpdateRequest)(nil), "cluster.ClusterUpdateRequest")
|
||||
}
|
||||
|
||||
@@ -111,17 +121,13 @@ type ClusterServiceClient interface {
|
||||
// List returns list of clusters
|
||||
List(ctx context.Context, in *ClusterQuery, opts ...grpc.CallOption) (*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.ClusterList, error)
|
||||
// Create creates a cluster
|
||||
Create(ctx context.Context, in *github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Cluster, opts ...grpc.CallOption) (*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Cluster, error)
|
||||
Create(ctx context.Context, in *ClusterCreateRequest, opts ...grpc.CallOption) (*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Cluster, error)
|
||||
// Get returns a cluster by server address
|
||||
Get(ctx context.Context, in *ClusterQuery, opts ...grpc.CallOption) (*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Cluster, error)
|
||||
// Update updates a cluster
|
||||
Update(ctx context.Context, in *github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Cluster, opts ...grpc.CallOption) (*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Cluster, error)
|
||||
// Update updates a cluster (special handler intended to be used only by the gRPC gateway)
|
||||
UpdateREST(ctx context.Context, in *ClusterUpdateRequest, opts ...grpc.CallOption) (*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Cluster, error)
|
||||
Update(ctx context.Context, in *ClusterUpdateRequest, opts ...grpc.CallOption) (*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Cluster, error)
|
||||
// Delete updates a cluster
|
||||
Delete(ctx context.Context, in *ClusterQuery, opts ...grpc.CallOption) (*ClusterResponse, error)
|
||||
// ListPods returns pods in a cluster
|
||||
ListPods(ctx context.Context, in *ClusterQuery, opts ...grpc.CallOption) (*k8s_io_api_core_v1.PodList, error)
|
||||
}
|
||||
|
||||
type clusterServiceClient struct {
|
||||
@@ -141,7 +147,7 @@ func (c *clusterServiceClient) List(ctx context.Context, in *ClusterQuery, opts
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *clusterServiceClient) Create(ctx context.Context, in *github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Cluster, opts ...grpc.CallOption) (*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Cluster, error) {
|
||||
func (c *clusterServiceClient) Create(ctx context.Context, in *ClusterCreateRequest, opts ...grpc.CallOption) (*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Cluster, error) {
|
||||
out := new(github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Cluster)
|
||||
err := grpc.Invoke(ctx, "/cluster.ClusterService/Create", in, out, c.cc, opts...)
|
||||
if err != nil {
|
||||
@@ -159,7 +165,7 @@ func (c *clusterServiceClient) Get(ctx context.Context, in *ClusterQuery, opts .
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *clusterServiceClient) Update(ctx context.Context, in *github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Cluster, opts ...grpc.CallOption) (*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Cluster, error) {
|
||||
func (c *clusterServiceClient) Update(ctx context.Context, in *ClusterUpdateRequest, opts ...grpc.CallOption) (*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Cluster, error) {
|
||||
out := new(github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Cluster)
|
||||
err := grpc.Invoke(ctx, "/cluster.ClusterService/Update", in, out, c.cc, opts...)
|
||||
if err != nil {
|
||||
@@ -168,15 +174,6 @@ func (c *clusterServiceClient) Update(ctx context.Context, in *github_com_argopr
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *clusterServiceClient) UpdateREST(ctx context.Context, in *ClusterUpdateRequest, opts ...grpc.CallOption) (*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Cluster, error) {
|
||||
out := new(github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Cluster)
|
||||
err := grpc.Invoke(ctx, "/cluster.ClusterService/UpdateREST", in, out, c.cc, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *clusterServiceClient) Delete(ctx context.Context, in *ClusterQuery, opts ...grpc.CallOption) (*ClusterResponse, error) {
|
||||
out := new(ClusterResponse)
|
||||
err := grpc.Invoke(ctx, "/cluster.ClusterService/Delete", in, out, c.cc, opts...)
|
||||
@@ -186,32 +183,19 @@ func (c *clusterServiceClient) Delete(ctx context.Context, in *ClusterQuery, opt
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *clusterServiceClient) ListPods(ctx context.Context, in *ClusterQuery, opts ...grpc.CallOption) (*k8s_io_api_core_v1.PodList, error) {
|
||||
out := new(k8s_io_api_core_v1.PodList)
|
||||
err := grpc.Invoke(ctx, "/cluster.ClusterService/ListPods", in, out, c.cc, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// Server API for ClusterService service
|
||||
|
||||
type ClusterServiceServer interface {
|
||||
// List returns list of clusters
|
||||
List(context.Context, *ClusterQuery) (*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.ClusterList, error)
|
||||
// Create creates a cluster
|
||||
Create(context.Context, *github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Cluster) (*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Cluster, error)
|
||||
Create(context.Context, *ClusterCreateRequest) (*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Cluster, error)
|
||||
// Get returns a cluster by server address
|
||||
Get(context.Context, *ClusterQuery) (*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Cluster, error)
|
||||
// Update updates a cluster
|
||||
Update(context.Context, *github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Cluster) (*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Cluster, error)
|
||||
// Update updates a cluster (special handler intended to be used only by the gRPC gateway)
|
||||
UpdateREST(context.Context, *ClusterUpdateRequest) (*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Cluster, error)
|
||||
Update(context.Context, *ClusterUpdateRequest) (*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Cluster, error)
|
||||
// Delete updates a cluster
|
||||
Delete(context.Context, *ClusterQuery) (*ClusterResponse, error)
|
||||
// ListPods returns pods in a cluster
|
||||
ListPods(context.Context, *ClusterQuery) (*k8s_io_api_core_v1.PodList, error)
|
||||
}
|
||||
|
||||
func RegisterClusterServiceServer(s *grpc.Server, srv ClusterServiceServer) {
|
||||
@@ -237,7 +221,7 @@ func _ClusterService_List_Handler(srv interface{}, ctx context.Context, dec func
|
||||
}
|
||||
|
||||
func _ClusterService_Create_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Cluster)
|
||||
in := new(ClusterCreateRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -249,7 +233,7 @@ func _ClusterService_Create_Handler(srv interface{}, ctx context.Context, dec fu
|
||||
FullMethod: "/cluster.ClusterService/Create",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ClusterServiceServer).Create(ctx, req.(*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Cluster))
|
||||
return srv.(ClusterServiceServer).Create(ctx, req.(*ClusterCreateRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
@@ -273,7 +257,7 @@ func _ClusterService_Get_Handler(srv interface{}, ctx context.Context, dec func(
|
||||
}
|
||||
|
||||
func _ClusterService_Update_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Cluster)
|
||||
in := new(ClusterUpdateRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -285,25 +269,7 @@ func _ClusterService_Update_Handler(srv interface{}, ctx context.Context, dec fu
|
||||
FullMethod: "/cluster.ClusterService/Update",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ClusterServiceServer).Update(ctx, req.(*github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Cluster))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _ClusterService_UpdateREST_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ClusterUpdateRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ClusterServiceServer).UpdateREST(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/cluster.ClusterService/UpdateREST",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ClusterServiceServer).UpdateREST(ctx, req.(*ClusterUpdateRequest))
|
||||
return srv.(ClusterServiceServer).Update(ctx, req.(*ClusterUpdateRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
@@ -326,24 +292,6 @@ func _ClusterService_Delete_Handler(srv interface{}, ctx context.Context, dec fu
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _ClusterService_ListPods_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ClusterQuery)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ClusterServiceServer).ListPods(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/cluster.ClusterService/ListPods",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ClusterServiceServer).ListPods(ctx, req.(*ClusterQuery))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
var _ClusterService_serviceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "cluster.ClusterService",
|
||||
HandlerType: (*ClusterServiceServer)(nil),
|
||||
@@ -364,56 +312,602 @@ var _ClusterService_serviceDesc = grpc.ServiceDesc{
|
||||
MethodName: "Update",
|
||||
Handler: _ClusterService_Update_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "UpdateREST",
|
||||
Handler: _ClusterService_UpdateREST_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "Delete",
|
||||
Handler: _ClusterService_Delete_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "ListPods",
|
||||
Handler: _ClusterService_ListPods_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "server/cluster/cluster.proto",
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("server/cluster/cluster.proto", fileDescriptor0) }
|
||||
|
||||
var fileDescriptor0 = []byte{
|
||||
// 496 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x54, 0xcd, 0x6e, 0xd4, 0x30,
|
||||
0x10, 0xc6, 0x05, 0xa5, 0x60, 0x10, 0x3f, 0xa3, 0x16, 0x2d, 0xd9, 0x82, 0x96, 0x08, 0x55, 0xd5,
|
||||
0x0a, 0x6c, 0x6d, 0xb9, 0xa0, 0x1e, 0x5b, 0x7e, 0x84, 0xc4, 0xa1, 0x6c, 0xe1, 0x82, 0x2a, 0x21,
|
||||
0x37, 0x19, 0xd2, 0xb0, 0x21, 0x36, 0xb6, 0x37, 0x12, 0x42, 0x08, 0x09, 0xae, 0x9c, 0xe0, 0xc8,
|
||||
0x33, 0xf0, 0x0e, 0xbc, 0x03, 0xaf, 0xc0, 0x83, 0xa0, 0x38, 0x36, 0x6d, 0xb7, 0x4a, 0x2f, 0xec,
|
||||
0x81, 0x53, 0xec, 0xb1, 0xf3, 0x7d, 0xf3, 0xcd, 0x7c, 0x1e, 0xba, 0x62, 0x50, 0xd7, 0xa8, 0x79,
|
||||
0x5a, 0x4e, 0x8d, 0x3d, 0xf8, 0x32, 0xa5, 0xa5, 0x95, 0xb0, 0xe8, 0xb7, 0xf1, 0x52, 0x2e, 0x73,
|
||||
0xe9, 0x62, 0xbc, 0x59, 0xb5, 0xc7, 0xf1, 0x4a, 0x2e, 0x65, 0x5e, 0x22, 0x17, 0xaa, 0xe0, 0xa2,
|
||||
0xaa, 0xa4, 0x15, 0xb6, 0x90, 0x95, 0xf1, 0xa7, 0xc9, 0xe4, 0x9e, 0x61, 0x85, 0x74, 0xa7, 0xa9,
|
||||
0xd4, 0xc8, 0xeb, 0x11, 0xcf, 0xb1, 0x42, 0x2d, 0x2c, 0x66, 0xfe, 0xce, 0xe3, 0xbc, 0xb0, 0xfb,
|
||||
0xd3, 0x3d, 0x96, 0xca, 0x37, 0x5c, 0x68, 0x47, 0xf1, 0xda, 0x2d, 0xee, 0xa4, 0x19, 0x57, 0x93,
|
||||
0xbc, 0xf9, 0xd9, 0x70, 0xa1, 0x54, 0x59, 0xa4, 0x0e, 0x9c, 0xd7, 0x23, 0x51, 0xaa, 0x7d, 0x71,
|
||||
0x0c, 0x2a, 0x59, 0xa5, 0x17, 0xb6, 0xda, 0x6c, 0x9f, 0x4e, 0x51, 0xbf, 0x83, 0xab, 0x34, 0x6a,
|
||||
0xb5, 0xf5, 0xc8, 0x80, 0xac, 0x9d, 0x1b, 0xfb, 0x5d, 0x72, 0x85, 0x5e, 0xf2, 0xf7, 0xc6, 0x68,
|
||||
0x94, 0xac, 0x0c, 0x26, 0x5f, 0x08, 0x5d, 0xf2, 0xb1, 0xe7, 0x2a, 0x13, 0x16, 0xc7, 0xf8, 0x76,
|
||||
0x8a, 0xc6, 0x76, 0x61, 0xc0, 0x2e, 0x0d, 0x95, 0xe9, 0x2d, 0x0c, 0xc8, 0xda, 0xf9, 0xf5, 0x4d,
|
||||
0x76, 0x20, 0x84, 0x05, 0x21, 0x6e, 0xf1, 0x32, 0xcd, 0x98, 0x9a, 0xe4, 0xac, 0x11, 0xc2, 0x0e,
|
||||
0x09, 0x61, 0x41, 0x08, 0x0b, 0xd9, 0x04, 0xc8, 0xf5, 0x9f, 0x8b, 0xf4, 0xa2, 0x0f, 0xee, 0xa0,
|
||||
0xae, 0x8b, 0x14, 0xe1, 0x23, 0x3d, 0xf3, 0xa4, 0x30, 0x16, 0x96, 0x59, 0x68, 0xd0, 0x61, 0xad,
|
||||
0xf1, 0xc3, 0x7f, 0xa7, 0x6f, 0xe0, 0x93, 0xde, 0xa7, 0x5f, 0xbf, 0xbf, 0x2d, 0x00, 0x5c, 0x76,
|
||||
0x4d, 0xab, 0x47, 0xc1, 0x0e, 0x06, 0x7e, 0x10, 0x1a, 0x6d, 0x69, 0x14, 0x16, 0x61, 0x0e, 0x5a,
|
||||
0xe3, 0x39, 0x60, 0x24, 0x7d, 0x97, 0xec, 0x72, 0x72, 0x2c, 0xd9, 0x0d, 0x32, 0x84, 0xcf, 0x84,
|
||||
0x9e, 0x7e, 0x84, 0x9d, 0x05, 0x9b, 0x07, 0xff, 0x4d, 0xc7, 0xdf, 0x87, 0x6b, 0xb3, 0xfc, 0xfc,
|
||||
0x7d, 0x6b, 0x93, 0x0f, 0xf0, 0x95, 0xd0, 0xa8, 0x75, 0xd4, 0x7f, 0x53, 0xb5, 0x53, 0xf0, 0x9d,
|
||||
0x50, 0xea, 0x6d, 0xfe, 0x60, 0xe7, 0x19, 0x5c, 0x9f, 0xad, 0xd0, 0x91, 0x27, 0x30, 0x17, 0xce,
|
||||
0xa1, 0xab, 0xd4, 0xad, 0xb8, 0xbb, 0x52, 0x1b, 0xc1, 0xfc, 0xb0, 0x4b, 0xa3, 0xfb, 0x58, 0xa2,
|
||||
0xc5, 0xae, 0xd6, 0xf5, 0x66, 0xc3, 0x7f, 0x9f, 0xb1, 0x6f, 0xc8, 0xf0, 0x84, 0x86, 0xbc, 0xa2,
|
||||
0x67, 0x1b, 0xa3, 0x6f, 0xcb, 0xcc, 0x74, 0xe1, 0xf7, 0x59, 0x3b, 0xb7, 0x1a, 0x5d, 0xac, 0x99,
|
||||
0x5b, 0xac, 0x1e, 0xb1, 0x6d, 0x99, 0xb9, 0x07, 0xb2, 0xea, 0x28, 0x06, 0x70, 0xa3, 0x93, 0x82,
|
||||
0x2b, 0x99, 0x99, 0xcd, 0xdb, 0x2f, 0x86, 0x27, 0x4d, 0xb6, 0xa3, 0x43, 0x77, 0x2f, 0x72, 0x13,
|
||||
0xec, 0xee, 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x3b, 0x95, 0xa3, 0x36, 0x8d, 0x05, 0x00, 0x00,
|
||||
func (m *ClusterQuery) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalTo(dAtA)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *ClusterQuery) MarshalTo(dAtA []byte) (int, error) {
|
||||
var i int
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if len(m.Server) > 0 {
|
||||
dAtA[i] = 0xa
|
||||
i++
|
||||
i = encodeVarintCluster(dAtA, i, uint64(len(m.Server)))
|
||||
i += copy(dAtA[i:], m.Server)
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
|
||||
func (m *ClusterResponse) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalTo(dAtA)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *ClusterResponse) MarshalTo(dAtA []byte) (int, error) {
|
||||
var i int
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
return i, nil
|
||||
}
|
||||
|
||||
func (m *ClusterCreateRequest) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalTo(dAtA)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *ClusterCreateRequest) MarshalTo(dAtA []byte) (int, error) {
|
||||
var i int
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if m.Cluster != nil {
|
||||
dAtA[i] = 0xa
|
||||
i++
|
||||
i = encodeVarintCluster(dAtA, i, uint64(m.Cluster.Size()))
|
||||
n1, err := m.Cluster.MarshalTo(dAtA[i:])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
i += n1
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
|
||||
func (m *ClusterUpdateRequest) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalTo(dAtA)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *ClusterUpdateRequest) MarshalTo(dAtA []byte) (int, error) {
|
||||
var i int
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if m.Cluster != nil {
|
||||
dAtA[i] = 0xa
|
||||
i++
|
||||
i = encodeVarintCluster(dAtA, i, uint64(m.Cluster.Size()))
|
||||
n2, err := m.Cluster.MarshalTo(dAtA[i:])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
i += n2
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
|
||||
func encodeVarintCluster(dAtA []byte, offset int, v uint64) int {
|
||||
for v >= 1<<7 {
|
||||
dAtA[offset] = uint8(v&0x7f | 0x80)
|
||||
v >>= 7
|
||||
offset++
|
||||
}
|
||||
dAtA[offset] = uint8(v)
|
||||
return offset + 1
|
||||
}
|
||||
func (m *ClusterQuery) Size() (n int) {
|
||||
var l int
|
||||
_ = l
|
||||
l = len(m.Server)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovCluster(uint64(l))
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *ClusterResponse) Size() (n int) {
|
||||
var l int
|
||||
_ = l
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *ClusterCreateRequest) Size() (n int) {
|
||||
var l int
|
||||
_ = l
|
||||
if m.Cluster != nil {
|
||||
l = m.Cluster.Size()
|
||||
n += 1 + l + sovCluster(uint64(l))
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *ClusterUpdateRequest) Size() (n int) {
|
||||
var l int
|
||||
_ = l
|
||||
if m.Cluster != nil {
|
||||
l = m.Cluster.Size()
|
||||
n += 1 + l + sovCluster(uint64(l))
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func sovCluster(x uint64) (n int) {
|
||||
for {
|
||||
n++
|
||||
x >>= 7
|
||||
if x == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return n
|
||||
}
|
||||
func sozCluster(x uint64) (n int) {
|
||||
return sovCluster(uint64((x << 1) ^ uint64((int64(x) >> 63))))
|
||||
}
|
||||
func (m *ClusterQuery) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowCluster
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: ClusterQuery: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: ClusterQuery: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Server", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowCluster
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthCluster
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Server = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipCluster(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if skippy < 0 {
|
||||
return ErrInvalidLengthCluster
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *ClusterResponse) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowCluster
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: ClusterResponse: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: ClusterResponse: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipCluster(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if skippy < 0 {
|
||||
return ErrInvalidLengthCluster
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *ClusterCreateRequest) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowCluster
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: ClusterCreateRequest: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: ClusterCreateRequest: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Cluster", wireType)
|
||||
}
|
||||
var msglen int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowCluster
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
msglen |= (int(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if msglen < 0 {
|
||||
return ErrInvalidLengthCluster
|
||||
}
|
||||
postIndex := iNdEx + msglen
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
if m.Cluster == nil {
|
||||
m.Cluster = &github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Cluster{}
|
||||
}
|
||||
if err := m.Cluster.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
|
||||
return err
|
||||
}
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipCluster(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if skippy < 0 {
|
||||
return ErrInvalidLengthCluster
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *ClusterUpdateRequest) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowCluster
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: ClusterUpdateRequest: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: ClusterUpdateRequest: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Cluster", wireType)
|
||||
}
|
||||
var msglen int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowCluster
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
msglen |= (int(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if msglen < 0 {
|
||||
return ErrInvalidLengthCluster
|
||||
}
|
||||
postIndex := iNdEx + msglen
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
if m.Cluster == nil {
|
||||
m.Cluster = &github_com_argoproj_argo_cd_pkg_apis_application_v1alpha1.Cluster{}
|
||||
}
|
||||
if err := m.Cluster.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
|
||||
return err
|
||||
}
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipCluster(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if skippy < 0 {
|
||||
return ErrInvalidLengthCluster
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func skipCluster(dAtA []byte) (n int, err error) {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowCluster
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
wireType := int(wire & 0x7)
|
||||
switch wireType {
|
||||
case 0:
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowCluster
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx++
|
||||
if dAtA[iNdEx-1] < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return iNdEx, nil
|
||||
case 1:
|
||||
iNdEx += 8
|
||||
return iNdEx, nil
|
||||
case 2:
|
||||
var length int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowCluster
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
length |= (int(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
iNdEx += length
|
||||
if length < 0 {
|
||||
return 0, ErrInvalidLengthCluster
|
||||
}
|
||||
return iNdEx, nil
|
||||
case 3:
|
||||
for {
|
||||
var innerWire uint64
|
||||
var start int = iNdEx
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowCluster
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
innerWire |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
innerWireType := int(innerWire & 0x7)
|
||||
if innerWireType == 4 {
|
||||
break
|
||||
}
|
||||
next, err := skipCluster(dAtA[start:])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
iNdEx = start + next
|
||||
}
|
||||
return iNdEx, nil
|
||||
case 4:
|
||||
return iNdEx, nil
|
||||
case 5:
|
||||
iNdEx += 4
|
||||
return iNdEx, nil
|
||||
default:
|
||||
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
|
||||
}
|
||||
}
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
var (
|
||||
ErrInvalidLengthCluster = fmt.Errorf("proto: negative length found during unmarshaling")
|
||||
ErrIntOverflowCluster = fmt.Errorf("proto: integer overflow")
|
||||
)
|
||||
|
||||
func init() { proto.RegisterFile("server/cluster/cluster.proto", fileDescriptorCluster) }
|
||||
|
||||
var fileDescriptorCluster = []byte{
|
||||
// 454 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x94, 0xcd, 0xaa, 0x13, 0x31,
|
||||
0x14, 0xc7, 0x89, 0x1f, 0x23, 0x46, 0xf1, 0x23, 0x5c, 0xa5, 0x8e, 0xd7, 0xe2, 0x9d, 0x85, 0xc8,
|
||||
0x45, 0x13, 0x5a, 0x37, 0x17, 0x97, 0xf7, 0x8a, 0x22, 0xb8, 0xb1, 0xe2, 0x46, 0x0a, 0x92, 0xce,
|
||||
0x1c, 0xd2, 0xb1, 0xe3, 0x24, 0x26, 0x99, 0x01, 0x11, 0x11, 0x74, 0xef, 0xc6, 0x07, 0x70, 0xeb,
|
||||
0xa3, 0xb8, 0x14, 0x7c, 0x01, 0x29, 0x3e, 0x88, 0x4c, 0x26, 0xb1, 0x1f, 0x43, 0xdd, 0x58, 0xee,
|
||||
0xaa, 0xc9, 0x49, 0x7a, 0xfe, 0xbf, 0xf3, 0xcf, 0x99, 0x83, 0x77, 0x0d, 0xe8, 0x1a, 0x34, 0x4b,
|
||||
0x8b, 0xca, 0xd8, 0xc5, 0x2f, 0x55, 0x5a, 0x5a, 0x49, 0xce, 0xf8, 0x6d, 0xbc, 0x23, 0xa4, 0x90,
|
||||
0x2e, 0xc6, 0x9a, 0x55, 0x7b, 0x1c, 0xef, 0x0a, 0x29, 0x45, 0x01, 0x8c, 0xab, 0x9c, 0xf1, 0xb2,
|
||||
0x94, 0x96, 0xdb, 0x5c, 0x96, 0xc6, 0x9f, 0x26, 0xb3, 0x03, 0x43, 0x73, 0xe9, 0x4e, 0x53, 0xa9,
|
||||
0x81, 0xd5, 0x03, 0x26, 0xa0, 0x04, 0xcd, 0x2d, 0x64, 0xfe, 0xce, 0x63, 0x91, 0xdb, 0x69, 0x35,
|
||||
0xa1, 0xa9, 0x7c, 0xcd, 0xb8, 0x76, 0x12, 0xaf, 0xdc, 0xe2, 0x6e, 0x9a, 0x31, 0x35, 0x13, 0xcd,
|
||||
0x9f, 0x0d, 0xe3, 0x4a, 0x15, 0x79, 0xea, 0x92, 0xb3, 0x7a, 0xc0, 0x0b, 0x35, 0xe5, 0x9d, 0x54,
|
||||
0xc9, 0x2d, 0x7c, 0xfe, 0xa8, 0xa5, 0x7d, 0x5a, 0x81, 0x7e, 0x4b, 0xae, 0xe2, 0xa8, 0xad, 0xad,
|
||||
0x87, 0x6e, 0xa2, 0xdb, 0x67, 0x47, 0x7e, 0x97, 0x5c, 0xc6, 0x17, 0xfd, 0xbd, 0x11, 0x18, 0x25,
|
||||
0x4b, 0x03, 0x89, 0xc5, 0x3b, 0x3e, 0x74, 0xa4, 0x81, 0x5b, 0x18, 0xc1, 0x9b, 0x0a, 0x8c, 0x25,
|
||||
0x63, 0x1c, 0x0c, 0x70, 0x39, 0xce, 0x0d, 0x0f, 0xe9, 0x82, 0x97, 0x06, 0x5e, 0xb7, 0x78, 0x99,
|
||||
0x66, 0x54, 0xcd, 0x04, 0x6d, 0x78, 0xe9, 0x12, 0x2f, 0x0d, 0xbc, 0x34, 0x88, 0x86, 0x94, 0x4b,
|
||||
0xaa, 0xcf, 0x55, 0x76, 0x5c, 0xaa, 0xc3, 0x6f, 0xa7, 0xf1, 0x05, 0x1f, 0x7c, 0x06, 0xba, 0xce,
|
||||
0x53, 0x20, 0x1f, 0xf0, 0xa9, 0x27, 0xb9, 0xb1, 0xe4, 0x0a, 0x0d, 0xaf, 0xbf, 0x6c, 0x64, 0xfc,
|
||||
0xf0, 0xff, 0xe5, 0x9b, 0xf4, 0x49, 0xef, 0xe3, 0xcf, 0xdf, 0x5f, 0x4e, 0x10, 0x72, 0xc9, 0x75,
|
||||
0x44, 0x3d, 0x08, 0xbd, 0x66, 0xc8, 0x67, 0x84, 0xa3, 0xd6, 0x79, 0x72, 0x63, 0x9d, 0x61, 0xe5,
|
||||
0x45, 0xe2, 0x2d, 0x58, 0x91, 0xec, 0x39, 0x8e, 0xeb, 0x49, 0x87, 0xe3, 0x7e, 0x30, 0x89, 0x7c,
|
||||
0x42, 0xf8, 0xe4, 0x23, 0xd8, 0xe8, 0xc8, 0x16, 0x29, 0xc8, 0xb5, 0x75, 0x0a, 0xf6, 0xae, 0x6d,
|
||||
0xd4, 0xf7, 0xe4, 0x2b, 0xc2, 0x51, 0xdb, 0x1a, 0x5d, 0x5b, 0x56, 0x5a, 0x66, 0x2b, 0x40, 0x43,
|
||||
0x07, 0x74, 0x27, 0xde, 0xeb, 0x02, 0x05, 0x6d, 0x0f, 0xb6, 0xf0, 0x69, 0x8c, 0xa3, 0x07, 0x50,
|
||||
0x80, 0x85, 0x4d, 0x4e, 0xf5, 0xd6, 0xc3, 0x7f, 0xbf, 0x39, 0x5f, 0xff, 0xfe, 0xe6, 0xfa, 0x0f,
|
||||
0x0f, 0xbe, 0xcf, 0xfb, 0xe8, 0xc7, 0xbc, 0x8f, 0x7e, 0xcd, 0xfb, 0xe8, 0xc5, 0xfe, 0xbf, 0x46,
|
||||
0xc5, 0xea, 0x14, 0x9b, 0x44, 0x6e, 0x24, 0xdc, 0xfb, 0x13, 0x00, 0x00, 0xff, 0xff, 0xe3, 0x32,
|
||||
0x83, 0x14, 0xde, 0x04, 0x00, 0x00,
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ import (
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/grpc-ecosystem/grpc-gateway/runtime"
|
||||
"github.com/grpc-ecosystem/grpc-gateway/utilities"
|
||||
@@ -47,10 +46,10 @@ func request_ClusterService_List_0(ctx context.Context, marshaler runtime.Marsha
|
||||
}
|
||||
|
||||
func request_ClusterService_Create_0(ctx context.Context, marshaler runtime.Marshaler, client ClusterServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq v1alpha1.Cluster
|
||||
var protoReq ClusterCreateRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil {
|
||||
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq.Cluster); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
@@ -86,7 +85,7 @@ func request_ClusterService_Get_0(ctx context.Context, marshaler runtime.Marshal
|
||||
|
||||
}
|
||||
|
||||
func request_ClusterService_UpdateREST_0(ctx context.Context, marshaler runtime.Marshaler, client ClusterServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
func request_ClusterService_Update_0(ctx context.Context, marshaler runtime.Marshaler, client ClusterServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq ClusterUpdateRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
@@ -101,18 +100,18 @@ func request_ClusterService_UpdateREST_0(ctx context.Context, marshaler runtime.
|
||||
_ = err
|
||||
)
|
||||
|
||||
val, ok = pathParams["server"]
|
||||
val, ok = pathParams["cluster.server"]
|
||||
if !ok {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "server")
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "cluster.server")
|
||||
}
|
||||
|
||||
protoReq.Server, err = runtime.String(val)
|
||||
err = runtime.PopulateFieldFromPath(&protoReq, "cluster.server", val)
|
||||
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "server", err)
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "cluster.server", err)
|
||||
}
|
||||
|
||||
msg, err := client.UpdateREST(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
msg, err := client.Update(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
@@ -144,33 +143,6 @@ func request_ClusterService_Delete_0(ctx context.Context, marshaler runtime.Mars
|
||||
|
||||
}
|
||||
|
||||
func request_ClusterService_ListPods_0(ctx context.Context, marshaler runtime.Marshaler, client ClusterServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq ClusterQuery
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
var (
|
||||
val string
|
||||
ok bool
|
||||
err error
|
||||
_ = err
|
||||
)
|
||||
|
||||
val, ok = pathParams["server"]
|
||||
if !ok {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "server")
|
||||
}
|
||||
|
||||
protoReq.Server, err = runtime.String(val)
|
||||
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "server", err)
|
||||
}
|
||||
|
||||
msg, err := client.ListPods(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
// RegisterClusterServiceHandlerFromEndpoint is same as RegisterClusterServiceHandler but
|
||||
// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
|
||||
func RegisterClusterServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
|
||||
@@ -296,7 +268,7 @@ func RegisterClusterServiceHandlerClient(ctx context.Context, mux *runtime.Serve
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("PUT", pattern_ClusterService_UpdateREST_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
mux.Handle("PUT", pattern_ClusterService_Update_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
if cn, ok := w.(http.CloseNotifier); ok {
|
||||
@@ -314,14 +286,14 @@ func RegisterClusterServiceHandlerClient(ctx context.Context, mux *runtime.Serve
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_ClusterService_UpdateREST_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
resp, md, err := request_ClusterService_Update_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_ClusterService_UpdateREST_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
forward_ClusterService_Update_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
@@ -354,35 +326,6 @@ func RegisterClusterServiceHandlerClient(ctx context.Context, mux *runtime.Serve
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_ClusterService_ListPods_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
if cn, ok := w.(http.CloseNotifier); ok {
|
||||
go func(done <-chan struct{}, closed <-chan bool) {
|
||||
select {
|
||||
case <-done:
|
||||
case <-closed:
|
||||
cancel()
|
||||
}
|
||||
}(ctx.Done(), cn.CloseNotify())
|
||||
}
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_ClusterService_ListPods_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_ClusterService_ListPods_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -393,11 +336,9 @@ var (
|
||||
|
||||
pattern_ClusterService_Get_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v1", "clusters", "server"}, ""))
|
||||
|
||||
pattern_ClusterService_UpdateREST_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v1", "clusters", "server"}, ""))
|
||||
pattern_ClusterService_Update_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v1", "clusters", "cluster.server"}, ""))
|
||||
|
||||
pattern_ClusterService_Delete_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v1", "clusters", "server"}, ""))
|
||||
|
||||
pattern_ClusterService_ListPods_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"api", "v1", "clusters", "server", "pods"}, ""))
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -407,9 +348,7 @@ var (
|
||||
|
||||
forward_ClusterService_Get_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_ClusterService_UpdateREST_0 = runtime.ForwardResponseMessage
|
||||
forward_ClusterService_Update_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_ClusterService_Delete_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_ClusterService_ListPods_0 = runtime.ForwardResponseMessage
|
||||
)
|
||||
|
||||
@@ -19,9 +19,12 @@ message ClusterQuery {
|
||||
|
||||
message ClusterResponse {}
|
||||
|
||||
message ClusterCreateRequest {
|
||||
github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.Cluster cluster = 1;
|
||||
}
|
||||
|
||||
message ClusterUpdateRequest {
|
||||
string server = 1;
|
||||
github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.Cluster cluster = 2;
|
||||
github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.Cluster cluster = 1;
|
||||
}
|
||||
|
||||
// ClusterService
|
||||
@@ -33,26 +36,22 @@ service ClusterService {
|
||||
}
|
||||
|
||||
// Create creates a cluster
|
||||
rpc Create(github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.Cluster) returns (github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.Cluster) {
|
||||
rpc Create(ClusterCreateRequest) returns (github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.Cluster) {
|
||||
option (google.api.http) = {
|
||||
post: "/api/v1/clusters"
|
||||
body: "*"
|
||||
body: "cluster"
|
||||
};
|
||||
}
|
||||
|
||||
// Get returns a cluster by server address
|
||||
rpc Get(ClusterQuery) returns (github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.Cluster) {
|
||||
// Get returns a cluster by server address
|
||||
rpc Get(ClusterQuery) returns (github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.Cluster) {
|
||||
option (google.api.http).get = "/api/v1/clusters/{server}";
|
||||
}
|
||||
|
||||
// Update updates a cluster
|
||||
rpc Update(github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.Cluster) returns (github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.Cluster) {
|
||||
}
|
||||
|
||||
// Update updates a cluster (special handler intended to be used only by the gRPC gateway)
|
||||
rpc UpdateREST(ClusterUpdateRequest) returns (github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.Cluster) {
|
||||
rpc Update(ClusterUpdateRequest) returns (github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.Cluster) {
|
||||
option (google.api.http) = {
|
||||
put: "/api/v1/clusters/{server}"
|
||||
put: "/api/v1/clusters/{cluster.server}"
|
||||
body: "cluster"
|
||||
};
|
||||
}
|
||||
@@ -62,9 +61,4 @@ service ClusterService {
|
||||
option (google.api.http).delete = "/api/v1/clusters/{server}";
|
||||
}
|
||||
|
||||
// ListPods returns pods in a cluster
|
||||
rpc ListPods(ClusterQuery) returns (k8s.io.api.core.v1.PodList) {
|
||||
option (google.api.http).get = "/api/v1/clusters/{server}/pods";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ package mocks
|
||||
import cluster "github.com/argoproj/argo-cd/server/cluster"
|
||||
import context "context"
|
||||
import mock "github.com/stretchr/testify/mock"
|
||||
import v1 "k8s.io/api/core/v1"
|
||||
import v1alpha1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
|
||||
|
||||
// ClusterServiceServer is an autogenerated mock type for the ClusterServiceServer type
|
||||
@@ -13,11 +12,11 @@ type ClusterServiceServer struct {
|
||||
}
|
||||
|
||||
// Create provides a mock function with given fields: _a0, _a1
|
||||
func (_m *ClusterServiceServer) Create(_a0 context.Context, _a1 *v1alpha1.Cluster) (*v1alpha1.Cluster, error) {
|
||||
func (_m *ClusterServiceServer) Create(_a0 context.Context, _a1 *cluster.ClusterCreateRequest) (*v1alpha1.Cluster, error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
||||
var r0 *v1alpha1.Cluster
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *v1alpha1.Cluster) *v1alpha1.Cluster); ok {
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *cluster.ClusterCreateRequest) *v1alpha1.Cluster); ok {
|
||||
r0 = rf(_a0, _a1)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
@@ -26,7 +25,7 @@ func (_m *ClusterServiceServer) Create(_a0 context.Context, _a1 *v1alpha1.Cluste
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *v1alpha1.Cluster) error); ok {
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *cluster.ClusterCreateRequest) error); ok {
|
||||
r1 = rf(_a0, _a1)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
@@ -104,54 +103,8 @@ func (_m *ClusterServiceServer) List(_a0 context.Context, _a1 *cluster.ClusterQu
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// ListPods provides a mock function with given fields: _a0, _a1
|
||||
func (_m *ClusterServiceServer) ListPods(_a0 context.Context, _a1 *cluster.ClusterQuery) (*v1.PodList, error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
||||
var r0 *v1.PodList
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *cluster.ClusterQuery) *v1.PodList); ok {
|
||||
r0 = rf(_a0, _a1)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*v1.PodList)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *cluster.ClusterQuery) error); ok {
|
||||
r1 = rf(_a0, _a1)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Update provides a mock function with given fields: _a0, _a1
|
||||
func (_m *ClusterServiceServer) Update(_a0 context.Context, _a1 *v1alpha1.Cluster) (*v1alpha1.Cluster, error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
||||
var r0 *v1alpha1.Cluster
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *v1alpha1.Cluster) *v1alpha1.Cluster); ok {
|
||||
r0 = rf(_a0, _a1)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*v1alpha1.Cluster)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *v1alpha1.Cluster) error); ok {
|
||||
r1 = rf(_a0, _a1)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// UpdateREST provides a mock function with given fields: _a0, _a1
|
||||
func (_m *ClusterServiceServer) UpdateREST(_a0 context.Context, _a1 *cluster.ClusterUpdateRequest) (*v1alpha1.Cluster, error) {
|
||||
func (_m *ClusterServiceServer) Update(_a0 context.Context, _a1 *cluster.ClusterUpdateRequest) (*v1alpha1.Cluster, error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
||||
var r0 *v1alpha1.Cluster
|
||||
|
||||
@@ -12,11 +12,11 @@ type RepositoryServiceServer struct {
|
||||
}
|
||||
|
||||
// Create provides a mock function with given fields: _a0, _a1
|
||||
func (_m *RepositoryServiceServer) Create(_a0 context.Context, _a1 *v1alpha1.Repository) (*v1alpha1.Repository, error) {
|
||||
func (_m *RepositoryServiceServer) Create(_a0 context.Context, _a1 *repository.RepoCreateRequest) (*v1alpha1.Repository, error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
||||
var r0 *v1alpha1.Repository
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *v1alpha1.Repository) *v1alpha1.Repository); ok {
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *repository.RepoCreateRequest) *v1alpha1.Repository); ok {
|
||||
r0 = rf(_a0, _a1)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
@@ -25,7 +25,7 @@ func (_m *RepositoryServiceServer) Create(_a0 context.Context, _a1 *v1alpha1.Rep
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *v1alpha1.Repository) error); ok {
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *repository.RepoCreateRequest) error); ok {
|
||||
r1 = rf(_a0, _a1)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
@@ -103,21 +103,21 @@ func (_m *RepositoryServiceServer) List(_a0 context.Context, _a1 *repository.Rep
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Update provides a mock function with given fields: _a0, _a1
|
||||
func (_m *RepositoryServiceServer) Update(_a0 context.Context, _a1 *v1alpha1.Repository) (*v1alpha1.Repository, error) {
|
||||
// ListKsonnetApps provides a mock function with given fields: _a0, _a1
|
||||
func (_m *RepositoryServiceServer) ListKsonnetApps(_a0 context.Context, _a1 *repository.RepoKsonnetQuery) (*repository.RepoKsonnetResponse, error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
||||
var r0 *v1alpha1.Repository
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *v1alpha1.Repository) *v1alpha1.Repository); ok {
|
||||
var r0 *repository.RepoKsonnetResponse
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *repository.RepoKsonnetQuery) *repository.RepoKsonnetResponse); ok {
|
||||
r0 = rf(_a0, _a1)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*v1alpha1.Repository)
|
||||
r0 = ret.Get(0).(*repository.RepoKsonnetResponse)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *v1alpha1.Repository) error); ok {
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *repository.RepoKsonnetQuery) error); ok {
|
||||
r1 = rf(_a0, _a1)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
@@ -126,8 +126,8 @@ func (_m *RepositoryServiceServer) Update(_a0 context.Context, _a1 *v1alpha1.Rep
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// UpdateREST provides a mock function with given fields: _a0, _a1
|
||||
func (_m *RepositoryServiceServer) UpdateREST(_a0 context.Context, _a1 *repository.RepoUpdateRequest) (*v1alpha1.Repository, error) {
|
||||
// Update provides a mock function with given fields: _a0, _a1
|
||||
func (_m *RepositoryServiceServer) Update(_a0 context.Context, _a1 *repository.RepoUpdateRequest) (*v1alpha1.Repository, error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
||||
var r0 *v1alpha1.Repository
|
||||
|
||||
@@ -2,169 +2,152 @@ package repository
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"hash/fnv"
|
||||
"strings"
|
||||
|
||||
"github.com/argoproj/argo-cd/common"
|
||||
appsv1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
|
||||
appclientset "github.com/argoproj/argo-cd/pkg/client/clientset/versioned"
|
||||
"github.com/argoproj/argo-cd/util/git"
|
||||
"github.com/ghodss/yaml"
|
||||
"golang.org/x/net/context"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
apiv1 "k8s.io/api/core/v1"
|
||||
apierr "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/selection"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
|
||||
appsv1 "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"
|
||||
"github.com/argoproj/argo-cd/util/grpc"
|
||||
"github.com/argoproj/argo-cd/util/rbac"
|
||||
)
|
||||
|
||||
// Server provides a Repository service
|
||||
type Server struct {
|
||||
ns string
|
||||
kubeclientset kubernetes.Interface
|
||||
appclientset appclientset.Interface
|
||||
db db.ArgoDB
|
||||
repoClientset reposerver.Clientset
|
||||
enf *rbac.Enforcer
|
||||
}
|
||||
|
||||
// NewServer returns a new instance of the Repository service
|
||||
func NewServer(namespace string, kubeclientset kubernetes.Interface, appclientset appclientset.Interface) *Server {
|
||||
func NewServer(
|
||||
repoClientset reposerver.Clientset,
|
||||
db db.ArgoDB,
|
||||
enf *rbac.Enforcer,
|
||||
) *Server {
|
||||
return &Server{
|
||||
ns: namespace,
|
||||
appclientset: appclientset,
|
||||
kubeclientset: kubeclientset,
|
||||
db: db,
|
||||
repoClientset: repoClientset,
|
||||
enf: enf,
|
||||
}
|
||||
}
|
||||
|
||||
// List returns list of repositories
|
||||
func (s *Server) List(ctx context.Context, q *RepoQuery) (*appsv1.RepositoryList, error) {
|
||||
listOpts := metav1.ListOptions{}
|
||||
labelSelector := labels.NewSelector()
|
||||
req, err := labels.NewRequirement(common.LabelKeySecretType, selection.Equals, []string{common.SecretTypeRepository})
|
||||
repoList, err := s.db.ListRepositories(ctx)
|
||||
if repoList != nil {
|
||||
newItems := make([]appsv1.Repository, 0)
|
||||
for _, repo := range repoList.Items {
|
||||
if s.enf.EnforceClaims(ctx.Value("claims"), "repositories", "get", fmt.Sprintf("*/%s", repo.Repo)) {
|
||||
newItems = append(newItems, *redact(&repo))
|
||||
}
|
||||
}
|
||||
repoList.Items = newItems
|
||||
}
|
||||
return repoList, err
|
||||
}
|
||||
|
||||
// ListKsonnetApps returns list of Ksonnet apps in the repo
|
||||
func (s *Server) ListKsonnetApps(ctx context.Context, q *RepoKsonnetQuery) (*RepoKsonnetResponse, error) {
|
||||
if !s.enf.EnforceClaims(ctx.Value("claims"), "repositories/apps", "get", fmt.Sprintf("*/%s", q.Repo)) {
|
||||
return nil, grpc.ErrPermissionDenied
|
||||
}
|
||||
repo, err := s.db.GetRepository(ctx, q.Repo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
labelSelector = labelSelector.Add(*req)
|
||||
listOpts.LabelSelector = labelSelector.String()
|
||||
repoSecrets, err := s.kubeclientset.CoreV1().Secrets(s.ns).List(listOpts)
|
||||
|
||||
// Test the repo
|
||||
conn, repoClient, err := s.repoClientset.NewRepositoryClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
repoList := appsv1.RepositoryList{
|
||||
Items: make([]appsv1.Repository, len(repoSecrets.Items)),
|
||||
defer util.Close(conn)
|
||||
|
||||
revision := q.Revision
|
||||
if revision == "" {
|
||||
revision = "HEAD"
|
||||
}
|
||||
for i, repoSec := range repoSecrets.Items {
|
||||
repoList.Items[i] = *secretToRepo(&repoSec)
|
||||
|
||||
// Verify app.yaml is functional
|
||||
req := repository.ListDirRequest{
|
||||
Repo: repo,
|
||||
Revision: revision,
|
||||
Path: "*app.yaml",
|
||||
}
|
||||
return &repoList, nil
|
||||
getRes, err := repoClient.ListDir(ctx, &req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
out := make([]*KsonnetAppSpec, 0)
|
||||
for _, path := range getRes.Items {
|
||||
getFileRes, err := repoClient.GetFile(ctx, &repository.GetFileRequest{
|
||||
Repo: repo,
|
||||
Revision: revision,
|
||||
Path: path,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var appSpec KsonnetAppSpec
|
||||
appSpec.Path = path
|
||||
err = yaml.Unmarshal(getFileRes.Data, &appSpec)
|
||||
if err == nil && appSpec.Name != "" && len(appSpec.Environments) > 0 {
|
||||
out = append(out, &appSpec)
|
||||
}
|
||||
}
|
||||
|
||||
return &RepoKsonnetResponse{
|
||||
Items: out,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Create creates a repository
|
||||
func (s *Server) Create(ctx context.Context, r *appsv1.Repository) (*appsv1.Repository, error) {
|
||||
shallowCopy := *r
|
||||
r = &shallowCopy
|
||||
r.Repo = git.NormalizeGitURL(r.Repo)
|
||||
err := git.TestRepo(r.Repo, r.Username, r.Password, r.SSHPrivateKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
func (s *Server) Create(ctx context.Context, q *RepoCreateRequest) (*appsv1.Repository, error) {
|
||||
if !s.enf.EnforceClaims(ctx.Value("claims"), "repositories", "create", fmt.Sprintf("*/%s", q.Repo.Repo)) {
|
||||
return nil, grpc.ErrPermissionDenied
|
||||
}
|
||||
secName := repoURLToSecretName(r.Repo)
|
||||
repoSecret := &apiv1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: secName,
|
||||
Labels: map[string]string{
|
||||
common.LabelKeySecretType: common.SecretTypeRepository,
|
||||
},
|
||||
},
|
||||
}
|
||||
repoSecret.StringData = repoToStringData(r)
|
||||
repoSecret, err = s.kubeclientset.CoreV1().Secrets(s.ns).Create(repoSecret)
|
||||
if err != nil {
|
||||
if apierr.IsAlreadyExists(err) {
|
||||
return nil, grpc.Errorf(codes.AlreadyExists, "repository '%s' already exists", r.Repo)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return secretToRepo(repoSecret), nil
|
||||
}
|
||||
|
||||
func (s *Server) getRepoSecret(repo string) (*apiv1.Secret, error) {
|
||||
secName := repoURLToSecretName(repo)
|
||||
repoSecret, err := s.kubeclientset.CoreV1().Secrets(s.ns).Get(secName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
if apierr.IsNotFound(err) {
|
||||
return nil, grpc.Errorf(codes.NotFound, "repo '%s' not found", repo)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return repoSecret, nil
|
||||
repo, err := s.db.CreateRepository(ctx, q.Repo)
|
||||
return redact(repo), err
|
||||
}
|
||||
|
||||
// Get returns a repository by URL
|
||||
func (s *Server) Get(ctx context.Context, q *RepoQuery) (*appsv1.Repository, error) {
|
||||
repoSecret, err := s.getRepoSecret(q.Repo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if !s.enf.EnforceClaims(ctx.Value("claims"), "repositories", "get", fmt.Sprintf("*/%s", q.Repo)) {
|
||||
return nil, grpc.ErrPermissionDenied
|
||||
}
|
||||
return secretToRepo(repoSecret), nil
|
||||
repo, err := s.db.GetRepository(ctx, q.Repo)
|
||||
return redact(repo), err
|
||||
}
|
||||
|
||||
// Update updates a repository
|
||||
func (s *Server) Update(ctx context.Context, r *appsv1.Repository) (*appsv1.Repository, error) {
|
||||
err := git.TestRepo(r.Repo, r.Username, r.Password, r.SSHPrivateKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
func (s *Server) Update(ctx context.Context, q *RepoUpdateRequest) (*appsv1.Repository, error) {
|
||||
if !s.enf.EnforceClaims(ctx.Value("claims"), "repositories", "update", fmt.Sprintf("*/%s", q.Repo.Repo)) {
|
||||
return nil, grpc.ErrPermissionDenied
|
||||
}
|
||||
repoSecret, err := s.getRepoSecret(r.Repo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
repoSecret.StringData = repoToStringData(r)
|
||||
repoSecret, err = s.kubeclientset.CoreV1().Secrets(s.ns).Update(repoSecret)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return secretToRepo(repoSecret), nil
|
||||
}
|
||||
|
||||
// UpdateREST updates a repository (from a REST request)
|
||||
func (s *Server) UpdateREST(ctx context.Context, r *RepoUpdateRequest) (*appsv1.Repository, error) {
|
||||
return s.Update(ctx, r.Repo)
|
||||
repo, err := s.db.UpdateRepository(ctx, q.Repo)
|
||||
return redact(repo), err
|
||||
}
|
||||
|
||||
// Delete updates a repository
|
||||
func (s *Server) Delete(ctx context.Context, q *RepoQuery) (*RepoResponse, error) {
|
||||
secName := repoURLToSecretName(q.Repo)
|
||||
err := s.kubeclientset.CoreV1().Secrets(s.ns).Delete(secName, &metav1.DeleteOptions{})
|
||||
if !s.enf.EnforceClaims(ctx.Value("claims"), "repositories", "delete", fmt.Sprintf("*/%s", q.Repo)) {
|
||||
return nil, grpc.ErrPermissionDenied
|
||||
}
|
||||
err := s.db.DeleteRepository(ctx, q.Repo)
|
||||
return &RepoResponse{}, err
|
||||
}
|
||||
|
||||
// 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 = 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())
|
||||
}
|
||||
|
||||
// repoToStringData converts a repository object to string data for serialization to a secret
|
||||
func repoToStringData(r *appsv1.Repository) map[string]string {
|
||||
return map[string]string{
|
||||
"repository": r.Repo,
|
||||
"username": r.Username,
|
||||
"password": r.Password,
|
||||
"sshPrivateKey": r.SSHPrivateKey,
|
||||
}
|
||||
}
|
||||
|
||||
// secretToRepo converts a secret into a repository object
|
||||
func secretToRepo(s *apiv1.Secret) *appsv1.Repository {
|
||||
return &appsv1.Repository{
|
||||
Repo: string(s.Data["repository"]),
|
||||
Username: string(s.Data["username"]),
|
||||
Password: string(s.Data["password"]),
|
||||
SSHPrivateKey: string(s.Data["sshPrivateKey"]),
|
||||
func redact(repo *appsv1.Repository) *appsv1.Repository {
|
||||
if repo == nil {
|
||||
return nil
|
||||
}
|
||||
repo.Password = ""
|
||||
repo.SSHPrivateKey = ""
|
||||
return repo
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -12,7 +12,6 @@ import (
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/grpc-ecosystem/grpc-gateway/runtime"
|
||||
"github.com/grpc-ecosystem/grpc-gateway/utilities"
|
||||
@@ -46,11 +45,46 @@ func request_RepositoryService_List_0(ctx context.Context, marshaler runtime.Mar
|
||||
|
||||
}
|
||||
|
||||
func request_RepositoryService_Create_0(ctx context.Context, marshaler runtime.Marshaler, client RepositoryServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq v1alpha1.Repository
|
||||
var (
|
||||
filter_RepositoryService_ListKsonnetApps_0 = &utilities.DoubleArray{Encoding: map[string]int{"repo": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}}
|
||||
)
|
||||
|
||||
func request_RepositoryService_ListKsonnetApps_0(ctx context.Context, marshaler runtime.Marshaler, client RepositoryServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq RepoKsonnetQuery
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil {
|
||||
var (
|
||||
val string
|
||||
ok bool
|
||||
err error
|
||||
_ = err
|
||||
)
|
||||
|
||||
val, ok = pathParams["repo"]
|
||||
if !ok {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "repo")
|
||||
}
|
||||
|
||||
protoReq.Repo, err = runtime.String(val)
|
||||
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "repo", err)
|
||||
}
|
||||
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_RepositoryService_ListKsonnetApps_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := client.ListKsonnetApps(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func request_RepositoryService_Create_0(ctx context.Context, marshaler runtime.Marshaler, client RepositoryServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq RepoCreateRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq.Repo); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
@@ -86,7 +120,7 @@ func request_RepositoryService_Get_0(ctx context.Context, marshaler runtime.Mars
|
||||
|
||||
}
|
||||
|
||||
func request_RepositoryService_UpdateREST_0(ctx context.Context, marshaler runtime.Marshaler, client RepositoryServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
func request_RepositoryService_Update_0(ctx context.Context, marshaler runtime.Marshaler, client RepositoryServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq RepoUpdateRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
@@ -101,18 +135,18 @@ func request_RepositoryService_UpdateREST_0(ctx context.Context, marshaler runti
|
||||
_ = err
|
||||
)
|
||||
|
||||
val, ok = pathParams["url"]
|
||||
val, ok = pathParams["repo.repo"]
|
||||
if !ok {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "url")
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "repo.repo")
|
||||
}
|
||||
|
||||
protoReq.Url, err = runtime.String(val)
|
||||
err = runtime.PopulateFieldFromPath(&protoReq, "repo.repo", val)
|
||||
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "url", err)
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "repo.repo", err)
|
||||
}
|
||||
|
||||
msg, err := client.UpdateREST(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
msg, err := client.Update(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
@@ -211,6 +245,35 @@ func RegisterRepositoryServiceHandlerClient(ctx context.Context, mux *runtime.Se
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_RepositoryService_ListKsonnetApps_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
if cn, ok := w.(http.CloseNotifier); ok {
|
||||
go func(done <-chan struct{}, closed <-chan bool) {
|
||||
select {
|
||||
case <-done:
|
||||
case <-closed:
|
||||
cancel()
|
||||
}
|
||||
}(ctx.Done(), cn.CloseNotify())
|
||||
}
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_RepositoryService_ListKsonnetApps_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_RepositoryService_ListKsonnetApps_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_RepositoryService_Create_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
@@ -269,7 +332,7 @@ func RegisterRepositoryServiceHandlerClient(ctx context.Context, mux *runtime.Se
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("PUT", pattern_RepositoryService_UpdateREST_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
mux.Handle("PUT", pattern_RepositoryService_Update_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
if cn, ok := w.(http.CloseNotifier); ok {
|
||||
@@ -287,14 +350,14 @@ func RegisterRepositoryServiceHandlerClient(ctx context.Context, mux *runtime.Se
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_RepositoryService_UpdateREST_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
resp, md, err := request_RepositoryService_Update_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_RepositoryService_UpdateREST_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
forward_RepositoryService_Update_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
@@ -333,11 +396,13 @@ func RegisterRepositoryServiceHandlerClient(ctx context.Context, mux *runtime.Se
|
||||
var (
|
||||
pattern_RepositoryService_List_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "repositories"}, ""))
|
||||
|
||||
pattern_RepositoryService_ListKsonnetApps_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"api", "v1", "repositories", "repo", "ksonnet"}, ""))
|
||||
|
||||
pattern_RepositoryService_Create_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "repositories"}, ""))
|
||||
|
||||
pattern_RepositoryService_Get_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v1", "repositories", "repo"}, ""))
|
||||
|
||||
pattern_RepositoryService_UpdateREST_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v1", "repositories", "url"}, ""))
|
||||
pattern_RepositoryService_Update_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v1", "repositories", "repo.repo"}, ""))
|
||||
|
||||
pattern_RepositoryService_Delete_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"api", "v1", "repositories", "repo"}, ""))
|
||||
)
|
||||
@@ -345,11 +410,13 @@ var (
|
||||
var (
|
||||
forward_RepositoryService_List_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_RepositoryService_ListKsonnetApps_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_RepositoryService_Create_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_RepositoryService_Get_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_RepositoryService_UpdateREST_0 = runtime.ForwardResponseMessage
|
||||
forward_RepositoryService_Update_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_RepositoryService_Delete_0 = runtime.ForwardResponseMessage
|
||||
)
|
||||
|
||||
@@ -11,6 +11,42 @@ import "google/api/annotations.proto";
|
||||
import "k8s.io/api/core/v1/generated.proto";
|
||||
import "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1/generated.proto";
|
||||
|
||||
// RepoKsonnetQuery is a query for Repository contents matching a particular path
|
||||
message RepoKsonnetQuery {
|
||||
string repo = 1;
|
||||
string revision = 2;
|
||||
}
|
||||
|
||||
// RepoKsonnetResponse is a response for Repository contents matching a particular path
|
||||
message RepoKsonnetResponse {
|
||||
repeated KsonnetAppSpec items = 1;
|
||||
}
|
||||
|
||||
// KsonnetAppSpec contains Ksonnet app response
|
||||
// This roughly reflects: ksonnet/ksonnet/metadata/app/schema.go
|
||||
message KsonnetAppSpec {
|
||||
string name = 1;
|
||||
string path = 2;
|
||||
map<string, KsonnetEnvironment> environments = 3;
|
||||
}
|
||||
|
||||
message KsonnetEnvironment {
|
||||
// Name is the user defined name of an environment
|
||||
string name = 1;
|
||||
// KubernetesVersion is the kubernetes version the targetted cluster is running on.
|
||||
string k8sVersion = 2;
|
||||
// Path is the relative project path containing metadata for this environment.
|
||||
string path = 3;
|
||||
// Destination stores the cluster address that this environment points to.
|
||||
KsonnetEnvironmentDestination destination = 4;
|
||||
}
|
||||
|
||||
message KsonnetEnvironmentDestination {
|
||||
// Server is the Kubernetes server that the cluster is running on.
|
||||
string server = 1;
|
||||
// Namespace is the namespace of the Kubernetes server that targets should be deployed to
|
||||
string namespace = 2;
|
||||
}
|
||||
|
||||
// RepoQuery is a query for Repository resources
|
||||
message RepoQuery {
|
||||
@@ -19,9 +55,12 @@ message RepoQuery {
|
||||
|
||||
message RepoResponse {}
|
||||
|
||||
message RepoCreateRequest {
|
||||
github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.Repository repo = 1;
|
||||
}
|
||||
|
||||
message RepoUpdateRequest {
|
||||
string url = 1;
|
||||
github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.Repository repo = 2;
|
||||
github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.Repository repo = 1;
|
||||
}
|
||||
|
||||
// RepositoryService
|
||||
@@ -32,27 +71,28 @@ service RepositoryService {
|
||||
option (google.api.http).get = "/api/v1/repositories";
|
||||
}
|
||||
|
||||
// ListKsonnetApps returns list of Ksonnet apps in the repo
|
||||
rpc ListKsonnetApps(RepoKsonnetQuery) returns (RepoKsonnetResponse) {
|
||||
option (google.api.http).get = "/api/v1/repositories/{repo}/ksonnet";
|
||||
}
|
||||
|
||||
// Create creates a repo
|
||||
rpc Create(github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.Repository) returns (github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.Repository) {
|
||||
rpc Create(RepoCreateRequest) returns (github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.Repository) {
|
||||
option (google.api.http) = {
|
||||
post: "/api/v1/repositories"
|
||||
body: "*"
|
||||
body: "repo"
|
||||
};
|
||||
}
|
||||
|
||||
// Get returns a repo by name
|
||||
rpc Get(RepoQuery) returns (github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.Repository) {
|
||||
// Get returns a repo by name
|
||||
rpc Get(RepoQuery) returns (github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.Repository) {
|
||||
option (google.api.http).get = "/api/v1/repositories/{repo}";
|
||||
}
|
||||
|
||||
// Update updates a repo
|
||||
rpc Update(github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.Repository) returns (github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.Repository) {
|
||||
}
|
||||
|
||||
// Update updates a repo (special handler intended to be used only by the gRPC gateway)
|
||||
rpc UpdateREST(RepoUpdateRequest) returns (github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.Repository) {
|
||||
rpc Update(RepoUpdateRequest) returns (github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.Repository) {
|
||||
option (google.api.http) = {
|
||||
put: "/api/v1/repositories/{url}"
|
||||
put: "/api/v1/repositories/{repo.repo}"
|
||||
body: "repo"
|
||||
};
|
||||
}
|
||||
|
||||
548
server/server.go
548
server/server.go
@@ -2,66 +2,123 @@ package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
argocd "github.com/argoproj/argo-cd"
|
||||
appclientset "github.com/argoproj/argo-cd/pkg/client/clientset/versioned"
|
||||
"github.com/argoproj/argo-cd/reposerver"
|
||||
"github.com/argoproj/argo-cd/server/application"
|
||||
"github.com/argoproj/argo-cd/server/cluster"
|
||||
"github.com/argoproj/argo-cd/server/repository"
|
||||
"github.com/argoproj/argo-cd/server/version"
|
||||
"github.com/argoproj/argo-cd/util"
|
||||
grpc_util "github.com/argoproj/argo-cd/util/grpc"
|
||||
jsonutil "github.com/argoproj/argo-cd/util/json"
|
||||
"github.com/gobuffalo/packr"
|
||||
golang_proto "github.com/golang/protobuf/proto"
|
||||
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
|
||||
grpc_auth "github.com/grpc-ecosystem/go-grpc-middleware/auth"
|
||||
grpc_logrus "github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus"
|
||||
"github.com/grpc-ecosystem/grpc-gateway/runtime"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/soheilhy/cmux"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/credentials"
|
||||
"google.golang.org/grpc/metadata"
|
||||
"google.golang.org/grpc/reflection"
|
||||
"google.golang.org/grpc/status"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
)
|
||||
|
||||
const (
|
||||
port = 8080
|
||||
argocd "github.com/argoproj/argo-cd"
|
||||
"github.com/argoproj/argo-cd/common"
|
||||
"github.com/argoproj/argo-cd/errors"
|
||||
"github.com/argoproj/argo-cd/pkg/apiclient"
|
||||
appclientset "github.com/argoproj/argo-cd/pkg/client/clientset/versioned"
|
||||
"github.com/argoproj/argo-cd/reposerver"
|
||||
"github.com/argoproj/argo-cd/server/application"
|
||||
"github.com/argoproj/argo-cd/server/cluster"
|
||||
"github.com/argoproj/argo-cd/server/repository"
|
||||
"github.com/argoproj/argo-cd/server/session"
|
||||
"github.com/argoproj/argo-cd/server/settings"
|
||||
"github.com/argoproj/argo-cd/server/version"
|
||||
"github.com/argoproj/argo-cd/util/db"
|
||||
"github.com/argoproj/argo-cd/util/dex"
|
||||
dexutil "github.com/argoproj/argo-cd/util/dex"
|
||||
grpc_util "github.com/argoproj/argo-cd/util/grpc"
|
||||
jsonutil "github.com/argoproj/argo-cd/util/json"
|
||||
"github.com/argoproj/argo-cd/util/rbac"
|
||||
util_session "github.com/argoproj/argo-cd/util/session"
|
||||
settings_util "github.com/argoproj/argo-cd/util/settings"
|
||||
tlsutil "github.com/argoproj/argo-cd/util/tls"
|
||||
"github.com/argoproj/argo-cd/util/webhook"
|
||||
)
|
||||
|
||||
var (
|
||||
endpoint = fmt.Sprintf("localhost:%d", port)
|
||||
// ErrNoSession indicates no auth token was supplied as part of a request
|
||||
ErrNoSession = status.Errorf(codes.Unauthenticated, "no session information")
|
||||
)
|
||||
|
||||
var backoff = wait.Backoff{
|
||||
Steps: 5,
|
||||
Duration: 500 * time.Millisecond,
|
||||
Factor: 1.0,
|
||||
Jitter: 0.1,
|
||||
}
|
||||
|
||||
var (
|
||||
box = packr.NewBox("../util/rbac")
|
||||
builtinPolicy string
|
||||
)
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
builtinPolicy, err = box.MustString("builtin-policy.csv")
|
||||
errors.CheckError(err)
|
||||
}
|
||||
|
||||
// ArgoCDServer is the API server for ArgoCD
|
||||
type ArgoCDServer struct {
|
||||
ns string
|
||||
staticAssetsDir string
|
||||
kubeclientset kubernetes.Interface
|
||||
appclientset appclientset.Interface
|
||||
repoclientset reposerver.Clientset
|
||||
settings util.ArgoCDSettings
|
||||
log *log.Entry
|
||||
ArgoCDServerOpts
|
||||
|
||||
ssoClientApp *dexutil.ClientApp
|
||||
settings *settings_util.ArgoCDSettings
|
||||
log *log.Entry
|
||||
sessionMgr *util_session.SessionManager
|
||||
settingsMgr *settings_util.SettingsManager
|
||||
enf *rbac.Enforcer
|
||||
|
||||
// stopCh is the channel which when closed, will shutdown the ArgoCD server
|
||||
stopCh chan struct{}
|
||||
}
|
||||
|
||||
type ArgoCDServerOpts struct {
|
||||
DisableAuth bool
|
||||
Insecure bool
|
||||
Namespace string
|
||||
StaticAssetsDir string
|
||||
KubeClientset kubernetes.Interface
|
||||
AppClientset appclientset.Interface
|
||||
RepoClientset reposerver.Clientset
|
||||
}
|
||||
|
||||
// NewServer returns a new instance of the ArgoCD API server
|
||||
func NewServer(
|
||||
kubeclientset kubernetes.Interface, appclientset appclientset.Interface, repoclientset reposerver.Clientset, namespace, staticAssetsDir, configMapName string) *ArgoCDServer {
|
||||
configManager := util.NewConfigManager(kubeclientset, namespace, configMapName)
|
||||
settings, err := configManager.GetSettings()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
func NewServer(opts ArgoCDServerOpts) *ArgoCDServer {
|
||||
settingsMgr := settings_util.NewSettingsManager(opts.KubeClientset, opts.Namespace)
|
||||
settings, err := settingsMgr.GetSettings()
|
||||
errors.CheckError(err)
|
||||
sessionMgr := util_session.NewSessionManager(settings)
|
||||
|
||||
enf := rbac.NewEnforcer(opts.KubeClientset, opts.Namespace, common.ArgoCDRBACConfigMapName, nil)
|
||||
enf.EnableEnforce(!opts.DisableAuth)
|
||||
err = enf.SetBuiltinPolicy(builtinPolicy)
|
||||
errors.CheckError(err)
|
||||
enf.EnableLog(os.Getenv(common.EnvVarRBACDebug) == "1")
|
||||
return &ArgoCDServer{
|
||||
ns: namespace,
|
||||
kubeclientset: kubeclientset,
|
||||
appclientset: appclientset,
|
||||
repoclientset: repoclientset,
|
||||
log: log.NewEntry(log.New()),
|
||||
staticAssetsDir: staticAssetsDir,
|
||||
settings: settings,
|
||||
ArgoCDServerOpts: opts,
|
||||
log: log.NewEntry(log.New()),
|
||||
settings: settings,
|
||||
sessionMgr: sessionMgr,
|
||||
settingsMgr: settingsMgr,
|
||||
enf: enf,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,87 +126,307 @@ func NewServer(
|
||||
// We use k8s.io/code-generator/cmd/go-to-protobuf to generate the .proto files from the API types.
|
||||
// k8s.io/ go-to-protobuf uses protoc-gen-gogo, which comes from gogo/protobuf (a fork of
|
||||
// golang/protobuf).
|
||||
func (a *ArgoCDServer) Run() {
|
||||
ctx := context.Background()
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
conn, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
func (a *ArgoCDServer) Run(ctx context.Context, port int) {
|
||||
grpcS := a.newGRPCServer()
|
||||
var httpS *http.Server
|
||||
var httpsS *http.Server
|
||||
if a.useTLS() {
|
||||
httpS = newRedirectServer(port)
|
||||
httpsS = a.newHTTPServer(ctx, port)
|
||||
} else {
|
||||
httpS = a.newHTTPServer(ctx, port)
|
||||
}
|
||||
|
||||
// Cmux is used to support servicing gRPC and HTTP1.1+JSON on the same port
|
||||
m := cmux.New(conn)
|
||||
grpcL := m.Match(cmux.HTTP2HeaderField("content-type", "application/grpc"))
|
||||
httpL := m.Match(cmux.HTTP1Fast())
|
||||
// Start listener
|
||||
var conn net.Listener
|
||||
var realErr error
|
||||
_ = wait.ExponentialBackoff(backoff, func() (bool, error) {
|
||||
conn, realErr = net.Listen("tcp", fmt.Sprintf(":%d", port))
|
||||
if realErr != nil {
|
||||
a.log.Warnf("failed listen: %v", realErr)
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
})
|
||||
errors.CheckError(realErr)
|
||||
|
||||
// gRPC Server
|
||||
grpcS := grpc.NewServer(
|
||||
grpc.StreamInterceptor(grpc_middleware.ChainStreamServer(
|
||||
grpc_logrus.StreamServerInterceptor(a.log),
|
||||
grpc_util.PanicLoggerStreamServerInterceptor(a.log),
|
||||
)),
|
||||
grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(
|
||||
grpc_logrus.UnaryServerInterceptor(a.log),
|
||||
grpc_util.PanicLoggerUnaryServerInterceptor(a.log),
|
||||
)),
|
||||
)
|
||||
// Cmux is used to support servicing gRPC and HTTP1.1+JSON on the same port
|
||||
tcpm := cmux.New(conn)
|
||||
var tlsm cmux.CMux
|
||||
var grpcL net.Listener
|
||||
var httpL net.Listener
|
||||
var httpsL net.Listener
|
||||
if !a.useTLS() {
|
||||
httpL = tcpm.Match(cmux.HTTP1Fast())
|
||||
grpcL = tcpm.Match(cmux.HTTP2HeaderField("content-type", "application/grpc"))
|
||||
} else {
|
||||
// We first match on HTTP 1.1 methods.
|
||||
httpL = tcpm.Match(cmux.HTTP1Fast())
|
||||
|
||||
// If not matched, we assume that its TLS.
|
||||
tlsl := tcpm.Match(cmux.Any())
|
||||
tlsConfig := tls.Config{
|
||||
Certificates: []tls.Certificate{*a.settings.Certificate},
|
||||
}
|
||||
tlsl = tls.NewListener(tlsl, &tlsConfig)
|
||||
|
||||
// Now, we build another mux recursively to match HTTPS and gRPC.
|
||||
tlsm = cmux.New(tlsl)
|
||||
httpsL = tlsm.Match(cmux.HTTP1Fast())
|
||||
grpcL = tlsm.Match(cmux.Any())
|
||||
}
|
||||
|
||||
// Start the muxed listeners for our servers
|
||||
log.Infof("argocd %s serving on port %d (url: %s, tls: %v, namespace: %s, sso: %v)",
|
||||
argocd.GetVersion(), port, a.settings.URL, a.useTLS(), a.Namespace, a.settings.IsSSOConfigured())
|
||||
go func() { a.checkServeErr("grpcS", grpcS.Serve(grpcL)) }()
|
||||
go func() { a.checkServeErr("httpS", httpS.Serve(httpL)) }()
|
||||
if a.useTLS() {
|
||||
go func() { a.checkServeErr("httpsS", httpsS.Serve(httpsL)) }()
|
||||
go func() { a.checkServeErr("tlsm", tlsm.Serve()) }()
|
||||
}
|
||||
go a.watchSettings(ctx)
|
||||
go a.rbacPolicyLoader(ctx)
|
||||
go func() { a.checkServeErr("tcpm", tcpm.Serve()) }()
|
||||
|
||||
a.stopCh = make(chan struct{})
|
||||
<-a.stopCh
|
||||
errors.CheckError(conn.Close())
|
||||
}
|
||||
|
||||
// checkServeErr checks the error from a .Serve() call to decide if it was a graceful shutdown
|
||||
func (a *ArgoCDServer) checkServeErr(name string, err error) {
|
||||
if err != nil {
|
||||
if a.stopCh == nil {
|
||||
// a nil stopCh indicates a graceful shutdown
|
||||
log.Infof("graceful shutdown %s: %v", name, err)
|
||||
} else {
|
||||
log.Fatalf("%s: %v", name, err)
|
||||
}
|
||||
} else {
|
||||
log.Infof("graceful shutdown %s", name)
|
||||
}
|
||||
}
|
||||
|
||||
func (a *ArgoCDServer) Shutdown() {
|
||||
log.Info("Shut down requested")
|
||||
stopCh := a.stopCh
|
||||
a.stopCh = nil
|
||||
if stopCh != nil {
|
||||
close(stopCh)
|
||||
}
|
||||
}
|
||||
|
||||
// watchSettings watches the configmap and secret for any setting updates that would warrant a
|
||||
// restart of the API server.
|
||||
func (a *ArgoCDServer) watchSettings(ctx context.Context) {
|
||||
a.settingsMgr.StartNotifier(ctx, a.settings)
|
||||
updateCh := make(chan struct{}, 1)
|
||||
a.settingsMgr.Subscribe(updateCh)
|
||||
|
||||
prevDexCfgBytes, err := dex.GenerateDexConfigYAML(a.settings)
|
||||
errors.CheckError(err)
|
||||
prevGitHubSecret := a.settings.WebhookGitHubSecret
|
||||
prevGitLabSecret := a.settings.WebhookGitLabSecret
|
||||
prevBitBucketUUID := a.settings.WebhookBitbucketUUID
|
||||
var prevCert, prevCertKey string
|
||||
if a.settings.Certificate != nil {
|
||||
prevCert, prevCertKey = tlsutil.EncodeX509KeyPairString(*a.settings.Certificate)
|
||||
}
|
||||
|
||||
for {
|
||||
<-updateCh
|
||||
newDexCfgBytes, err := dex.GenerateDexConfigYAML(a.settings)
|
||||
errors.CheckError(err)
|
||||
if string(newDexCfgBytes) != string(prevDexCfgBytes) {
|
||||
log.Infof("dex config modified. restarting")
|
||||
break
|
||||
}
|
||||
if prevGitHubSecret != a.settings.WebhookGitHubSecret {
|
||||
log.Infof("github secret modified. restarting")
|
||||
break
|
||||
}
|
||||
if prevGitLabSecret != a.settings.WebhookGitLabSecret {
|
||||
log.Infof("gitlab secret modified. restarting")
|
||||
break
|
||||
}
|
||||
if prevBitBucketUUID != a.settings.WebhookBitbucketUUID {
|
||||
log.Infof("bitbucket uuid modified. restarting")
|
||||
break
|
||||
}
|
||||
var newCert, newCertKey string
|
||||
if a.settings.Certificate != nil {
|
||||
newCert, newCertKey = tlsutil.EncodeX509KeyPairString(*a.settings.Certificate)
|
||||
}
|
||||
if newCert != prevCert || newCertKey != prevCertKey {
|
||||
log.Infof("tls certificate modified. restarting")
|
||||
break
|
||||
}
|
||||
}
|
||||
log.Info("shutting down settings watch")
|
||||
a.Shutdown()
|
||||
a.settingsMgr.Unsubscribe(updateCh)
|
||||
close(updateCh)
|
||||
}
|
||||
|
||||
func (a *ArgoCDServer) rbacPolicyLoader(ctx context.Context) {
|
||||
err := a.enf.RunPolicyLoader(ctx)
|
||||
errors.CheckError(err)
|
||||
}
|
||||
|
||||
func (a *ArgoCDServer) useTLS() bool {
|
||||
if a.Insecure || a.settings.Certificate == nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (a *ArgoCDServer) newGRPCServer() *grpc.Server {
|
||||
var sOpts []grpc.ServerOption
|
||||
// NOTE: notice we do not configure the gRPC server here with TLS (e.g. grpc.Creds(creds))
|
||||
// This is because TLS handshaking occurs in cmux handling
|
||||
sOpts = append(sOpts, grpc.StreamInterceptor(grpc_middleware.ChainStreamServer(
|
||||
grpc_logrus.StreamServerInterceptor(a.log),
|
||||
grpc_auth.StreamServerInterceptor(a.authenticate),
|
||||
grpc_util.ErrorCodeStreamServerInterceptor(),
|
||||
grpc_util.PanicLoggerStreamServerInterceptor(a.log),
|
||||
)))
|
||||
sOpts = append(sOpts, grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(
|
||||
bug21955WorkaroundInterceptor,
|
||||
grpc_logrus.UnaryServerInterceptor(a.log),
|
||||
grpc_auth.UnaryServerInterceptor(a.authenticate),
|
||||
grpc_util.ErrorCodeUnaryServerInterceptor(),
|
||||
grpc_util.PanicLoggerUnaryServerInterceptor(a.log),
|
||||
)))
|
||||
|
||||
grpcS := grpc.NewServer(sOpts...)
|
||||
db := db.NewDB(a.Namespace, a.KubeClientset)
|
||||
clusterService := cluster.NewServer(db, a.enf)
|
||||
repoService := repository.NewServer(a.RepoClientset, db, a.enf)
|
||||
sessionService := session.NewServer(a.sessionMgr)
|
||||
applicationService := application.NewServer(a.Namespace, a.KubeClientset, a.AppClientset, a.RepoClientset, db, a.enf)
|
||||
settingsService := settings.NewServer(a.settingsMgr)
|
||||
version.RegisterVersionServiceServer(grpcS, &version.Server{})
|
||||
clusterService := cluster.NewServer(a.ns, a.kubeclientset, a.appclientset)
|
||||
repoService := repository.NewServer(a.ns, a.kubeclientset, a.appclientset)
|
||||
cluster.RegisterClusterServiceServer(grpcS, clusterService)
|
||||
application.RegisterApplicationServiceServer(grpcS, application.NewServer(a.ns, a.kubeclientset, a.appclientset, a.repoclientset, repoService, clusterService))
|
||||
application.RegisterApplicationServiceServer(grpcS, applicationService)
|
||||
repository.RegisterRepositoryServiceServer(grpcS, repoService)
|
||||
session.RegisterSessionServiceServer(grpcS, sessionService)
|
||||
settings.RegisterSettingsServiceServer(grpcS, settingsService)
|
||||
|
||||
// Register reflection service on gRPC server.
|
||||
reflection.Register(grpcS)
|
||||
return grpcS
|
||||
}
|
||||
|
||||
// TranslateGrpcCookieHeader conditionally sets a cookie on the response.
|
||||
func (a *ArgoCDServer) translateGrpcCookieHeader(ctx context.Context, w http.ResponseWriter, resp golang_proto.Message) error {
|
||||
if sessionResp, ok := resp.(*session.SessionResponse); ok {
|
||||
flags := []string{"path=/"}
|
||||
if !a.Insecure {
|
||||
flags = append(flags, "Secure")
|
||||
}
|
||||
cookie := util_session.MakeCookieMetadata(common.AuthCookieName, sessionResp.Token, flags...)
|
||||
w.Header().Set("Set-Cookie", cookie)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// newHTTPServer returns the HTTP server to serve HTTP/HTTPS requests. This is implemented
|
||||
// using grpc-gateway as a proxy to the gRPC server.
|
||||
func (a *ArgoCDServer) newHTTPServer(ctx context.Context, port int) *http.Server {
|
||||
endpoint := fmt.Sprintf("localhost:%d", port)
|
||||
mux := http.NewServeMux()
|
||||
httpS := http.Server{
|
||||
Addr: endpoint,
|
||||
Handler: &bug21955Workaround{handler: mux},
|
||||
}
|
||||
var dOpts []grpc.DialOption
|
||||
if a.useTLS() {
|
||||
// The following sets up the dial Options for grpc-gateway to talk to gRPC server over TLS.
|
||||
// grpc-gateway is just translating HTTP/HTTPS requests as gRPC requests over localhost,
|
||||
// so we need to supply the same certificates to establish the connections that a normal,
|
||||
// external gRPC client would need.
|
||||
tlsConfig := a.settings.TLSConfig()
|
||||
tlsConfig.InsecureSkipVerify = true
|
||||
dCreds := credentials.NewTLS(tlsConfig)
|
||||
dOpts = append(dOpts, grpc.WithTransportCredentials(dCreds))
|
||||
} else {
|
||||
dOpts = append(dOpts, grpc.WithInsecure())
|
||||
}
|
||||
|
||||
// HTTP 1.1+JSON Server
|
||||
// grpc-ecosystem/grpc-gateway is used to proxy HTTP requests to the corresponding gRPC call
|
||||
mux := http.NewServeMux()
|
||||
// NOTE: if a marshaller option is not supplied, grpc-gateway will default to the jsonpb from
|
||||
// golang/protobuf. Which does not support types such as time.Time. gogo/protobuf does support
|
||||
// time.Time, but does not support custom UnmarshalJSON() and MarshalJSON() methods. Therefore
|
||||
// we use our own Marshaler
|
||||
gwMuxOpts := runtime.WithMarshalerOption(runtime.MIMEWildcard, new(jsonutil.JSONMarshaler))
|
||||
gwmux := runtime.NewServeMux(gwMuxOpts)
|
||||
gwCookieOpts := runtime.WithForwardResponseOption(a.translateGrpcCookieHeader)
|
||||
gwmux := runtime.NewServeMux(gwMuxOpts, gwCookieOpts)
|
||||
mux.Handle("/api/", gwmux)
|
||||
dOpts := []grpc.DialOption{grpc.WithInsecure()}
|
||||
mustRegisterGWHandler(version.RegisterVersionServiceHandlerFromEndpoint, ctx, gwmux, endpoint, dOpts)
|
||||
mustRegisterGWHandler(cluster.RegisterClusterServiceHandlerFromEndpoint, ctx, gwmux, endpoint, dOpts)
|
||||
mustRegisterGWHandler(application.RegisterApplicationServiceHandlerFromEndpoint, ctx, gwmux, endpoint, dOpts)
|
||||
mustRegisterGWHandler(repository.RegisterRepositoryServiceHandlerFromEndpoint, ctx, gwmux, endpoint, dOpts)
|
||||
mustRegisterGWHandler(session.RegisterSessionServiceHandlerFromEndpoint, ctx, gwmux, endpoint, dOpts)
|
||||
mustRegisterGWHandler(settings.RegisterSettingsServiceHandlerFromEndpoint, ctx, gwmux, endpoint, dOpts)
|
||||
|
||||
if a.staticAssetsDir != "" {
|
||||
// Dex reverse proxy and client app and OAuth2 login/callback
|
||||
a.registerDexHandlers(mux)
|
||||
|
||||
// Webhook handler for git events
|
||||
acdWebhookHandler := webhook.NewHandler(a.Namespace, a.AppClientset, a.settings)
|
||||
mux.HandleFunc("/api/webhook", acdWebhookHandler.Handler)
|
||||
|
||||
if a.StaticAssetsDir != "" {
|
||||
mux.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
|
||||
acceptHtml := false
|
||||
acceptHTML := false
|
||||
for _, acceptType := range strings.Split(request.Header.Get("Accept"), ",") {
|
||||
if acceptType == "text/html" || acceptType == "html" {
|
||||
acceptHtml = true
|
||||
acceptHTML = true
|
||||
break
|
||||
}
|
||||
}
|
||||
fileRequest := request.URL.Path != "/index.html" && strings.Contains(request.URL.Path, ".")
|
||||
|
||||
// serve index.html for non file requests to support HTML5 History API
|
||||
if acceptHtml && !fileRequest && (request.Method == "GET" || request.Method == "HEAD") {
|
||||
http.ServeFile(writer, request, a.staticAssetsDir+"/index.html")
|
||||
if acceptHTML && !fileRequest && (request.Method == "GET" || request.Method == "HEAD") {
|
||||
http.ServeFile(writer, request, a.StaticAssetsDir+"/index.html")
|
||||
} else {
|
||||
http.ServeFile(writer, request, a.staticAssetsDir+request.URL.Path)
|
||||
http.ServeFile(writer, request, a.StaticAssetsDir+request.URL.Path)
|
||||
}
|
||||
})
|
||||
}
|
||||
return &httpS
|
||||
}
|
||||
|
||||
httpS := &http.Server{
|
||||
Addr: endpoint,
|
||||
Handler: mux,
|
||||
// registerDexHandlers will register dex HTTP handlers, creating the the OAuth client app
|
||||
func (a *ArgoCDServer) registerDexHandlers(mux *http.ServeMux) {
|
||||
if !a.settings.IsSSOConfigured() {
|
||||
return
|
||||
}
|
||||
// Run dex OpenID Connect Identity Provider behind a reverse proxy (served at /api/dex)
|
||||
var err error
|
||||
mux.HandleFunc(common.DexAPIEndpoint+"/", dexutil.NewDexHTTPReverseProxy())
|
||||
tlsConfig := a.settings.TLSConfig()
|
||||
tlsConfig.InsecureSkipVerify = true
|
||||
a.ssoClientApp, err = dexutil.NewClientApp(a.settings, a.sessionMgr)
|
||||
errors.CheckError(err)
|
||||
mux.HandleFunc(common.LoginEndpoint, a.ssoClientApp.HandleLogin)
|
||||
mux.HandleFunc(common.CallbackEndpoint, a.ssoClientApp.HandleCallback)
|
||||
}
|
||||
|
||||
// Start the muxed listeners for our servers
|
||||
log.Infof("argocd %s serving on port %d (namespace: %s)", argocd.GetVersion(), port, a.ns)
|
||||
go func() { _ = grpcS.Serve(grpcL) }()
|
||||
go func() { _ = httpS.Serve(httpL) }()
|
||||
err = m.Serve()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
// newRedirectServer returns an HTTP server which does a 307 redirect to the HTTPS server
|
||||
func newRedirectServer(port int) *http.Server {
|
||||
return &http.Server{
|
||||
Addr: fmt.Sprintf("localhost:%d", port),
|
||||
Handler: http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
target := "https://" + req.Host + req.URL.Path
|
||||
if len(req.URL.RawQuery) > 0 {
|
||||
target += "?" + req.URL.RawQuery
|
||||
}
|
||||
http.Redirect(w, req, target, http.StatusTemporaryRedirect)
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,3 +439,112 @@ func mustRegisterGWHandler(register registerFunc, ctx context.Context, mux *runt
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Authenticate checks for the presence of a valid token when accessing server-side resources.
|
||||
func (a *ArgoCDServer) authenticate(ctx context.Context) (context.Context, error) {
|
||||
if a.DisableAuth {
|
||||
return ctx, nil
|
||||
}
|
||||
md, ok := metadata.FromIncomingContext(ctx)
|
||||
if !ok {
|
||||
return ctx, ErrNoSession
|
||||
}
|
||||
tokenString := getToken(md)
|
||||
if tokenString == "" {
|
||||
return ctx, ErrNoSession
|
||||
}
|
||||
claims, err := a.sessionMgr.VerifyToken(tokenString)
|
||||
if err != nil {
|
||||
return ctx, status.Errorf(codes.Unauthenticated, "invalid session: %v", err)
|
||||
}
|
||||
// Add claims to the context to inspect for RBAC
|
||||
ctx = context.WithValue(ctx, "claims", claims)
|
||||
return ctx, nil
|
||||
}
|
||||
|
||||
// getToken extracts the token from gRPC metadata or cookie headers
|
||||
func getToken(md metadata.MD) string {
|
||||
// check the "token" metadata
|
||||
tokens, ok := md[apiclient.MetaDataTokenKey]
|
||||
if ok && len(tokens) > 0 {
|
||||
return tokens[0]
|
||||
}
|
||||
// check the legacy key (v0.3.2 and below). 'tokens' was renamed to 'token'
|
||||
tokens, ok = md["tokens"]
|
||||
if ok && len(tokens) > 0 {
|
||||
return tokens[0]
|
||||
}
|
||||
// check the HTTP cookie
|
||||
for _, cookieToken := range md["grpcgateway-cookie"] {
|
||||
header := http.Header{}
|
||||
header.Add("Cookie", cookieToken)
|
||||
request := http.Request{Header: header}
|
||||
token, err := request.Cookie(common.AuthCookieName)
|
||||
if err == nil {
|
||||
return token.Value
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Workaround for https://github.com/golang/go/issues/21955 to support escaped URLs in URL path.
|
||||
type bug21955Workaround struct {
|
||||
handler http.Handler
|
||||
}
|
||||
|
||||
func (bf *bug21955Workaround) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
paths := map[string][]string{
|
||||
"/api/v1/repositories/": {"ksonnet"},
|
||||
"/api/v1/clusters/": {},
|
||||
}
|
||||
for path, subPaths := range paths {
|
||||
if strings.Index(r.URL.Path, path) > -1 {
|
||||
postfix := ""
|
||||
for _, subPath := range subPaths {
|
||||
if strings.LastIndex(r.URL.Path, subPath) == len(r.URL.Path)-len(subPath) {
|
||||
postfix = "/" + subPath
|
||||
r.URL.Path = r.URL.Path[0 : len(r.URL.Path)-len(subPath)-1]
|
||||
break
|
||||
}
|
||||
}
|
||||
r.URL.Path = path + url.QueryEscape(r.URL.Path[len(path):]) + postfix
|
||||
break
|
||||
}
|
||||
}
|
||||
bf.handler.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
func bug21955WorkaroundInterceptor(ctx context.Context, req interface{}, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
|
||||
if rq, ok := req.(*repository.RepoQuery); ok {
|
||||
repo, err := url.QueryUnescape(rq.Repo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rq.Repo = repo
|
||||
} else if rk, ok := req.(*repository.RepoKsonnetQuery); ok {
|
||||
repo, err := url.QueryUnescape(rk.Repo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rk.Repo = repo
|
||||
} else if ru, ok := req.(*repository.RepoUpdateRequest); ok {
|
||||
repo, err := url.QueryUnescape(ru.Repo.Repo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ru.Repo.Repo = repo
|
||||
} else if cq, ok := req.(*cluster.ClusterQuery); ok {
|
||||
server, err := url.QueryUnescape(cq.Server)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cq.Server = server
|
||||
} else if cu, ok := req.(*cluster.ClusterUpdateRequest); ok {
|
||||
server, err := url.QueryUnescape(cu.Cluster.Server)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cu.Cluster.Server = server
|
||||
}
|
||||
return handler(ctx, req)
|
||||
}
|
||||
|
||||
72
server/session/mocks/SessionServiceClient.go
Normal file
72
server/session/mocks/SessionServiceClient.go
Normal file
@@ -0,0 +1,72 @@
|
||||
// Code generated by mockery v1.0.0
|
||||
package mocks
|
||||
|
||||
import context "context"
|
||||
import grpc "google.golang.org/grpc"
|
||||
import mock "github.com/stretchr/testify/mock"
|
||||
import session "github.com/argoproj/argo-cd/server/session"
|
||||
|
||||
// SessionServiceClient is an autogenerated mock type for the SessionServiceClient type
|
||||
type SessionServiceClient struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// Create provides a mock function with given fields: ctx, in, opts
|
||||
func (_m *SessionServiceClient) Create(ctx context.Context, in *session.SessionCreateRequest, opts ...grpc.CallOption) (*session.SessionResponse, error) {
|
||||
_va := make([]interface{}, len(opts))
|
||||
for _i := range opts {
|
||||
_va[_i] = opts[_i]
|
||||
}
|
||||
var _ca []interface{}
|
||||
_ca = append(_ca, ctx, in)
|
||||
_ca = append(_ca, _va...)
|
||||
ret := _m.Called(_ca...)
|
||||
|
||||
var r0 *session.SessionResponse
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *session.SessionCreateRequest, ...grpc.CallOption) *session.SessionResponse); ok {
|
||||
r0 = rf(ctx, in, opts...)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*session.SessionResponse)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *session.SessionCreateRequest, ...grpc.CallOption) error); ok {
|
||||
r1 = rf(ctx, in, opts...)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Delete provides a mock function with given fields: ctx, in, opts
|
||||
func (_m *SessionServiceClient) Delete(ctx context.Context, in *session.SessionDeleteRequest, opts ...grpc.CallOption) (*session.SessionResponse, error) {
|
||||
_va := make([]interface{}, len(opts))
|
||||
for _i := range opts {
|
||||
_va[_i] = opts[_i]
|
||||
}
|
||||
var _ca []interface{}
|
||||
_ca = append(_ca, ctx, in)
|
||||
_ca = append(_ca, _va...)
|
||||
ret := _m.Called(_ca...)
|
||||
|
||||
var r0 *session.SessionResponse
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *session.SessionDeleteRequest, ...grpc.CallOption) *session.SessionResponse); ok {
|
||||
r0 = rf(ctx, in, opts...)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*session.SessionResponse)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *session.SessionDeleteRequest, ...grpc.CallOption) error); ok {
|
||||
r1 = rf(ctx, in, opts...)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
57
server/session/mocks/SessionServiceServer.go
Normal file
57
server/session/mocks/SessionServiceServer.go
Normal file
@@ -0,0 +1,57 @@
|
||||
// Code generated by mockery v1.0.0
|
||||
package mocks
|
||||
|
||||
import context "context"
|
||||
import mock "github.com/stretchr/testify/mock"
|
||||
import session "github.com/argoproj/argo-cd/server/session"
|
||||
|
||||
// SessionServiceServer is an autogenerated mock type for the SessionServiceServer type
|
||||
type SessionServiceServer struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// Create provides a mock function with given fields: _a0, _a1
|
||||
func (_m *SessionServiceServer) Create(_a0 context.Context, _a1 *session.SessionCreateRequest) (*session.SessionResponse, error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
||||
var r0 *session.SessionResponse
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *session.SessionCreateRequest) *session.SessionResponse); ok {
|
||||
r0 = rf(_a0, _a1)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*session.SessionResponse)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *session.SessionCreateRequest) error); ok {
|
||||
r1 = rf(_a0, _a1)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Delete provides a mock function with given fields: _a0, _a1
|
||||
func (_m *SessionServiceServer) Delete(_a0 context.Context, _a1 *session.SessionDeleteRequest) (*session.SessionResponse, error) {
|
||||
ret := _m.Called(_a0, _a1)
|
||||
|
||||
var r0 *session.SessionResponse
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *session.SessionDeleteRequest) *session.SessionResponse); ok {
|
||||
r0 = rf(_a0, _a1)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*session.SessionResponse)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *session.SessionDeleteRequest) error); ok {
|
||||
r1 = rf(_a0, _a1)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
74
server/session/session.go
Normal file
74
server/session/session.go
Normal file
@@ -0,0 +1,74 @@
|
||||
package session
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
|
||||
"github.com/argoproj/argo-cd/util/jwt"
|
||||
sessionmgr "github.com/argoproj/argo-cd/util/session"
|
||||
)
|
||||
|
||||
// Server provides a Session service
|
||||
type Server struct {
|
||||
mgr *sessionmgr.SessionManager
|
||||
}
|
||||
|
||||
// NewServer returns a new instance of the Session service
|
||||
func NewServer(mgr *sessionmgr.SessionManager) *Server {
|
||||
return &Server{
|
||||
mgr: mgr,
|
||||
}
|
||||
}
|
||||
|
||||
// Create generates a non-expiring JWT token signed by ArgoCD. This endpoint is used in two circumstances:
|
||||
// 1. Web/CLI logins for local users (i.e. admin), for when SSO is not configured. In this case,
|
||||
// username/password.
|
||||
// 2. CLI login which completed an OAuth2 login flow but wish to store a permanent token in their config
|
||||
func (s *Server) Create(ctx context.Context, q *SessionCreateRequest) (*SessionResponse, error) {
|
||||
var tokenString string
|
||||
var err error
|
||||
if q.Password != "" {
|
||||
// first case
|
||||
err = s.mgr.VerifyUsernamePassword(q.Username, q.Password)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tokenString, err = s.mgr.Create(q.Username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else if q.Token != "" {
|
||||
// second case
|
||||
claimsIf, err := s.mgr.VerifyToken(q.Token)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
claims, err := jwt.MapClaims(claimsIf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tokenString, err = s.mgr.ReissueClaims(claims)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to resign claims: %v", err)
|
||||
}
|
||||
} else {
|
||||
return nil, status.Errorf(codes.Unauthenticated, "no credentials supplied")
|
||||
}
|
||||
return &SessionResponse{Token: tokenString}, nil
|
||||
}
|
||||
|
||||
// Delete an authentication cookie from the client. This makes sense only for the Web client.
|
||||
func (s *Server) Delete(ctx context.Context, q *SessionDeleteRequest) (*SessionResponse, error) {
|
||||
return &SessionResponse{""}, nil
|
||||
}
|
||||
|
||||
// AuthFuncOverride overrides the authentication function and let us not require auth to receive auth.
|
||||
// Without this function here, ArgoCDServer.authenticate would be invoked and credentials checked.
|
||||
// Since this service is generally invoked when the user has _no_ credentials, that would create a
|
||||
// chicken-and-egg situation if we didn't place this here to allow traffic to pass through.
|
||||
func (s *Server) AuthFuncOverride(ctx context.Context, fullMethodName string) (context.Context, error) {
|
||||
return ctx, nil
|
||||
}
|
||||
751
server/session/session.pb.go
Normal file
751
server/session/session.pb.go
Normal file
@@ -0,0 +1,751 @@
|
||||
// Code generated by protoc-gen-gogo. DO NOT EDIT.
|
||||
// source: server/session/session.proto
|
||||
|
||||
/*
|
||||
Package session is a generated protocol buffer package.
|
||||
|
||||
Session Service
|
||||
|
||||
Session Service API performs CRUD actions against session resources
|
||||
|
||||
It is generated from these files:
|
||||
server/session/session.proto
|
||||
|
||||
It has these top-level messages:
|
||||
SessionCreateRequest
|
||||
SessionDeleteRequest
|
||||
SessionResponse
|
||||
*/
|
||||
package session
|
||||
|
||||
import proto "github.com/gogo/protobuf/proto"
|
||||
import fmt "fmt"
|
||||
import math "math"
|
||||
import _ "github.com/gogo/protobuf/gogoproto"
|
||||
import _ "google.golang.org/genproto/googleapis/api/annotations"
|
||||
import _ "k8s.io/api/core/v1"
|
||||
import _ "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
|
||||
|
||||
import context "golang.org/x/net/context"
|
||||
import grpc "google.golang.org/grpc"
|
||||
|
||||
import io "io"
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package
|
||||
|
||||
// SessionCreateRequest is for logging in.
|
||||
type SessionCreateRequest struct {
|
||||
Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"`
|
||||
Password string `protobuf:"bytes,2,opt,name=password,proto3" json:"password,omitempty"`
|
||||
Token string `protobuf:"bytes,3,opt,name=token,proto3" json:"token,omitempty"`
|
||||
}
|
||||
|
||||
func (m *SessionCreateRequest) Reset() { *m = SessionCreateRequest{} }
|
||||
func (m *SessionCreateRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*SessionCreateRequest) ProtoMessage() {}
|
||||
func (*SessionCreateRequest) Descriptor() ([]byte, []int) { return fileDescriptorSession, []int{0} }
|
||||
|
||||
func (m *SessionCreateRequest) GetUsername() string {
|
||||
if m != nil {
|
||||
return m.Username
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *SessionCreateRequest) GetPassword() string {
|
||||
if m != nil {
|
||||
return m.Password
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *SessionCreateRequest) GetToken() string {
|
||||
if m != nil {
|
||||
return m.Token
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// SessionDeleteRequest is for logging out.
|
||||
type SessionDeleteRequest struct {
|
||||
}
|
||||
|
||||
func (m *SessionDeleteRequest) Reset() { *m = SessionDeleteRequest{} }
|
||||
func (m *SessionDeleteRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*SessionDeleteRequest) ProtoMessage() {}
|
||||
func (*SessionDeleteRequest) Descriptor() ([]byte, []int) { return fileDescriptorSession, []int{1} }
|
||||
|
||||
// SessionResponse wraps the created token or returns an empty string if deleted.
|
||||
type SessionResponse struct {
|
||||
Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"`
|
||||
}
|
||||
|
||||
func (m *SessionResponse) Reset() { *m = SessionResponse{} }
|
||||
func (m *SessionResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*SessionResponse) ProtoMessage() {}
|
||||
func (*SessionResponse) Descriptor() ([]byte, []int) { return fileDescriptorSession, []int{2} }
|
||||
|
||||
func (m *SessionResponse) GetToken() string {
|
||||
if m != nil {
|
||||
return m.Token
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*SessionCreateRequest)(nil), "session.SessionCreateRequest")
|
||||
proto.RegisterType((*SessionDeleteRequest)(nil), "session.SessionDeleteRequest")
|
||||
proto.RegisterType((*SessionResponse)(nil), "session.SessionResponse")
|
||||
}
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ context.Context
|
||||
var _ grpc.ClientConn
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
const _ = grpc.SupportPackageIsVersion4
|
||||
|
||||
// Client API for SessionService service
|
||||
|
||||
type SessionServiceClient interface {
|
||||
// Create a new JWT for authentication.
|
||||
Create(ctx context.Context, in *SessionCreateRequest, opts ...grpc.CallOption) (*SessionResponse, error)
|
||||
// Create a new JWT for authentication.
|
||||
Delete(ctx context.Context, in *SessionDeleteRequest, opts ...grpc.CallOption) (*SessionResponse, error)
|
||||
}
|
||||
|
||||
type sessionServiceClient struct {
|
||||
cc *grpc.ClientConn
|
||||
}
|
||||
|
||||
func NewSessionServiceClient(cc *grpc.ClientConn) SessionServiceClient {
|
||||
return &sessionServiceClient{cc}
|
||||
}
|
||||
|
||||
func (c *sessionServiceClient) Create(ctx context.Context, in *SessionCreateRequest, opts ...grpc.CallOption) (*SessionResponse, error) {
|
||||
out := new(SessionResponse)
|
||||
err := grpc.Invoke(ctx, "/session.SessionService/Create", in, out, c.cc, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *sessionServiceClient) Delete(ctx context.Context, in *SessionDeleteRequest, opts ...grpc.CallOption) (*SessionResponse, error) {
|
||||
out := new(SessionResponse)
|
||||
err := grpc.Invoke(ctx, "/session.SessionService/Delete", in, out, c.cc, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// Server API for SessionService service
|
||||
|
||||
type SessionServiceServer interface {
|
||||
// Create a new JWT for authentication.
|
||||
Create(context.Context, *SessionCreateRequest) (*SessionResponse, error)
|
||||
// Create a new JWT for authentication.
|
||||
Delete(context.Context, *SessionDeleteRequest) (*SessionResponse, error)
|
||||
}
|
||||
|
||||
func RegisterSessionServiceServer(s *grpc.Server, srv SessionServiceServer) {
|
||||
s.RegisterService(&_SessionService_serviceDesc, srv)
|
||||
}
|
||||
|
||||
func _SessionService_Create_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(SessionCreateRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(SessionServiceServer).Create(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/session.SessionService/Create",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(SessionServiceServer).Create(ctx, req.(*SessionCreateRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _SessionService_Delete_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(SessionDeleteRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(SessionServiceServer).Delete(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/session.SessionService/Delete",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(SessionServiceServer).Delete(ctx, req.(*SessionDeleteRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
var _SessionService_serviceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "session.SessionService",
|
||||
HandlerType: (*SessionServiceServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "Create",
|
||||
Handler: _SessionService_Create_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "Delete",
|
||||
Handler: _SessionService_Delete_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "server/session/session.proto",
|
||||
}
|
||||
|
||||
func (m *SessionCreateRequest) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalTo(dAtA)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *SessionCreateRequest) MarshalTo(dAtA []byte) (int, error) {
|
||||
var i int
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if len(m.Username) > 0 {
|
||||
dAtA[i] = 0xa
|
||||
i++
|
||||
i = encodeVarintSession(dAtA, i, uint64(len(m.Username)))
|
||||
i += copy(dAtA[i:], m.Username)
|
||||
}
|
||||
if len(m.Password) > 0 {
|
||||
dAtA[i] = 0x12
|
||||
i++
|
||||
i = encodeVarintSession(dAtA, i, uint64(len(m.Password)))
|
||||
i += copy(dAtA[i:], m.Password)
|
||||
}
|
||||
if len(m.Token) > 0 {
|
||||
dAtA[i] = 0x1a
|
||||
i++
|
||||
i = encodeVarintSession(dAtA, i, uint64(len(m.Token)))
|
||||
i += copy(dAtA[i:], m.Token)
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
|
||||
func (m *SessionDeleteRequest) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalTo(dAtA)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *SessionDeleteRequest) MarshalTo(dAtA []byte) (int, error) {
|
||||
var i int
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
return i, nil
|
||||
}
|
||||
|
||||
func (m *SessionResponse) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalTo(dAtA)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *SessionResponse) MarshalTo(dAtA []byte) (int, error) {
|
||||
var i int
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if len(m.Token) > 0 {
|
||||
dAtA[i] = 0xa
|
||||
i++
|
||||
i = encodeVarintSession(dAtA, i, uint64(len(m.Token)))
|
||||
i += copy(dAtA[i:], m.Token)
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
|
||||
func encodeVarintSession(dAtA []byte, offset int, v uint64) int {
|
||||
for v >= 1<<7 {
|
||||
dAtA[offset] = uint8(v&0x7f | 0x80)
|
||||
v >>= 7
|
||||
offset++
|
||||
}
|
||||
dAtA[offset] = uint8(v)
|
||||
return offset + 1
|
||||
}
|
||||
func (m *SessionCreateRequest) Size() (n int) {
|
||||
var l int
|
||||
_ = l
|
||||
l = len(m.Username)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovSession(uint64(l))
|
||||
}
|
||||
l = len(m.Password)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovSession(uint64(l))
|
||||
}
|
||||
l = len(m.Token)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovSession(uint64(l))
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *SessionDeleteRequest) Size() (n int) {
|
||||
var l int
|
||||
_ = l
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *SessionResponse) Size() (n int) {
|
||||
var l int
|
||||
_ = l
|
||||
l = len(m.Token)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovSession(uint64(l))
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func sovSession(x uint64) (n int) {
|
||||
for {
|
||||
n++
|
||||
x >>= 7
|
||||
if x == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return n
|
||||
}
|
||||
func sozSession(x uint64) (n int) {
|
||||
return sovSession(uint64((x << 1) ^ uint64((int64(x) >> 63))))
|
||||
}
|
||||
func (m *SessionCreateRequest) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowSession
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: SessionCreateRequest: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: SessionCreateRequest: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Username", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowSession
|
||||
}
|
||||
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 ErrInvalidLengthSession
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Username = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
case 2:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Password", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowSession
|
||||
}
|
||||
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 ErrInvalidLengthSession
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Password = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
case 3:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Token", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowSession
|
||||
}
|
||||
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 ErrInvalidLengthSession
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Token = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipSession(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if skippy < 0 {
|
||||
return ErrInvalidLengthSession
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *SessionDeleteRequest) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowSession
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: SessionDeleteRequest: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: SessionDeleteRequest: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipSession(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if skippy < 0 {
|
||||
return ErrInvalidLengthSession
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *SessionResponse) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowSession
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: SessionResponse: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: SessionResponse: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Token", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowSession
|
||||
}
|
||||
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 ErrInvalidLengthSession
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Token = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipSession(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if skippy < 0 {
|
||||
return ErrInvalidLengthSession
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func skipSession(dAtA []byte) (n int, err error) {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowSession
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
wireType := int(wire & 0x7)
|
||||
switch wireType {
|
||||
case 0:
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowSession
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx++
|
||||
if dAtA[iNdEx-1] < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return iNdEx, nil
|
||||
case 1:
|
||||
iNdEx += 8
|
||||
return iNdEx, nil
|
||||
case 2:
|
||||
var length int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowSession
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
length |= (int(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
iNdEx += length
|
||||
if length < 0 {
|
||||
return 0, ErrInvalidLengthSession
|
||||
}
|
||||
return iNdEx, nil
|
||||
case 3:
|
||||
for {
|
||||
var innerWire uint64
|
||||
var start int = iNdEx
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowSession
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
innerWire |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
innerWireType := int(innerWire & 0x7)
|
||||
if innerWireType == 4 {
|
||||
break
|
||||
}
|
||||
next, err := skipSession(dAtA[start:])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
iNdEx = start + next
|
||||
}
|
||||
return iNdEx, nil
|
||||
case 4:
|
||||
return iNdEx, nil
|
||||
case 5:
|
||||
iNdEx += 4
|
||||
return iNdEx, nil
|
||||
default:
|
||||
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
|
||||
}
|
||||
}
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
var (
|
||||
ErrInvalidLengthSession = fmt.Errorf("proto: negative length found during unmarshaling")
|
||||
ErrIntOverflowSession = fmt.Errorf("proto: integer overflow")
|
||||
)
|
||||
|
||||
func init() { proto.RegisterFile("server/session/session.proto", fileDescriptorSession) }
|
||||
|
||||
var fileDescriptorSession = []byte{
|
||||
// 356 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x92, 0xb1, 0x4e, 0xeb, 0x30,
|
||||
0x14, 0x86, 0xe5, 0x5e, 0xdd, 0xde, 0x7b, 0x3d, 0xdc, 0x8a, 0x28, 0x82, 0x28, 0x2a, 0x15, 0xca,
|
||||
0x02, 0xaa, 0x44, 0xac, 0xc2, 0x52, 0x31, 0x02, 0x0b, 0x6b, 0xbb, 0x55, 0x62, 0x70, 0x93, 0xa3,
|
||||
0xd4, 0x34, 0xf5, 0x31, 0xb6, 0x1b, 0x76, 0x5e, 0x81, 0x97, 0x42, 0x62, 0x41, 0xe2, 0x05, 0x50,
|
||||
0xc5, 0x83, 0xa0, 0x3a, 0x49, 0xa1, 0x2d, 0xea, 0x14, 0xff, 0xfe, 0x9d, 0xef, 0x3f, 0x3e, 0xc7,
|
||||
0xb4, 0x6d, 0x40, 0x17, 0xa0, 0x99, 0x01, 0x63, 0x04, 0xca, 0xfa, 0x1b, 0x2b, 0x8d, 0x16, 0xbd,
|
||||
0x3f, 0x95, 0x0c, 0xfd, 0x0c, 0x33, 0x74, 0x7b, 0x6c, 0xb9, 0x2a, 0xed, 0xb0, 0x9d, 0x21, 0x66,
|
||||
0x39, 0x30, 0xae, 0x04, 0xe3, 0x52, 0xa2, 0xe5, 0x56, 0xa0, 0x34, 0x95, 0x1b, 0x4d, 0xfb, 0x26,
|
||||
0x16, 0xe8, 0xdc, 0x04, 0x35, 0xb0, 0xa2, 0xc7, 0x32, 0x90, 0xa0, 0xb9, 0x85, 0xb4, 0x3a, 0x73,
|
||||
0x93, 0x09, 0x3b, 0x99, 0x8f, 0xe3, 0x04, 0x67, 0x8c, 0x6b, 0x17, 0x71, 0xe7, 0x16, 0xa7, 0x49,
|
||||
0xca, 0xd4, 0x34, 0x5b, 0xfe, 0x6c, 0x18, 0x57, 0x2a, 0x17, 0x89, 0x83, 0xb3, 0xa2, 0xc7, 0x73,
|
||||
0x35, 0xe1, 0x5b, 0xa8, 0x28, 0xa5, 0xfe, 0xb0, 0xac, 0xf6, 0x4a, 0x03, 0xb7, 0x30, 0x80, 0xfb,
|
||||
0x39, 0x18, 0xeb, 0x85, 0xf4, 0xef, 0xdc, 0x80, 0x96, 0x7c, 0x06, 0x01, 0x39, 0x22, 0x27, 0xff,
|
||||
0x06, 0x2b, 0xbd, 0xf4, 0x14, 0x37, 0xe6, 0x01, 0x75, 0x1a, 0x34, 0x4a, 0xaf, 0xd6, 0x9e, 0x4f,
|
||||
0x7f, 0x5b, 0x9c, 0x82, 0x0c, 0x7e, 0x39, 0xa3, 0x14, 0xd1, 0xfe, 0x2a, 0xe5, 0x1a, 0x72, 0x58,
|
||||
0xa5, 0x44, 0xc7, 0xb4, 0x55, 0xed, 0x0f, 0xc0, 0x28, 0x94, 0x06, 0xbe, 0x00, 0xe4, 0x1b, 0xe0,
|
||||
0xec, 0x85, 0xd0, 0xff, 0xd5, 0xc9, 0x21, 0xe8, 0x42, 0x24, 0xe0, 0xdd, 0xd2, 0x66, 0x59, 0xb2,
|
||||
0x77, 0x18, 0xd7, 0xfd, 0xff, 0xe9, 0x2a, 0x61, 0xb0, 0x69, 0xd7, 0x59, 0x51, 0xf8, 0xf8, 0xf6,
|
||||
0xf1, 0xd4, 0xf0, 0xa3, 0x96, 0xeb, 0x76, 0xd1, 0xab, 0xe7, 0x78, 0x41, 0xba, 0xde, 0x88, 0x36,
|
||||
0xcb, 0x5a, 0xb7, 0xf1, 0x6b, 0x77, 0xd8, 0x81, 0x3f, 0x70, 0xf8, 0xbd, 0xee, 0x26, 0xfe, 0xb2,
|
||||
0xff, 0xbc, 0xe8, 0x90, 0xd7, 0x45, 0x87, 0xbc, 0x2f, 0x3a, 0x64, 0xd4, 0xdd, 0x35, 0xcd, 0xf5,
|
||||
0x87, 0x36, 0x6e, 0xba, 0xa9, 0x9d, 0x7f, 0x06, 0x00, 0x00, 0xff, 0xff, 0x9e, 0x28, 0x53, 0xc6,
|
||||
0x81, 0x02, 0x00, 0x00,
|
||||
}
|
||||
162
server/session/session.pb.gw.go
Normal file
162
server/session/session.pb.gw.go
Normal file
@@ -0,0 +1,162 @@
|
||||
// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT.
|
||||
// source: server/session/session.proto
|
||||
|
||||
/*
|
||||
Package session is a reverse proxy.
|
||||
|
||||
It translates gRPC into RESTful JSON APIs.
|
||||
*/
|
||||
package session
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/grpc-ecosystem/grpc-gateway/runtime"
|
||||
"github.com/grpc-ecosystem/grpc-gateway/utilities"
|
||||
"golang.org/x/net/context"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/grpclog"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
var _ codes.Code
|
||||
var _ io.Reader
|
||||
var _ status.Status
|
||||
var _ = runtime.String
|
||||
var _ = utilities.NewDoubleArray
|
||||
|
||||
func request_SessionService_Create_0(ctx context.Context, marshaler runtime.Marshaler, client SessionServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq SessionCreateRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := client.Create(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func request_SessionService_Delete_0(ctx context.Context, marshaler runtime.Marshaler, client SessionServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq SessionDeleteRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
msg, err := client.Delete(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
// RegisterSessionServiceHandlerFromEndpoint is same as RegisterSessionServiceHandler but
|
||||
// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
|
||||
func RegisterSessionServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
|
||||
conn, err := grpc.Dial(endpoint, opts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
if cerr := conn.Close(); cerr != nil {
|
||||
grpclog.Printf("Failed to close conn to %s: %v", endpoint, cerr)
|
||||
}
|
||||
return
|
||||
}
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
if cerr := conn.Close(); cerr != nil {
|
||||
grpclog.Printf("Failed to close conn to %s: %v", endpoint, cerr)
|
||||
}
|
||||
}()
|
||||
}()
|
||||
|
||||
return RegisterSessionServiceHandler(ctx, mux, conn)
|
||||
}
|
||||
|
||||
// RegisterSessionServiceHandler registers the http handlers for service SessionService to "mux".
|
||||
// The handlers forward requests to the grpc endpoint over "conn".
|
||||
func RegisterSessionServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
|
||||
return RegisterSessionServiceHandlerClient(ctx, mux, NewSessionServiceClient(conn))
|
||||
}
|
||||
|
||||
// RegisterSessionServiceHandler registers the http handlers for service SessionService to "mux".
|
||||
// The handlers forward requests to the grpc endpoint over the given implementation of "SessionServiceClient".
|
||||
// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "SessionServiceClient"
|
||||
// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in
|
||||
// "SessionServiceClient" to call the correct interceptors.
|
||||
func RegisterSessionServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client SessionServiceClient) error {
|
||||
|
||||
mux.Handle("POST", pattern_SessionService_Create_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
if cn, ok := w.(http.CloseNotifier); ok {
|
||||
go func(done <-chan struct{}, closed <-chan bool) {
|
||||
select {
|
||||
case <-done:
|
||||
case <-closed:
|
||||
cancel()
|
||||
}
|
||||
}(ctx.Done(), cn.CloseNotify())
|
||||
}
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_SessionService_Create_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_SessionService_Create_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("DELETE", pattern_SessionService_Delete_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
if cn, ok := w.(http.CloseNotifier); ok {
|
||||
go func(done <-chan struct{}, closed <-chan bool) {
|
||||
select {
|
||||
case <-done:
|
||||
case <-closed:
|
||||
cancel()
|
||||
}
|
||||
}(ctx.Done(), cn.CloseNotify())
|
||||
}
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_SessionService_Delete_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_SessionService_Delete_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
pattern_SessionService_Create_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "session"}, ""))
|
||||
|
||||
pattern_SessionService_Delete_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "session"}, ""))
|
||||
)
|
||||
|
||||
var (
|
||||
forward_SessionService_Create_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_SessionService_Delete_0 = runtime.ForwardResponseMessage
|
||||
)
|
||||
47
server/session/session.proto
Normal file
47
server/session/session.proto
Normal file
@@ -0,0 +1,47 @@
|
||||
syntax = "proto3";
|
||||
option go_package = "github.com/argoproj/argo-cd/server/session";
|
||||
|
||||
// Session Service
|
||||
//
|
||||
// Session Service API performs CRUD actions against session resources
|
||||
package session;
|
||||
|
||||
import "gogoproto/gogo.proto";
|
||||
import "google/api/annotations.proto";
|
||||
import "k8s.io/api/core/v1/generated.proto";
|
||||
import "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1/generated.proto";
|
||||
|
||||
|
||||
// SessionCreateRequest is for logging in.
|
||||
message SessionCreateRequest {
|
||||
string username = 1;
|
||||
string password = 2;
|
||||
string token = 3;
|
||||
}
|
||||
|
||||
// SessionDeleteRequest is for logging out.
|
||||
message SessionDeleteRequest {}
|
||||
|
||||
// SessionResponse wraps the created token or returns an empty string if deleted.
|
||||
message SessionResponse {
|
||||
string token = 1;
|
||||
}
|
||||
|
||||
// SessionService
|
||||
service SessionService {
|
||||
|
||||
// Create a new JWT for authentication.
|
||||
rpc Create(SessionCreateRequest) returns (SessionResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/api/v1/session"
|
||||
body: "*"
|
||||
};
|
||||
}
|
||||
|
||||
// Create a new JWT for authentication.
|
||||
rpc Delete(SessionDeleteRequest) returns (SessionResponse) {
|
||||
option (google.api.http) = {
|
||||
delete: "/api/v1/session"
|
||||
};
|
||||
}
|
||||
}
|
||||
41
server/settings/settings.go
Normal file
41
server/settings/settings.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package settings
|
||||
|
||||
import (
|
||||
"github.com/argoproj/argo-cd/util/settings"
|
||||
"github.com/ghodss/yaml"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// Server provides a Settings service
|
||||
type Server struct {
|
||||
mgr *settings.SettingsManager
|
||||
}
|
||||
|
||||
// NewServer returns a new instance of the Repository service
|
||||
func NewServer(mgr *settings.SettingsManager) *Server {
|
||||
return &Server{
|
||||
mgr: mgr,
|
||||
}
|
||||
}
|
||||
|
||||
// Get returns ArgoCD settings
|
||||
func (s *Server) Get(ctx context.Context, q *SettingsQuery) (*Settings, error) {
|
||||
argoCDSettings, err := s.mgr.GetSettings()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
set := Settings{
|
||||
URL: argoCDSettings.URL,
|
||||
}
|
||||
var cfg DexConfig
|
||||
err = yaml.Unmarshal([]byte(argoCDSettings.DexConfig), &cfg)
|
||||
if err == nil {
|
||||
set.DexConfig = &cfg
|
||||
}
|
||||
return &set, nil
|
||||
}
|
||||
|
||||
// AuthFuncOverride disables authentication for settings service
|
||||
func (s *Server) AuthFuncOverride(ctx context.Context, fullMethodName string) (context.Context, error) {
|
||||
return ctx, nil
|
||||
}
|
||||
859
server/settings/settings.pb.go
Normal file
859
server/settings/settings.pb.go
Normal file
@@ -0,0 +1,859 @@
|
||||
// Code generated by protoc-gen-gogo. DO NOT EDIT.
|
||||
// source: server/settings/settings.proto
|
||||
|
||||
/*
|
||||
Package settings is a generated protocol buffer package.
|
||||
|
||||
Settings Service
|
||||
|
||||
Settings Service API retrives ArgoCD settings
|
||||
|
||||
It is generated from these files:
|
||||
server/settings/settings.proto
|
||||
|
||||
It has these top-level messages:
|
||||
SettingsQuery
|
||||
Settings
|
||||
DexConfig
|
||||
Connector
|
||||
*/
|
||||
package settings
|
||||
|
||||
import proto "github.com/gogo/protobuf/proto"
|
||||
import fmt "fmt"
|
||||
import math "math"
|
||||
import _ "github.com/gogo/protobuf/gogoproto"
|
||||
import _ "google.golang.org/genproto/googleapis/api/annotations"
|
||||
|
||||
import context "golang.org/x/net/context"
|
||||
import grpc "google.golang.org/grpc"
|
||||
|
||||
import io "io"
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package
|
||||
|
||||
// SettingsQuery is a query for ArgoCD settings
|
||||
type SettingsQuery struct {
|
||||
}
|
||||
|
||||
func (m *SettingsQuery) Reset() { *m = SettingsQuery{} }
|
||||
func (m *SettingsQuery) String() string { return proto.CompactTextString(m) }
|
||||
func (*SettingsQuery) ProtoMessage() {}
|
||||
func (*SettingsQuery) Descriptor() ([]byte, []int) { return fileDescriptorSettings, []int{0} }
|
||||
|
||||
type Settings struct {
|
||||
URL string `protobuf:"bytes,1,opt,name=url,proto3" json:"url,omitempty"`
|
||||
DexConfig *DexConfig `protobuf:"bytes,2,opt,name=dexConfig" json:"dexConfig,omitempty"`
|
||||
}
|
||||
|
||||
func (m *Settings) Reset() { *m = Settings{} }
|
||||
func (m *Settings) String() string { return proto.CompactTextString(m) }
|
||||
func (*Settings) ProtoMessage() {}
|
||||
func (*Settings) Descriptor() ([]byte, []int) { return fileDescriptorSettings, []int{1} }
|
||||
|
||||
func (m *Settings) GetURL() string {
|
||||
if m != nil {
|
||||
return m.URL
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Settings) GetDexConfig() *DexConfig {
|
||||
if m != nil {
|
||||
return m.DexConfig
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type DexConfig struct {
|
||||
Connectors []*Connector `protobuf:"bytes,1,rep,name=connectors" json:"connectors,omitempty"`
|
||||
}
|
||||
|
||||
func (m *DexConfig) Reset() { *m = DexConfig{} }
|
||||
func (m *DexConfig) String() string { return proto.CompactTextString(m) }
|
||||
func (*DexConfig) ProtoMessage() {}
|
||||
func (*DexConfig) Descriptor() ([]byte, []int) { return fileDescriptorSettings, []int{2} }
|
||||
|
||||
func (m *DexConfig) GetConnectors() []*Connector {
|
||||
if m != nil {
|
||||
return m.Connectors
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Connector struct {
|
||||
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
||||
Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"`
|
||||
}
|
||||
|
||||
func (m *Connector) Reset() { *m = Connector{} }
|
||||
func (m *Connector) String() string { return proto.CompactTextString(m) }
|
||||
func (*Connector) ProtoMessage() {}
|
||||
func (*Connector) Descriptor() ([]byte, []int) { return fileDescriptorSettings, []int{3} }
|
||||
|
||||
func (m *Connector) GetName() string {
|
||||
if m != nil {
|
||||
return m.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Connector) GetType() string {
|
||||
if m != nil {
|
||||
return m.Type
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*SettingsQuery)(nil), "cluster.SettingsQuery")
|
||||
proto.RegisterType((*Settings)(nil), "cluster.Settings")
|
||||
proto.RegisterType((*DexConfig)(nil), "cluster.DexConfig")
|
||||
proto.RegisterType((*Connector)(nil), "cluster.Connector")
|
||||
}
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ context.Context
|
||||
var _ grpc.ClientConn
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
const _ = grpc.SupportPackageIsVersion4
|
||||
|
||||
// Client API for SettingsService service
|
||||
|
||||
type SettingsServiceClient interface {
|
||||
// Get returns ArgoCD settings
|
||||
Get(ctx context.Context, in *SettingsQuery, opts ...grpc.CallOption) (*Settings, error)
|
||||
}
|
||||
|
||||
type settingsServiceClient struct {
|
||||
cc *grpc.ClientConn
|
||||
}
|
||||
|
||||
func NewSettingsServiceClient(cc *grpc.ClientConn) SettingsServiceClient {
|
||||
return &settingsServiceClient{cc}
|
||||
}
|
||||
|
||||
func (c *settingsServiceClient) Get(ctx context.Context, in *SettingsQuery, opts ...grpc.CallOption) (*Settings, error) {
|
||||
out := new(Settings)
|
||||
err := grpc.Invoke(ctx, "/cluster.SettingsService/Get", in, out, c.cc, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// Server API for SettingsService service
|
||||
|
||||
type SettingsServiceServer interface {
|
||||
// Get returns ArgoCD settings
|
||||
Get(context.Context, *SettingsQuery) (*Settings, error)
|
||||
}
|
||||
|
||||
func RegisterSettingsServiceServer(s *grpc.Server, srv SettingsServiceServer) {
|
||||
s.RegisterService(&_SettingsService_serviceDesc, srv)
|
||||
}
|
||||
|
||||
func _SettingsService_Get_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(SettingsQuery)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(SettingsServiceServer).Get(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/cluster.SettingsService/Get",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(SettingsServiceServer).Get(ctx, req.(*SettingsQuery))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
var _SettingsService_serviceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "cluster.SettingsService",
|
||||
HandlerType: (*SettingsServiceServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "Get",
|
||||
Handler: _SettingsService_Get_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "server/settings/settings.proto",
|
||||
}
|
||||
|
||||
func (m *SettingsQuery) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalTo(dAtA)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *SettingsQuery) MarshalTo(dAtA []byte) (int, error) {
|
||||
var i int
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
return i, nil
|
||||
}
|
||||
|
||||
func (m *Settings) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalTo(dAtA)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *Settings) MarshalTo(dAtA []byte) (int, error) {
|
||||
var i int
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if len(m.URL) > 0 {
|
||||
dAtA[i] = 0xa
|
||||
i++
|
||||
i = encodeVarintSettings(dAtA, i, uint64(len(m.URL)))
|
||||
i += copy(dAtA[i:], m.URL)
|
||||
}
|
||||
if m.DexConfig != nil {
|
||||
dAtA[i] = 0x12
|
||||
i++
|
||||
i = encodeVarintSettings(dAtA, i, uint64(m.DexConfig.Size()))
|
||||
n1, err := m.DexConfig.MarshalTo(dAtA[i:])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
i += n1
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
|
||||
func (m *DexConfig) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalTo(dAtA)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *DexConfig) MarshalTo(dAtA []byte) (int, error) {
|
||||
var i int
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if len(m.Connectors) > 0 {
|
||||
for _, msg := range m.Connectors {
|
||||
dAtA[i] = 0xa
|
||||
i++
|
||||
i = encodeVarintSettings(dAtA, i, uint64(msg.Size()))
|
||||
n, err := msg.MarshalTo(dAtA[i:])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
i += n
|
||||
}
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
|
||||
func (m *Connector) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalTo(dAtA)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *Connector) MarshalTo(dAtA []byte) (int, error) {
|
||||
var i int
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if len(m.Name) > 0 {
|
||||
dAtA[i] = 0xa
|
||||
i++
|
||||
i = encodeVarintSettings(dAtA, i, uint64(len(m.Name)))
|
||||
i += copy(dAtA[i:], m.Name)
|
||||
}
|
||||
if len(m.Type) > 0 {
|
||||
dAtA[i] = 0x12
|
||||
i++
|
||||
i = encodeVarintSettings(dAtA, i, uint64(len(m.Type)))
|
||||
i += copy(dAtA[i:], m.Type)
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
|
||||
func encodeVarintSettings(dAtA []byte, offset int, v uint64) int {
|
||||
for v >= 1<<7 {
|
||||
dAtA[offset] = uint8(v&0x7f | 0x80)
|
||||
v >>= 7
|
||||
offset++
|
||||
}
|
||||
dAtA[offset] = uint8(v)
|
||||
return offset + 1
|
||||
}
|
||||
func (m *SettingsQuery) Size() (n int) {
|
||||
var l int
|
||||
_ = l
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *Settings) Size() (n int) {
|
||||
var l int
|
||||
_ = l
|
||||
l = len(m.URL)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovSettings(uint64(l))
|
||||
}
|
||||
if m.DexConfig != nil {
|
||||
l = m.DexConfig.Size()
|
||||
n += 1 + l + sovSettings(uint64(l))
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *DexConfig) Size() (n int) {
|
||||
var l int
|
||||
_ = l
|
||||
if len(m.Connectors) > 0 {
|
||||
for _, e := range m.Connectors {
|
||||
l = e.Size()
|
||||
n += 1 + l + sovSettings(uint64(l))
|
||||
}
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *Connector) Size() (n int) {
|
||||
var l int
|
||||
_ = l
|
||||
l = len(m.Name)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovSettings(uint64(l))
|
||||
}
|
||||
l = len(m.Type)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovSettings(uint64(l))
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func sovSettings(x uint64) (n int) {
|
||||
for {
|
||||
n++
|
||||
x >>= 7
|
||||
if x == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return n
|
||||
}
|
||||
func sozSettings(x uint64) (n int) {
|
||||
return sovSettings(uint64((x << 1) ^ uint64((int64(x) >> 63))))
|
||||
}
|
||||
func (m *SettingsQuery) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowSettings
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: SettingsQuery: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: SettingsQuery: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipSettings(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if skippy < 0 {
|
||||
return ErrInvalidLengthSettings
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *Settings) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowSettings
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: Settings: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: Settings: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field URL", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowSettings
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthSettings
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.URL = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
case 2:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field DexConfig", wireType)
|
||||
}
|
||||
var msglen int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowSettings
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
msglen |= (int(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if msglen < 0 {
|
||||
return ErrInvalidLengthSettings
|
||||
}
|
||||
postIndex := iNdEx + msglen
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
if m.DexConfig == nil {
|
||||
m.DexConfig = &DexConfig{}
|
||||
}
|
||||
if err := m.DexConfig.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
|
||||
return err
|
||||
}
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipSettings(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if skippy < 0 {
|
||||
return ErrInvalidLengthSettings
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *DexConfig) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowSettings
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: DexConfig: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: DexConfig: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Connectors", wireType)
|
||||
}
|
||||
var msglen int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowSettings
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
msglen |= (int(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if msglen < 0 {
|
||||
return ErrInvalidLengthSettings
|
||||
}
|
||||
postIndex := iNdEx + msglen
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Connectors = append(m.Connectors, &Connector{})
|
||||
if err := m.Connectors[len(m.Connectors)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
|
||||
return err
|
||||
}
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipSettings(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if skippy < 0 {
|
||||
return ErrInvalidLengthSettings
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *Connector) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowSettings
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: Connector: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: Connector: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowSettings
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthSettings
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Name = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
case 2:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Type", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowSettings
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthSettings
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Type = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipSettings(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if skippy < 0 {
|
||||
return ErrInvalidLengthSettings
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func skipSettings(dAtA []byte) (n int, err error) {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowSettings
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
wireType := int(wire & 0x7)
|
||||
switch wireType {
|
||||
case 0:
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowSettings
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx++
|
||||
if dAtA[iNdEx-1] < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return iNdEx, nil
|
||||
case 1:
|
||||
iNdEx += 8
|
||||
return iNdEx, nil
|
||||
case 2:
|
||||
var length int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowSettings
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
length |= (int(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
iNdEx += length
|
||||
if length < 0 {
|
||||
return 0, ErrInvalidLengthSettings
|
||||
}
|
||||
return iNdEx, nil
|
||||
case 3:
|
||||
for {
|
||||
var innerWire uint64
|
||||
var start int = iNdEx
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowSettings
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
innerWire |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
innerWireType := int(innerWire & 0x7)
|
||||
if innerWireType == 4 {
|
||||
break
|
||||
}
|
||||
next, err := skipSettings(dAtA[start:])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
iNdEx = start + next
|
||||
}
|
||||
return iNdEx, nil
|
||||
case 4:
|
||||
return iNdEx, nil
|
||||
case 5:
|
||||
iNdEx += 4
|
||||
return iNdEx, nil
|
||||
default:
|
||||
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
|
||||
}
|
||||
}
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
var (
|
||||
ErrInvalidLengthSettings = fmt.Errorf("proto: negative length found during unmarshaling")
|
||||
ErrIntOverflowSettings = fmt.Errorf("proto: integer overflow")
|
||||
)
|
||||
|
||||
func init() { proto.RegisterFile("server/settings/settings.proto", fileDescriptorSettings) }
|
||||
|
||||
var fileDescriptorSettings = []byte{
|
||||
// 322 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x91, 0x41, 0x4b, 0xc3, 0x40,
|
||||
0x10, 0x85, 0xd9, 0x46, 0xac, 0x19, 0x91, 0xea, 0x22, 0x12, 0x8b, 0xc4, 0x92, 0x53, 0x41, 0x4c,
|
||||
0xb4, 0x3d, 0x79, 0x12, 0x5a, 0x41, 0x10, 0x2f, 0xa6, 0x88, 0x20, 0x78, 0x48, 0xd3, 0x71, 0x8d,
|
||||
0xb4, 0x3b, 0x65, 0xb3, 0x29, 0xf6, 0xea, 0x5f, 0xf0, 0x4f, 0x79, 0x14, 0xbc, 0x8b, 0x04, 0x7f,
|
||||
0x88, 0x74, 0xdb, 0x44, 0xab, 0xb7, 0xc7, 0xf7, 0x66, 0x92, 0xb7, 0xf3, 0xc0, 0x4d, 0x51, 0x4d,
|
||||
0x50, 0x05, 0x29, 0x6a, 0x9d, 0x48, 0x91, 0x96, 0xc2, 0x1f, 0x2b, 0xd2, 0xc4, 0xab, 0xf1, 0x30,
|
||||
0x4b, 0x35, 0xaa, 0xfa, 0xb6, 0x20, 0x41, 0x86, 0x05, 0x33, 0x35, 0xb7, 0xeb, 0x7b, 0x82, 0x48,
|
||||
0x0c, 0x31, 0x88, 0xc6, 0x49, 0x10, 0x49, 0x49, 0x3a, 0xd2, 0x09, 0xc9, 0xc5, 0xb2, 0x57, 0x83,
|
||||
0x8d, 0xde, 0xe2, 0x73, 0x57, 0x19, 0xaa, 0xa9, 0x77, 0x03, 0x6b, 0x05, 0xe0, 0xbb, 0x60, 0x65,
|
||||
0x6a, 0xe8, 0xb0, 0x06, 0x6b, 0xda, 0x9d, 0x6a, 0xfe, 0xb1, 0x6f, 0x5d, 0x87, 0x97, 0xe1, 0x8c,
|
||||
0xf1, 0x23, 0xb0, 0x07, 0xf8, 0xd4, 0x25, 0x79, 0x9f, 0x08, 0xa7, 0xd2, 0x60, 0xcd, 0xf5, 0x16,
|
||||
0xf7, 0x17, 0x41, 0xfc, 0xb3, 0xc2, 0x09, 0x7f, 0x86, 0xbc, 0x53, 0xb0, 0x4b, 0xce, 0x5b, 0x00,
|
||||
0x31, 0x49, 0x89, 0xb1, 0x26, 0x95, 0x3a, 0xac, 0x61, 0x2d, 0xed, 0x77, 0x0b, 0x2b, 0xfc, 0x35,
|
||||
0xe5, 0xb5, 0xc1, 0x2e, 0x0d, 0xce, 0x61, 0x45, 0x46, 0x23, 0x9c, 0x67, 0x0b, 0x8d, 0x9e, 0x31,
|
||||
0x3d, 0x1d, 0xa3, 0x89, 0x63, 0x87, 0x46, 0xb7, 0xee, 0xa0, 0x56, 0x3c, 0xa7, 0x87, 0x6a, 0x92,
|
||||
0xc4, 0xc8, 0x2f, 0xc0, 0x3a, 0x47, 0xcd, 0x77, 0xca, 0xdf, 0x2d, 0x1d, 0xa0, 0xbe, 0xf5, 0x8f,
|
||||
0x7b, 0xce, 0xf3, 0xfb, 0xd7, 0x4b, 0x85, 0xf3, 0x4d, 0x73, 0xc4, 0xc9, 0x71, 0xd9, 0x40, 0xe7,
|
||||
0xe4, 0x35, 0x77, 0xd9, 0x5b, 0xee, 0xb2, 0xcf, 0xdc, 0x65, 0xb7, 0x07, 0x22, 0xd1, 0x0f, 0x59,
|
||||
0xdf, 0x8f, 0x69, 0x14, 0x44, 0xca, 0x74, 0xf1, 0x68, 0xc4, 0x61, 0x3c, 0x08, 0xfe, 0xb4, 0xd8,
|
||||
0x5f, 0x35, 0x05, 0xb4, 0xbf, 0x03, 0x00, 0x00, 0xff, 0xff, 0xef, 0x0e, 0xd5, 0xb9, 0xdf, 0x01,
|
||||
0x00, 0x00,
|
||||
}
|
||||
116
server/settings/settings.pb.gw.go
Normal file
116
server/settings/settings.pb.gw.go
Normal file
@@ -0,0 +1,116 @@
|
||||
// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT.
|
||||
// source: server/settings/settings.proto
|
||||
|
||||
/*
|
||||
Package settings is a reverse proxy.
|
||||
|
||||
It translates gRPC into RESTful JSON APIs.
|
||||
*/
|
||||
package settings
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/grpc-ecosystem/grpc-gateway/runtime"
|
||||
"github.com/grpc-ecosystem/grpc-gateway/utilities"
|
||||
"golang.org/x/net/context"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/grpclog"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
var _ codes.Code
|
||||
var _ io.Reader
|
||||
var _ status.Status
|
||||
var _ = runtime.String
|
||||
var _ = utilities.NewDoubleArray
|
||||
|
||||
func request_SettingsService_Get_0(ctx context.Context, marshaler runtime.Marshaler, client SettingsServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq SettingsQuery
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
msg, err := client.Get(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
// RegisterSettingsServiceHandlerFromEndpoint is same as RegisterSettingsServiceHandler but
|
||||
// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
|
||||
func RegisterSettingsServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
|
||||
conn, err := grpc.Dial(endpoint, opts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
if cerr := conn.Close(); cerr != nil {
|
||||
grpclog.Printf("Failed to close conn to %s: %v", endpoint, cerr)
|
||||
}
|
||||
return
|
||||
}
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
if cerr := conn.Close(); cerr != nil {
|
||||
grpclog.Printf("Failed to close conn to %s: %v", endpoint, cerr)
|
||||
}
|
||||
}()
|
||||
}()
|
||||
|
||||
return RegisterSettingsServiceHandler(ctx, mux, conn)
|
||||
}
|
||||
|
||||
// RegisterSettingsServiceHandler registers the http handlers for service SettingsService to "mux".
|
||||
// The handlers forward requests to the grpc endpoint over "conn".
|
||||
func RegisterSettingsServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
|
||||
return RegisterSettingsServiceHandlerClient(ctx, mux, NewSettingsServiceClient(conn))
|
||||
}
|
||||
|
||||
// RegisterSettingsServiceHandler registers the http handlers for service SettingsService to "mux".
|
||||
// The handlers forward requests to the grpc endpoint over the given implementation of "SettingsServiceClient".
|
||||
// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "SettingsServiceClient"
|
||||
// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in
|
||||
// "SettingsServiceClient" to call the correct interceptors.
|
||||
func RegisterSettingsServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client SettingsServiceClient) error {
|
||||
|
||||
mux.Handle("GET", pattern_SettingsService_Get_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
if cn, ok := w.(http.CloseNotifier); ok {
|
||||
go func(done <-chan struct{}, closed <-chan bool) {
|
||||
select {
|
||||
case <-done:
|
||||
case <-closed:
|
||||
cancel()
|
||||
}
|
||||
}(ctx.Done(), cn.CloseNotify())
|
||||
}
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_SettingsService_Get_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_SettingsService_Get_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
pattern_SettingsService_Get_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "settings"}, ""))
|
||||
)
|
||||
|
||||
var (
|
||||
forward_SettingsService_Get_0 = runtime.ForwardResponseMessage
|
||||
)
|
||||
38
server/settings/settings.proto
Normal file
38
server/settings/settings.proto
Normal file
@@ -0,0 +1,38 @@
|
||||
syntax = "proto3";
|
||||
option go_package = "github.com/argoproj/argo-cd/server/settings";
|
||||
|
||||
// Settings Service
|
||||
//
|
||||
// Settings Service API retrives ArgoCD settings
|
||||
package cluster;
|
||||
|
||||
import "gogoproto/gogo.proto";
|
||||
import "google/api/annotations.proto";
|
||||
|
||||
// SettingsQuery is a query for ArgoCD settings
|
||||
message SettingsQuery {
|
||||
}
|
||||
|
||||
message Settings {
|
||||
string url = 1 [(gogoproto.customname) = "URL"];
|
||||
DexConfig dexConfig = 2;
|
||||
}
|
||||
|
||||
message DexConfig {
|
||||
repeated Connector connectors = 1;
|
||||
}
|
||||
|
||||
message Connector {
|
||||
string name = 1;
|
||||
string type = 2;
|
||||
}
|
||||
|
||||
// SettingsService
|
||||
service SettingsService {
|
||||
|
||||
// Get returns ArgoCD settings
|
||||
rpc Get(SettingsQuery) returns (Settings) {
|
||||
option (google.api.http).get = "/api/v1/settings";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -22,3 +22,8 @@ func (s *Server) Version(context.Context, *empty.Empty) (*VersionMessage, error)
|
||||
Platform: vers.Platform,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// AuthFuncOverride allows the version to be returned without auth
|
||||
func (s *Server) AuthFuncOverride(ctx context.Context, fullMethodName string) (context.Context, error) {
|
||||
return ctx, nil
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user