Compare commits
189 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a4871724ac | ||
|
|
a7d6446d8f | ||
|
|
635a17ef1e | ||
|
|
6280fbce17 | ||
|
|
daa72e72b0 | ||
|
|
35bb770697 | ||
|
|
9cc5a7d8de | ||
|
|
9b62f01b53 | ||
|
|
a643a82006 | ||
|
|
82b74d8689 | ||
|
|
a5825bb9f5 | ||
|
|
88a890d717 | ||
|
|
be6fab795d | ||
|
|
7a5b9e2991 | ||
|
|
ee1f70841c | ||
|
|
adc3d17eab | ||
|
|
f909d6fde2 | ||
|
|
016a388147 | ||
|
|
aea442e7e1 | ||
|
|
bb013ceb28 | ||
|
|
dd65e9b89d | ||
|
|
12146eda8c | ||
|
|
cd87fbba0d | ||
|
|
c73541f81f | ||
|
|
4618998792 | ||
|
|
0a3b581aa9 | ||
|
|
aaa319b9bf | ||
|
|
25e782177b | ||
|
|
e940fd3d1f | ||
|
|
31d5cb4ad8 | ||
|
|
21576fe459 | ||
|
|
65863a2cb8 | ||
|
|
cdd055bfa6 | ||
|
|
fedf960a5f | ||
|
|
4546fa3270 | ||
|
|
979f3f557c | ||
|
|
48a38a8a5d | ||
|
|
9880b32b0a | ||
|
|
e664ef7a8d | ||
|
|
7cfef379d0 | ||
|
|
093a91c7fc | ||
|
|
94687a047f | ||
|
|
38fdc603ad | ||
|
|
55cecb7f96 | ||
|
|
32e949598e | ||
|
|
6d0c8aff4b | ||
|
|
5eecf03af6 | ||
|
|
76e9884032 | ||
|
|
9867c4baf0 | ||
|
|
2bc05c8cbd | ||
|
|
d15b0107e4 | ||
|
|
c64cb1304d | ||
|
|
c1f209c7a5 | ||
|
|
116ccd6b3b | ||
|
|
b6f30ae3e1 | ||
|
|
5c522ed2e1 | ||
|
|
bc29b80912 | ||
|
|
cfbc17fbf8 | ||
|
|
af0c939302 | ||
|
|
e02538d38d | ||
|
|
001d37567c | ||
|
|
af82ce31a6 | ||
|
|
12ad4908fa | ||
|
|
40ef94ab45 | ||
|
|
8834ab0210 | ||
|
|
128d23720f | ||
|
|
90f4891ca9 | ||
|
|
61ac81c4d9 | ||
|
|
bd05a8173c | ||
|
|
e3d6461a80 | ||
|
|
2bb582f7ed | ||
|
|
2f9a52852f | ||
|
|
137f083b4d | ||
|
|
11f4c54a40 | ||
|
|
c813eaf6d1 | ||
|
|
ffdaa9dfe9 | ||
|
|
182928002b | ||
|
|
7222af2b7e | ||
|
|
034ead5272 | ||
|
|
eca1f19e95 | ||
|
|
ec70c14649 | ||
|
|
65d906a735 | ||
|
|
b981bae1db | ||
|
|
d2df9ccf33 | ||
|
|
5e51f51449 | ||
|
|
2c044a27e4 | ||
|
|
d274a1115e | ||
|
|
bfae2899f3 | ||
|
|
5352a7e13a | ||
|
|
c49f9ef26a | ||
|
|
4a7376c5f5 | ||
|
|
567ce7f987 | ||
|
|
26bc0a8100 | ||
|
|
e7ff319685 | ||
|
|
072138deff | ||
|
|
dd8dc90c1e | ||
|
|
8f1da33375 | ||
|
|
c02fbc2794 | ||
|
|
371db07108 | ||
|
|
99f5dbf16b | ||
|
|
0db06c8962 | ||
|
|
a8e5876b2e | ||
|
|
8273851b73 | ||
|
|
c2967240bb | ||
|
|
282a6270c8 | ||
|
|
1b299fad90 | ||
|
|
aa8dced7ad | ||
|
|
050ba951b0 | ||
|
|
5e47c16099 | ||
|
|
902db4c732 | ||
|
|
86462fbee6 | ||
|
|
48bed79439 | ||
|
|
26b61c2b6b | ||
|
|
3b2253ddc0 | ||
|
|
5ddcb39129 | ||
|
|
59adef5bcc | ||
|
|
875aefc8dd | ||
|
|
0dbc9d213e | ||
|
|
9f4c53e321 | ||
|
|
3c8716f6ac | ||
|
|
1a7f31ae2e | ||
|
|
64ad69acfe | ||
|
|
9f47b55aa9 | ||
|
|
53a1db0703 | ||
|
|
2a789ec705 | ||
|
|
3047b25193 | ||
|
|
f66399cdc0 | ||
|
|
37fb0f632b | ||
|
|
e5dd0c7ff8 | ||
|
|
51392cd54c | ||
|
|
02bcb4ff3c | ||
|
|
d84297a5b5 | ||
|
|
c3876e30a9 | ||
|
|
10711ed780 | ||
|
|
de4e266e33 | ||
|
|
15442969f8 | ||
|
|
bed48ada82 | ||
|
|
a66004f567 | ||
|
|
72a4e3b3b8 | ||
|
|
16761e4fca | ||
|
|
ba34a6d401 | ||
|
|
23912e4091 | ||
|
|
17468cb5f5 | ||
|
|
5ea7aa0a75 | ||
|
|
7792cd6a10 | ||
|
|
237d186207 | ||
|
|
c41487598e | ||
|
|
2c0aa3c3af | ||
|
|
cedb33b2b9 | ||
|
|
06a3aa2c60 | ||
|
|
3fadc94711 | ||
|
|
61d02bf5e4 | ||
|
|
a62976461e | ||
|
|
d7a893acf9 | ||
|
|
0c67e75fb6 | ||
|
|
e6b84c4cfc | ||
|
|
5d2e793386 | ||
|
|
f0517906b7 | ||
|
|
16fa167931 | ||
|
|
b036999b8c | ||
|
|
1911766b7b | ||
|
|
9f7835d818 | ||
|
|
1df45e4857 | ||
|
|
47a1743965 | ||
|
|
d5844bbdaa | ||
|
|
128c87ab33 | ||
|
|
f4adcae79a | ||
|
|
ba4df070cf | ||
|
|
ce4ecfb388 | ||
|
|
e6006e0833 | ||
|
|
d500cc0bd1 | ||
|
|
71995b4f83 | ||
|
|
932c91d022 | ||
|
|
107e7424d1 | ||
|
|
c93181c0ad | ||
|
|
050fca6767 | ||
|
|
71827b4a1a | ||
|
|
1d0315bf5e | ||
|
|
b2b64e7283 | ||
|
|
fe0e2edd37 | ||
|
|
e5bb3d5645 | ||
|
|
b88a99347b | ||
|
|
344a909d19 | ||
|
|
3cbe3aab25 | ||
|
|
9e3a4b1810 | ||
|
|
e855bbaa29 | ||
|
|
78d7dca985 | ||
|
|
9da7ded976 | ||
|
|
427b107d0e |
17
.github/aur/flux-bin/.SRCINFO.template
vendored
Normal file
17
.github/aur/flux-bin/.SRCINFO.template
vendored
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
pkgbase = flux-bin
|
||||||
|
pkgdesc = Open and extensible continuous delivery solution for Kubernetes
|
||||||
|
pkgver = ${PKGVER}
|
||||||
|
pkgrel = ${PKGREL}
|
||||||
|
url = https://fluxcd.io/
|
||||||
|
arch = x86_64
|
||||||
|
arch = armv6h
|
||||||
|
arch = armv7h
|
||||||
|
arch = aarch64
|
||||||
|
license = APACHE
|
||||||
|
optdepends = kubectl
|
||||||
|
source_x86_64 = flux-bin-${PKGVER}.tar.gz::https://github.com/fluxcd/flux2/releases/download/v1/flux_${PKGVER}_linux_amd64.tar.gz
|
||||||
|
source_armv6h = flux-bin-${PKGVER}.tar.gz::https://github.com/fluxcd/flux2/releases/download/v1/flux_${PKGVER}_linux_arm.tar.gz
|
||||||
|
source_armv7h = flux-bin-${PKGVER}.tar.gz::https://github.com/fluxcd/flux2/releases/download/v1/flux_${PKGVER}_linux_arm.tar.gz
|
||||||
|
source_aarch64 = flux-bin-${PKGVER}.tar.gz::https://github.com/fluxcd/flux2/releases/download/v1/flux_${PKGVER}_linux_arm64.tar.gz
|
||||||
|
|
||||||
|
pkgname = flux-bin
|
||||||
1
.github/aur/flux-bin/.gitignore
vendored
Normal file
1
.github/aur/flux-bin/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
.pkg
|
||||||
39
.github/aur/flux-bin/PKGBUILD.template
vendored
Normal file
39
.github/aur/flux-bin/PKGBUILD.template
vendored
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
# Maintainer: Aurel Canciu <aurelcanciu@gmail.com>
|
||||||
|
# Maintainer: Hidde Beydals <hello@hidde.co>
|
||||||
|
|
||||||
|
pkgname=flux-bin
|
||||||
|
pkgver=${PKGVER}
|
||||||
|
pkgrel=${PKGREL}
|
||||||
|
pkgdesc="Open and extensible continuous delivery solution for Kubernetes"
|
||||||
|
url="https://fluxcd.io/"
|
||||||
|
arch=("x86_64" "armv6h" "armv7h" "aarch64")
|
||||||
|
license=("APACHE")
|
||||||
|
optdepends=("kubectl")
|
||||||
|
source_x86_64=(
|
||||||
|
"$pkgname-$pkgver.tar.gz::https://github.com/fluxcd/flux2/releases/download/v${pkgver}/flux_${pkgver}_linux_amd64.tar.gz"
|
||||||
|
)
|
||||||
|
source_armv6h=(
|
||||||
|
"$pkgname-$pkgver.tar.gz::https://github.com/fluxcd/flux2/releases/download/v${pkgver}/flux_${pkgver}_linux_arm.tar.gz"
|
||||||
|
)
|
||||||
|
source_armv7h=(
|
||||||
|
"$pkgname-$pkgver.tar.gz::https://github.com/fluxcd/flux2/releases/download/v${pkgver}/flux_${pkgver}_linux_arm.tar.gz"
|
||||||
|
)
|
||||||
|
source_aarch64=(
|
||||||
|
"$pkgname-$pkgver.tar.gz::https://github.com/fluxcd/flux2/releases/download/v${pkgver}/flux_${pkgver}_linux_arm64.tar.gz"
|
||||||
|
)
|
||||||
|
sha256sums_x86_64=(
|
||||||
|
${SHA256SUM_AMD64}
|
||||||
|
)
|
||||||
|
sha256sums_armv6h=(
|
||||||
|
${SHA256SUM_ARM}
|
||||||
|
)
|
||||||
|
sha256sums_armv7h=(
|
||||||
|
${SHA256SUM_ARM}
|
||||||
|
)
|
||||||
|
sha256sums_aarch64=(
|
||||||
|
${SHA256SUM_ARM64}
|
||||||
|
)
|
||||||
|
|
||||||
|
package() {
|
||||||
|
install -Dm755 flux "$pkgdir/usr/bin/flux"
|
||||||
|
}
|
||||||
55
.github/aur/flux-bin/publish.sh
vendored
Executable file
55
.github/aur/flux-bin/publish.sh
vendored
Executable file
@@ -0,0 +1,55 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
WD=$(cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd)
|
||||||
|
PKGNAME=$(basename $WD)
|
||||||
|
ROOT=${WD%/.github/aur/$PKGNAME}
|
||||||
|
|
||||||
|
LOCKFILE=/tmp/aur-$PKGNAME.lock
|
||||||
|
exec 100>$LOCKFILE || exit 0
|
||||||
|
flock -n 100 || exit 0
|
||||||
|
trap "rm -f $LOCKFILE" EXIT
|
||||||
|
|
||||||
|
export VERSION=$1
|
||||||
|
echo "Publishing to AUR as version ${VERSION}"
|
||||||
|
|
||||||
|
cd $WD
|
||||||
|
|
||||||
|
export GIT_SSH_COMMAND="ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no"
|
||||||
|
|
||||||
|
eval $(ssh-agent -s)
|
||||||
|
ssh-add <(echo "$AUR_BOT_SSH_PRIVATE_KEY")
|
||||||
|
|
||||||
|
GITDIR=$(mktemp -d /tmp/aur-$PKGNAME-XXX)
|
||||||
|
trap "rm -rf $GITDIR" EXIT
|
||||||
|
git clone aur@aur.archlinux.org:$PKGNAME $GITDIR 2>&1
|
||||||
|
|
||||||
|
CURRENT_PKGVER=$(cat $GITDIR/.SRCINFO | grep pkgver | awk '{ print $3 }')
|
||||||
|
CURRENT_PKGREL=$(cat $GITDIR/.SRCINFO | grep pkgrel | awk '{ print $3 }')
|
||||||
|
|
||||||
|
export PKGVER=${VERSION/-/}
|
||||||
|
|
||||||
|
if [[ "${CURRENT_PKGVER}" == "${PKGVER}" ]]; then
|
||||||
|
export PKGREL=$((CURRENT_PKGREL+1))
|
||||||
|
else
|
||||||
|
export PKGREL=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
export SHA256SUM_ARM=$(sha256sum ${ROOT}/dist/flux_${PKGVER}_linux_arm.tar.gz | awk '{ print $1 }')
|
||||||
|
export SHA256SUM_ARM64=$(sha256sum ${ROOT}/dist/flux_${PKGVER}_linux_arm64.tar.gz | awk '{ print $1 }')
|
||||||
|
export SHA256SUM_AMD64=$(sha256sum ${ROOT}/dist/flux_${PKGVER}_linux_amd64.tar.gz | awk '{ print $1 }')
|
||||||
|
|
||||||
|
envsubst '$PKGVER $PKGREL $SHA256SUM_AMD64 $SHA256SUM_ARM $SHA256SUM_ARM64' < .SRCINFO.template > $GITDIR/.SRCINFO
|
||||||
|
envsubst '$PKGVER $PKGREL $SHA256SUM_AMD64 $SHA256SUM_ARM $SHA256SUM_ARM64' < PKGBUILD.template > $GITDIR/PKGBUILD
|
||||||
|
|
||||||
|
cd $GITDIR
|
||||||
|
git config user.name "fluxcdbot"
|
||||||
|
git config user.email "fluxcdbot@users.noreply.github.com"
|
||||||
|
git add -A
|
||||||
|
if [ -z "$(git status --porcelain)" ]; then
|
||||||
|
echo "No changes."
|
||||||
|
else
|
||||||
|
git commit -m "Updated to version v${PKGVER} release ${PKGREL}"
|
||||||
|
git push origin master
|
||||||
|
fi
|
||||||
19
.github/aur/flux-go/.SRCINFO.template
vendored
Normal file
19
.github/aur/flux-go/.SRCINFO.template
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
pkgbase = flux-go
|
||||||
|
pkgdesc = Open and extensible continuous delivery solution for Kubernetes
|
||||||
|
pkgver = ${PKGVER}
|
||||||
|
pkgrel = ${PKGREL}
|
||||||
|
url = https://fluxcd.io/
|
||||||
|
arch = x86_64
|
||||||
|
arch = armv6h
|
||||||
|
arch = armv7h
|
||||||
|
arch = aarch64
|
||||||
|
license = APACHE
|
||||||
|
makedepends = go
|
||||||
|
depends = glibc
|
||||||
|
optdepends = kubectl
|
||||||
|
provides = flux-bin
|
||||||
|
conflicts = flux-bin
|
||||||
|
replaces = flux-cli
|
||||||
|
source = flux-go-${PKGVER}.tar.gz::https://github.com/fluxcd/flux2/archive/v${PKGVER}.tar.gz
|
||||||
|
|
||||||
|
pkgname = flux-go
|
||||||
1
.github/aur/flux-go/.gitignore
vendored
Normal file
1
.github/aur/flux-go/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
.pkg
|
||||||
43
.github/aur/flux-go/PKGBUILD.template
vendored
Normal file
43
.github/aur/flux-go/PKGBUILD.template
vendored
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
# Maintainer: Aurel Canciu <aurelcanciu@gmail.com>
|
||||||
|
# Maintainer: Hidde Beydals <hello@hidde.co>
|
||||||
|
|
||||||
|
pkgname=flux-go
|
||||||
|
pkgver=${PKGVER}
|
||||||
|
pkgrel=${PKGREL}
|
||||||
|
pkgdesc="Open and extensible continuous delivery solution for Kubernetes"
|
||||||
|
url="https://fluxcd.io/"
|
||||||
|
arch=("x86_64" "armv6h" "armv7h" "aarch64")
|
||||||
|
license=("APACHE")
|
||||||
|
provides=("flux-bin")
|
||||||
|
conflicts=("flux-bin")
|
||||||
|
replaces=("flux-cli")
|
||||||
|
depends=("glibc")
|
||||||
|
makedepends=("go")
|
||||||
|
optdepends=("kubectl")
|
||||||
|
source=(
|
||||||
|
"$pkgname-$pkgver.tar.gz::https://github.com/fluxcd/flux2/archive/v$pkgver.tar.gz"
|
||||||
|
)
|
||||||
|
sha256sums=(
|
||||||
|
${SHA256SUM}
|
||||||
|
)
|
||||||
|
|
||||||
|
build() {
|
||||||
|
cd "flux2-$pkgver"
|
||||||
|
export CGO_LDFLAGS="$LDFLAGS"
|
||||||
|
export CGO_CFLAGS="$CFLAGS"
|
||||||
|
export CGO_CXXFLAGS="$CXXFLAGS"
|
||||||
|
export CGO_CPPFLAGS="$CPPFLAGS"
|
||||||
|
export GOFLAGS="-buildmode=pie -trimpath -ldflags=-linkmode=external -mod=readonly -modcacherw"
|
||||||
|
go build -ldflags "-X main.VERSION=$pkgver" -o flux-bin ./cmd/flux
|
||||||
|
}
|
||||||
|
|
||||||
|
check() {
|
||||||
|
cd "flux2-$pkgver"
|
||||||
|
make test
|
||||||
|
}
|
||||||
|
|
||||||
|
package() {
|
||||||
|
cd "flux2-$pkgver"
|
||||||
|
install -Dm755 flux-bin "$pkgdir/usr/bin/flux"
|
||||||
|
install -Dm644 LICENSE "$pkgdir/usr/share/licenses/$pkgname/LICENSE"
|
||||||
|
}
|
||||||
53
.github/aur/flux-go/publish.sh
vendored
Executable file
53
.github/aur/flux-go/publish.sh
vendored
Executable file
@@ -0,0 +1,53 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
WD=$(cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd)
|
||||||
|
PKGNAME=$(basename $WD)
|
||||||
|
ROOT=${WD%/.github/aur/$PKGNAME}
|
||||||
|
|
||||||
|
LOCKFILE=/tmp/aur-$PKGNAME.lock
|
||||||
|
exec 100>$LOCKFILE || exit 0
|
||||||
|
flock -n 100 || exit 0
|
||||||
|
trap "rm -f $LOCKFILE" EXIT
|
||||||
|
|
||||||
|
export VERSION=$1
|
||||||
|
echo "Publishing to AUR as version ${VERSION}"
|
||||||
|
|
||||||
|
cd $WD
|
||||||
|
|
||||||
|
export GIT_SSH_COMMAND="ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no"
|
||||||
|
|
||||||
|
eval $(ssh-agent -s)
|
||||||
|
ssh-add <(echo "$AUR_BOT_SSH_PRIVATE_KEY")
|
||||||
|
|
||||||
|
GITDIR=$(mktemp -d /tmp/aur-$PKGNAME-XXX)
|
||||||
|
trap "rm -rf $GITDIR" EXIT
|
||||||
|
git clone aur@aur.archlinux.org:$PKGNAME $GITDIR 2>&1
|
||||||
|
|
||||||
|
CURRENT_PKGVER=$(cat $GITDIR/.SRCINFO | grep pkgver | awk '{ print $3 }')
|
||||||
|
CURRENT_PKGREL=$(cat $GITDIR/.SRCINFO | grep pkgrel | awk '{ print $3 }')
|
||||||
|
|
||||||
|
export PKGVER=${VERSION/-/}
|
||||||
|
|
||||||
|
if [[ "${CURRENT_PKGVER}" == "${PKGVER}" ]]; then
|
||||||
|
export PKGREL=$((CURRENT_PKGREL+1))
|
||||||
|
else
|
||||||
|
export PKGREL=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
export SHA256SUM=$(curl -sL https://github.com/fluxcd/flux2/archive/v$PKGVER.tar.gz | sha256sum | awk '{ print $1 }')
|
||||||
|
|
||||||
|
envsubst '$PKGVER $PKGREL $SHA256SUM' < .SRCINFO.template > $GITDIR/.SRCINFO
|
||||||
|
envsubst '$PKGVER $PKGREL $SHA256SUM' < PKGBUILD.template > $GITDIR/PKGBUILD
|
||||||
|
|
||||||
|
cd $GITDIR
|
||||||
|
git config user.name "fluxcdbot"
|
||||||
|
git config user.email "fluxcdbot@users.noreply.github.com"
|
||||||
|
git add -A
|
||||||
|
if [ -z "$(git status --porcelain)" ]; then
|
||||||
|
echo "No changes."
|
||||||
|
else
|
||||||
|
git commit -m "Updated to version v${PKGVER} release ${PKGREL}"
|
||||||
|
git push origin master
|
||||||
|
fi
|
||||||
19
.github/aur/flux-scm/.SRCINFO.template
vendored
Normal file
19
.github/aur/flux-scm/.SRCINFO.template
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
pkgbase = flux-scm
|
||||||
|
pkgdesc = Open and extensible continuous delivery solution for Kubernetes
|
||||||
|
pkgver = ${PKGVER}
|
||||||
|
pkgrel = ${PKGREL}
|
||||||
|
url = https://fluxcd.io/
|
||||||
|
arch = x86_64
|
||||||
|
arch = armv6h
|
||||||
|
arch = armv7h
|
||||||
|
arch = aarch64
|
||||||
|
license = APACHE
|
||||||
|
makedepends = go
|
||||||
|
depends = glibc
|
||||||
|
optdepends = kubectl
|
||||||
|
provides = flux-bin
|
||||||
|
conflicts = flux-bin
|
||||||
|
source = git+https://github.com/fluxcd/flux2.git
|
||||||
|
md5sums = SKIP
|
||||||
|
|
||||||
|
pkgname = flux-scm
|
||||||
1
.github/aur/flux-scm/.gitignore
vendored
Normal file
1
.github/aur/flux-scm/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
.pkg
|
||||||
45
.github/aur/flux-scm/PKGBUILD.template
vendored
Normal file
45
.github/aur/flux-scm/PKGBUILD.template
vendored
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
# Maintainer: Aurel Canciu <aurelcanciu@gmail.com>
|
||||||
|
# Maintainer: Hidde Beydals <hello@hidde.co>
|
||||||
|
|
||||||
|
pkgname=flux-scm
|
||||||
|
pkgver=${PKGVER}
|
||||||
|
pkgrel=${PKGREL}
|
||||||
|
pkgdesc="Open and extensible continuous delivery solution for Kubernetes"
|
||||||
|
url="https://fluxcd.io/"
|
||||||
|
arch=("x86_64" "armv6h" "armv7h" "aarch64")
|
||||||
|
license=("APACHE")
|
||||||
|
provides=("flux-bin")
|
||||||
|
conflicts=("flux-bin")
|
||||||
|
depends=("glibc")
|
||||||
|
makedepends=("go")
|
||||||
|
optdepends=("kubectl")
|
||||||
|
source=(
|
||||||
|
"git+https://github.com/fluxcd/flux2.git"
|
||||||
|
)
|
||||||
|
md5sums=('SKIP')
|
||||||
|
|
||||||
|
pkgver() {
|
||||||
|
cd "flux2"
|
||||||
|
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||||
|
}
|
||||||
|
|
||||||
|
build() {
|
||||||
|
cd "flux2"
|
||||||
|
export CGO_LDFLAGS="$LDFLAGS"
|
||||||
|
export CGO_CFLAGS="$CFLAGS"
|
||||||
|
export CGO_CXXFLAGS="$CXXFLAGS"
|
||||||
|
export CGO_CPPFLAGS="$CPPFLAGS"
|
||||||
|
export GOFLAGS="-buildmode=pie -trimpath -ldflags=-linkmode=external -mod=readonly -modcacherw"
|
||||||
|
go build -ldflags "-X main.VERSION=$pkgver" -o flux-bin ./cmd/flux
|
||||||
|
}
|
||||||
|
|
||||||
|
check() {
|
||||||
|
cd "flux2"
|
||||||
|
make test
|
||||||
|
}
|
||||||
|
|
||||||
|
package() {
|
||||||
|
cd "flux2"
|
||||||
|
install -Dm755 flux-bin "$pkgdir/usr/bin/flux"
|
||||||
|
install -Dm644 LICENSE "$pkgdir/usr/share/licenses/$pkgname/LICENSE"
|
||||||
|
}
|
||||||
51
.github/aur/flux-scm/publish.sh
vendored
Executable file
51
.github/aur/flux-scm/publish.sh
vendored
Executable file
@@ -0,0 +1,51 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
WD=$(cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd)
|
||||||
|
PKGNAME=$(basename $WD)
|
||||||
|
ROOT=${WD%/.github/aur/$PKGNAME}
|
||||||
|
|
||||||
|
LOCKFILE=/tmp/aur-$PKGNAME.lock
|
||||||
|
exec 100>$LOCKFILE || exit 0
|
||||||
|
flock -n 100 || exit 0
|
||||||
|
trap "rm -f $LOCKFILE" EXIT
|
||||||
|
|
||||||
|
export VERSION=$1
|
||||||
|
echo "Publishing to AUR as version ${VERSION}"
|
||||||
|
|
||||||
|
cd $WD
|
||||||
|
|
||||||
|
export GIT_SSH_COMMAND="ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no"
|
||||||
|
|
||||||
|
eval $(ssh-agent -s)
|
||||||
|
ssh-add <(echo "$AUR_BOT_SSH_PRIVATE_KEY")
|
||||||
|
|
||||||
|
GITDIR=$(mktemp -d /tmp/aur-$PKGNAME-XXX)
|
||||||
|
trap "rm -rf $GITDIR" EXIT
|
||||||
|
git clone aur@aur.archlinux.org:$PKGNAME $GITDIR 2>&1
|
||||||
|
|
||||||
|
CURRENT_PKGVER=$(cat $GITDIR/.SRCINFO | grep pkgver | awk '{ print $3 }')
|
||||||
|
CURRENT_PKGREL=$(cat $GITDIR/.SRCINFO | grep pkgrel | awk '{ print $3 }')
|
||||||
|
|
||||||
|
export PKGVER=${VERSION/-/}
|
||||||
|
|
||||||
|
if [[ "${CURRENT_PKGVER}" == "${PKGVER}" ]]; then
|
||||||
|
export PKGREL=$((CURRENT_PKGREL+1))
|
||||||
|
else
|
||||||
|
export PKGREL=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
envsubst '$PKGVER $PKGREL' < .SRCINFO.template > $GITDIR/.SRCINFO
|
||||||
|
envsubst '$PKGVER $PKGREL' < PKGBUILD.template > $GITDIR/PKGBUILD
|
||||||
|
|
||||||
|
cd $GITDIR
|
||||||
|
git config user.name "fluxcdbot"
|
||||||
|
git config user.email "fluxcdbot@users.noreply.github.com"
|
||||||
|
git add -A
|
||||||
|
if [ -z "$(git status --porcelain)" ]; then
|
||||||
|
echo "No changes."
|
||||||
|
else
|
||||||
|
git commit -m "Updated to version v${PKGVER} release ${PKGREL}"
|
||||||
|
git push origin master
|
||||||
|
fi
|
||||||
4
.github/workflows/bootstrap.yaml
vendored
4
.github/workflows/bootstrap.yaml
vendored
@@ -21,9 +21,9 @@ jobs:
|
|||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v2
|
uses: actions/setup-go@v2
|
||||||
with:
|
with:
|
||||||
go-version: 1.14.x
|
go-version: 1.15.x
|
||||||
- name: Setup Kubernetes
|
- name: Setup Kubernetes
|
||||||
uses: engineerd/setup-kind@v0.4.0
|
uses: engineerd/setup-kind@v0.5.0
|
||||||
- name: Set outputs
|
- name: Set outputs
|
||||||
id: vars
|
id: vars
|
||||||
run: echo "::set-output name=sha_short::$(git rev-parse --short HEAD)"
|
run: echo "::set-output name=sha_short::$(git rev-parse --short HEAD)"
|
||||||
|
|||||||
12
.github/workflows/e2e.yaml
vendored
12
.github/workflows/e2e.yaml
vendored
@@ -24,7 +24,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
go-version: 1.15.x
|
go-version: 1.15.x
|
||||||
- name: Setup Kubernetes
|
- name: Setup Kubernetes
|
||||||
uses: engineerd/setup-kind@v0.4.0
|
uses: engineerd/setup-kind@v0.5.0
|
||||||
with:
|
with:
|
||||||
image: kindest/node:v1.16.9
|
image: kindest/node:v1.16.9
|
||||||
- name: Run test
|
- name: Run test
|
||||||
@@ -136,6 +136,16 @@ jobs:
|
|||||||
- name: flux delete source git
|
- name: flux delete source git
|
||||||
run: |
|
run: |
|
||||||
./bin/flux delete source git podinfo --silent
|
./bin/flux delete source git podinfo --silent
|
||||||
|
- name: flux create tenant
|
||||||
|
run: |
|
||||||
|
./bin/flux create tenant dev-team --with-namespace=apps
|
||||||
|
./bin/flux -n apps create source helm podinfo \
|
||||||
|
--url https://stefanprodan.github.io/podinfo
|
||||||
|
./bin/flux -n apps create hr podinfo-helm \
|
||||||
|
--source=HelmRepository/podinfo \
|
||||||
|
--chart=podinfo \
|
||||||
|
--chart-version="5.0.x" \
|
||||||
|
--service-account=dev-team
|
||||||
- name: flux check
|
- name: flux check
|
||||||
run: |
|
run: |
|
||||||
./bin/flux check
|
./bin/flux check
|
||||||
|
|||||||
22
.github/workflows/release.yaml
vendored
22
.github/workflows/release.yaml
vendored
@@ -59,24 +59,9 @@ jobs:
|
|||||||
|
|
||||||
# create tarball
|
# create tarball
|
||||||
cd ./output && tar -cvzf manifests.tar.gz $files
|
cd ./output && tar -cvzf manifests.tar.gz $files
|
||||||
- name: Create release
|
- name: Generate install manifest
|
||||||
id: create_release
|
run: |
|
||||||
uses: actions/create-release@latest
|
kustomize build ./manifests/install > ./output/install.yaml
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
with:
|
|
||||||
tag_name: ${{ github.ref }}
|
|
||||||
release_name: ${{ github.ref }}
|
|
||||||
- name: Upload artifacts
|
|
||||||
id: upload-release-asset
|
|
||||||
uses: actions/upload-release-asset@v1
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
with:
|
|
||||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
|
||||||
asset_path: ./output/manifests.tar.gz
|
|
||||||
asset_name: manifests.tar.gz
|
|
||||||
asset_content_type: application/gzip
|
|
||||||
- name: Run GoReleaser
|
- name: Run GoReleaser
|
||||||
uses: goreleaser/goreleaser-action@v1
|
uses: goreleaser/goreleaser-action@v1
|
||||||
with:
|
with:
|
||||||
@@ -85,3 +70,4 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
HOMEBREW_TAP_GITHUB_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN }}
|
HOMEBREW_TAP_GITHUB_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN }}
|
||||||
|
AUR_BOT_SSH_PRIVATE_KEY: ${{ secrets.AUR_BOT_SSH_PRIVATE_KEY }}
|
||||||
|
|||||||
@@ -50,3 +50,23 @@ brews:
|
|||||||
type: optional
|
type: optional
|
||||||
test: |
|
test: |
|
||||||
system "#{bin}/flux --version"
|
system "#{bin}/flux --version"
|
||||||
|
publishers:
|
||||||
|
- name: aur-pkg-bin
|
||||||
|
env:
|
||||||
|
- AUR_BOT_SSH_PRIVATE_KEY={{ .Env.AUR_BOT_SSH_PRIVATE_KEY }}
|
||||||
|
cmd: |
|
||||||
|
.github/aur/flux-bin/publish.sh {{ .Version }}
|
||||||
|
- name: aur-pkg-scm
|
||||||
|
env:
|
||||||
|
- AUR_BOT_SSH_PRIVATE_KEY={{ .Env.AUR_BOT_SSH_PRIVATE_KEY }}
|
||||||
|
cmd: |
|
||||||
|
.github/aur/flux-scm/publish.sh {{ .Version }}
|
||||||
|
- name: aur-pkg-go
|
||||||
|
env:
|
||||||
|
- AUR_BOT_SSH_PRIVATE_KEY={{ .Env.AUR_BOT_SSH_PRIVATE_KEY }}
|
||||||
|
cmd: |
|
||||||
|
.github/aur/flux-go/publish.sh {{ .Version }}
|
||||||
|
release:
|
||||||
|
extra_files:
|
||||||
|
- glob: ./output/manifests.tar.gz
|
||||||
|
- glob: ./output/install.yaml
|
||||||
|
|||||||
10
MAINTAINERS
10
MAINTAINERS
@@ -2,7 +2,17 @@ The maintainers are generally available in Slack at
|
|||||||
https://cloud-native.slack.com in #flux (https://cloud-native.slack.com/messages/CLAJ40HV3)
|
https://cloud-native.slack.com in #flux (https://cloud-native.slack.com/messages/CLAJ40HV3)
|
||||||
(obtain an invitation at https://slack.cncf.io/).
|
(obtain an invitation at https://slack.cncf.io/).
|
||||||
|
|
||||||
|
These maintainers are shared with other Flux v2-related git
|
||||||
|
repositories under https://github.com/fluxcd, as noted in their
|
||||||
|
respective MAINTAINERS files.
|
||||||
|
|
||||||
|
For convenience, they are reflected in the GitHub team
|
||||||
|
@fluxcd/flux2-maintainers -- if the list here changes, that team also
|
||||||
|
should.
|
||||||
|
|
||||||
In alphabetical order:
|
In alphabetical order:
|
||||||
|
|
||||||
|
Aurel Canciu, Sortlist <aurel@sortlist.com> (github: @relu, slack: relu)
|
||||||
Hidde Beydals, Weaveworks <hidde@weave.works> (github: @hiddeco, slack: hidde)
|
Hidde Beydals, Weaveworks <hidde@weave.works> (github: @hiddeco, slack: hidde)
|
||||||
|
Philip Laine, Xenit <philip.laine@xenit.se> (github: @phillebaba, slack: phillebaba)
|
||||||
Stefan Prodan, Weaveworks <stefan@weave.works> (github: @stefanprodan, slack: stefanprodan)
|
Stefan Prodan, Weaveworks <stefan@weave.works> (github: @stefanprodan, slack: stefanprodan)
|
||||||
|
|||||||
25
README.md
25
README.md
@@ -4,7 +4,6 @@
|
|||||||
[](https://goreportcard.com/report/github.com/fluxcd/flux2)
|
[](https://goreportcard.com/report/github.com/fluxcd/flux2)
|
||||||
[](https://github.com/fluxcd/flux2/blob/main/LICENSE)
|
[](https://github.com/fluxcd/flux2/blob/main/LICENSE)
|
||||||
[](https://github.com/fluxcd/flux2/releases)
|
[](https://github.com/fluxcd/flux2/releases)
|
||||||

|
|
||||||
|
|
||||||
Flux is a tool for keeping Kubernetes clusters in sync with sources of
|
Flux is a tool for keeping Kubernetes clusters in sync with sources of
|
||||||
configuration (like Git repositories), and automating updates to
|
configuration (like Git repositories), and automating updates to
|
||||||
@@ -37,6 +36,15 @@ curl -s https://toolkit.fluxcd.io/install.sh | sudo bash
|
|||||||
. <(flux completion bash)
|
. <(flux completion bash)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Arch Linux (AUR) packages:
|
||||||
|
|
||||||
|
- [flux-bin](https://aur.archlinux.org/packages/flux-bin): install the latest
|
||||||
|
stable version using a pre-build binary (recommended)
|
||||||
|
- [flux-go](https://aur.archlinux.org/packages/flux-go): build the latest
|
||||||
|
stable version from source code
|
||||||
|
- [flux-scm](https://aur.archlinux.org/packages/flux-scm): build the latest
|
||||||
|
(unstable) version from source code from our git `main` branch
|
||||||
|
|
||||||
Binaries for macOS, Windows and Linux AMD64/ARM are available to download on the
|
Binaries for macOS, Windows and Linux AMD64/ARM are available to download on the
|
||||||
[release page](https://github.com/fluxcd/flux2/releases).
|
[release page](https://github.com/fluxcd/flux2/releases).
|
||||||
|
|
||||||
@@ -65,6 +73,8 @@ runtime for Flux v2. The APIs comprise Kubernetes custom resources,
|
|||||||
which can be created and updated by a cluster user, or by other
|
which can be created and updated by a cluster user, or by other
|
||||||
automation tooling.
|
automation tooling.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
You can use the toolkit to extend Flux, or to build your own systems
|
You can use the toolkit to extend Flux, or to build your own systems
|
||||||
for continuous delivery -- see [the developer
|
for continuous delivery -- see [the developer
|
||||||
guides](https://toolkit.fluxcd.io/dev-guides/source-watcher/).
|
guides](https://toolkit.fluxcd.io/dev-guides/source-watcher/).
|
||||||
@@ -97,19 +107,18 @@ Depending on what you want to do, some of the following bits might be your first
|
|||||||
- To be part of the conversation about Flux's development, [join the flux-dev mailing list](https://lists.cncf.io/g/cncf-flux-dev).
|
- To be part of the conversation about Flux's development, [join the flux-dev mailing list](https://lists.cncf.io/g/cncf-flux-dev).
|
||||||
- Check out [how to contribute](CONTRIBUTING.md) to the project
|
- Check out [how to contribute](CONTRIBUTING.md) to the project
|
||||||
|
|
||||||
|
### Upcoming Events
|
||||||
|
|
||||||
|
- 14 Dec 2020 - [The Power of GitOps with Flux and Flagger with Leigh Capili](https://www.meetup.com/GitOps-Community/events/274924513/)
|
||||||
|
|
||||||
### Featured Talks
|
### Featured Talks
|
||||||
|
|
||||||
|
- 24 Nov 2020 - [Flux CD v2 with GitOps Toolkit - Kubernetes Deployment and Sync Mechanism](https://youtu.be/R6OeIgb7lUI)
|
||||||
- 28 Oct 2020 - [The Kubelist Podcast: Flux with Michael Bridgen](https://www.heavybit.com/library/podcasts/the-kubelist-podcast/ep-5-flux-with-michael-bridgen-of-weaveworks/)
|
- 28 Oct 2020 - [The Kubelist Podcast: Flux with Michael Bridgen](https://www.heavybit.com/library/podcasts/the-kubelist-podcast/ep-5-flux-with-michael-bridgen-of-weaveworks/)
|
||||||
- 19 Oct 2020 - [The Power of GitOps with Flux & GitOps Toolkit - Part 1 with Leigh Capili](https://youtu.be/0v5bjysXTL8)
|
- 19 Oct 2020 - [The Power of GitOps with Flux & GitOps Toolkit - Part 1 with Leigh Capili](https://youtu.be/0v5bjysXTL8)
|
||||||
|
- 30 Nov 2020 - [The Power of GitOps with Flux 2 - Part 3 with Leigh Capili](https://youtu.be/N_K5g7o9JKg)
|
||||||
- 12 Oct 2020 - [Rawkode Live: Introduction to GitOps Toolkit with Stefan Prodan](https://youtu.be/HqTzuOBP0eY)
|
- 12 Oct 2020 - [Rawkode Live: Introduction to GitOps Toolkit with Stefan Prodan](https://youtu.be/HqTzuOBP0eY)
|
||||||
- 4 Sep 2020 - [KubeCon Europe: The road to Flux v2 and Progressive Delivery with Stefan Prodan & Hidde Beydals](https://youtu.be/8v94nUkXsxU)
|
- 4 Sep 2020 - [KubeCon Europe: The road to Flux v2 and Progressive Delivery with Stefan Prodan & Hidde Beydals](https://youtu.be/8v94nUkXsxU)
|
||||||
- 25 June 2020 - [Cloud Native Nordics: Introduction to GitOps & GitOps Toolkit with Alexis Richardson & Stefan Prodan](https://youtu.be/qQBtSkgl7tI)
|
- 25 June 2020 - [Cloud Native Nordics: Introduction to GitOps & GitOps Toolkit with Alexis Richardson & Stefan Prodan](https://youtu.be/qQBtSkgl7tI)
|
||||||
- 7 May 2020 - [GitOps Days - Community Special: GitOps Toolkit Experimentation with Stefan Prodan](https://youtu.be/WHzxunv4DKk?t=6521)
|
|
||||||
|
|
||||||
### Upcoming Events
|
|
||||||
|
|
||||||
- 2 Nov 2020 - [The Power of GitOps with Flux & GitOps Toolkit - Part 2 with Leigh Capili](https://www.meetup.com/GitOps-Community/events/273934676/)
|
|
||||||
- 12-13 Nov 2020 - [GitOps Days EMEA](https://www.gitopsdays.com/) with talks and workshops on migrating to Flux v2 and Helm Controller
|
|
||||||
- 19 Nov 2020 - [KubeCon NA: Progressive Delivery Techniques with Flagger and Flux v2 with Stefan Prodan](https://kccncna20.sched.com/event/1b04f8408b49976b843a5d0019cb8112)
|
|
||||||
|
|
||||||
We are looking forward to seeing you with us!
|
We are looking forward to seeing you with us!
|
||||||
|
|||||||
6
action/Dockerfile
Normal file
6
action/Dockerfile
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
FROM stefanprodan/alpine-base:latest
|
||||||
|
|
||||||
|
COPY entrypoint.sh /entrypoint.sh
|
||||||
|
RUN chmod +x /entrypoint.sh
|
||||||
|
|
||||||
|
ENTRYPOINT ["/entrypoint.sh"]
|
||||||
79
action/README.md
Normal file
79
action/README.md
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
# Flux GitHub Action
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
steps:
|
||||||
|
- name: Setup Flux CLI
|
||||||
|
uses: fluxcd/flux2/action@main
|
||||||
|
- name: Run Flux commands
|
||||||
|
run: flux -v
|
||||||
|
```
|
||||||
|
|
||||||
|
### Automate Flux updates
|
||||||
|
|
||||||
|
Example workflow for updating Flux's components generated with `flux bootstrap --arch=amd64 --path=clusters/production`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
name: update-flux
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
schedule:
|
||||||
|
- cron: "0 * * * *"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
components:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Check out code
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Setup Flux CLI
|
||||||
|
uses: fluxcd/flux2/action@main
|
||||||
|
- name: Check for updates
|
||||||
|
id: update
|
||||||
|
run: |
|
||||||
|
flux install --arch=amd64 \
|
||||||
|
--export > ./clusters/production/flux-system/gotk-components.yaml
|
||||||
|
|
||||||
|
VERSION="$(flux -v)"
|
||||||
|
echo "::set-output name=flux_version::$VERSION"
|
||||||
|
- name: Create Pull Request
|
||||||
|
uses: peter-evans/create-pull-request@v3
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
branch: update-flux
|
||||||
|
commit-message: Update to ${{ steps.update.outputs.flux_version }}
|
||||||
|
title: Update to ${{ steps.update.outputs.flux_version }}
|
||||||
|
body: |
|
||||||
|
${{ steps.update.outputs.flux_version }}
|
||||||
|
```
|
||||||
|
|
||||||
|
### End-to-end testing
|
||||||
|
|
||||||
|
Example workflow for running Flux in Kubernetes Kind:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
name: e2e
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- '*'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
kubernetes:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Setup Flux CLI
|
||||||
|
uses: fluxcd/flux2/action@main
|
||||||
|
- name: Setup Kubernetes Kind
|
||||||
|
uses: engineerd/setup-kind@v0.5.0
|
||||||
|
- name: Install Flux in Kubernetes Kind
|
||||||
|
run: flux install
|
||||||
|
```
|
||||||
|
|
||||||
|
A complete e2e testing workflow is available here
|
||||||
|
[flux2-kustomize-helm-example](https://github.com/fluxcd/flux2-kustomize-helm-example/blob/main/.github/workflows/e2e.yaml)
|
||||||
15
action/action.yml
Normal file
15
action/action.yml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
name: 'kustomize'
|
||||||
|
description: 'A GitHub Action for running Flux commands'
|
||||||
|
author: 'Flux project'
|
||||||
|
branding:
|
||||||
|
icon: 'command'
|
||||||
|
color: 'blue'
|
||||||
|
inputs:
|
||||||
|
version:
|
||||||
|
description: 'strict semver'
|
||||||
|
required: false
|
||||||
|
runs:
|
||||||
|
using: 'docker'
|
||||||
|
image: 'Dockerfile'
|
||||||
|
args:
|
||||||
|
- ${{ inputs.version }}
|
||||||
40
action/entrypoint.sh
Executable file
40
action/entrypoint.sh
Executable file
@@ -0,0 +1,40 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Copyright 2020 The Flux authors
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
VERSION=$1
|
||||||
|
|
||||||
|
if [ -z $VERSION ]; then
|
||||||
|
# Find latest release if no version is specified
|
||||||
|
VERSION=$(curl https://api.github.com/repos/fluxcd/flux2/releases/latest -sL | grep tag_name | sed -E 's/.*"([^"]+)".*/\1/' | cut -c 2-)
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Download linux binary
|
||||||
|
BIN_URL="https://github.com/fluxcd/flux2/releases/download/v${VERSION}/flux_${VERSION}_linux_amd64.tar.gz"
|
||||||
|
curl -sL $BIN_URL | tar xz
|
||||||
|
|
||||||
|
# Copy binary to GitHub runner
|
||||||
|
mkdir -p $GITHUB_WORKSPACE/bin
|
||||||
|
cp ./flux $GITHUB_WORKSPACE/bin
|
||||||
|
chmod +x $GITHUB_WORKSPACE/bin/flux
|
||||||
|
|
||||||
|
# Print version
|
||||||
|
$GITHUB_WORKSPACE/bin/flux -v
|
||||||
|
|
||||||
|
# Add binary to GitHub runner path
|
||||||
|
echo "$GITHUB_WORKSPACE/bin" >> $GITHUB_PATH
|
||||||
|
echo "$RUNNER_WORKSPACE/$(basename $GITHUB_REPOSITORY)/bin" >> $GITHUB_PATH
|
||||||
@@ -57,6 +57,7 @@ var (
|
|||||||
bootstrapArch = flags.Arch(defaults.Arch)
|
bootstrapArch = flags.Arch(defaults.Arch)
|
||||||
bootstrapLogLevel = flags.LogLevel(defaults.LogLevel)
|
bootstrapLogLevel = flags.LogLevel(defaults.LogLevel)
|
||||||
bootstrapRequiredComponents = []string{"source-controller", "kustomize-controller"}
|
bootstrapRequiredComponents = []string{"source-controller", "kustomize-controller"}
|
||||||
|
bootstrapTokenAuth bool
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -75,14 +76,16 @@ func init() {
|
|||||||
bootstrapCmd.PersistentFlags().Var(&bootstrapArch, "arch", bootstrapArch.Description())
|
bootstrapCmd.PersistentFlags().Var(&bootstrapArch, "arch", bootstrapArch.Description())
|
||||||
bootstrapCmd.PersistentFlags().StringVar(&bootstrapBranch, "branch", bootstrapDefaultBranch,
|
bootstrapCmd.PersistentFlags().StringVar(&bootstrapBranch, "branch", bootstrapDefaultBranch,
|
||||||
"default branch (for GitHub this must match the default branch setting for the organization)")
|
"default branch (for GitHub this must match the default branch setting for the organization)")
|
||||||
rootCmd.AddCommand(bootstrapCmd)
|
|
||||||
bootstrapCmd.PersistentFlags().BoolVar(&bootstrapWatchAllNamespaces, "watch-all-namespaces", true,
|
bootstrapCmd.PersistentFlags().BoolVar(&bootstrapWatchAllNamespaces, "watch-all-namespaces", true,
|
||||||
"watch for custom resources in all namespaces, if set to false it will only watch the namespace where the toolkit is installed")
|
"watch for custom resources in all namespaces, if set to false it will only watch the namespace where the toolkit is installed")
|
||||||
bootstrapCmd.PersistentFlags().BoolVar(&bootstrapNetworkPolicy, "network-policy", true,
|
bootstrapCmd.PersistentFlags().BoolVar(&bootstrapNetworkPolicy, "network-policy", true,
|
||||||
"deny ingress access to the toolkit controllers from other namespaces using network policies")
|
"deny ingress access to the toolkit controllers from other namespaces using network policies")
|
||||||
|
bootstrapCmd.PersistentFlags().BoolVar(&bootstrapTokenAuth, "token-auth", false,
|
||||||
|
"when enabled, the personal access token will be used instead of SSH deploy key")
|
||||||
bootstrapCmd.PersistentFlags().Var(&bootstrapLogLevel, "log-level", bootstrapLogLevel.Description())
|
bootstrapCmd.PersistentFlags().Var(&bootstrapLogLevel, "log-level", bootstrapLogLevel.Description())
|
||||||
bootstrapCmd.PersistentFlags().StringVar(&bootstrapManifestsPath, "manifests", "", "path to the manifest directory")
|
bootstrapCmd.PersistentFlags().StringVar(&bootstrapManifestsPath, "manifests", "", "path to the manifest directory")
|
||||||
bootstrapCmd.PersistentFlags().MarkHidden("manifests")
|
bootstrapCmd.PersistentFlags().MarkHidden("manifests")
|
||||||
|
rootCmd.AddCommand(bootstrapCmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
func bootstrapValidate() error {
|
func bootstrapValidate() error {
|
||||||
@@ -132,13 +135,13 @@ func generateInstallManifests(targetPath, namespace, tmpDir string, localManifes
|
|||||||
|
|
||||||
func applyInstallManifests(ctx context.Context, manifestPath string, components []string) error {
|
func applyInstallManifests(ctx context.Context, manifestPath string, components []string) error {
|
||||||
kubectlArgs := []string{"apply", "-f", manifestPath}
|
kubectlArgs := []string{"apply", "-f", manifestPath}
|
||||||
if _, err := utils.ExecKubectlCommand(ctx, utils.ModeOS, kubectlArgs...); err != nil {
|
if _, err := utils.ExecKubectlCommand(ctx, utils.ModeOS, kubeconfig, kubecontext, kubectlArgs...); err != nil {
|
||||||
return fmt.Errorf("install failed")
|
return fmt.Errorf("install failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, deployment := range components {
|
for _, deployment := range components {
|
||||||
kubectlArgs = []string{"-n", namespace, "rollout", "status", "deployment", deployment, "--timeout", timeout.String()}
|
kubectlArgs = []string{"-n", namespace, "rollout", "status", "deployment", deployment, "--timeout", timeout.String()}
|
||||||
if _, err := utils.ExecKubectlCommand(ctx, utils.ModeOS, kubectlArgs...); err != nil {
|
if _, err := utils.ExecKubectlCommand(ctx, utils.ModeOS, kubeconfig, kubecontext, kubectlArgs...); err != nil {
|
||||||
return fmt.Errorf("install failed")
|
return fmt.Errorf("install failed")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -174,7 +177,7 @@ func generateSyncManifests(url, branch, name, namespace, targetPath, tmpDir stri
|
|||||||
|
|
||||||
func applySyncManifests(ctx context.Context, kubeClient client.Client, name, namespace, targetPath, tmpDir string) error {
|
func applySyncManifests(ctx context.Context, kubeClient client.Client, name, namespace, targetPath, tmpDir string) error {
|
||||||
kubectlArgs := []string{"apply", "-k", filepath.Join(tmpDir, targetPath, namespace)}
|
kubectlArgs := []string{"apply", "-k", filepath.Join(tmpDir, targetPath, namespace)}
|
||||||
if _, err := utils.ExecKubectlCommand(ctx, utils.ModeStderrOS, kubectlArgs...); err != nil {
|
if _, err := utils.ExecKubectlCommand(ctx, utils.ModeStderrOS, kubeconfig, kubecontext, kubectlArgs...); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
|
||||||
"github.com/fluxcd/flux2/internal/utils"
|
"github.com/fluxcd/flux2/internal/utils"
|
||||||
"github.com/fluxcd/pkg/git"
|
"github.com/fluxcd/pkg/git"
|
||||||
@@ -35,7 +37,7 @@ var bootstrapGitHubCmd = &cobra.Command{
|
|||||||
Use: "github",
|
Use: "github",
|
||||||
Short: "Bootstrap toolkit components in a GitHub repository",
|
Short: "Bootstrap toolkit components in a GitHub repository",
|
||||||
Long: `The bootstrap github command creates the GitHub repository if it doesn't exists and
|
Long: `The bootstrap github command creates the GitHub repository if it doesn't exists and
|
||||||
commits the toolkit components manifests to the master branch.
|
commits the toolkit components manifests to the main branch.
|
||||||
Then it configures the target cluster to synchronize with the repository.
|
Then it configures the target cluster to synchronize with the repository.
|
||||||
If the toolkit components are present on the cluster,
|
If the toolkit components are present on the cluster,
|
||||||
the bootstrap command will perform an upgrade if needed.`,
|
the bootstrap command will perform an upgrade if needed.`,
|
||||||
@@ -54,8 +56,11 @@ the bootstrap command will perform an upgrade if needed.`,
|
|||||||
# Run bootstrap for a public repository on a personal account
|
# Run bootstrap for a public repository on a personal account
|
||||||
flux bootstrap github --owner=<user> --repository=<repo name> --private=false --personal=true
|
flux bootstrap github --owner=<user> --repository=<repo name> --private=false --personal=true
|
||||||
|
|
||||||
# Run bootstrap for a private repo hosted on GitHub Enterprise
|
# Run bootstrap for a private repo hosted on GitHub Enterprise using SSH auth
|
||||||
flux bootstrap github --owner=<organization> --repository=<repo name> --hostname=<domain>
|
flux bootstrap github --owner=<organization> --repository=<repo name> --hostname=<domain> --ssh-hostname=<domain>
|
||||||
|
|
||||||
|
# Run bootstrap for a private repo hosted on GitHub Enterprise using HTTPS auth
|
||||||
|
flux bootstrap github --owner=<organization> --repository=<repo name> --hostname=<domain> --token-auth
|
||||||
|
|
||||||
# Run bootstrap for a an existing repository with a branch named main
|
# Run bootstrap for a an existing repository with a branch named main
|
||||||
flux bootstrap github --owner=<organization> --repository=<repo name> --branch=main
|
flux bootstrap github --owner=<organization> --repository=<repo name> --branch=main
|
||||||
@@ -64,15 +69,16 @@ the bootstrap command will perform an upgrade if needed.`,
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ghOwner string
|
ghOwner string
|
||||||
ghRepository string
|
ghRepository string
|
||||||
ghInterval time.Duration
|
ghInterval time.Duration
|
||||||
ghPersonal bool
|
ghPersonal bool
|
||||||
ghPrivate bool
|
ghPrivate bool
|
||||||
ghHostname string
|
ghHostname string
|
||||||
ghPath string
|
ghPath string
|
||||||
ghTeams []string
|
ghTeams []string
|
||||||
ghDelete bool
|
ghDelete bool
|
||||||
|
ghSSHHostname string
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -87,6 +93,7 @@ func init() {
|
|||||||
bootstrapGitHubCmd.Flags().BoolVar(&ghPrivate, "private", true, "is private repository")
|
bootstrapGitHubCmd.Flags().BoolVar(&ghPrivate, "private", true, "is private repository")
|
||||||
bootstrapGitHubCmd.Flags().DurationVar(&ghInterval, "interval", time.Minute, "sync interval")
|
bootstrapGitHubCmd.Flags().DurationVar(&ghInterval, "interval", time.Minute, "sync interval")
|
||||||
bootstrapGitHubCmd.Flags().StringVar(&ghHostname, "hostname", git.GitHubDefaultHostname, "GitHub hostname")
|
bootstrapGitHubCmd.Flags().StringVar(&ghHostname, "hostname", git.GitHubDefaultHostname, "GitHub hostname")
|
||||||
|
bootstrapGitHubCmd.Flags().StringVar(&ghSSHHostname, "ssh-hostname", "", "GitHub SSH hostname, to be used when the SSH host differs from the HTTPS one")
|
||||||
bootstrapGitHubCmd.Flags().StringVar(&ghPath, "path", "", "repository path, when specified the cluster sync will be scoped to this path")
|
bootstrapGitHubCmd.Flags().StringVar(&ghPath, "path", "", "repository path, when specified the cluster sync will be scoped to this path")
|
||||||
|
|
||||||
bootstrapGitHubCmd.Flags().BoolVar(&ghDelete, "delete", false, "delete repository (used for testing only)")
|
bootstrapGitHubCmd.Flags().BoolVar(&ghDelete, "delete", false, "delete repository (used for testing only)")
|
||||||
@@ -110,6 +117,10 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ghSSHHostname != "" {
|
||||||
|
repository.SSHHost = ghSSHHostname
|
||||||
|
}
|
||||||
|
|
||||||
provider := &git.GithubProvider{
|
provider := &git.GithubProvider{
|
||||||
IsPrivate: ghPrivate,
|
IsPrivate: ghPrivate,
|
||||||
IsPersonal: ghPersonal,
|
IsPersonal: ghPersonal,
|
||||||
@@ -155,7 +166,7 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// clone repository and checkout the master branch
|
// clone repository and checkout the main branch
|
||||||
if err := repository.Checkout(ctx, bootstrapBranch, tmpDir); err != nil {
|
if err := repository.Checkout(ctx, bootstrapBranch, tmpDir); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -184,7 +195,7 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
logger.Successf("components are up to date")
|
logger.Successf("components are up to date")
|
||||||
}
|
}
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(kubeconfig)
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -201,34 +212,54 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
logger.Successf("install completed")
|
logger.Successf("install completed")
|
||||||
}
|
}
|
||||||
|
|
||||||
// setup SSH deploy key
|
repoURL := repository.GetURL()
|
||||||
if shouldCreateDeployKey(ctx, kubeClient, namespace) {
|
|
||||||
logger.Actionf("configuring deploy key")
|
|
||||||
u, err := url.Parse(repository.GetSSH())
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("git URL parse failed: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
key, err := generateDeployKey(ctx, kubeClient, u, namespace)
|
if bootstrapTokenAuth {
|
||||||
if err != nil {
|
// setup HTTPS token auth
|
||||||
return fmt.Errorf("generating deploy key failed: %w", err)
|
secret := corev1.Secret{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: namespace,
|
||||||
|
Namespace: namespace,
|
||||||
|
},
|
||||||
|
StringData: map[string]string{
|
||||||
|
"username": "git",
|
||||||
|
"password": ghToken,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
if err := upsertSecret(ctx, kubeClient, secret); err != nil {
|
||||||
keyName := "flux"
|
|
||||||
if ghPath != "" {
|
|
||||||
keyName = fmt.Sprintf("flux-%s", ghPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
if changed, err := provider.AddDeployKey(ctx, repository, key, keyName); err != nil {
|
|
||||||
return err
|
return err
|
||||||
} else if changed {
|
}
|
||||||
logger.Successf("deploy key configured")
|
} else {
|
||||||
|
// setup SSH deploy key
|
||||||
|
repoURL = repository.GetSSH()
|
||||||
|
if shouldCreateDeployKey(ctx, kubeClient, namespace) {
|
||||||
|
logger.Actionf("configuring deploy key")
|
||||||
|
u, err := url.Parse(repository.GetSSH())
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("git URL parse failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
key, err := generateDeployKey(ctx, kubeClient, u, namespace)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("generating deploy key failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
keyName := "flux"
|
||||||
|
if ghPath != "" {
|
||||||
|
keyName = fmt.Sprintf("flux-%s", ghPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
if changed, err := provider.AddDeployKey(ctx, repository, key, keyName); err != nil {
|
||||||
|
return err
|
||||||
|
} else if changed {
|
||||||
|
logger.Successf("deploy key configured")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// configure repo synchronization
|
// configure repo synchronization
|
||||||
logger.Actionf("generating sync manifests")
|
logger.Actionf("generating sync manifests")
|
||||||
if err := generateSyncManifests(repository.GetSSH(), bootstrapBranch, namespace, namespace, ghPath, tmpDir, ghInterval); err != nil {
|
if err := generateSyncManifests(repoURL, bootstrapBranch, namespace, namespace, ghPath, tmpDir, ghInterval); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -45,22 +45,22 @@ the bootstrap command will perform an upgrade if needed.`,
|
|||||||
export GITLAB_TOKEN=<my-token>
|
export GITLAB_TOKEN=<my-token>
|
||||||
|
|
||||||
# Run bootstrap for a private repo using HTTPS token authentication
|
# Run bootstrap for a private repo using HTTPS token authentication
|
||||||
flux bootstrap gitlab --owner=<group> --repository=<repo name>
|
flux bootstrap gitlab --owner=<group> --repository=<repo name> --token-auth
|
||||||
|
|
||||||
# Run bootstrap for a private repo using SSH authentication
|
# Run bootstrap for a private repo using SSH authentication
|
||||||
flux bootstrap gitlab --owner=<group> --repository=<repo name> --ssh-hostname=gitlab.com
|
flux bootstrap gitlab --owner=<group> --repository=<repo name>
|
||||||
|
|
||||||
# Run bootstrap for a repository path
|
# Run bootstrap for a repository path
|
||||||
flux bootstrap gitlab --owner=<group> --repository=<repo name> --path=dev-cluster
|
flux bootstrap gitlab --owner=<group> --repository=<repo name> --path=dev-cluster
|
||||||
|
|
||||||
# Run bootstrap for a public repository on a personal account
|
# Run bootstrap for a public repository on a personal account
|
||||||
flux bootstrap gitlab --owner=<user> --repository=<repo name> --private=false --personal=true
|
flux bootstrap gitlab --owner=<user> --repository=<repo name> --private=false --personal --token-auth
|
||||||
|
|
||||||
# Run bootstrap for a private repo hosted on a GitLab server
|
# Run bootstrap for a private repo hosted on a GitLab server
|
||||||
flux bootstrap gitlab --owner=<group> --repository=<repo name> --hostname=<domain>
|
flux bootstrap gitlab --owner=<group> --repository=<repo name> --hostname=<domain> --token-auth
|
||||||
|
|
||||||
# Run bootstrap for a an existing repository with a branch named main
|
# Run bootstrap for a an existing repository with a branch named main
|
||||||
flux bootstrap gitlab --owner=<organization> --repository=<repo name> --branch=main
|
flux bootstrap gitlab --owner=<organization> --repository=<repo name> --branch=main --token-auth
|
||||||
`,
|
`,
|
||||||
RunE: bootstrapGitLabCmdRun,
|
RunE: bootstrapGitLabCmdRun,
|
||||||
}
|
}
|
||||||
@@ -83,7 +83,7 @@ func init() {
|
|||||||
bootstrapGitLabCmd.Flags().BoolVar(&glPrivate, "private", true, "is private repository")
|
bootstrapGitLabCmd.Flags().BoolVar(&glPrivate, "private", true, "is private repository")
|
||||||
bootstrapGitLabCmd.Flags().DurationVar(&glInterval, "interval", time.Minute, "sync interval")
|
bootstrapGitLabCmd.Flags().DurationVar(&glInterval, "interval", time.Minute, "sync interval")
|
||||||
bootstrapGitLabCmd.Flags().StringVar(&glHostname, "hostname", git.GitLabDefaultHostname, "GitLab hostname")
|
bootstrapGitLabCmd.Flags().StringVar(&glHostname, "hostname", git.GitLabDefaultHostname, "GitLab hostname")
|
||||||
bootstrapGitLabCmd.Flags().StringVar(&glSSHHostname, "ssh-hostname", "", "GitLab SSH hostname, when specified a deploy key will be added to the repository")
|
bootstrapGitLabCmd.Flags().StringVar(&glSSHHostname, "ssh-hostname", "", "GitLab SSH hostname, to be used when the SSH host differs from the HTTPS one")
|
||||||
bootstrapGitLabCmd.Flags().StringVar(&glPath, "path", "", "repository path, when specified the cluster sync will be scoped to this path")
|
bootstrapGitLabCmd.Flags().StringVar(&glPath, "path", "", "repository path, when specified the cluster sync will be scoped to this path")
|
||||||
|
|
||||||
bootstrapCmd.AddCommand(bootstrapGitLabCmd)
|
bootstrapCmd.AddCommand(bootstrapGitLabCmd)
|
||||||
@@ -113,7 +113,7 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
IsPersonal: glPersonal,
|
IsPersonal: glPersonal,
|
||||||
}
|
}
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(kubeconfig)
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -180,7 +180,22 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
|
|
||||||
repoURL := repository.GetURL()
|
repoURL := repository.GetURL()
|
||||||
|
|
||||||
if glSSHHostname != "" {
|
if bootstrapTokenAuth {
|
||||||
|
// setup HTTPS token auth
|
||||||
|
secret := corev1.Secret{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: namespace,
|
||||||
|
Namespace: namespace,
|
||||||
|
},
|
||||||
|
StringData: map[string]string{
|
||||||
|
"username": "git",
|
||||||
|
"password": glToken,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if err := upsertSecret(ctx, kubeClient, secret); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
// setup SSH deploy key
|
// setup SSH deploy key
|
||||||
repoURL = repository.GetSSH()
|
repoURL = repository.GetSSH()
|
||||||
if shouldCreateDeployKey(ctx, kubeClient, namespace) {
|
if shouldCreateDeployKey(ctx, kubeClient, namespace) {
|
||||||
@@ -206,21 +221,6 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
logger.Successf("deploy key configured")
|
logger.Successf("deploy key configured")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// setup HTTPS token auth
|
|
||||||
secret := corev1.Secret{
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
Name: namespace,
|
|
||||||
Namespace: namespace,
|
|
||||||
},
|
|
||||||
StringData: map[string]string{
|
|
||||||
"username": "git",
|
|
||||||
"password": glToken,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
if err := upsertSecret(ctx, kubeClient, secret); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// configure repo synchronization
|
// configure repo synchronization
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ func kubectlCheck(ctx context.Context, version string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
kubectlArgs := []string{"version", "--client", "--output", "json"}
|
kubectlArgs := []string{"version", "--client", "--output", "json"}
|
||||||
output, err := utils.ExecKubectlCommand(ctx, utils.ModeCapture, kubectlArgs...)
|
output, err := utils.ExecKubectlCommand(ctx, utils.ModeCapture, kubeconfig, kubecontext, kubectlArgs...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Failuref("kubectl version can't be determined")
|
logger.Failuref("kubectl version can't be determined")
|
||||||
return false
|
return false
|
||||||
@@ -174,12 +174,16 @@ func componentsCheck() bool {
|
|||||||
ok := true
|
ok := true
|
||||||
for _, deployment := range checkComponents {
|
for _, deployment := range checkComponents {
|
||||||
kubectlArgs := []string{"-n", namespace, "rollout", "status", "deployment", deployment, "--timeout", timeout.String()}
|
kubectlArgs := []string{"-n", namespace, "rollout", "status", "deployment", deployment, "--timeout", timeout.String()}
|
||||||
if output, err := utils.ExecKubectlCommand(ctx, utils.ModeCapture, kubectlArgs...); err != nil {
|
if output, err := utils.ExecKubectlCommand(ctx, utils.ModeCapture, kubeconfig, kubecontext, kubectlArgs...); err != nil {
|
||||||
logger.Failuref("%s: %s", deployment, strings.TrimSuffix(output, "\n"))
|
logger.Failuref("%s: %s", deployment, strings.TrimSuffix(output, "\n"))
|
||||||
ok = false
|
ok = false
|
||||||
} else {
|
} else {
|
||||||
logger.Successf("%s is healthy", deployment)
|
logger.Successf("%s is healthy", deployment)
|
||||||
}
|
}
|
||||||
|
kubectlArgs = []string{"-n", namespace, "get", "deployment", deployment, "-o", "jsonpath=\"{..image}\""}
|
||||||
|
if output, err := utils.ExecKubectlCommand(ctx, utils.ModeCapture, kubeconfig, kubecontext, kubectlArgs...); err == nil {
|
||||||
|
logger.Actionf(strings.TrimPrefix(strings.TrimSuffix(output, "\""), "\""))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import (
|
|||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/api/errors"
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
|
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
@@ -120,7 +121,7 @@ func createAlertCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(kubeconfig)
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -179,11 +180,11 @@ func isAlertReady(ctx context.Context, kubeClient client.Client,
|
|||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if c := meta.GetCondition(alert.Status.Conditions, meta.ReadyCondition); c != nil {
|
if c := apimeta.FindStatusCondition(alert.Status.Conditions, meta.ReadyCondition); c != nil {
|
||||||
switch c.Status {
|
switch c.Status {
|
||||||
case corev1.ConditionTrue:
|
case metav1.ConditionTrue:
|
||||||
return true, nil
|
return true, nil
|
||||||
case corev1.ConditionFalse:
|
case metav1.ConditionFalse:
|
||||||
return false, fmt.Errorf(c.Message)
|
return false, fmt.Errorf(c.Message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import (
|
|||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/api/errors"
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
|
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
@@ -116,7 +117,7 @@ func createAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(kubeconfig)
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -177,11 +178,11 @@ func isAlertProviderReady(ctx context.Context, kubeClient client.Client,
|
|||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if c := meta.GetCondition(provider.Status.Conditions, meta.ReadyCondition); c != nil {
|
if c := apimeta.FindStatusCondition(provider.Status.Conditions, meta.ReadyCondition); c != nil {
|
||||||
switch c.Status {
|
switch c.Status {
|
||||||
case corev1.ConditionTrue:
|
case metav1.ConditionTrue:
|
||||||
return true, nil
|
return true, nil
|
||||||
case corev1.ConditionFalse:
|
case metav1.ConditionFalse:
|
||||||
return false, fmt.Errorf(c.Message)
|
return false, fmt.Errorf(c.Message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import (
|
|||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||||
"k8s.io/apimachinery/pkg/api/errors"
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
|
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
@@ -67,6 +68,14 @@ var createHelmReleaseCmd = &cobra.Command{
|
|||||||
--chart=podinfo \
|
--chart=podinfo \
|
||||||
--values=./my-values.yaml
|
--values=./my-values.yaml
|
||||||
|
|
||||||
|
# Create a HelmRelease with values from a Kubernetes secret
|
||||||
|
kubectl -n app create secret generic my-secret-values \
|
||||||
|
--from-file=values.yaml=/path/to/my-secret-values.yaml
|
||||||
|
flux -n app create hr podinfo \
|
||||||
|
--source=HelmRepository/podinfo \
|
||||||
|
--chart=podinfo \
|
||||||
|
--values-from=Secret/my-secret-values
|
||||||
|
|
||||||
# Create a HelmRelease with a custom release name
|
# Create a HelmRelease with a custom release name
|
||||||
flux create hr podinfo \
|
flux create hr podinfo \
|
||||||
--release-name=podinfo-dev
|
--release-name=podinfo-dev
|
||||||
@@ -97,6 +106,8 @@ var (
|
|||||||
hrChartVersion string
|
hrChartVersion string
|
||||||
hrTargetNamespace string
|
hrTargetNamespace string
|
||||||
hrValuesFile string
|
hrValuesFile string
|
||||||
|
hrValuesFrom flags.HelmReleaseValuesFrom
|
||||||
|
hrSAName string
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@@ -106,7 +117,9 @@ func init() {
|
|||||||
createHelmReleaseCmd.Flags().StringVar(&hrChartVersion, "chart-version", "", "Helm chart version, accepts a semver range (ignored for charts from GitRepository sources)")
|
createHelmReleaseCmd.Flags().StringVar(&hrChartVersion, "chart-version", "", "Helm chart version, accepts a semver range (ignored for charts from GitRepository sources)")
|
||||||
createHelmReleaseCmd.Flags().StringArrayVar(&hrDependsOn, "depends-on", nil, "HelmReleases that must be ready before this release can be installed, supported formats '<name>' and '<namespace>/<name>'")
|
createHelmReleaseCmd.Flags().StringArrayVar(&hrDependsOn, "depends-on", nil, "HelmReleases that must be ready before this release can be installed, supported formats '<name>' and '<namespace>/<name>'")
|
||||||
createHelmReleaseCmd.Flags().StringVar(&hrTargetNamespace, "target-namespace", "", "namespace to install this release, defaults to the HelmRelease namespace")
|
createHelmReleaseCmd.Flags().StringVar(&hrTargetNamespace, "target-namespace", "", "namespace to install this release, defaults to the HelmRelease namespace")
|
||||||
|
createHelmReleaseCmd.Flags().StringVar(&hrSAName, "service-account", "", "the name of the service account to impersonate when reconciling this HelmRelease")
|
||||||
createHelmReleaseCmd.Flags().StringVar(&hrValuesFile, "values", "", "local path to the values.yaml file")
|
createHelmReleaseCmd.Flags().StringVar(&hrValuesFile, "values", "", "local path to the values.yaml file")
|
||||||
|
createHelmReleaseCmd.Flags().Var(&hrValuesFrom, "values-from", hrValuesFrom.Description())
|
||||||
createCmd.AddCommand(createHelmReleaseCmd)
|
createCmd.AddCommand(createHelmReleaseCmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,6 +169,10 @@ func createHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if hrSAName != "" {
|
||||||
|
helmRelease.Spec.ServiceAccountName = hrSAName
|
||||||
|
}
|
||||||
|
|
||||||
if hrValuesFile != "" {
|
if hrValuesFile != "" {
|
||||||
data, err := ioutil.ReadFile(hrValuesFile)
|
data, err := ioutil.ReadFile(hrValuesFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -170,6 +187,13 @@ func createHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
helmRelease.Spec.Values = &apiextensionsv1.JSON{Raw: json}
|
helmRelease.Spec.Values = &apiextensionsv1.JSON{Raw: json}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if hrValuesFrom.String() != "" {
|
||||||
|
helmRelease.Spec.ValuesFrom = []helmv2.ValuesReference{{
|
||||||
|
Kind: hrValuesFrom.Kind,
|
||||||
|
Name: hrValuesFrom.Name,
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
if export {
|
if export {
|
||||||
return exportHelmRelease(helmRelease)
|
return exportHelmRelease(helmRelease)
|
||||||
}
|
}
|
||||||
@@ -177,7 +201,7 @@ func createHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(kubeconfig)
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -243,6 +267,6 @@ func isHelmReleaseReady(ctx context.Context, kubeClient client.Client,
|
|||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return meta.HasReadyCondition(helmRelease.Status.Conditions), nil
|
return apimeta.IsStatusConditionTrue(helmRelease.Status.Conditions, meta.ReadyCondition), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import (
|
|||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/api/errors"
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
|
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
@@ -80,23 +81,23 @@ var (
|
|||||||
ksHealthCheck []string
|
ksHealthCheck []string
|
||||||
ksHealthTimeout time.Duration
|
ksHealthTimeout time.Duration
|
||||||
ksSAName string
|
ksSAName string
|
||||||
ksSANamespace string
|
|
||||||
ksDecryptionProvider flags.DecryptionProvider
|
ksDecryptionProvider flags.DecryptionProvider
|
||||||
ksDecryptionSecret string
|
ksDecryptionSecret string
|
||||||
|
ksTargetNamespace string
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
createKsCmd.Flags().Var(&ksSource, "source", ksSource.Description())
|
createKsCmd.Flags().Var(&ksSource, "source", ksSource.Description())
|
||||||
createKsCmd.Flags().StringVar(&ksPath, "path", "./", "path to the directory containing the Kustomization file")
|
createKsCmd.Flags().StringVar(&ksPath, "path", "./", "path to the directory containing a kustomization.yaml file")
|
||||||
createKsCmd.Flags().BoolVar(&ksPrune, "prune", false, "enable garbage collection")
|
createKsCmd.Flags().BoolVar(&ksPrune, "prune", false, "enable garbage collection")
|
||||||
createKsCmd.Flags().StringArrayVar(&ksHealthCheck, "health-check", nil, "workload to be included in the health assessment, in the format '<kind>/<name>.<namespace>'")
|
createKsCmd.Flags().StringArrayVar(&ksHealthCheck, "health-check", nil, "workload to be included in the health assessment, in the format '<kind>/<name>.<namespace>'")
|
||||||
createKsCmd.Flags().DurationVar(&ksHealthTimeout, "health-check-timeout", 2*time.Minute, "timeout of health checking operations")
|
createKsCmd.Flags().DurationVar(&ksHealthTimeout, "health-check-timeout", 2*time.Minute, "timeout of health checking operations")
|
||||||
createKsCmd.Flags().StringVar(&ksValidation, "validation", "", "validate the manifests before applying them on the cluster, can be 'client' or 'server'")
|
createKsCmd.Flags().StringVar(&ksValidation, "validation", "", "validate the manifests before applying them on the cluster, can be 'client' or 'server'")
|
||||||
createKsCmd.Flags().StringArrayVar(&ksDependsOn, "depends-on", nil, "Kustomization that must be ready before this Kustomization can be applied, supported formats '<name>' and '<namespace>/<name>'")
|
createKsCmd.Flags().StringArrayVar(&ksDependsOn, "depends-on", nil, "Kustomization that must be ready before this Kustomization can be applied, supported formats '<name>' and '<namespace>/<name>'")
|
||||||
createKsCmd.Flags().StringVar(&ksSAName, "sa-name", "", "service account name")
|
createKsCmd.Flags().StringVar(&ksSAName, "service-account", "", "the name of the service account to impersonate when reconciling this Kustomization")
|
||||||
createKsCmd.Flags().StringVar(&ksSANamespace, "sa-namespace", "", "service account namespace")
|
|
||||||
createKsCmd.Flags().Var(&ksDecryptionProvider, "decryption-provider", ksDecryptionProvider.Description())
|
createKsCmd.Flags().Var(&ksDecryptionProvider, "decryption-provider", ksDecryptionProvider.Description())
|
||||||
createKsCmd.Flags().StringVar(&ksDecryptionSecret, "decryption-secret", "", "set the Kubernetes secret name that contains the OpenPGP private keys used for sops decryption")
|
createKsCmd.Flags().StringVar(&ksDecryptionSecret, "decryption-secret", "", "set the Kubernetes secret name that contains the OpenPGP private keys used for sops decryption")
|
||||||
|
createKsCmd.Flags().StringVar(&ksTargetNamespace, "target-namespace", "", "overrides the namespace of all Kustomization objects reconciled by this Kustomization")
|
||||||
createCmd.AddCommand(createKsCmd)
|
createCmd.AddCommand(createKsCmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,8 +140,9 @@ func createKsCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
Kind: ksSource.Kind,
|
Kind: ksSource.Kind,
|
||||||
Name: ksSource.Name,
|
Name: ksSource.Name,
|
||||||
},
|
},
|
||||||
Suspend: false,
|
Suspend: false,
|
||||||
Validation: ksValidation,
|
Validation: ksValidation,
|
||||||
|
TargetNamespace: ksTargetNamespace,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,11 +187,8 @@ func createKsCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ksSAName != "" && ksSANamespace != "" {
|
if ksSAName != "" {
|
||||||
kustomization.Spec.ServiceAccount = &kustomizev1.ServiceAccount{
|
kustomization.Spec.ServiceAccountName = ksSAName
|
||||||
Name: ksSAName,
|
|
||||||
Namespace: ksSANamespace,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ksDecryptionProvider != "" {
|
if ksDecryptionProvider != "" {
|
||||||
@@ -209,7 +208,7 @@ func createKsCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(kubeconfig)
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -275,11 +274,11 @@ func isKustomizationReady(ctx context.Context, kubeClient client.Client,
|
|||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if c := meta.GetCondition(kustomization.Status.Conditions, meta.ReadyCondition); c != nil {
|
if c := apimeta.FindStatusCondition(kustomization.Status.Conditions, meta.ReadyCondition); c != nil {
|
||||||
switch c.Status {
|
switch c.Status {
|
||||||
case corev1.ConditionTrue:
|
case metav1.ConditionTrue:
|
||||||
return true, nil
|
return true, nil
|
||||||
case corev1.ConditionFalse:
|
case metav1.ConditionFalse:
|
||||||
return false, fmt.Errorf(c.Message)
|
return false, fmt.Errorf(c.Message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import (
|
|||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/api/errors"
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
|
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
@@ -128,7 +129,7 @@ func createReceiverCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(kubeconfig)
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -189,11 +190,11 @@ func isReceiverReady(ctx context.Context, kubeClient client.Client,
|
|||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if c := meta.GetCondition(receiver.Status.Conditions, meta.ReadyCondition); c != nil {
|
if c := apimeta.FindStatusCondition(receiver.Status.Conditions, meta.ReadyCondition); c != nil {
|
||||||
switch c.Status {
|
switch c.Status {
|
||||||
case corev1.ConditionTrue:
|
case metav1.ConditionTrue:
|
||||||
return true, nil
|
return true, nil
|
||||||
case corev1.ConditionFalse:
|
case metav1.ConditionFalse:
|
||||||
return false, fmt.Errorf(c.Message)
|
return false, fmt.Errorf(c.Message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
52
cmd/flux/create_secret.go
Normal file
52
cmd/flux/create_secret.go
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 The Flux authors
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"sigs.k8s.io/yaml"
|
||||||
|
)
|
||||||
|
|
||||||
|
var createSecretCmd = &cobra.Command{
|
||||||
|
Use: "secret",
|
||||||
|
Short: "Create or update Kubernetes secrets",
|
||||||
|
Long: "The create source sub-commands generate Kubernetes secrets specific to Flux.",
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
createCmd.AddCommand(createSecretCmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func exportSecret(secret corev1.Secret) error {
|
||||||
|
secret.TypeMeta = metav1.TypeMeta{
|
||||||
|
APIVersion: "v1",
|
||||||
|
Kind: "Secret",
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := yaml.Marshal(secret)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("---")
|
||||||
|
fmt.Println(resourceToString(data))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
173
cmd/flux/create_secret_git.go
Normal file
173
cmd/flux/create_secret_git.go
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 The Flux authors
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/elliptic"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
|
||||||
|
"github.com/fluxcd/flux2/internal/flags"
|
||||||
|
"github.com/fluxcd/flux2/internal/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
var createSecretGitCmd = &cobra.Command{
|
||||||
|
Use: "git [name]",
|
||||||
|
Short: "Create or update a Kubernetes secret for Git authentication",
|
||||||
|
Long: `
|
||||||
|
The create secret git command generates a Kubernetes secret with Git credentials.
|
||||||
|
For Git over SSH, the host and SSH keys are automatically generated and stored in the secret.
|
||||||
|
For Git over HTTP/S, the provided basic authentication credentials are stored in the secret.`,
|
||||||
|
Example: ` # Create a Git SSH authentication secret using an ECDSA P-521 curve public key
|
||||||
|
|
||||||
|
flux create secret git podinfo-auth \
|
||||||
|
--url=ssh://git@github.com/stefanprodan/podinfo \
|
||||||
|
--ssh-key-algorithm=ecdsa \
|
||||||
|
--ssh-ecdsa-curve=p521
|
||||||
|
|
||||||
|
# Create a secret for a Git repository using basic authentication
|
||||||
|
flux create secret git podinfo-auth \
|
||||||
|
--url=https://github.com/stefanprodan/podinfo \
|
||||||
|
--username=username \
|
||||||
|
--password=password
|
||||||
|
|
||||||
|
# Create a Git SSH secret on disk and print the deploy key
|
||||||
|
flux create secret git podinfo-auth \
|
||||||
|
--url=ssh://git@github.com/stefanprodan/podinfo \
|
||||||
|
--export > podinfo-auth.yaml
|
||||||
|
|
||||||
|
yq read podinfo-auth.yaml 'data."identity.pub"' | base64 --decode
|
||||||
|
|
||||||
|
# Create a Git SSH secret on disk and encrypt it with Mozilla SOPS
|
||||||
|
flux create secret git podinfo-auth \
|
||||||
|
--namespace=apps \
|
||||||
|
--url=ssh://git@github.com/stefanprodan/podinfo \
|
||||||
|
--export > podinfo-auth.yaml
|
||||||
|
|
||||||
|
sops --encrypt --encrypted-regex '^(data|stringData)$' \
|
||||||
|
--in-place podinfo-auth.yaml
|
||||||
|
`,
|
||||||
|
RunE: createSecretGitCmdRun,
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
secretGitURL string
|
||||||
|
secretGitUsername string
|
||||||
|
secretGitPassword string
|
||||||
|
secretGitKeyAlgorithm flags.PublicKeyAlgorithm = "rsa"
|
||||||
|
secretGitRSABits flags.RSAKeyBits = 2048
|
||||||
|
secretGitECDSACurve = flags.ECDSACurve{Curve: elliptic.P384()}
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
createSecretGitCmd.Flags().StringVar(&secretGitURL, "url", "", "git address, e.g. ssh://git@host/org/repository")
|
||||||
|
createSecretGitCmd.Flags().StringVarP(&secretGitUsername, "username", "u", "", "basic authentication username")
|
||||||
|
createSecretGitCmd.Flags().StringVarP(&secretGitPassword, "password", "p", "", "basic authentication password")
|
||||||
|
createSecretGitCmd.Flags().Var(&secretGitKeyAlgorithm, "ssh-key-algorithm", sourceGitKeyAlgorithm.Description())
|
||||||
|
createSecretGitCmd.Flags().Var(&secretGitRSABits, "ssh-rsa-bits", sourceGitRSABits.Description())
|
||||||
|
createSecretGitCmd.Flags().Var(&secretGitECDSACurve, "ssh-ecdsa-curve", sourceGitECDSACurve.Description())
|
||||||
|
|
||||||
|
createSecretCmd.AddCommand(createSecretGitCmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func createSecretGitCmdRun(cmd *cobra.Command, args []string) error {
|
||||||
|
if len(args) < 1 {
|
||||||
|
return fmt.Errorf("secret name is required")
|
||||||
|
}
|
||||||
|
name := args[0]
|
||||||
|
|
||||||
|
if secretGitURL == "" {
|
||||||
|
return fmt.Errorf("url is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
u, err := url.Parse(secretGitURL)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("git URL parse failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
secretLabels, err := parseLabels()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
secret := corev1.Secret{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: name,
|
||||||
|
Namespace: namespace,
|
||||||
|
Labels: secretLabels,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
switch u.Scheme {
|
||||||
|
case "ssh":
|
||||||
|
pair, err := generateKeyPair(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
hostKey, err := scanHostKey(ctx, u)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
secret.Data = map[string][]byte{
|
||||||
|
"identity": pair.PrivateKey,
|
||||||
|
"identity.pub": pair.PublicKey,
|
||||||
|
"known_hosts": hostKey,
|
||||||
|
}
|
||||||
|
|
||||||
|
if !export {
|
||||||
|
logger.Generatef("deploy key: %s", string(pair.PublicKey))
|
||||||
|
}
|
||||||
|
case "http", "https":
|
||||||
|
if secretGitUsername == "" || secretGitPassword == "" {
|
||||||
|
return fmt.Errorf("for Git over HTTP/S the username and password are required")
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: add cert data when it's implemented in source-controller
|
||||||
|
secret.Data = map[string][]byte{
|
||||||
|
"username": []byte(secretGitUsername),
|
||||||
|
"password": []byte(secretGitPassword),
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("git URL scheme '%s' not supported, can be: ssh, http and https", u.Scheme)
|
||||||
|
}
|
||||||
|
|
||||||
|
if export {
|
||||||
|
return exportSecret(secret)
|
||||||
|
}
|
||||||
|
|
||||||
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := upsertSecret(ctx, kubeClient, secret); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Actionf("secret '%s' created in '%s' namespace", name, namespace)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -140,7 +140,7 @@ func createSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(kubeconfig)
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -154,6 +154,7 @@ func createSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: secretName,
|
Name: secretName,
|
||||||
Namespace: namespace,
|
Namespace: namespace,
|
||||||
|
Labels: sourceLabels,
|
||||||
},
|
},
|
||||||
StringData: map[string]string{},
|
StringData: map[string]string{},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ import (
|
|||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/api/errors"
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
|
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
@@ -94,10 +95,11 @@ var (
|
|||||||
sourceGitUsername string
|
sourceGitUsername string
|
||||||
sourceGitPassword string
|
sourceGitPassword string
|
||||||
|
|
||||||
sourceGitKeyAlgorithm flags.PublicKeyAlgorithm = "rsa"
|
sourceGitKeyAlgorithm flags.PublicKeyAlgorithm = "rsa"
|
||||||
sourceGitRSABits flags.RSAKeyBits = 2048
|
sourceGitRSABits flags.RSAKeyBits = 2048
|
||||||
sourceGitECDSACurve = flags.ECDSACurve{Curve: elliptic.P384()}
|
sourceGitECDSACurve = flags.ECDSACurve{Curve: elliptic.P384()}
|
||||||
sourceGitSecretRef string
|
sourceGitSecretRef string
|
||||||
|
sourceGitImplementation string
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@@ -111,6 +113,7 @@ func init() {
|
|||||||
createSourceGitCmd.Flags().Var(&sourceGitRSABits, "ssh-rsa-bits", sourceGitRSABits.Description())
|
createSourceGitCmd.Flags().Var(&sourceGitRSABits, "ssh-rsa-bits", sourceGitRSABits.Description())
|
||||||
createSourceGitCmd.Flags().Var(&sourceGitECDSACurve, "ssh-ecdsa-curve", sourceGitECDSACurve.Description())
|
createSourceGitCmd.Flags().Var(&sourceGitECDSACurve, "ssh-ecdsa-curve", sourceGitECDSACurve.Description())
|
||||||
createSourceGitCmd.Flags().StringVarP(&sourceGitSecretRef, "secret-ref", "", "", "the name of an existing secret containing SSH or basic credentials")
|
createSourceGitCmd.Flags().StringVarP(&sourceGitSecretRef, "secret-ref", "", "", "the name of an existing secret containing SSH or basic credentials")
|
||||||
|
createSourceGitCmd.Flags().StringVar(&sourceGitImplementation, "git-implementation", "", "the git implementation to use, can be 'go-git' or 'libgit2'")
|
||||||
|
|
||||||
createSourceCmd.AddCommand(createSourceGitCmd)
|
createSourceCmd.AddCommand(createSourceGitCmd)
|
||||||
}
|
}
|
||||||
@@ -141,6 +144,10 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !utils.ContainsItemString([]string{sourcev1.GoGitImplementation, sourcev1.LibGit2Implementation, ""}, sourceGitImplementation) {
|
||||||
|
return fmt.Errorf("Invalid git implementation %q", sourceGitImplementation)
|
||||||
|
}
|
||||||
|
|
||||||
gitRepository := sourcev1.GitRepository{
|
gitRepository := sourcev1.GitRepository{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: name,
|
Name: name,
|
||||||
@@ -152,7 +159,8 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
Interval: metav1.Duration{
|
Interval: metav1.Duration{
|
||||||
Duration: interval,
|
Duration: interval,
|
||||||
},
|
},
|
||||||
Reference: &sourcev1.GitRepositoryRef{},
|
Reference: &sourcev1.GitRepositoryRef{},
|
||||||
|
GitImplementation: sourceGitImplementation,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,7 +184,7 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(kubeconfig)
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -186,13 +194,13 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
if sourceGitSecretRef != "" {
|
if sourceGitSecretRef != "" {
|
||||||
withAuth = true
|
withAuth = true
|
||||||
} else if u.Scheme == "ssh" {
|
} else if u.Scheme == "ssh" {
|
||||||
logger.Actionf("generating deploy key pair")
|
logger.Generatef("generating deploy key pair")
|
||||||
pair, err := generateKeyPair(ctx)
|
pair, err := generateKeyPair(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("%s", pair.PublicKey)
|
logger.Successf("deploy key: %s", pair.PublicKey)
|
||||||
prompt := promptui.Prompt{
|
prompt := promptui.Prompt{
|
||||||
Label: "Have you added the deploy key to your repository",
|
Label: "Have you added the deploy key to your repository",
|
||||||
IsConfirm: true,
|
IsConfirm: true,
|
||||||
@@ -206,14 +214,14 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
logger.Successf("collected public key from SSH server:")
|
logger.Successf("collected public key from SSH server:\n%s", hostKey)
|
||||||
fmt.Printf("%s", hostKey)
|
|
||||||
|
|
||||||
logger.Actionf("applying secret with keys")
|
logger.Actionf("applying secret with keys")
|
||||||
secret := corev1.Secret{
|
secret := corev1.Secret{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: name,
|
Name: name,
|
||||||
Namespace: namespace,
|
Namespace: namespace,
|
||||||
|
Labels: sourceLabels,
|
||||||
},
|
},
|
||||||
StringData: map[string]string{
|
StringData: map[string]string{
|
||||||
"identity": string(pair.PrivateKey),
|
"identity": string(pair.PrivateKey),
|
||||||
@@ -231,6 +239,7 @@ func createSourceGitCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: name,
|
Name: name,
|
||||||
Namespace: namespace,
|
Namespace: namespace,
|
||||||
|
Labels: sourceLabels,
|
||||||
},
|
},
|
||||||
StringData: map[string]string{
|
StringData: map[string]string{
|
||||||
"username": sourceGitUsername,
|
"username": sourceGitUsername,
|
||||||
@@ -375,11 +384,11 @@ func isGitRepositoryReady(ctx context.Context, kubeClient client.Client,
|
|||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if c := meta.GetCondition(gitRepository.Status.Conditions, meta.ReadyCondition); c != nil {
|
if c := apimeta.FindStatusCondition(gitRepository.Status.Conditions, meta.ReadyCondition); c != nil {
|
||||||
switch c.Status {
|
switch c.Status {
|
||||||
case corev1.ConditionTrue:
|
case metav1.ConditionTrue:
|
||||||
return true, nil
|
return true, nil
|
||||||
case corev1.ConditionFalse:
|
case metav1.ConditionFalse:
|
||||||
return false, fmt.Errorf(c.Message)
|
return false, fmt.Errorf(c.Message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,9 +23,11 @@ import (
|
|||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/fluxcd/pkg/apis/meta"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/api/errors"
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
|
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
@@ -136,7 +138,7 @@ func createSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(kubeconfig)
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -149,6 +151,7 @@ func createSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: secretName,
|
Name: secretName,
|
||||||
Namespace: namespace,
|
Namespace: namespace,
|
||||||
|
Labels: sourceLabels,
|
||||||
},
|
},
|
||||||
StringData: map[string]string{},
|
StringData: map[string]string{},
|
||||||
}
|
}
|
||||||
@@ -242,3 +245,28 @@ func upsertHelmRepository(ctx context.Context, kubeClient client.Client,
|
|||||||
logger.Successf("source updated")
|
logger.Successf("source updated")
|
||||||
return namespacedName, nil
|
return namespacedName, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isHelmRepositoryReady(ctx context.Context, kubeClient client.Client,
|
||||||
|
namespacedName types.NamespacedName, helmRepository *sourcev1.HelmRepository) wait.ConditionFunc {
|
||||||
|
return func() (bool, error) {
|
||||||
|
err := kubeClient.Get(ctx, namespacedName, helmRepository)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Confirm the state we are observing is for the current generation
|
||||||
|
if helmRepository.Generation != helmRepository.Status.ObservedGeneration {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if c := apimeta.FindStatusCondition(helmRepository.Status.Conditions, meta.ReadyCondition); c != nil {
|
||||||
|
switch c.Status {
|
||||||
|
case metav1.ConditionTrue:
|
||||||
|
return true, nil
|
||||||
|
case metav1.ConditionFalse:
|
||||||
|
return false, fmt.Errorf(c.Message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ var createTenantCmd = &cobra.Command{
|
|||||||
Use: "tenant",
|
Use: "tenant",
|
||||||
Short: "Create or update a tenant",
|
Short: "Create or update a tenant",
|
||||||
Long: `
|
Long: `
|
||||||
The create tenant command generates namespaces and role bindings to limit the
|
The create tenant command generates namespaces, service accounts and role bindings to limit the
|
||||||
reconcilers scope to the tenant namespaces.`,
|
reconcilers scope to the tenant namespaces.`,
|
||||||
Example: ` # Create a tenant with access to a namespace
|
Example: ` # Create a tenant with access to a namespace
|
||||||
flux create tenant dev-team \
|
flux create tenant dev-team \
|
||||||
@@ -55,8 +55,7 @@ reconcilers scope to the tenant namespaces.`,
|
|||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
tenantLabel = "toolkit.fluxcd.io/tenant"
|
tenantLabel = "toolkit.fluxcd.io/tenant"
|
||||||
tenantRoleBinding = "gotk-reconciler"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -65,7 +64,6 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
createTenantCmd.Hidden = true
|
|
||||||
createTenantCmd.Flags().StringSliceVar(&tenantNamespaces, "with-namespace", nil, "namespace belonging to this tenant")
|
createTenantCmd.Flags().StringSliceVar(&tenantNamespaces, "with-namespace", nil, "namespace belonging to this tenant")
|
||||||
createTenantCmd.Flags().StringVar(&tenantClusterRole, "cluster-role", "cluster-admin", "cluster role of the tenant role binding")
|
createTenantCmd.Flags().StringVar(&tenantClusterRole, "cluster-role", "cluster-admin", "cluster role of the tenant role binding")
|
||||||
createCmd.AddCommand(createTenantCmd)
|
createCmd.AddCommand(createTenantCmd)
|
||||||
@@ -89,6 +87,7 @@ func createTenantCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var namespaces []corev1.Namespace
|
var namespaces []corev1.Namespace
|
||||||
|
var accounts []corev1.ServiceAccount
|
||||||
var roleBindings []rbacv1.RoleBinding
|
var roleBindings []rbacv1.RoleBinding
|
||||||
|
|
||||||
for _, ns := range tenantNamespaces {
|
for _, ns := range tenantNamespaces {
|
||||||
@@ -111,9 +110,19 @@ func createTenantCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
}
|
}
|
||||||
namespaces = append(namespaces, namespace)
|
namespaces = append(namespaces, namespace)
|
||||||
|
|
||||||
|
account := corev1.ServiceAccount{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: tenant,
|
||||||
|
Namespace: ns,
|
||||||
|
Labels: objLabels,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
accounts = append(accounts, account)
|
||||||
|
|
||||||
roleBinding := rbacv1.RoleBinding{
|
roleBinding := rbacv1.RoleBinding{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: tenantRoleBinding,
|
Name: fmt.Sprintf("%s-reconciler", tenant),
|
||||||
Namespace: ns,
|
Namespace: ns,
|
||||||
Labels: objLabels,
|
Labels: objLabels,
|
||||||
},
|
},
|
||||||
@@ -123,6 +132,11 @@ func createTenantCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
Kind: "User",
|
Kind: "User",
|
||||||
Name: fmt.Sprintf("gotk:%s:reconciler", ns),
|
Name: fmt.Sprintf("gotk:%s:reconciler", ns),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Kind: "ServiceAccount",
|
||||||
|
Name: tenant,
|
||||||
|
Namespace: ns,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
RoleRef: rbacv1.RoleRef{
|
RoleRef: rbacv1.RoleRef{
|
||||||
APIGroup: "rbac.authorization.k8s.io",
|
APIGroup: "rbac.authorization.k8s.io",
|
||||||
@@ -135,7 +149,7 @@ func createTenantCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
|
|
||||||
if export {
|
if export {
|
||||||
for i, _ := range tenantNamespaces {
|
for i, _ := range tenantNamespaces {
|
||||||
if err := exportTenant(namespaces[i], roleBindings[1]); err != nil {
|
if err := exportTenant(namespaces[i], accounts[i], roleBindings[i]); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -145,7 +159,7 @@ func createTenantCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(kubeconfig)
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -156,6 +170,11 @@ func createTenantCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.Actionf("applying service account %s", accounts[i].Name)
|
||||||
|
if err := upsertServiceAccount(ctx, kubeClient, accounts[i]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
logger.Actionf("applying role binding %s", roleBindings[i].Name)
|
logger.Actionf("applying role binding %s", roleBindings[i].Name)
|
||||||
if err := upsertRoleBinding(ctx, kubeClient, roleBindings[i]); err != nil {
|
if err := upsertRoleBinding(ctx, kubeClient, roleBindings[i]); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -195,6 +214,35 @@ func upsertNamespace(ctx context.Context, kubeClient client.Client, namespace co
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func upsertServiceAccount(ctx context.Context, kubeClient client.Client, account corev1.ServiceAccount) error {
|
||||||
|
namespacedName := types.NamespacedName{
|
||||||
|
Namespace: account.GetNamespace(),
|
||||||
|
Name: account.GetName(),
|
||||||
|
}
|
||||||
|
|
||||||
|
var existing corev1.ServiceAccount
|
||||||
|
err := kubeClient.Get(ctx, namespacedName, &existing)
|
||||||
|
if err != nil {
|
||||||
|
if errors.IsNotFound(err) {
|
||||||
|
if err := kubeClient.Create(ctx, &account); err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !equality.Semantic.DeepDerivative(account.Labels, existing.Labels) {
|
||||||
|
existing.Labels = account.Labels
|
||||||
|
if err := kubeClient.Update(ctx, &existing); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func upsertRoleBinding(ctx context.Context, kubeClient client.Client, roleBinding rbacv1.RoleBinding) error {
|
func upsertRoleBinding(ctx context.Context, kubeClient client.Client, roleBinding rbacv1.RoleBinding) error {
|
||||||
namespacedName := types.NamespacedName{
|
namespacedName := types.NamespacedName{
|
||||||
Namespace: roleBinding.GetNamespace(),
|
Namespace: roleBinding.GetNamespace(),
|
||||||
@@ -228,7 +276,7 @@ func upsertRoleBinding(ctx context.Context, kubeClient client.Client, roleBindin
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func exportTenant(namespace corev1.Namespace, roleBinding rbacv1.RoleBinding) error {
|
func exportTenant(namespace corev1.Namespace, account corev1.ServiceAccount, roleBinding rbacv1.RoleBinding) error {
|
||||||
namespace.TypeMeta = metav1.TypeMeta{
|
namespace.TypeMeta = metav1.TypeMeta{
|
||||||
APIVersion: "v1",
|
APIVersion: "v1",
|
||||||
Kind: "Namespace",
|
Kind: "Namespace",
|
||||||
@@ -242,6 +290,19 @@ func exportTenant(namespace corev1.Namespace, roleBinding rbacv1.RoleBinding) er
|
|||||||
data = bytes.Replace(data, []byte("spec: {}\n"), []byte(""), 1)
|
data = bytes.Replace(data, []byte("spec: {}\n"), []byte(""), 1)
|
||||||
fmt.Println(resourceToString(data))
|
fmt.Println(resourceToString(data))
|
||||||
|
|
||||||
|
account.TypeMeta = metav1.TypeMeta{
|
||||||
|
APIVersion: "v1",
|
||||||
|
Kind: "ServiceAccount",
|
||||||
|
}
|
||||||
|
data, err = yaml.Marshal(account)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("---")
|
||||||
|
data = bytes.Replace(data, []byte("spec: {}\n"), []byte(""), 1)
|
||||||
|
fmt.Println(resourceToString(data))
|
||||||
|
|
||||||
roleBinding.TypeMeta = metav1.TypeMeta{
|
roleBinding.TypeMeta = metav1.TypeMeta{
|
||||||
APIVersion: "rbac.authorization.k8s.io/v1",
|
APIVersion: "rbac.authorization.k8s.io/v1",
|
||||||
Kind: "RoleBinding",
|
Kind: "RoleBinding",
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ func deleteAlertCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(kubeconfig)
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ func deleteAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(kubeconfig)
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ func deleteHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(kubeconfig)
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ func deleteKsCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(kubeconfig)
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ func deleteReceiverCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(kubeconfig)
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ func deleteSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(kubeconfig)
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ func deleteSourceGitCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(kubeconfig)
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ func deleteSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(kubeconfig)
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ func exportAlertCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(kubeconfig)
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ func exportAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(kubeconfig)
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ func exportHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(kubeconfig)
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ func exportKsCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(kubeconfig)
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ func exportReceiverCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(kubeconfig)
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ func exportSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(kubeconfig)
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ func exportSourceGitCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(kubeconfig)
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ func exportSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(kubeconfig)
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
corev1 "k8s.io/api/core/v1"
|
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
|
||||||
"github.com/fluxcd/flux2/internal/utils"
|
"github.com/fluxcd/flux2/internal/utils"
|
||||||
@@ -49,7 +50,7 @@ func getAlertCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(kubeconfig)
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -69,28 +70,26 @@ func getAlertCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
header := []string{"Name", "Suspended", "Ready", "Message"}
|
header := []string{"Name", "Ready", "Message", "Suspended"}
|
||||||
if allNamespaces {
|
if allNamespaces {
|
||||||
header = append([]string{"Namespace"}, header...)
|
header = append([]string{"Namespace"}, header...)
|
||||||
}
|
}
|
||||||
var rows [][]string
|
var rows [][]string
|
||||||
for _, alert := range list.Items {
|
for _, alert := range list.Items {
|
||||||
row := []string{}
|
row := []string{}
|
||||||
if c := meta.GetCondition(alert.Status.Conditions, meta.ReadyCondition); c != nil {
|
if c := apimeta.FindStatusCondition(alert.Status.Conditions, meta.ReadyCondition); c != nil {
|
||||||
row = []string{
|
row = []string{
|
||||||
alert.GetName(),
|
alert.GetName(),
|
||||||
//alert.Status.LastAppliedRevision,
|
|
||||||
strings.Title(strconv.FormatBool(alert.Spec.Suspend)),
|
|
||||||
string(c.Status),
|
string(c.Status),
|
||||||
c.Message,
|
c.Message,
|
||||||
|
strings.Title(strconv.FormatBool(alert.Spec.Suspend)),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
row = []string{
|
row = []string{
|
||||||
alert.GetName(),
|
alert.GetName(),
|
||||||
//alert.Status.LastAppliedRevision,
|
string(metav1.ConditionFalse),
|
||||||
strings.Title(strconv.FormatBool(alert.Spec.Suspend)),
|
|
||||||
string(corev1.ConditionFalse),
|
|
||||||
"waiting to be reconciled",
|
"waiting to be reconciled",
|
||||||
|
strings.Title(strconv.FormatBool(alert.Spec.Suspend)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if allNamespaces {
|
if allNamespaces {
|
||||||
|
|||||||
@@ -21,7 +21,8 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
corev1 "k8s.io/api/core/v1"
|
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
|
||||||
"github.com/fluxcd/flux2/internal/utils"
|
"github.com/fluxcd/flux2/internal/utils"
|
||||||
@@ -47,7 +48,7 @@ func getAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(kubeconfig)
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -74,7 +75,7 @@ func getAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
var rows [][]string
|
var rows [][]string
|
||||||
for _, provider := range list.Items {
|
for _, provider := range list.Items {
|
||||||
row := []string{}
|
row := []string{}
|
||||||
if c := meta.GetCondition(provider.Status.Conditions, meta.ReadyCondition); c != nil {
|
if c := apimeta.FindStatusCondition(provider.Status.Conditions, meta.ReadyCondition); c != nil {
|
||||||
row = []string{
|
row = []string{
|
||||||
provider.GetName(),
|
provider.GetName(),
|
||||||
string(c.Status),
|
string(c.Status),
|
||||||
@@ -83,7 +84,7 @@ func getAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
} else {
|
} else {
|
||||||
row = []string{
|
row = []string{
|
||||||
provider.GetName(),
|
provider.GetName(),
|
||||||
string(corev1.ConditionFalse),
|
string(metav1.ConditionFalse),
|
||||||
"waiting to be reconciled",
|
"waiting to be reconciled",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,8 @@ import (
|
|||||||
"github.com/fluxcd/pkg/apis/meta"
|
"github.com/fluxcd/pkg/apis/meta"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
corev1 "k8s.io/api/core/v1"
|
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
|
||||||
helmv2 "github.com/fluxcd/helm-controller/api/v2beta1"
|
helmv2 "github.com/fluxcd/helm-controller/api/v2beta1"
|
||||||
@@ -51,7 +52,7 @@ func getHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(kubeconfig)
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -71,28 +72,28 @@ func getHelmReleaseCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
header := []string{"Name", "Revision", "Suspended", "Ready", "Message"}
|
header := []string{"Name", "Ready", "Message", "Revision", "Suspended"}
|
||||||
if allNamespaces {
|
if allNamespaces {
|
||||||
header = append([]string{"Namespace"}, header...)
|
header = append([]string{"Namespace"}, header...)
|
||||||
}
|
}
|
||||||
var rows [][]string
|
var rows [][]string
|
||||||
for _, helmRelease := range list.Items {
|
for _, helmRelease := range list.Items {
|
||||||
row := []string{}
|
row := []string{}
|
||||||
if c := meta.GetCondition(helmRelease.Status.Conditions, meta.ReadyCondition); c != nil {
|
if c := apimeta.FindStatusCondition(helmRelease.Status.Conditions, meta.ReadyCondition); c != nil {
|
||||||
row = []string{
|
row = []string{
|
||||||
helmRelease.GetName(),
|
helmRelease.GetName(),
|
||||||
helmRelease.Status.LastAppliedRevision,
|
|
||||||
strings.Title(strconv.FormatBool(helmRelease.Spec.Suspend)),
|
|
||||||
string(c.Status),
|
string(c.Status),
|
||||||
c.Message,
|
c.Message,
|
||||||
|
helmRelease.Status.LastAppliedRevision,
|
||||||
|
strings.Title(strconv.FormatBool(helmRelease.Spec.Suspend)),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
row = []string{
|
row = []string{
|
||||||
helmRelease.GetName(),
|
helmRelease.GetName(),
|
||||||
|
string(metav1.ConditionFalse),
|
||||||
|
"waiting to be reconciled",
|
||||||
helmRelease.Status.LastAppliedRevision,
|
helmRelease.Status.LastAppliedRevision,
|
||||||
strings.Title(strconv.FormatBool(helmRelease.Spec.Suspend)),
|
strings.Title(strconv.FormatBool(helmRelease.Spec.Suspend)),
|
||||||
string(corev1.ConditionFalse),
|
|
||||||
"waiting to be reconciled",
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if allNamespaces {
|
if allNamespaces {
|
||||||
|
|||||||
@@ -27,7 +27,8 @@ import (
|
|||||||
|
|
||||||
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1"
|
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
corev1 "k8s.io/api/core/v1"
|
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -50,7 +51,7 @@ func getKsCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(kubeconfig)
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -70,28 +71,28 @@ func getKsCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
header := []string{"Name", "Revision", "Suspended", "Ready", "Message"}
|
header := []string{"Name", "Ready", "Message", "Revision", "Suspended"}
|
||||||
if allNamespaces {
|
if allNamespaces {
|
||||||
header = append([]string{"Namespace"}, header...)
|
header = append([]string{"Namespace"}, header...)
|
||||||
}
|
}
|
||||||
var rows [][]string
|
var rows [][]string
|
||||||
for _, kustomization := range list.Items {
|
for _, kustomization := range list.Items {
|
||||||
row := []string{}
|
row := []string{}
|
||||||
if c := meta.GetCondition(kustomization.Status.Conditions, meta.ReadyCondition); c != nil {
|
if c := apimeta.FindStatusCondition(kustomization.Status.Conditions, meta.ReadyCondition); c != nil {
|
||||||
row = []string{
|
row = []string{
|
||||||
kustomization.GetName(),
|
kustomization.GetName(),
|
||||||
kustomization.Status.LastAppliedRevision,
|
|
||||||
strings.Title(strconv.FormatBool(kustomization.Spec.Suspend)),
|
|
||||||
string(c.Status),
|
string(c.Status),
|
||||||
c.Message,
|
c.Message,
|
||||||
|
kustomization.Status.LastAppliedRevision,
|
||||||
|
strings.Title(strconv.FormatBool(kustomization.Spec.Suspend)),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
row = []string{
|
row = []string{
|
||||||
kustomization.GetName(),
|
kustomization.GetName(),
|
||||||
|
string(metav1.ConditionFalse),
|
||||||
|
"waiting to be reconciled",
|
||||||
kustomization.Status.LastAppliedRevision,
|
kustomization.Status.LastAppliedRevision,
|
||||||
strings.Title(strconv.FormatBool(kustomization.Spec.Suspend)),
|
strings.Title(strconv.FormatBool(kustomization.Spec.Suspend)),
|
||||||
string(corev1.ConditionFalse),
|
|
||||||
"waiting to be reconciled",
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if allNamespaces {
|
if allNamespaces {
|
||||||
|
|||||||
@@ -23,7 +23,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
corev1 "k8s.io/api/core/v1"
|
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
|
||||||
"github.com/fluxcd/flux2/internal/utils"
|
"github.com/fluxcd/flux2/internal/utils"
|
||||||
@@ -49,7 +50,7 @@ func getReceiverCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(kubeconfig)
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -69,26 +70,26 @@ func getReceiverCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
header := []string{"Name", "Suspended", "Ready", "Message"}
|
header := []string{"Name", "Ready", "Message", "Suspended"}
|
||||||
if allNamespaces {
|
if allNamespaces {
|
||||||
header = append([]string{"Namespace"}, header...)
|
header = append([]string{"Namespace"}, header...)
|
||||||
}
|
}
|
||||||
var rows [][]string
|
var rows [][]string
|
||||||
for _, receiver := range list.Items {
|
for _, receiver := range list.Items {
|
||||||
row := []string{}
|
row := []string{}
|
||||||
if c := meta.GetCondition(receiver.Status.Conditions, meta.ReadyCondition); c != nil {
|
if c := apimeta.FindStatusCondition(receiver.Status.Conditions, meta.ReadyCondition); c != nil {
|
||||||
row = []string{
|
row = []string{
|
||||||
receiver.GetName(),
|
receiver.GetName(),
|
||||||
strings.Title(strconv.FormatBool(receiver.Spec.Suspend)),
|
|
||||||
string(c.Status),
|
string(c.Status),
|
||||||
c.Message,
|
c.Message,
|
||||||
|
strings.Title(strconv.FormatBool(receiver.Spec.Suspend)),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
row = []string{
|
row = []string{
|
||||||
receiver.GetName(),
|
receiver.GetName(),
|
||||||
strings.Title(strconv.FormatBool(receiver.Spec.Suspend)),
|
string(metav1.ConditionFalse),
|
||||||
string(corev1.ConditionFalse),
|
|
||||||
"waiting to be reconciled",
|
"waiting to be reconciled",
|
||||||
|
strings.Title(strconv.FormatBool(receiver.Spec.Suspend)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rows = append(rows, row)
|
rows = append(rows, row)
|
||||||
|
|||||||
@@ -19,13 +19,16 @@ package main
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"os"
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/fluxcd/flux2/internal/utils"
|
"github.com/fluxcd/flux2/internal/utils"
|
||||||
"github.com/fluxcd/pkg/apis/meta"
|
"github.com/fluxcd/pkg/apis/meta"
|
||||||
|
|
||||||
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
|
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
corev1 "k8s.io/api/core/v1"
|
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -35,6 +38,9 @@ var getSourceBucketCmd = &cobra.Command{
|
|||||||
Long: "The get sources bucket command prints the status of the Bucket sources.",
|
Long: "The get sources bucket command prints the status of the Bucket sources.",
|
||||||
Example: ` # List all Buckets and their status
|
Example: ` # List all Buckets and their status
|
||||||
flux get sources bucket
|
flux get sources bucket
|
||||||
|
|
||||||
|
# List buckets from all namespaces
|
||||||
|
flux get sources helm --all-namespaces
|
||||||
`,
|
`,
|
||||||
RunE: getSourceBucketCmdRun,
|
RunE: getSourceBucketCmdRun,
|
||||||
}
|
}
|
||||||
@@ -47,7 +53,7 @@ func getSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(kubeconfig)
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -67,7 +73,7 @@ func getSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
header := []string{"Name", "Revision", "Ready", "Message"}
|
header := []string{"Name", "Ready", "Message", "Revision", "Suspended"}
|
||||||
if allNamespaces {
|
if allNamespaces {
|
||||||
header = append([]string{"Namespace"}, header...)
|
header = append([]string{"Namespace"}, header...)
|
||||||
}
|
}
|
||||||
@@ -78,19 +84,21 @@ func getSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
if source.GetArtifact() != nil {
|
if source.GetArtifact() != nil {
|
||||||
revision = source.GetArtifact().Revision
|
revision = source.GetArtifact().Revision
|
||||||
}
|
}
|
||||||
if c := meta.GetCondition(source.Status.Conditions, meta.ReadyCondition); c != nil {
|
if c := apimeta.FindStatusCondition(source.Status.Conditions, meta.ReadyCondition); c != nil {
|
||||||
row = []string{
|
row = []string{
|
||||||
source.GetName(),
|
source.GetName(),
|
||||||
revision,
|
|
||||||
string(c.Status),
|
string(c.Status),
|
||||||
c.Message,
|
c.Message,
|
||||||
|
revision,
|
||||||
|
strings.Title(strconv.FormatBool(source.Spec.Suspend)),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
row = []string{
|
row = []string{
|
||||||
source.GetName(),
|
source.GetName(),
|
||||||
revision,
|
string(metav1.ConditionFalse),
|
||||||
string(corev1.ConditionFalse),
|
|
||||||
"waiting to be reconciled",
|
"waiting to be reconciled",
|
||||||
|
revision,
|
||||||
|
strings.Title(strconv.FormatBool(source.Spec.Suspend)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if allNamespaces {
|
if allNamespaces {
|
||||||
|
|||||||
111
cmd/flux/get_source_chart.go
Normal file
111
cmd/flux/get_source_chart.go
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 The Flux authors
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/fluxcd/flux2/internal/utils"
|
||||||
|
"github.com/fluxcd/pkg/apis/meta"
|
||||||
|
|
||||||
|
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
)
|
||||||
|
|
||||||
|
var getSourceHelmChartCmd = &cobra.Command{
|
||||||
|
Use: "chart",
|
||||||
|
Short: "Get HelmChart statuses",
|
||||||
|
Long: "The get sources chart command prints the status of the HelmCharts.",
|
||||||
|
Example: ` # List all Helm charts and their status
|
||||||
|
flux get sources chart
|
||||||
|
|
||||||
|
# List Helm charts from all namespaces
|
||||||
|
flux get sources chart --all-namespaces
|
||||||
|
`,
|
||||||
|
RunE: getSourceHelmChartCmdRun,
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
getSourceCmd.AddCommand(getSourceHelmChartCmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSourceHelmChartCmdRun(cmd *cobra.Command, args []string) error {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var listOpts []client.ListOption
|
||||||
|
if !allNamespaces {
|
||||||
|
listOpts = append(listOpts, client.InNamespace(namespace))
|
||||||
|
}
|
||||||
|
var list sourcev1.HelmChartList
|
||||||
|
err = kubeClient.List(ctx, &list, listOpts...)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(list.Items) == 0 {
|
||||||
|
logger.Failuref("no chart sources found in %s namespace", namespace)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
header := []string{"Name", "Ready", "Message", "Revision", "Suspended"}
|
||||||
|
if allNamespaces {
|
||||||
|
header = append([]string{"Namespace"}, header...)
|
||||||
|
}
|
||||||
|
var rows [][]string
|
||||||
|
for _, source := range list.Items {
|
||||||
|
var row []string
|
||||||
|
var revision string
|
||||||
|
if source.GetArtifact() != nil {
|
||||||
|
revision = source.GetArtifact().Revision
|
||||||
|
}
|
||||||
|
if c := apimeta.FindStatusCondition(source.Status.Conditions, meta.ReadyCondition); c != nil {
|
||||||
|
row = []string{
|
||||||
|
source.GetName(),
|
||||||
|
string(c.Status),
|
||||||
|
c.Message,
|
||||||
|
revision,
|
||||||
|
strings.Title(strconv.FormatBool(source.Spec.Suspend)),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
row = []string{
|
||||||
|
source.GetName(),
|
||||||
|
string(metav1.ConditionFalse),
|
||||||
|
"waiting to be reconciled",
|
||||||
|
revision,
|
||||||
|
strings.Title(strconv.FormatBool(source.Spec.Suspend)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if allNamespaces {
|
||||||
|
row = append([]string{source.Namespace}, row...)
|
||||||
|
}
|
||||||
|
rows = append(rows, row)
|
||||||
|
}
|
||||||
|
utils.PrintTable(os.Stdout, header, rows)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -19,13 +19,16 @@ package main
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"os"
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/fluxcd/flux2/internal/utils"
|
"github.com/fluxcd/flux2/internal/utils"
|
||||||
"github.com/fluxcd/pkg/apis/meta"
|
"github.com/fluxcd/pkg/apis/meta"
|
||||||
|
|
||||||
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
|
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
corev1 "k8s.io/api/core/v1"
|
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -35,6 +38,9 @@ var getSourceGitCmd = &cobra.Command{
|
|||||||
Long: "The get sources git command prints the status of the GitRepository sources.",
|
Long: "The get sources git command prints the status of the GitRepository sources.",
|
||||||
Example: ` # List all Git repositories and their status
|
Example: ` # List all Git repositories and their status
|
||||||
flux get sources git
|
flux get sources git
|
||||||
|
|
||||||
|
# List Git repositories from all namespaces
|
||||||
|
flux get sources git --all-namespaces
|
||||||
`,
|
`,
|
||||||
RunE: getSourceGitCmdRun,
|
RunE: getSourceGitCmdRun,
|
||||||
}
|
}
|
||||||
@@ -47,7 +53,7 @@ func getSourceGitCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(kubeconfig)
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -67,7 +73,7 @@ func getSourceGitCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
header := []string{"Name", "Revision", "Ready", "Message"}
|
header := []string{"Name", "Ready", "Message", "Revision", "Suspended"}
|
||||||
if allNamespaces {
|
if allNamespaces {
|
||||||
header = append([]string{"Namespace"}, header...)
|
header = append([]string{"Namespace"}, header...)
|
||||||
}
|
}
|
||||||
@@ -78,19 +84,21 @@ func getSourceGitCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
if source.GetArtifact() != nil {
|
if source.GetArtifact() != nil {
|
||||||
revision = source.GetArtifact().Revision
|
revision = source.GetArtifact().Revision
|
||||||
}
|
}
|
||||||
if c := meta.GetCondition(source.Status.Conditions, meta.ReadyCondition); c != nil {
|
if c := apimeta.FindStatusCondition(source.Status.Conditions, meta.ReadyCondition); c != nil {
|
||||||
row = []string{
|
row = []string{
|
||||||
source.GetName(),
|
source.GetName(),
|
||||||
revision,
|
|
||||||
string(c.Status),
|
string(c.Status),
|
||||||
c.Message,
|
c.Message,
|
||||||
|
revision,
|
||||||
|
strings.Title(strconv.FormatBool(source.Spec.Suspend)),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
row = []string{
|
row = []string{
|
||||||
source.GetName(),
|
source.GetName(),
|
||||||
revision,
|
string(metav1.ConditionFalse),
|
||||||
string(corev1.ConditionFalse),
|
|
||||||
"waiting to be reconciled",
|
"waiting to be reconciled",
|
||||||
|
revision,
|
||||||
|
strings.Title(strconv.FormatBool(source.Spec.Suspend)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if allNamespaces {
|
if allNamespaces {
|
||||||
|
|||||||
@@ -19,13 +19,16 @@ package main
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"os"
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/fluxcd/flux2/internal/utils"
|
"github.com/fluxcd/flux2/internal/utils"
|
||||||
"github.com/fluxcd/pkg/apis/meta"
|
"github.com/fluxcd/pkg/apis/meta"
|
||||||
|
|
||||||
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
|
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
corev1 "k8s.io/api/core/v1"
|
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -35,6 +38,9 @@ var getSourceHelmCmd = &cobra.Command{
|
|||||||
Long: "The get sources helm command prints the status of the HelmRepository sources.",
|
Long: "The get sources helm command prints the status of the HelmRepository sources.",
|
||||||
Example: ` # List all Helm repositories and their status
|
Example: ` # List all Helm repositories and their status
|
||||||
flux get sources helm
|
flux get sources helm
|
||||||
|
|
||||||
|
# List Helm repositories from all namespaces
|
||||||
|
flux get sources helm --all-namespaces
|
||||||
`,
|
`,
|
||||||
RunE: getSourceHelmCmdRun,
|
RunE: getSourceHelmCmdRun,
|
||||||
}
|
}
|
||||||
@@ -47,7 +53,7 @@ func getSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(kubeconfig)
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -67,7 +73,7 @@ func getSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
header := []string{"Name", "Revision", "Ready", "Message"}
|
header := []string{"Name", "Ready", "Message", "Revision", "Suspended"}
|
||||||
if allNamespaces {
|
if allNamespaces {
|
||||||
header = append([]string{"Namespace"}, header...)
|
header = append([]string{"Namespace"}, header...)
|
||||||
}
|
}
|
||||||
@@ -78,19 +84,21 @@ func getSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
if source.GetArtifact() != nil {
|
if source.GetArtifact() != nil {
|
||||||
revision = source.GetArtifact().Revision
|
revision = source.GetArtifact().Revision
|
||||||
}
|
}
|
||||||
if c := meta.GetCondition(source.Status.Conditions, meta.ReadyCondition); c != nil {
|
if c := apimeta.FindStatusCondition(source.Status.Conditions, meta.ReadyCondition); c != nil {
|
||||||
row = []string{
|
row = []string{
|
||||||
source.GetName(),
|
source.GetName(),
|
||||||
revision,
|
|
||||||
string(c.Status),
|
string(c.Status),
|
||||||
c.Message,
|
c.Message,
|
||||||
|
revision,
|
||||||
|
strings.Title(strconv.FormatBool(source.Spec.Suspend)),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
row = []string{
|
row = []string{
|
||||||
source.GetName(),
|
source.GetName(),
|
||||||
revision,
|
string(metav1.ConditionFalse),
|
||||||
string(corev1.ConditionFalse),
|
|
||||||
"waiting to be reconciled",
|
"waiting to be reconciled",
|
||||||
|
revision,
|
||||||
|
strings.Title(strconv.FormatBool(source.Spec.Suspend)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if allNamespaces {
|
if allNamespaces {
|
||||||
|
|||||||
@@ -152,10 +152,10 @@ func installCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
|
|
||||||
kubectlArgs := []string{"apply", "-f", filepath.Join(tmpDir, manifest.Path)}
|
kubectlArgs := []string{"apply", "-f", filepath.Join(tmpDir, manifest.Path)}
|
||||||
if installDryRun {
|
if installDryRun {
|
||||||
args = append(args, "--dry-run=client")
|
kubectlArgs = append(kubectlArgs, "--dry-run=client")
|
||||||
applyOutput = utils.ModeOS
|
applyOutput = utils.ModeOS
|
||||||
}
|
}
|
||||||
if _, err := utils.ExecKubectlCommand(ctx, applyOutput, kubectlArgs...); err != nil {
|
if _, err := utils.ExecKubectlCommand(ctx, applyOutput, kubeconfig, kubecontext, kubectlArgs...); err != nil {
|
||||||
return fmt.Errorf("install failed")
|
return fmt.Errorf("install failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,7 +169,7 @@ func installCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
logger.Waitingf("verifying installation")
|
logger.Waitingf("verifying installation")
|
||||||
for _, deployment := range installComponents {
|
for _, deployment := range installComponents {
|
||||||
kubectlArgs = []string{"-n", namespace, "rollout", "status", "deployment", deployment, "--timeout", timeout.String()}
|
kubectlArgs = []string{"-n", namespace, "rollout", "status", "deployment", deployment, "--timeout", timeout.String()}
|
||||||
if _, err := utils.ExecKubectlCommand(ctx, applyOutput, kubectlArgs...); err != nil {
|
if _, err := utils.ExecKubectlCommand(ctx, applyOutput, kubeconfig, kubecontext, kubectlArgs...); err != nil {
|
||||||
return fmt.Errorf("install failed")
|
return fmt.Errorf("install failed")
|
||||||
} else {
|
} else {
|
||||||
logger.Successf("%s ready", deployment)
|
logger.Successf("%s ready", deployment)
|
||||||
|
|||||||
@@ -16,26 +16,31 @@ limitations under the License.
|
|||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import "fmt"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
type printLogger struct{}
|
type stderrLogger struct {
|
||||||
|
stderr io.Writer
|
||||||
func (l printLogger) Actionf(format string, a ...interface{}) {
|
|
||||||
fmt.Println(`►`, fmt.Sprintf(format, a...))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l printLogger) Generatef(format string, a ...interface{}) {
|
func (l stderrLogger) Actionf(format string, a ...interface{}) {
|
||||||
fmt.Println(`✚`, fmt.Sprintf(format, a...))
|
fmt.Fprintln(l.stderr, `►`, fmt.Sprintf(format, a...))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l printLogger) Waitingf(format string, a ...interface{}) {
|
func (l stderrLogger) Generatef(format string, a ...interface{}) {
|
||||||
fmt.Println(`◎`, fmt.Sprintf(format, a...))
|
fmt.Fprintln(l.stderr, `✚`, fmt.Sprintf(format, a...))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l printLogger) Successf(format string, a ...interface{}) {
|
func (l stderrLogger) Waitingf(format string, a ...interface{}) {
|
||||||
fmt.Println(`✔`, fmt.Sprintf(format, a...))
|
fmt.Fprintln(l.stderr, `◎`, fmt.Sprintf(format, a...))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l printLogger) Failuref(format string, a ...interface{}) {
|
func (l stderrLogger) Successf(format string, a ...interface{}) {
|
||||||
fmt.Println(`✗`, fmt.Sprintf(format, a...))
|
fmt.Fprintln(l.stderr, `✔`, fmt.Sprintf(format, a...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l stderrLogger) Failuref(format string, a ...interface{}) {
|
||||||
|
fmt.Fprintln(l.stderr, `✗`, fmt.Sprintf(format, a...))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -96,11 +96,12 @@ var rootCmd = &cobra.Command{
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
kubeconfig string
|
kubeconfig string
|
||||||
|
kubecontext string
|
||||||
namespace string
|
namespace string
|
||||||
timeout time.Duration
|
timeout time.Duration
|
||||||
verbose bool
|
verbose bool
|
||||||
pollInterval = 2 * time.Second
|
pollInterval = 2 * time.Second
|
||||||
logger fluxlog.Logger = printLogger{}
|
logger fluxlog.Logger = stderrLogger{stderr: os.Stderr}
|
||||||
defaults = install.MakeDefaultOptions()
|
defaults = install.MakeDefaultOptions()
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -108,6 +109,7 @@ func init() {
|
|||||||
rootCmd.PersistentFlags().StringVarP(&namespace, "namespace", "n", defaults.Namespace, "the namespace scope for this operation")
|
rootCmd.PersistentFlags().StringVarP(&namespace, "namespace", "n", defaults.Namespace, "the namespace scope for this operation")
|
||||||
rootCmd.PersistentFlags().DurationVar(&timeout, "timeout", 5*time.Minute, "timeout for this operation")
|
rootCmd.PersistentFlags().DurationVar(&timeout, "timeout", 5*time.Minute, "timeout for this operation")
|
||||||
rootCmd.PersistentFlags().BoolVar(&verbose, "verbose", false, "print generated objects")
|
rootCmd.PersistentFlags().BoolVar(&verbose, "verbose", false, "print generated objects")
|
||||||
|
rootCmd.PersistentFlags().StringVarP(&kubecontext, "context", "", "", "kubernetes context to use")
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ func reconcileAlertCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(kubeconfig)
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -64,13 +64,17 @@ func reconcileAlertCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
Name: name,
|
Name: name,
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Actionf("annotating Alert %s in %s namespace", name, namespace)
|
|
||||||
var alert notificationv1.Alert
|
var alert notificationv1.Alert
|
||||||
err = kubeClient.Get(ctx, namespacedName, &alert)
|
err = kubeClient.Get(ctx, namespacedName, &alert)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if alert.Spec.Suspend {
|
||||||
|
return fmt.Errorf("resource is suspended")
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Actionf("annotating Alert %s in %s namespace", name, namespace)
|
||||||
if alert.Annotations == nil {
|
if alert.Annotations == nil {
|
||||||
alert.Annotations = map[string]string{
|
alert.Annotations = map[string]string{
|
||||||
meta.ReconcileAtAnnotation: time.Now().Format(time.RFC3339Nano),
|
meta.ReconcileAtAnnotation: time.Now().Format(time.RFC3339Nano),
|
||||||
@@ -78,6 +82,7 @@ func reconcileAlertCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
} else {
|
} else {
|
||||||
alert.Annotations[meta.ReconcileAtAnnotation] = time.Now().Format(time.RFC3339Nano)
|
alert.Annotations[meta.ReconcileAtAnnotation] = time.Now().Format(time.RFC3339Nano)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := kubeClient.Update(ctx, &alert); err != nil {
|
if err := kubeClient.Update(ctx, &alert); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ func reconcileAlertProviderCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(kubeconfig)
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,8 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
corev1 "k8s.io/api/core/v1"
|
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
"k8s.io/client-go/util/retry"
|
"k8s.io/client-go/util/retry"
|
||||||
@@ -69,7 +70,7 @@ func reconcileHrCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(kubeconfig)
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -85,6 +86,10 @@ func reconcileHrCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if helmRelease.Spec.Suspend {
|
||||||
|
return fmt.Errorf("resource is suspended")
|
||||||
|
}
|
||||||
|
|
||||||
if syncHrWithSource {
|
if syncHrWithSource {
|
||||||
switch helmRelease.Spec.Chart.Spec.SourceRef.Kind {
|
switch helmRelease.Spec.Chart.Spec.SourceRef.Kind {
|
||||||
case sourcev1.HelmRepositoryKind:
|
case sourcev1.HelmRepositoryKind:
|
||||||
@@ -118,9 +123,9 @@ func reconcileHrCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if c := meta.GetCondition(helmRelease.Status.Conditions, meta.ReadyCondition); c != nil {
|
if c := apimeta.FindStatusCondition(helmRelease.Status.Conditions, meta.ReadyCondition); c != nil {
|
||||||
switch c.Status {
|
switch c.Status {
|
||||||
case corev1.ConditionFalse:
|
case metav1.ConditionFalse:
|
||||||
return fmt.Errorf("HelmRelease reconciliation failed: %s", c.Message)
|
return fmt.Errorf("HelmRelease reconciliation failed: %s", c.Message)
|
||||||
default:
|
default:
|
||||||
logger.Successf("reconciled revision %s", helmRelease.Status.LastAppliedRevision)
|
logger.Successf("reconciled revision %s", helmRelease.Status.LastAppliedRevision)
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
corev1 "k8s.io/api/core/v1"
|
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||||
"k8s.io/client-go/util/retry"
|
"k8s.io/client-go/util/retry"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
|
||||||
@@ -69,7 +69,7 @@ func reconcileKsCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(kubeconfig)
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -84,6 +84,10 @@ func reconcileKsCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if kustomization.Spec.Suspend {
|
||||||
|
return fmt.Errorf("resource is suspended")
|
||||||
|
}
|
||||||
|
|
||||||
if syncKsWithSource {
|
if syncKsWithSource {
|
||||||
switch kustomization.Spec.SourceRef.Kind {
|
switch kustomization.Spec.SourceRef.Kind {
|
||||||
case sourcev1.GitRepositoryKind:
|
case sourcev1.GitRepositoryKind:
|
||||||
@@ -112,14 +116,10 @@ func reconcileKsCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
}
|
}
|
||||||
logger.Successf("Kustomization reconciliation completed")
|
logger.Successf("Kustomization reconciliation completed")
|
||||||
|
|
||||||
if c := meta.GetCondition(kustomization.Status.Conditions, meta.ReadyCondition); c != nil {
|
if apimeta.IsStatusConditionFalse(kustomization.Status.Conditions, meta.ReadyCondition) {
|
||||||
switch c.Status {
|
return fmt.Errorf("Kustomization reconciliation failed")
|
||||||
case corev1.ConditionFalse:
|
|
||||||
return fmt.Errorf("Kustomization reconciliation failed")
|
|
||||||
default:
|
|
||||||
logger.Successf("reconciled revision %s", kustomization.Status.LastAppliedRevision)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
logger.Successf("reconciled revision %s", kustomization.Status.LastAppliedRevision)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ func reconcileReceiverCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(kubeconfig)
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -64,13 +64,17 @@ func reconcileReceiverCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
Name: name,
|
Name: name,
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Actionf("annotating Receiver %s in %s namespace", name, namespace)
|
|
||||||
var receiver notificationv1.Receiver
|
var receiver notificationv1.Receiver
|
||||||
err = kubeClient.Get(ctx, namespacedName, &receiver)
|
err = kubeClient.Get(ctx, namespacedName, &receiver)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if receiver.Spec.Suspend {
|
||||||
|
return fmt.Errorf("resource is suspended")
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Actionf("annotating Receiver %s in %s namespace", name, namespace)
|
||||||
if receiver.Annotations == nil {
|
if receiver.Annotations == nil {
|
||||||
receiver.Annotations = map[string]string{
|
receiver.Annotations = map[string]string{
|
||||||
meta.ReconcileAtAnnotation: time.Now().Format(time.RFC3339Nano),
|
meta.ReconcileAtAnnotation: time.Now().Format(time.RFC3339Nano),
|
||||||
|
|||||||
@@ -21,11 +21,14 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/fluxcd/flux2/internal/utils"
|
|
||||||
"github.com/fluxcd/pkg/apis/meta"
|
"github.com/fluxcd/pkg/apis/meta"
|
||||||
|
"k8s.io/client-go/util/retry"
|
||||||
|
|
||||||
|
"github.com/fluxcd/flux2/internal/utils"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
corev1 "k8s.io/api/core/v1"
|
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
@@ -56,7 +59,7 @@ func reconcileSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(kubeconfig)
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -65,35 +68,34 @@ func reconcileSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
Namespace: namespace,
|
Namespace: namespace,
|
||||||
Name: name,
|
Name: name,
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Actionf("annotating Bucket source %s in %s namespace", name, namespace)
|
|
||||||
var bucket sourcev1.Bucket
|
var bucket sourcev1.Bucket
|
||||||
err = kubeClient.Get(ctx, namespacedName, &bucket)
|
err = kubeClient.Get(ctx, namespacedName, &bucket)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if bucket.Annotations == nil {
|
if bucket.Spec.Suspend {
|
||||||
bucket.Annotations = map[string]string{
|
return fmt.Errorf("resource is suspended")
|
||||||
meta.ReconcileAtAnnotation: time.Now().Format(time.RFC3339Nano),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
bucket.Annotations[meta.ReconcileAtAnnotation] = time.Now().Format(time.RFC3339Nano)
|
|
||||||
}
|
}
|
||||||
if err := kubeClient.Update(ctx, &bucket); err != nil {
|
|
||||||
|
lastHandledReconcileAt := bucket.Status.LastHandledReconcileAt
|
||||||
|
logger.Actionf("annotating Bucket source %s in %s namespace", name, namespace)
|
||||||
|
if err := requestBucketReconciliation(ctx, kubeClient, namespacedName, &bucket); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
logger.Successf("Bucket source annotated")
|
logger.Successf("Bucket source annotated")
|
||||||
|
|
||||||
logger.Waitingf("waiting for Bucket source reconciliation")
|
logger.Waitingf("waiting for Bucket source reconciliation")
|
||||||
if err := wait.PollImmediate(pollInterval, timeout,
|
if err := wait.PollImmediate(
|
||||||
isBucketReady(ctx, kubeClient, namespacedName, &bucket)); err != nil {
|
pollInterval, timeout,
|
||||||
|
bucketReconciliationHandled(ctx, kubeClient, namespacedName, &bucket, lastHandledReconcileAt),
|
||||||
|
); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
logger.Successf("Bucket source reconciliation completed")
|
logger.Successf("Bucket source reconciliation completed")
|
||||||
|
|
||||||
if bucket.Status.Artifact == nil {
|
if apimeta.IsStatusConditionFalse(bucket.Status.Conditions, meta.ReadyCondition) {
|
||||||
return fmt.Errorf("Bucket source reconciliation completed but no artifact was found")
|
return fmt.Errorf("Bucket source reconciliation failed")
|
||||||
}
|
}
|
||||||
logger.Successf("fetched revision %s", bucket.Status.Artifact.Revision)
|
logger.Successf("fetched revision %s", bucket.Status.Artifact.Revision)
|
||||||
return nil
|
return nil
|
||||||
@@ -112,14 +114,42 @@ func isBucketReady(ctx context.Context, kubeClient client.Client,
|
|||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if c := meta.GetCondition(bucket.Status.Conditions, meta.ReadyCondition); c != nil {
|
if c := apimeta.FindStatusCondition(bucket.Status.Conditions, meta.ReadyCondition); c != nil {
|
||||||
switch c.Status {
|
switch c.Status {
|
||||||
case corev1.ConditionTrue:
|
case metav1.ConditionTrue:
|
||||||
return true, nil
|
return true, nil
|
||||||
case corev1.ConditionFalse:
|
case metav1.ConditionFalse:
|
||||||
return false, fmt.Errorf(c.Message)
|
return false, fmt.Errorf(c.Message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func bucketReconciliationHandled(ctx context.Context, kubeClient client.Client,
|
||||||
|
namespacedName types.NamespacedName, bucket *sourcev1.Bucket, lastHandledReconcileAt string) wait.ConditionFunc {
|
||||||
|
return func() (bool, error) {
|
||||||
|
err := kubeClient.Get(ctx, namespacedName, bucket)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return bucket.Status.LastHandledReconcileAt != lastHandledReconcileAt, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func requestBucketReconciliation(ctx context.Context, kubeClient client.Client,
|
||||||
|
namespacedName types.NamespacedName, bucket *sourcev1.Bucket) error {
|
||||||
|
return retry.RetryOnConflict(retry.DefaultBackoff, func() (err error) {
|
||||||
|
if err := kubeClient.Get(ctx, namespacedName, bucket); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if bucket.Annotations == nil {
|
||||||
|
bucket.Annotations = map[string]string{
|
||||||
|
meta.ReconcileAtAnnotation: time.Now().Format(time.RFC3339Nano),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
bucket.Annotations[meta.ReconcileAtAnnotation] = time.Now().Format(time.RFC3339Nano)
|
||||||
|
}
|
||||||
|
return kubeClient.Update(ctx, bucket)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -23,6 +23,9 @@ import (
|
|||||||
|
|
||||||
"github.com/fluxcd/flux2/internal/utils"
|
"github.com/fluxcd/flux2/internal/utils"
|
||||||
"github.com/fluxcd/pkg/apis/meta"
|
"github.com/fluxcd/pkg/apis/meta"
|
||||||
|
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||||
|
"k8s.io/client-go/util/retry"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
@@ -54,7 +57,7 @@ func reconcileSourceGitCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(kubeconfig)
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -63,36 +66,61 @@ func reconcileSourceGitCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
Namespace: namespace,
|
Namespace: namespace,
|
||||||
Name: name,
|
Name: name,
|
||||||
}
|
}
|
||||||
|
var repository sourcev1.GitRepository
|
||||||
logger.Actionf("annotating GitRepository source %s in %s namespace", name, namespace)
|
err = kubeClient.Get(ctx, namespacedName, &repository)
|
||||||
var gitRepository sourcev1.GitRepository
|
|
||||||
err = kubeClient.Get(ctx, namespacedName, &gitRepository)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if gitRepository.Annotations == nil {
|
if repository.Spec.Suspend {
|
||||||
gitRepository.Annotations = map[string]string{
|
return fmt.Errorf("resource is suspended")
|
||||||
meta.ReconcileAtAnnotation: time.Now().Format(time.RFC3339Nano),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
gitRepository.Annotations[meta.ReconcileAtAnnotation] = time.Now().Format(time.RFC3339Nano)
|
|
||||||
}
|
}
|
||||||
if err := kubeClient.Update(ctx, &gitRepository); err != nil {
|
|
||||||
|
logger.Actionf("annotating GitRepository source %s in %s namespace", name, namespace)
|
||||||
|
if err := requestGitRepositoryReconciliation(ctx, kubeClient, namespacedName, &repository); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
logger.Successf("GitRepository source annotated")
|
logger.Successf("GitRepository source annotated")
|
||||||
|
|
||||||
|
lastHandledReconcileAt := repository.Status.LastHandledReconcileAt
|
||||||
logger.Waitingf("waiting for GitRepository source reconciliation")
|
logger.Waitingf("waiting for GitRepository source reconciliation")
|
||||||
if err := wait.PollImmediate(pollInterval, timeout,
|
if err := wait.PollImmediate(pollInterval, timeout,
|
||||||
isGitRepositoryReady(ctx, kubeClient, namespacedName, &gitRepository)); err != nil {
|
gitRepositoryReconciliationHandled(ctx, kubeClient, namespacedName, &repository, lastHandledReconcileAt)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
logger.Successf("GitRepository source reconciliation completed")
|
logger.Successf("GitRepository source reconciliation completed")
|
||||||
|
|
||||||
if gitRepository.Status.Artifact == nil {
|
if apimeta.IsStatusConditionFalse(repository.Status.Conditions, meta.ReadyCondition) {
|
||||||
return fmt.Errorf("GitRepository source reconciliation completed but no artifact was found")
|
return fmt.Errorf("GitRepository source reconciliation failed")
|
||||||
}
|
}
|
||||||
logger.Successf("fetched revision %s", gitRepository.Status.Artifact.Revision)
|
logger.Successf("fetched revision %s", repository.Status.Artifact.Revision)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func gitRepositoryReconciliationHandled(ctx context.Context, kubeClient client.Client,
|
||||||
|
namespacedName types.NamespacedName, repository *sourcev1.GitRepository, lastHandledReconcileAt string) wait.ConditionFunc {
|
||||||
|
return func() (bool, error) {
|
||||||
|
err := kubeClient.Get(ctx, namespacedName, repository)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return repository.Status.LastHandledReconcileAt != lastHandledReconcileAt, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func requestGitRepositoryReconciliation(ctx context.Context, kubeClient client.Client,
|
||||||
|
namespacedName types.NamespacedName, repository *sourcev1.GitRepository) error {
|
||||||
|
return retry.RetryOnConflict(retry.DefaultBackoff, func() (err error) {
|
||||||
|
if err := kubeClient.Get(ctx, namespacedName, repository); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if repository.Annotations == nil {
|
||||||
|
repository.Annotations = map[string]string{
|
||||||
|
meta.ReconcileAtAnnotation: time.Now().Format(time.RFC3339Nano),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
repository.Annotations[meta.ReconcileAtAnnotation] = time.Now().Format(time.RFC3339Nano)
|
||||||
|
}
|
||||||
|
return kubeClient.Update(ctx, repository)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -21,11 +21,13 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/fluxcd/flux2/internal/utils"
|
|
||||||
"github.com/fluxcd/pkg/apis/meta"
|
"github.com/fluxcd/pkg/apis/meta"
|
||||||
|
"k8s.io/client-go/util/retry"
|
||||||
|
|
||||||
|
"github.com/fluxcd/flux2/internal/utils"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
corev1 "k8s.io/api/core/v1"
|
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
@@ -56,7 +58,7 @@ func reconcileSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(kubeconfig)
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -65,61 +67,61 @@ func reconcileSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
Namespace: namespace,
|
Namespace: namespace,
|
||||||
Name: name,
|
Name: name,
|
||||||
}
|
}
|
||||||
|
var repository sourcev1.HelmRepository
|
||||||
logger.Actionf("annotating HelmRepository source %s in %s namespace", name, namespace)
|
err = kubeClient.Get(ctx, namespacedName, &repository)
|
||||||
var helmRepository sourcev1.HelmRepository
|
|
||||||
err = kubeClient.Get(ctx, namespacedName, &helmRepository)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if helmRepository.Annotations == nil {
|
if repository.Spec.Suspend {
|
||||||
helmRepository.Annotations = map[string]string{
|
return fmt.Errorf("resource is suspended")
|
||||||
meta.ReconcileAtAnnotation: time.Now().Format(time.RFC3339Nano),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
helmRepository.Annotations[meta.ReconcileAtAnnotation] = time.Now().Format(time.RFC3339Nano)
|
|
||||||
}
|
}
|
||||||
if err := kubeClient.Update(ctx, &helmRepository); err != nil {
|
|
||||||
|
logger.Actionf("annotating HelmRepository source %s in %s namespace", name, namespace)
|
||||||
|
if err := requestHelmRepositoryReconciliation(ctx, kubeClient, namespacedName, &repository); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
logger.Successf("HelmRepository source annotated")
|
logger.Successf("HelmRepository source annotated")
|
||||||
|
|
||||||
|
lastHandledReconcileAt := repository.Status.LastHandledReconcileAt
|
||||||
logger.Waitingf("waiting for HelmRepository source reconciliation")
|
logger.Waitingf("waiting for HelmRepository source reconciliation")
|
||||||
if err := wait.PollImmediate(pollInterval, timeout,
|
if err := wait.PollImmediate(pollInterval, timeout,
|
||||||
isHelmRepositoryReady(ctx, kubeClient, namespacedName, &helmRepository)); err != nil {
|
helmRepositoryReconciliationHandled(ctx, kubeClient, namespacedName, &repository, lastHandledReconcileAt)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
logger.Successf("HelmRepository source reconciliation completed")
|
logger.Successf("HelmRepository source reconciliation completed")
|
||||||
|
|
||||||
if helmRepository.Status.Artifact == nil {
|
if apimeta.IsStatusConditionFalse(repository.Status.Conditions, meta.ReadyCondition) {
|
||||||
return fmt.Errorf("HelmRepository source reconciliation completed but no artifact was found")
|
return fmt.Errorf("HelmRepository source reconciliation failed")
|
||||||
}
|
}
|
||||||
logger.Successf("fetched revision %s", helmRepository.Status.Artifact.Revision)
|
logger.Successf("fetched revision %s", repository.Status.Artifact.Revision)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func isHelmRepositoryReady(ctx context.Context, kubeClient client.Client,
|
func helmRepositoryReconciliationHandled(ctx context.Context, kubeClient client.Client,
|
||||||
namespacedName types.NamespacedName, helmRepository *sourcev1.HelmRepository) wait.ConditionFunc {
|
namespacedName types.NamespacedName, repository *sourcev1.HelmRepository, lastHandledReconcileAt string) wait.ConditionFunc {
|
||||||
return func() (bool, error) {
|
return func() (bool, error) {
|
||||||
err := kubeClient.Get(ctx, namespacedName, helmRepository)
|
err := kubeClient.Get(ctx, namespacedName, repository)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
return repository.Status.LastHandledReconcileAt != lastHandledReconcileAt, nil
|
||||||
// Confirm the state we are observing is for the current generation
|
|
||||||
if helmRepository.Generation != helmRepository.Status.ObservedGeneration {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if c := meta.GetCondition(helmRepository.Status.Conditions, meta.ReadyCondition); c != nil {
|
|
||||||
switch c.Status {
|
|
||||||
case corev1.ConditionTrue:
|
|
||||||
return true, nil
|
|
||||||
case corev1.ConditionFalse:
|
|
||||||
return false, fmt.Errorf(c.Message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false, nil
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func requestHelmRepositoryReconciliation(ctx context.Context, kubeClient client.Client,
|
||||||
|
namespacedName types.NamespacedName, repository *sourcev1.HelmRepository) error {
|
||||||
|
return retry.RetryOnConflict(retry.DefaultBackoff, func() (err error) {
|
||||||
|
if err := kubeClient.Get(ctx, namespacedName, repository); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if repository.Annotations == nil {
|
||||||
|
repository.Annotations = map[string]string{
|
||||||
|
meta.ReconcileAtAnnotation: time.Now().Format(time.RFC3339Nano),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
repository.Annotations[meta.ReconcileAtAnnotation] = time.Now().Format(time.RFC3339Nano)
|
||||||
|
}
|
||||||
|
return kubeClient.Update(ctx, repository)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ import (
|
|||||||
"github.com/fluxcd/pkg/apis/meta"
|
"github.com/fluxcd/pkg/apis/meta"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
corev1 "k8s.io/api/core/v1"
|
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
@@ -56,7 +57,7 @@ func resumeAlertCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(kubeconfig)
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -95,11 +96,11 @@ func isAlertResumed(ctx context.Context, kubeClient client.Client,
|
|||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if c := meta.GetCondition(alert.Status.Conditions, meta.ReadyCondition); c != nil {
|
if c := apimeta.FindStatusCondition(alert.Status.Conditions, meta.ReadyCondition); c != nil {
|
||||||
switch c.Status {
|
switch c.Status {
|
||||||
case corev1.ConditionTrue:
|
case metav1.ConditionTrue:
|
||||||
return true, nil
|
return true, nil
|
||||||
case corev1.ConditionFalse:
|
case metav1.ConditionFalse:
|
||||||
if c.Reason == meta.SuspendedReason {
|
if c.Reason == meta.SuspendedReason {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ import (
|
|||||||
"github.com/fluxcd/pkg/apis/meta"
|
"github.com/fluxcd/pkg/apis/meta"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
corev1 "k8s.io/api/core/v1"
|
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
@@ -57,7 +58,7 @@ func resumeHrCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(kubeconfig)
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -103,14 +104,11 @@ func isHelmReleaseResumed(ctx context.Context, kubeClient client.Client,
|
|||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if c := meta.GetCondition(helmRelease.Status.Conditions, meta.ReadyCondition); c != nil {
|
if c := apimeta.FindStatusCondition(helmRelease.Status.Conditions, meta.ReadyCondition); c != nil {
|
||||||
switch c.Status {
|
switch c.Status {
|
||||||
case corev1.ConditionTrue:
|
case metav1.ConditionTrue:
|
||||||
return true, nil
|
return true, nil
|
||||||
case corev1.ConditionFalse:
|
case metav1.ConditionFalse:
|
||||||
if c.Reason == meta.SuspendedReason {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
return false, fmt.Errorf(c.Message)
|
return false, fmt.Errorf(c.Message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,8 @@ import (
|
|||||||
|
|
||||||
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1"
|
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
corev1 "k8s.io/api/core/v1"
|
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
@@ -56,7 +57,7 @@ func resumeKsCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(kubeconfig)
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -102,14 +103,11 @@ func isKustomizationResumed(ctx context.Context, kubeClient client.Client,
|
|||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if c := meta.GetCondition(kustomization.Status.Conditions, meta.ReadyCondition); c != nil {
|
if c := apimeta.FindStatusCondition(kustomization.Status.Conditions, meta.ReadyCondition); c != nil {
|
||||||
switch c.Status {
|
switch c.Status {
|
||||||
case corev1.ConditionTrue:
|
case metav1.ConditionTrue:
|
||||||
return true, nil
|
return true, nil
|
||||||
case corev1.ConditionFalse:
|
case metav1.ConditionFalse:
|
||||||
if c.Reason == meta.SuspendedReason {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
return false, fmt.Errorf(c.Message)
|
return false, fmt.Errorf(c.Message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ import (
|
|||||||
"github.com/fluxcd/pkg/apis/meta"
|
"github.com/fluxcd/pkg/apis/meta"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
corev1 "k8s.io/api/core/v1"
|
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
@@ -56,7 +57,7 @@ func resumeReceiverCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(kubeconfig)
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -96,11 +97,11 @@ func isReceiverResumed(ctx context.Context, kubeClient client.Client,
|
|||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if c := meta.GetCondition(receiver.Status.Conditions, meta.ReadyCondition); c != nil {
|
if c := apimeta.FindStatusCondition(receiver.Status.Conditions, meta.ReadyCondition); c != nil {
|
||||||
switch c.Status {
|
switch c.Status {
|
||||||
case corev1.ConditionTrue:
|
case metav1.ConditionTrue:
|
||||||
return true, nil
|
return true, nil
|
||||||
case corev1.ConditionFalse:
|
case metav1.ConditionFalse:
|
||||||
if c.Reason == meta.SuspendedReason {
|
if c.Reason == meta.SuspendedReason {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|||||||
31
cmd/flux/resume_source.go
Normal file
31
cmd/flux/resume_source.go
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 The Flux authors
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
var resumeSourceCmd = &cobra.Command{
|
||||||
|
Use: "source",
|
||||||
|
Short: "Resume sources",
|
||||||
|
Long: "The resume sub-commands resume a suspended source.",
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
resumeCmd.AddCommand(resumeSourceCmd)
|
||||||
|
}
|
||||||
115
cmd/flux/resume_source_bucket.go
Normal file
115
cmd/flux/resume_source_bucket.go
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 The Flux authors
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/fluxcd/flux2/internal/utils"
|
||||||
|
"github.com/fluxcd/pkg/apis/meta"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
|
||||||
|
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
|
||||||
|
)
|
||||||
|
|
||||||
|
var resumeSourceBucketCmd = &cobra.Command{
|
||||||
|
Use: "bucket [name]",
|
||||||
|
Short: "Resume a suspended Bucket",
|
||||||
|
Long: `The resume command marks a previously suspended Bucket resource for reconciliation and waits for it to finish.`,
|
||||||
|
Example: ` # Resume reconciliation for an existing Bucket
|
||||||
|
flux resume source bucket podinfo
|
||||||
|
`,
|
||||||
|
RunE: resumeSourceBucketCmdRun,
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
resumeSourceCmd.AddCommand(resumeSourceBucketCmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resumeSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
|
||||||
|
if len(args) < 1 {
|
||||||
|
return fmt.Errorf("source name is required")
|
||||||
|
}
|
||||||
|
name := args[0]
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
namespacedName := types.NamespacedName{
|
||||||
|
Namespace: namespace,
|
||||||
|
Name: name,
|
||||||
|
}
|
||||||
|
var bucket sourcev1.Bucket
|
||||||
|
err = kubeClient.Get(ctx, namespacedName, &bucket)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Actionf("resuming source %s in %s namespace", name, namespace)
|
||||||
|
bucket.Spec.Suspend = false
|
||||||
|
if err := kubeClient.Update(ctx, &bucket); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Successf("source resumed")
|
||||||
|
|
||||||
|
logger.Waitingf("waiting for Bucket reconciliation")
|
||||||
|
if err := wait.PollImmediate(pollInterval, timeout,
|
||||||
|
isBucketResumed(ctx, kubeClient, namespacedName, &bucket)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Successf("Bucket reconciliation completed")
|
||||||
|
|
||||||
|
logger.Successf("fetched revision %s", bucket.Status.Artifact.Revision)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func isBucketResumed(ctx context.Context, kubeClient client.Client,
|
||||||
|
namespacedName types.NamespacedName, bucket *sourcev1.Bucket) wait.ConditionFunc {
|
||||||
|
return func() (bool, error) {
|
||||||
|
err := kubeClient.Get(ctx, namespacedName, bucket)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Confirm the state we are observing is for the current generation
|
||||||
|
if bucket.Generation != bucket.Status.ObservedGeneration {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if c := apimeta.FindStatusCondition(bucket.Status.Conditions, meta.ReadyCondition); c != nil {
|
||||||
|
switch c.Status {
|
||||||
|
case metav1.ConditionTrue:
|
||||||
|
return true, nil
|
||||||
|
case metav1.ConditionFalse:
|
||||||
|
return false, fmt.Errorf(c.Message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
115
cmd/flux/resume_source_chart.go
Normal file
115
cmd/flux/resume_source_chart.go
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 The Flux authors
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/fluxcd/flux2/internal/utils"
|
||||||
|
"github.com/fluxcd/pkg/apis/meta"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
|
||||||
|
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
|
||||||
|
)
|
||||||
|
|
||||||
|
var resumeSourceHelmChartCmd = &cobra.Command{
|
||||||
|
Use: "chart [name]",
|
||||||
|
Short: "Resume a suspended HelmChart",
|
||||||
|
Long: `The resume command marks a previously suspended HelmChart resource for reconciliation and waits for it to finish.`,
|
||||||
|
Example: ` # Resume reconciliation for an existing HelmChart
|
||||||
|
flux resume source chart podinfo
|
||||||
|
`,
|
||||||
|
RunE: resumeSourceHelmChartCmdRun,
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
resumeSourceCmd.AddCommand(resumeSourceHelmChartCmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resumeSourceHelmChartCmdRun(cmd *cobra.Command, args []string) error {
|
||||||
|
if len(args) < 1 {
|
||||||
|
return fmt.Errorf("source name is required")
|
||||||
|
}
|
||||||
|
name := args[0]
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
namespacedName := types.NamespacedName{
|
||||||
|
Namespace: namespace,
|
||||||
|
Name: name,
|
||||||
|
}
|
||||||
|
var repository sourcev1.HelmChart
|
||||||
|
err = kubeClient.Get(ctx, namespacedName, &repository)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Actionf("resuming source %s in %s namespace", name, namespace)
|
||||||
|
repository.Spec.Suspend = false
|
||||||
|
if err := kubeClient.Update(ctx, &repository); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Successf("source resumed")
|
||||||
|
|
||||||
|
logger.Waitingf("waiting for HelmChart reconciliation")
|
||||||
|
if err := wait.PollImmediate(pollInterval, timeout,
|
||||||
|
isHelmChartResumed(ctx, kubeClient, namespacedName, &repository)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Successf("HelmChart reconciliation completed")
|
||||||
|
|
||||||
|
logger.Successf("fetched revision %s", repository.Status.Artifact.Revision)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func isHelmChartResumed(ctx context.Context, kubeClient client.Client,
|
||||||
|
namespacedName types.NamespacedName, chart *sourcev1.HelmChart) wait.ConditionFunc {
|
||||||
|
return func() (bool, error) {
|
||||||
|
err := kubeClient.Get(ctx, namespacedName, chart)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Confirm the state we are observing is for the current generation
|
||||||
|
if chart.Generation != chart.Status.ObservedGeneration {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if c := apimeta.FindStatusCondition(chart.Status.Conditions, meta.ReadyCondition); c != nil {
|
||||||
|
switch c.Status {
|
||||||
|
case metav1.ConditionTrue:
|
||||||
|
return true, nil
|
||||||
|
case metav1.ConditionFalse:
|
||||||
|
return false, fmt.Errorf(c.Message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
115
cmd/flux/resume_source_git.go
Normal file
115
cmd/flux/resume_source_git.go
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 The Flux authors
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/fluxcd/flux2/internal/utils"
|
||||||
|
"github.com/fluxcd/pkg/apis/meta"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
|
||||||
|
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
|
||||||
|
)
|
||||||
|
|
||||||
|
var resumeSourceGitCmd = &cobra.Command{
|
||||||
|
Use: "git [name]",
|
||||||
|
Short: "Resume a suspended GitRepository",
|
||||||
|
Long: `The resume command marks a previously suspended GitRepository resource for reconciliation and waits for it to finish.`,
|
||||||
|
Example: ` # Resume reconciliation for an existing GitRepository
|
||||||
|
flux resume source git podinfo
|
||||||
|
`,
|
||||||
|
RunE: resumeSourceGitCmdRun,
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
resumeSourceCmd.AddCommand(resumeSourceGitCmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resumeSourceGitCmdRun(cmd *cobra.Command, args []string) error {
|
||||||
|
if len(args) < 1 {
|
||||||
|
return fmt.Errorf("source name is required")
|
||||||
|
}
|
||||||
|
name := args[0]
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
namespacedName := types.NamespacedName{
|
||||||
|
Namespace: namespace,
|
||||||
|
Name: name,
|
||||||
|
}
|
||||||
|
var repository sourcev1.GitRepository
|
||||||
|
err = kubeClient.Get(ctx, namespacedName, &repository)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Actionf("resuming source %s in %s namespace", name, namespace)
|
||||||
|
repository.Spec.Suspend = false
|
||||||
|
if err := kubeClient.Update(ctx, &repository); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Successf("source resumed")
|
||||||
|
|
||||||
|
logger.Waitingf("waiting for GitRepository reconciliation")
|
||||||
|
if err := wait.PollImmediate(pollInterval, timeout,
|
||||||
|
isGitRepositoryResumed(ctx, kubeClient, namespacedName, &repository)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Successf("GitRepository reconciliation completed")
|
||||||
|
|
||||||
|
logger.Successf("fetched revision %s", repository.Status.Artifact.Revision)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func isGitRepositoryResumed(ctx context.Context, kubeClient client.Client,
|
||||||
|
namespacedName types.NamespacedName, repository *sourcev1.GitRepository) wait.ConditionFunc {
|
||||||
|
return func() (bool, error) {
|
||||||
|
err := kubeClient.Get(ctx, namespacedName, repository)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Confirm the state we are observing is for the current generation
|
||||||
|
if repository.Generation != repository.Status.ObservedGeneration {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if c := apimeta.FindStatusCondition(repository.Status.Conditions, meta.ReadyCondition); c != nil {
|
||||||
|
switch c.Status {
|
||||||
|
case metav1.ConditionTrue:
|
||||||
|
return true, nil
|
||||||
|
case metav1.ConditionFalse:
|
||||||
|
return false, fmt.Errorf(c.Message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
115
cmd/flux/resume_source_helm.go
Normal file
115
cmd/flux/resume_source_helm.go
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 The Flux authors
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/fluxcd/flux2/internal/utils"
|
||||||
|
"github.com/fluxcd/pkg/apis/meta"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
|
||||||
|
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
|
||||||
|
)
|
||||||
|
|
||||||
|
var resumeSourceHelmCmd = &cobra.Command{
|
||||||
|
Use: "helm [name]",
|
||||||
|
Short: "Resume a suspended HelmRepository",
|
||||||
|
Long: `The resume command marks a previously suspended HelmRepository resource for reconciliation and waits for it to finish.`,
|
||||||
|
Example: ` # Resume reconciliation for an existing HelmRepository
|
||||||
|
flux resume source helm bitnami
|
||||||
|
`,
|
||||||
|
RunE: resumeSourceHelmCmdRun,
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
resumeSourceCmd.AddCommand(resumeSourceHelmCmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resumeSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
|
||||||
|
if len(args) < 1 {
|
||||||
|
return fmt.Errorf("source name is required")
|
||||||
|
}
|
||||||
|
name := args[0]
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
namespacedName := types.NamespacedName{
|
||||||
|
Namespace: namespace,
|
||||||
|
Name: name,
|
||||||
|
}
|
||||||
|
var repository sourcev1.HelmRepository
|
||||||
|
err = kubeClient.Get(ctx, namespacedName, &repository)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Actionf("resuming source %s in %s namespace", name, namespace)
|
||||||
|
repository.Spec.Suspend = false
|
||||||
|
if err := kubeClient.Update(ctx, &repository); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Successf("source resumed")
|
||||||
|
|
||||||
|
logger.Waitingf("waiting for HelmRepository reconciliation")
|
||||||
|
if err := wait.PollImmediate(pollInterval, timeout,
|
||||||
|
isHelmRepositoryResumed(ctx, kubeClient, namespacedName, &repository)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Successf("HelmRepository reconciliation completed")
|
||||||
|
|
||||||
|
logger.Successf("fetched revision %s", repository.Status.Artifact.Revision)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func isHelmRepositoryResumed(ctx context.Context, kubeClient client.Client,
|
||||||
|
namespacedName types.NamespacedName, repository *sourcev1.HelmRepository) wait.ConditionFunc {
|
||||||
|
return func() (bool, error) {
|
||||||
|
err := kubeClient.Get(ctx, namespacedName, repository)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Confirm the state we are observing is for the current generation
|
||||||
|
if repository.Generation != repository.Status.ObservedGeneration {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if c := apimeta.FindStatusCondition(repository.Status.Conditions, meta.ReadyCondition); c != nil {
|
||||||
|
switch c.Status {
|
||||||
|
case metav1.ConditionTrue:
|
||||||
|
return true, nil
|
||||||
|
case metav1.ConditionFalse:
|
||||||
|
return false, fmt.Errorf(c.Message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -50,7 +50,7 @@ func suspendAlertCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(kubeconfig)
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ func suspendHrCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(kubeconfig)
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ func suspendKsCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(kubeconfig)
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ func suspendReceiverCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(kubeconfig)
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
31
cmd/flux/suspend_source.go
Normal file
31
cmd/flux/suspend_source.go
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 The Flux authors
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
var suspendSourceCmd = &cobra.Command{
|
||||||
|
Use: "source",
|
||||||
|
Short: "Suspend sources",
|
||||||
|
Long: "The suspend sub-commands suspend the reconciliation of a source.",
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
suspendCmd.AddCommand(suspendSourceCmd)
|
||||||
|
}
|
||||||
75
cmd/flux/suspend_source_bucket.go
Normal file
75
cmd/flux/suspend_source_bucket.go
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 The Flux authors
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
|
||||||
|
|
||||||
|
"github.com/fluxcd/flux2/internal/utils"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
var suspendSourceBucketCmd = &cobra.Command{
|
||||||
|
Use: "bucket [name]",
|
||||||
|
Short: "Suspend reconciliation of a Bucket",
|
||||||
|
Long: "The suspend command disables the reconciliation of a Bucket resource.",
|
||||||
|
Example: ` # Suspend reconciliation for an existing Bucket
|
||||||
|
flux suspend source bucket podinfo
|
||||||
|
`,
|
||||||
|
RunE: suspendSourceBucketCmdRun,
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
suspendSourceCmd.AddCommand(suspendSourceBucketCmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func suspendSourceBucketCmdRun(cmd *cobra.Command, args []string) error {
|
||||||
|
if len(args) < 1 {
|
||||||
|
return fmt.Errorf("source name is required")
|
||||||
|
}
|
||||||
|
name := args[0]
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
namespacedName := types.NamespacedName{
|
||||||
|
Namespace: namespace,
|
||||||
|
Name: name,
|
||||||
|
}
|
||||||
|
var bucket sourcev1.Bucket
|
||||||
|
err = kubeClient.Get(ctx, namespacedName, &bucket)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Actionf("suspending source %s in %s namespace", name, namespace)
|
||||||
|
bucket.Spec.Suspend = true
|
||||||
|
if err := kubeClient.Update(ctx, &bucket); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Successf("source suspended")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
75
cmd/flux/suspend_source_chart.go
Normal file
75
cmd/flux/suspend_source_chart.go
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 The Flux authors
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
|
||||||
|
|
||||||
|
"github.com/fluxcd/flux2/internal/utils"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
var suspendSourceHelmChartCmd = &cobra.Command{
|
||||||
|
Use: "chart [name]",
|
||||||
|
Short: "Suspend reconciliation of a HelmChart",
|
||||||
|
Long: "The suspend command disables the reconciliation of a HelmChart resource.",
|
||||||
|
Example: ` # Suspend reconciliation for an existing HelmChart
|
||||||
|
flux suspend source chart podinfo
|
||||||
|
`,
|
||||||
|
RunE: suspendSourceHelmChartCmdRun,
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
suspendSourceCmd.AddCommand(suspendSourceHelmChartCmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func suspendSourceHelmChartCmdRun(cmd *cobra.Command, args []string) error {
|
||||||
|
if len(args) < 1 {
|
||||||
|
return fmt.Errorf("source name is required")
|
||||||
|
}
|
||||||
|
name := args[0]
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
namespacedName := types.NamespacedName{
|
||||||
|
Namespace: namespace,
|
||||||
|
Name: name,
|
||||||
|
}
|
||||||
|
var chart sourcev1.HelmChart
|
||||||
|
err = kubeClient.Get(ctx, namespacedName, &chart)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Actionf("suspending source %s in %s namespace", name, namespace)
|
||||||
|
chart.Spec.Suspend = true
|
||||||
|
if err := kubeClient.Update(ctx, &chart); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Successf("source suspended")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
75
cmd/flux/suspend_source_git.go
Normal file
75
cmd/flux/suspend_source_git.go
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 The Flux authors
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
|
||||||
|
|
||||||
|
"github.com/fluxcd/flux2/internal/utils"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
var suspendSourceGitCmd = &cobra.Command{
|
||||||
|
Use: "git [name]",
|
||||||
|
Short: "Suspend reconciliation of a GitRepository",
|
||||||
|
Long: "The suspend command disables the reconciliation of a GitRepository resource.",
|
||||||
|
Example: ` # Suspend reconciliation for an existing GitRepository
|
||||||
|
flux suspend source git podinfo
|
||||||
|
`,
|
||||||
|
RunE: suspendSourceGitCmdRun,
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
suspendSourceCmd.AddCommand(suspendSourceGitCmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func suspendSourceGitCmdRun(cmd *cobra.Command, args []string) error {
|
||||||
|
if len(args) < 1 {
|
||||||
|
return fmt.Errorf("source name is required")
|
||||||
|
}
|
||||||
|
name := args[0]
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
namespacedName := types.NamespacedName{
|
||||||
|
Namespace: namespace,
|
||||||
|
Name: name,
|
||||||
|
}
|
||||||
|
var repository sourcev1.GitRepository
|
||||||
|
err = kubeClient.Get(ctx, namespacedName, &repository)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Actionf("suspending source %s in %s namespace", name, namespace)
|
||||||
|
repository.Spec.Suspend = true
|
||||||
|
if err := kubeClient.Update(ctx, &repository); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Successf("source suspended")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
75
cmd/flux/suspend_source_helm.go
Normal file
75
cmd/flux/suspend_source_helm.go
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 The Flux authors
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
|
||||||
|
|
||||||
|
"github.com/fluxcd/flux2/internal/utils"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
var suspendSourceHelmCmd = &cobra.Command{
|
||||||
|
Use: "helm [name]",
|
||||||
|
Short: "Suspend reconciliation of a HelmRepository",
|
||||||
|
Long: "The suspend command disables the reconciliation of a HelmRepository resource.",
|
||||||
|
Example: ` # Suspend reconciliation for an existing HelmRepository
|
||||||
|
flux suspend source helm bitnami
|
||||||
|
`,
|
||||||
|
RunE: suspendSourceHelmCmdRun,
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
suspendSourceCmd.AddCommand(suspendSourceHelmCmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func suspendSourceHelmCmdRun(cmd *cobra.Command, args []string) error {
|
||||||
|
if len(args) < 1 {
|
||||||
|
return fmt.Errorf("source name is required")
|
||||||
|
}
|
||||||
|
name := args[0]
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
namespacedName := types.NamespacedName{
|
||||||
|
Namespace: namespace,
|
||||||
|
Name: name,
|
||||||
|
}
|
||||||
|
var repository sourcev1.HelmRepository
|
||||||
|
err = kubeClient.Get(ctx, namespacedName, &repository)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Actionf("suspending source %s in %s namespace", name, namespace)
|
||||||
|
repository.Spec.Suspend = true
|
||||||
|
if err := kubeClient.Update(ctx, &repository); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
logger.Successf("source suspended")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -69,7 +69,7 @@ func uninstallCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(kubeconfig)
|
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -144,7 +144,7 @@ func uninstallCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
if uninstallDryRun {
|
if uninstallDryRun {
|
||||||
kubectlArgs = append(kubectlArgs, dryRun)
|
kubectlArgs = append(kubectlArgs, dryRun)
|
||||||
}
|
}
|
||||||
if _, err := utils.ExecKubectlCommand(ctx, utils.ModeOS, kubectlArgs...); err != nil {
|
if _, err := utils.ExecKubectlCommand(ctx, utils.ModeOS, kubeconfig, kubecontext, kubectlArgs...); err != nil {
|
||||||
return fmt.Errorf("uninstall failed: %w", err)
|
return fmt.Errorf("uninstall failed: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -164,6 +164,6 @@ func deleteAll(ctx context.Context, kind string, dryRun bool) error {
|
|||||||
kubectlArgs = append(kubectlArgs, "--dry-run=server")
|
kubectlArgs = append(kubectlArgs, "--dry-run=server")
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := utils.ExecKubectlCommand(ctx, utils.ModeOS, kubectlArgs...)
|
_, err := utils.ExecKubectlCommand(ctx, utils.ModeOS, kubeconfig, kubecontext, kubectlArgs...)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ Command line utility for assembling Kubernetes CD pipelines the GitOps way.
|
|||||||
### Options
|
### Options
|
||||||
|
|
||||||
```
|
```
|
||||||
|
--context string kubernetes context to use
|
||||||
-h, --help help for flux
|
-h, --help help for flux
|
||||||
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
||||||
-n, --namespace string the namespace scope for this operation (default "flux-system")
|
-n, --namespace string the namespace scope for this operation (default "flux-system")
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ The bootstrap sub-commands bootstrap the toolkit components on the targeted Git
|
|||||||
--log-level logLevel log level, available options are: (debug, info, error) (default info)
|
--log-level logLevel log level, available options are: (debug, info, error) (default info)
|
||||||
--network-policy deny ingress access to the toolkit controllers from other namespaces using network policies (default true)
|
--network-policy deny ingress access to the toolkit controllers from other namespaces using network policies (default true)
|
||||||
--registry string container registry where the toolkit images are published (default "ghcr.io/fluxcd")
|
--registry string container registry where the toolkit images are published (default "ghcr.io/fluxcd")
|
||||||
|
--token-auth when enabled, the personal access token will be used instead of SSH deploy key
|
||||||
-v, --version string toolkit version (default "latest")
|
-v, --version string toolkit version (default "latest")
|
||||||
--watch-all-namespaces watch for custom resources in all namespaces, if set to false it will only watch the namespace where the toolkit is installed (default true)
|
--watch-all-namespaces watch for custom resources in all namespaces, if set to false it will only watch the namespace where the toolkit is installed (default true)
|
||||||
```
|
```
|
||||||
@@ -24,6 +25,7 @@ The bootstrap sub-commands bootstrap the toolkit components on the targeted Git
|
|||||||
### Options inherited from parent commands
|
### Options inherited from parent commands
|
||||||
|
|
||||||
```
|
```
|
||||||
|
--context string kubernetes context to use
|
||||||
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
||||||
-n, --namespace string the namespace scope for this operation (default "flux-system")
|
-n, --namespace string the namespace scope for this operation (default "flux-system")
|
||||||
--timeout duration timeout for this operation (default 5m0s)
|
--timeout duration timeout for this operation (default 5m0s)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ Bootstrap toolkit components in a GitHub repository
|
|||||||
### Synopsis
|
### Synopsis
|
||||||
|
|
||||||
The bootstrap github command creates the GitHub repository if it doesn't exists and
|
The bootstrap github command creates the GitHub repository if it doesn't exists and
|
||||||
commits the toolkit components manifests to the master branch.
|
commits the toolkit components manifests to the main branch.
|
||||||
Then it configures the target cluster to synchronize with the repository.
|
Then it configures the target cluster to synchronize with the repository.
|
||||||
If the toolkit components are present on the cluster,
|
If the toolkit components are present on the cluster,
|
||||||
the bootstrap command will perform an upgrade if needed.
|
the bootstrap command will perform an upgrade if needed.
|
||||||
@@ -32,8 +32,11 @@ flux bootstrap github [flags]
|
|||||||
# Run bootstrap for a public repository on a personal account
|
# Run bootstrap for a public repository on a personal account
|
||||||
flux bootstrap github --owner=<user> --repository=<repo name> --private=false --personal=true
|
flux bootstrap github --owner=<user> --repository=<repo name> --private=false --personal=true
|
||||||
|
|
||||||
# Run bootstrap for a private repo hosted on GitHub Enterprise
|
# Run bootstrap for a private repo hosted on GitHub Enterprise using SSH auth
|
||||||
flux bootstrap github --owner=<organization> --repository=<repo name> --hostname=<domain>
|
flux bootstrap github --owner=<organization> --repository=<repo name> --hostname=<domain> --ssh-hostname=<domain>
|
||||||
|
|
||||||
|
# Run bootstrap for a private repo hosted on GitHub Enterprise using HTTPS auth
|
||||||
|
flux bootstrap github --owner=<organization> --repository=<repo name> --hostname=<domain> --token-auth
|
||||||
|
|
||||||
# Run bootstrap for a an existing repository with a branch named main
|
# Run bootstrap for a an existing repository with a branch named main
|
||||||
flux bootstrap github --owner=<organization> --repository=<repo name> --branch=main
|
flux bootstrap github --owner=<organization> --repository=<repo name> --branch=main
|
||||||
@@ -43,15 +46,16 @@ flux bootstrap github [flags]
|
|||||||
### Options
|
### Options
|
||||||
|
|
||||||
```
|
```
|
||||||
-h, --help help for github
|
-h, --help help for github
|
||||||
--hostname string GitHub hostname (default "github.com")
|
--hostname string GitHub hostname (default "github.com")
|
||||||
--interval duration sync interval (default 1m0s)
|
--interval duration sync interval (default 1m0s)
|
||||||
--owner string GitHub user or organization name
|
--owner string GitHub user or organization name
|
||||||
--path string repository path, when specified the cluster sync will be scoped to this path
|
--path string repository path, when specified the cluster sync will be scoped to this path
|
||||||
--personal is personal repository
|
--personal is personal repository
|
||||||
--private is private repository (default true)
|
--private is private repository (default true)
|
||||||
--repository string GitHub repository name
|
--repository string GitHub repository name
|
||||||
--team stringArray GitHub team to be given maintainer access
|
--ssh-hostname string GitHub SSH hostname, to be used when the SSH host differs from the HTTPS one
|
||||||
|
--team stringArray GitHub team to be given maintainer access
|
||||||
```
|
```
|
||||||
|
|
||||||
### Options inherited from parent commands
|
### Options inherited from parent commands
|
||||||
@@ -60,6 +64,7 @@ flux bootstrap github [flags]
|
|||||||
--arch arch cluster architecture, available options are: (amd64, arm, arm64) (default amd64)
|
--arch arch cluster architecture, available options are: (amd64, arm, arm64) (default amd64)
|
||||||
--branch string default branch (for GitHub this must match the default branch setting for the organization) (default "main")
|
--branch string default branch (for GitHub this must match the default branch setting for the organization) (default "main")
|
||||||
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller,helm-controller,notification-controller])
|
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller,helm-controller,notification-controller])
|
||||||
|
--context string kubernetes context to use
|
||||||
--image-pull-secret string Kubernetes secret name used for pulling the toolkit images from a private registry
|
--image-pull-secret string Kubernetes secret name used for pulling the toolkit images from a private registry
|
||||||
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
||||||
--log-level logLevel log level, available options are: (debug, info, error) (default info)
|
--log-level logLevel log level, available options are: (debug, info, error) (default info)
|
||||||
@@ -67,6 +72,7 @@ flux bootstrap github [flags]
|
|||||||
--network-policy deny ingress access to the toolkit controllers from other namespaces using network policies (default true)
|
--network-policy deny ingress access to the toolkit controllers from other namespaces using network policies (default true)
|
||||||
--registry string container registry where the toolkit images are published (default "ghcr.io/fluxcd")
|
--registry string container registry where the toolkit images are published (default "ghcr.io/fluxcd")
|
||||||
--timeout duration timeout for this operation (default 5m0s)
|
--timeout duration timeout for this operation (default 5m0s)
|
||||||
|
--token-auth when enabled, the personal access token will be used instead of SSH deploy key
|
||||||
--verbose print generated objects
|
--verbose print generated objects
|
||||||
-v, --version string toolkit version (default "latest")
|
-v, --version string toolkit version (default "latest")
|
||||||
--watch-all-namespaces watch for custom resources in all namespaces, if set to false it will only watch the namespace where the toolkit is installed (default true)
|
--watch-all-namespaces watch for custom resources in all namespaces, if set to false it will only watch the namespace where the toolkit is installed (default true)
|
||||||
|
|||||||
@@ -21,22 +21,22 @@ flux bootstrap gitlab [flags]
|
|||||||
export GITLAB_TOKEN=<my-token>
|
export GITLAB_TOKEN=<my-token>
|
||||||
|
|
||||||
# Run bootstrap for a private repo using HTTPS token authentication
|
# Run bootstrap for a private repo using HTTPS token authentication
|
||||||
flux bootstrap gitlab --owner=<group> --repository=<repo name>
|
flux bootstrap gitlab --owner=<group> --repository=<repo name> --token-auth
|
||||||
|
|
||||||
# Run bootstrap for a private repo using SSH authentication
|
# Run bootstrap for a private repo using SSH authentication
|
||||||
flux bootstrap gitlab --owner=<group> --repository=<repo name> --ssh-hostname=gitlab.com
|
flux bootstrap gitlab --owner=<group> --repository=<repo name>
|
||||||
|
|
||||||
# Run bootstrap for a repository path
|
# Run bootstrap for a repository path
|
||||||
flux bootstrap gitlab --owner=<group> --repository=<repo name> --path=dev-cluster
|
flux bootstrap gitlab --owner=<group> --repository=<repo name> --path=dev-cluster
|
||||||
|
|
||||||
# Run bootstrap for a public repository on a personal account
|
# Run bootstrap for a public repository on a personal account
|
||||||
flux bootstrap gitlab --owner=<user> --repository=<repo name> --private=false --personal=true
|
flux bootstrap gitlab --owner=<user> --repository=<repo name> --private=false --personal --token-auth
|
||||||
|
|
||||||
# Run bootstrap for a private repo hosted on a GitLab server
|
# Run bootstrap for a private repo hosted on a GitLab server
|
||||||
flux bootstrap gitlab --owner=<group> --repository=<repo name> --hostname=<domain>
|
flux bootstrap gitlab --owner=<group> --repository=<repo name> --hostname=<domain> --token-auth
|
||||||
|
|
||||||
# Run bootstrap for a an existing repository with a branch named main
|
# Run bootstrap for a an existing repository with a branch named main
|
||||||
flux bootstrap gitlab --owner=<organization> --repository=<repo name> --branch=main
|
flux bootstrap gitlab --owner=<organization> --repository=<repo name> --branch=main --token-auth
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ flux bootstrap gitlab [flags]
|
|||||||
--personal is personal repository
|
--personal is personal repository
|
||||||
--private is private repository (default true)
|
--private is private repository (default true)
|
||||||
--repository string GitLab repository name
|
--repository string GitLab repository name
|
||||||
--ssh-hostname string GitLab SSH hostname, when specified a deploy key will be added to the repository
|
--ssh-hostname string GitLab SSH hostname, to be used when the SSH host differs from the HTTPS one
|
||||||
```
|
```
|
||||||
|
|
||||||
### Options inherited from parent commands
|
### Options inherited from parent commands
|
||||||
@@ -60,6 +60,7 @@ flux bootstrap gitlab [flags]
|
|||||||
--arch arch cluster architecture, available options are: (amd64, arm, arm64) (default amd64)
|
--arch arch cluster architecture, available options are: (amd64, arm, arm64) (default amd64)
|
||||||
--branch string default branch (for GitHub this must match the default branch setting for the organization) (default "main")
|
--branch string default branch (for GitHub this must match the default branch setting for the organization) (default "main")
|
||||||
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller,helm-controller,notification-controller])
|
--components strings list of components, accepts comma-separated values (default [source-controller,kustomize-controller,helm-controller,notification-controller])
|
||||||
|
--context string kubernetes context to use
|
||||||
--image-pull-secret string Kubernetes secret name used for pulling the toolkit images from a private registry
|
--image-pull-secret string Kubernetes secret name used for pulling the toolkit images from a private registry
|
||||||
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
||||||
--log-level logLevel log level, available options are: (debug, info, error) (default info)
|
--log-level logLevel log level, available options are: (debug, info, error) (default info)
|
||||||
@@ -67,6 +68,7 @@ flux bootstrap gitlab [flags]
|
|||||||
--network-policy deny ingress access to the toolkit controllers from other namespaces using network policies (default true)
|
--network-policy deny ingress access to the toolkit controllers from other namespaces using network policies (default true)
|
||||||
--registry string container registry where the toolkit images are published (default "ghcr.io/fluxcd")
|
--registry string container registry where the toolkit images are published (default "ghcr.io/fluxcd")
|
||||||
--timeout duration timeout for this operation (default 5m0s)
|
--timeout duration timeout for this operation (default 5m0s)
|
||||||
|
--token-auth when enabled, the personal access token will be used instead of SSH deploy key
|
||||||
--verbose print generated objects
|
--verbose print generated objects
|
||||||
-v, --version string toolkit version (default "latest")
|
-v, --version string toolkit version (default "latest")
|
||||||
--watch-all-namespaces watch for custom resources in all namespaces, if set to false it will only watch the namespace where the toolkit is installed (default true)
|
--watch-all-namespaces watch for custom resources in all namespaces, if set to false it will only watch the namespace where the toolkit is installed (default true)
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ flux check [flags]
|
|||||||
### Options inherited from parent commands
|
### Options inherited from parent commands
|
||||||
|
|
||||||
```
|
```
|
||||||
|
--context string kubernetes context to use
|
||||||
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
||||||
-n, --namespace string the namespace scope for this operation (default "flux-system")
|
-n, --namespace string the namespace scope for this operation (default "flux-system")
|
||||||
--timeout duration timeout for this operation (default 5m0s)
|
--timeout duration timeout for this operation (default 5m0s)
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ The completion sub-command generates completion scripts for various shells
|
|||||||
### Options inherited from parent commands
|
### Options inherited from parent commands
|
||||||
|
|
||||||
```
|
```
|
||||||
|
--context string kubernetes context to use
|
||||||
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
||||||
-n, --namespace string the namespace scope for this operation (default "flux-system")
|
-n, --namespace string the namespace scope for this operation (default "flux-system")
|
||||||
--timeout duration timeout for this operation (default 5m0s)
|
--timeout duration timeout for this operation (default 5m0s)
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ command -v flux >/dev/null && . <(flux completion bash)
|
|||||||
### Options inherited from parent commands
|
### Options inherited from parent commands
|
||||||
|
|
||||||
```
|
```
|
||||||
|
--context string kubernetes context to use
|
||||||
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
||||||
-n, --namespace string the namespace scope for this operation (default "flux-system")
|
-n, --namespace string the namespace scope for this operation (default "flux-system")
|
||||||
--timeout duration timeout for this operation (default 5m0s)
|
--timeout duration timeout for this operation (default 5m0s)
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ See http://fishshell.com/docs/current/index.html#completion-own for more details
|
|||||||
### Options inherited from parent commands
|
### Options inherited from parent commands
|
||||||
|
|
||||||
```
|
```
|
||||||
|
--context string kubernetes context to use
|
||||||
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
--kubeconfig string path to the kubeconfig file (default "~/.kube/config")
|
||||||
-n, --namespace string the namespace scope for this operation (default "flux-system")
|
-n, --namespace string the namespace scope for this operation (default "flux-system")
|
||||||
--timeout duration timeout for this operation (default 5m0s)
|
--timeout duration timeout for this operation (default 5m0s)
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user