Compare commits
35 Commits
encrypt-in
...
v0.16.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0ae39d5a0a | ||
|
|
d8911e0c77 | ||
|
|
1be006a45f | ||
|
|
b95e75ddb4 | ||
|
|
15a5f75fe7 | ||
|
|
b01e27f50f | ||
|
|
b1a9583262 | ||
|
|
dd5e6377f8 | ||
|
|
fcb73554c9 | ||
|
|
5c4b3d1080 | ||
|
|
c98cd10621 | ||
|
|
e4af8ddcc8 | ||
|
|
b5ce02b8cf | ||
|
|
cd42b3fb44 | ||
|
|
6dedb767c3 | ||
|
|
4de3268f3b | ||
|
|
a72ff06d79 | ||
|
|
cf239deb3d | ||
|
|
8735229745 | ||
|
|
3f081ba2d9 | ||
|
|
3f613341cb | ||
|
|
4305b8a77d | ||
|
|
fab91d44c3 | ||
|
|
34484734d8 | ||
|
|
10c58bb007 | ||
|
|
1c1fd62a91 | ||
|
|
637ac1e3fe | ||
|
|
f52387e849 | ||
|
|
9efc4986f9 | ||
|
|
fdc366ec1c | ||
|
|
d455db444c | ||
|
|
17418c9858 | ||
|
|
5da7eb7d0d | ||
|
|
9da977ee7a | ||
|
|
8e4b2ead9b |
42
.github/runners/README.md
vendored
Normal file
42
.github/runners/README.md
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
# Flux GitHub runners
|
||||
|
||||
How to provision GitHub Actions self-hosted runners for Flux conformance testing.
|
||||
|
||||
## ARM64 Instance specs
|
||||
|
||||
In order to add a new runner to the GitHub Actions pool,
|
||||
first create an instance on Oracle Cloud with the following configuration:
|
||||
- OS: Canonical Ubuntu 20.04
|
||||
- Shape: VM.Standard.A1.Flex
|
||||
- OCPU Count: 2
|
||||
- Memory (GB): 12
|
||||
- Network Bandwidth (Gbps): 2
|
||||
- Local Disk: Block Storage Only
|
||||
|
||||
Note that the instance image source must be **Canonical Ubuntu** instead of the default Oracle Linux.
|
||||
|
||||
## ARM64 Instance setup
|
||||
|
||||
- SSH into a newly created instance
|
||||
```shell
|
||||
ssh ubuntu@<instance-public-IP>
|
||||
```
|
||||
- Create the action runner dir
|
||||
```shell
|
||||
mkdir -p actions-runner && cd actions-runner
|
||||
```
|
||||
- Download the provisioning script
|
||||
```shell
|
||||
curl -sL https://raw.githubusercontent.com/fluxcd/flux2/main/.github/runners/arm64.sh > arm64.sh \
|
||||
&& chmod +x ./arm64.sh
|
||||
```
|
||||
- Retrieve the GitHub runner token from the repository [settings page](https://github.com/fluxcd/flux2/settings/actions/runners/new?arch=arm64&os=linux)
|
||||
- Run the provisioning script passing the token as the first argument
|
||||
```shell
|
||||
sudo ./arm64.sh <TOKEN>
|
||||
```
|
||||
- Reboot the instance
|
||||
```shell
|
||||
sudo reboot
|
||||
```
|
||||
- Navigate to the GitHub repository [runners page](https://github.com/fluxcd/flux2/settings/actions/runners) and check the runner status
|
||||
73
.github/runners/arm64.sh
vendored
Executable file
73
.github/runners/arm64.sh
vendored
Executable file
@@ -0,0 +1,73 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Copyright 2021 The Flux authors. All rights reserved.
|
||||
#
|
||||
# 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.
|
||||
|
||||
# This script is meant to be run locally and in CI to validate the Kubernetes
|
||||
# manifests (including Flux custom resources) before changes are merged into
|
||||
# the branch synced by Flux in-cluster.
|
||||
|
||||
set -eu
|
||||
|
||||
REPOSITORY_TOKEN=$1
|
||||
REPOSITORY_URL=${2:-https://github.com/fluxcd/flux2}
|
||||
|
||||
KIND_VERSION=0.11.1
|
||||
KUBECTL_VERSION=1.21.2
|
||||
KUSTOMIZE_VERSION=4.1.3
|
||||
GITHUB_RUNNER_VERSION=2.278.0
|
||||
PACKAGES="apt-transport-https ca-certificates software-properties-common build-essential libssl-dev gnupg lsb-release jq"
|
||||
|
||||
# install prerequisites
|
||||
apt-get update \
|
||||
&& apt-get install -y -q ${PACKAGES} \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# install docker
|
||||
curl -fsSL https://get.docker.com -o get-docker.sh \
|
||||
&& chmod +x get-docker.sh
|
||||
./get-docker.sh
|
||||
systemctl enable docker.service
|
||||
systemctl enable containerd.service
|
||||
usermod -aG docker ubuntu
|
||||
|
||||
# install kind
|
||||
curl -Lo ./kind https://kind.sigs.k8s.io/dl/v${KIND_VERSION}/kind-linux-arm64
|
||||
install -o root -g root -m 0755 kind /usr/local/bin/kind
|
||||
|
||||
# install kubectl
|
||||
curl -LO "https://dl.k8s.io/release/v${KUBECTL_VERSION}/bin/linux/arm64/kubectl"
|
||||
install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
|
||||
|
||||
# install kustomize
|
||||
curl -Lo ./kustomize.tar.gz https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize%2Fv${KUSTOMIZE_VERSION}/kustomize_v${KUSTOMIZE_VERSION}_linux_arm64.tar.gz \
|
||||
&& tar -zxvf kustomize.tar.gz \
|
||||
&& rm kustomize.tar.gz
|
||||
install -o root -g root -m 0755 kustomize /usr/local/bin/kustomize
|
||||
|
||||
# download runner
|
||||
curl -o actions-runner-linux-arm64.tar.gz -L https://github.com/actions/runner/releases/download/v${GITHUB_RUNNER_VERSION}/actions-runner-linux-arm64-${GITHUB_RUNNER_VERSION}.tar.gz \
|
||||
&& tar xzf actions-runner-linux-arm64.tar.gz \
|
||||
&& rm actions-runner-linux-arm64.tar.gz
|
||||
|
||||
# install runner dependencies
|
||||
./bin/installdependencies.sh
|
||||
|
||||
# register runner with GitHub
|
||||
sudo -u ubuntu ./config.sh --unattended --url ${REPOSITORY_URL} --token ${REPOSITORY_TOKEN}
|
||||
|
||||
# start runner
|
||||
./svc.sh install
|
||||
./svc.sh start
|
||||
10
.github/workflows/bootstrap.yaml
vendored
10
.github/workflows/bootstrap.yaml
vendored
@@ -26,6 +26,9 @@ jobs:
|
||||
go-version: 1.16.x
|
||||
- name: Setup Kubernetes
|
||||
uses: engineerd/setup-kind@v0.5.0
|
||||
with:
|
||||
version: v0.11.1
|
||||
image: kindest/node:v1.21.1@sha256:69860bda5563ac81e3c0057d654b5253219618a22ec3a346306239bba8cfa1a6
|
||||
- name: Setup Kustomize
|
||||
uses: fluxcd/pkg//actions/kustomize@main
|
||||
- name: Build
|
||||
@@ -61,6 +64,13 @@ jobs:
|
||||
--team=team-z
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITPROVIDER_BOT_TOKEN }}
|
||||
- name: libgit2
|
||||
run: |
|
||||
/tmp/flux create source git test-libgit2 \
|
||||
--url=ssh://git@github.com/fluxcd-testing/${{ steps.vars.outputs.test_repo_name }} \
|
||||
--git-implementation=libgit2 \
|
||||
--secret-ref=flux-system \
|
||||
--branch=main
|
||||
- name: uninstall
|
||||
run: |
|
||||
/tmp/flux uninstall -s --keep-namespace
|
||||
|
||||
5
.github/workflows/e2e-arm64.yaml
vendored
5
.github/workflows/e2e-arm64.yaml
vendored
@@ -9,9 +9,7 @@ jobs:
|
||||
ampere:
|
||||
# Runner info
|
||||
# Owner: Stefan Prodan
|
||||
# VM: Oracle Cloud VM.Standard.A1.Flex 4CPU 24GB RAM
|
||||
# OS: Linux 5.4.0-1045-oracle #49-Ubuntu SMP aarch64
|
||||
# Packages: docker, kind, kubectl, kustomize
|
||||
# Docs: https://github.com/fluxcd/flux2/tree/main/.github/runners
|
||||
runs-on: [self-hosted, Linux, ARM64]
|
||||
steps:
|
||||
- name: Checkout
|
||||
@@ -102,6 +100,7 @@ jobs:
|
||||
if: failure()
|
||||
run: |
|
||||
kubectl --context ${{ steps.prep.outputs.CONTEXT }} -n flux-system get all
|
||||
kubectl --context ${{ steps.prep.outputs.CONTEXT }} -n flux-system describe pods
|
||||
/tmp/flux logs --all-namespaces
|
||||
- name: Cleanup
|
||||
if: always()
|
||||
|
||||
13
.github/workflows/e2e.yaml
vendored
13
.github/workflows/e2e.yaml
vendored
@@ -26,8 +26,8 @@ jobs:
|
||||
- name: Setup Kubernetes
|
||||
uses: engineerd/setup-kind@v0.5.0
|
||||
with:
|
||||
version: "v0.10.0"
|
||||
image: kindest/node:v1.20.2@sha256:8f7ea6e7642c0da54f04a7ee10431549c0257315b3a634f6ef2fecaaedb19bab
|
||||
version: v0.11.1
|
||||
image: kindest/node:v1.21.1@sha256:69860bda5563ac81e3c0057d654b5253219618a22ec3a346306239bba8cfa1a6
|
||||
config: .github/kind/config.yaml # disable KIND-net
|
||||
- name: Setup Calico for network policy
|
||||
run: |
|
||||
@@ -91,6 +91,12 @@ jobs:
|
||||
--health-check="Deployment/frontend.dev" \
|
||||
--health-check="Deployment/backend.dev" \
|
||||
--health-check-timeout=3m
|
||||
- name: flux trace
|
||||
run: |
|
||||
/tmp/flux trace frontend \
|
||||
--kind=deployment \
|
||||
--api-version=apps/v1 \
|
||||
--namespace=dev
|
||||
- name: flux reconcile kustomization --with-source
|
||||
run: |
|
||||
/tmp/flux reconcile kustomization podinfo --with-source
|
||||
@@ -193,7 +199,7 @@ jobs:
|
||||
/tmp/flux create kustomization flux-system \
|
||||
--source=flux-system \
|
||||
--path=./clusters/staging
|
||||
kubectl -n flux-system wait kustomization/apps --for=condition=ready --timeout=2m
|
||||
kubectl -n flux-system wait kustomization/apps --for=condition=ready --timeout=5m
|
||||
- name: flux check
|
||||
run: |
|
||||
/tmp/flux check
|
||||
@@ -205,6 +211,7 @@ jobs:
|
||||
run: |
|
||||
kubectl version --client --short
|
||||
kubectl -n flux-system get all
|
||||
kubectl -n flux-system describe pods
|
||||
kubectl -n flux-system get kustomizations -oyaml
|
||||
kubectl -n flux-system logs deploy/source-controller
|
||||
kubectl -n flux-system logs deploy/kustomize-controller
|
||||
|
||||
@@ -10,11 +10,21 @@ Usage:
|
||||
run: flux -v
|
||||
```
|
||||
|
||||
Note that this action can only be used on GitHub **Linux AMD64** runners.
|
||||
The latest stable version of the `flux` binary is downloaded from
|
||||
GitHub [releases](https://github.com/fluxcd/flux2/releases)
|
||||
and placed at `/usr/local/bin/flux`.
|
||||
|
||||
Note that this action can only be used on GitHub **Linux** runners.
|
||||
You can change the arch (defaults to `amd64`) with:
|
||||
|
||||
```yaml
|
||||
steps:
|
||||
- name: Setup Flux CLI
|
||||
uses: fluxcd/flux2/action@main
|
||||
with:
|
||||
arch: arm64 # can be amd64, arm64 or arm
|
||||
```
|
||||
|
||||
You can download a specific version with:
|
||||
|
||||
```yaml
|
||||
|
||||
@@ -8,19 +8,24 @@ inputs:
|
||||
version:
|
||||
description: "Flux version e.g. 0.8.0 (defaults to latest stable release)"
|
||||
required: false
|
||||
arch:
|
||||
description: "arch can be amd64, arm64 or arm"
|
||||
required: true
|
||||
default: "amd64"
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: "Download flux binary to tmp"
|
||||
shell: bash
|
||||
run: |
|
||||
ARCH=${{ inputs.arch }}
|
||||
VERSION=${{ inputs.version }}
|
||||
|
||||
if [ -z $VERSION ]; then
|
||||
VERSION=$(curl https://api.github.com/repos/fluxcd/flux2/releases/latest -sL | grep tag_name | sed -E 's/.*"([^"]+)".*/\1/' | cut -c 2-)
|
||||
fi
|
||||
|
||||
BIN_URL="https://github.com/fluxcd/flux2/releases/download/v${VERSION}/flux_${VERSION}_linux_amd64.tar.gz"
|
||||
BIN_URL="https://github.com/fluxcd/flux2/releases/download/v${VERSION}/flux_${VERSION}_linux_${ARCH}.tar.gz"
|
||||
curl -sL ${BIN_URL} -o /tmp/flux.tar.gz
|
||||
mkdir -p /tmp/flux
|
||||
tar -C /tmp/flux/ -zxvf /tmp/flux.tar.gz
|
||||
|
||||
@@ -28,7 +28,7 @@ import (
|
||||
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
|
||||
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1alpha2"
|
||||
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1beta1"
|
||||
)
|
||||
|
||||
var createImagePolicyCmd = &cobra.Command{
|
||||
|
||||
@@ -26,7 +26,7 @@ import (
|
||||
|
||||
"github.com/fluxcd/pkg/apis/meta"
|
||||
|
||||
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1alpha2"
|
||||
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1beta1"
|
||||
)
|
||||
|
||||
var createImageRepositoryCmd = &cobra.Command{
|
||||
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
autov1 "github.com/fluxcd/image-automation-controller/api/v1alpha2"
|
||||
autov1 "github.com/fluxcd/image-automation-controller/api/v1beta1"
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
|
||||
)
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ package main
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1alpha2"
|
||||
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1beta1"
|
||||
)
|
||||
|
||||
var deleteImagePolicyCmd = &cobra.Command{
|
||||
|
||||
@@ -19,7 +19,7 @@ package main
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1alpha2"
|
||||
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1beta1"
|
||||
)
|
||||
|
||||
var deleteImageRepositoryCmd = &cobra.Command{
|
||||
|
||||
@@ -19,7 +19,7 @@ package main
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
autov1 "github.com/fluxcd/image-automation-controller/api/v1alpha2"
|
||||
autov1 "github.com/fluxcd/image-automation-controller/api/v1beta1"
|
||||
)
|
||||
|
||||
var deleteImageUpdateCmd = &cobra.Command{
|
||||
|
||||
@@ -20,7 +20,7 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1alpha2"
|
||||
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1beta1"
|
||||
)
|
||||
|
||||
var exportImagePolicyCmd = &cobra.Command{
|
||||
|
||||
@@ -20,7 +20,7 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1alpha2"
|
||||
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1beta1"
|
||||
)
|
||||
|
||||
var exportImageRepositoryCmd = &cobra.Command{
|
||||
|
||||
@@ -20,7 +20,7 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
autov1 "github.com/fluxcd/image-automation-controller/api/v1alpha2"
|
||||
autov1 "github.com/fluxcd/image-automation-controller/api/v1beta1"
|
||||
)
|
||||
|
||||
var exportImageUpdateCmd = &cobra.Command{
|
||||
|
||||
@@ -39,7 +39,9 @@ var getCmd = &cobra.Command{
|
||||
}
|
||||
|
||||
type GetFlags struct {
|
||||
allNamespaces bool
|
||||
allNamespaces bool
|
||||
noHeader bool
|
||||
statusSelector string
|
||||
}
|
||||
|
||||
var getArgs GetFlags
|
||||
@@ -47,6 +49,9 @@ var getArgs GetFlags
|
||||
func init() {
|
||||
getCmd.PersistentFlags().BoolVarP(&getArgs.allNamespaces, "all-namespaces", "A", false,
|
||||
"list the requested object(s) across all namespaces")
|
||||
getCmd.PersistentFlags().BoolVarP(&getArgs.noHeader, "no-header", "", false, "skip the header when printing the results")
|
||||
getCmd.PersistentFlags().StringVar(&getArgs.statusSelector, "status-selector", "",
|
||||
"specify the status condition name and the desired state to filter the get result, e.g. ready=false")
|
||||
rootCmd.AddCommand(getCmd)
|
||||
}
|
||||
|
||||
@@ -54,6 +59,7 @@ type summarisable interface {
|
||||
listAdapter
|
||||
summariseItem(i int, includeNamespace bool, includeKind bool) []string
|
||||
headers(includeNamespace bool) []string
|
||||
statusSelectorMatches(i int, conditionType, conditionStatus string) bool
|
||||
}
|
||||
|
||||
// --- these help with implementations of summarisable
|
||||
@@ -65,6 +71,20 @@ func statusAndMessage(conditions []metav1.Condition) (string, string) {
|
||||
return string(metav1.ConditionFalse), "waiting to be reconciled"
|
||||
}
|
||||
|
||||
func statusMatches(conditionType, conditionStatus string, conditions []metav1.Condition) bool {
|
||||
// we don't use apimeta.FindStatusCondition because we'd like to use EqualFold to compare two strings
|
||||
var c *metav1.Condition
|
||||
for i := range conditions {
|
||||
if strings.EqualFold(conditions[i].Type, conditionType) {
|
||||
c = &conditions[i]
|
||||
}
|
||||
}
|
||||
if c != nil {
|
||||
return strings.EqualFold(string(c.Status), conditionStatus)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func nameColumns(item named, includeNamespace bool, includeKind bool) []string {
|
||||
name := item.GetName()
|
||||
if includeKind {
|
||||
@@ -117,11 +137,27 @@ func (get getCommand) run(cmd *cobra.Command, args []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
header := get.list.headers(getArgs.allNamespaces)
|
||||
var header []string
|
||||
if !getArgs.noHeader {
|
||||
header = get.list.headers(getArgs.allNamespaces)
|
||||
}
|
||||
noFilter := true
|
||||
var conditionType, conditionStatus string
|
||||
if getArgs.statusSelector != "" {
|
||||
parts := strings.SplitN(getArgs.statusSelector, "=", 2)
|
||||
if len(parts) != 2 {
|
||||
return fmt.Errorf("expected status selector in type=status format, but found: %s", getArgs.statusSelector)
|
||||
}
|
||||
conditionType = parts[0]
|
||||
conditionStatus = parts[1]
|
||||
noFilter = false
|
||||
}
|
||||
var rows [][]string
|
||||
for i := 0; i < get.list.len(); i++ {
|
||||
row := get.list.summariseItem(i, getArgs.allNamespaces, getAll)
|
||||
rows = append(rows, row)
|
||||
if noFilter || get.list.statusSelectorMatches(i, conditionType, conditionStatus) {
|
||||
row := get.list.summariseItem(i, getArgs.allNamespaces, getAll)
|
||||
rows = append(rows, row)
|
||||
}
|
||||
}
|
||||
utils.PrintTable(os.Stdout, header, rows)
|
||||
|
||||
|
||||
@@ -55,3 +55,8 @@ func (s alertListAdapter) headers(includeNamespace bool) []string {
|
||||
}
|
||||
return headers
|
||||
}
|
||||
|
||||
func (s alertListAdapter) statusSelectorMatches(i int, conditionType, conditionStatus string) bool {
|
||||
item := s.Items[i]
|
||||
return statusMatches(conditionType, conditionStatus, item.Status.Conditions)
|
||||
}
|
||||
|
||||
@@ -52,3 +52,8 @@ func (s alertProviderListAdapter) headers(includeNamespace bool) []string {
|
||||
}
|
||||
return headers
|
||||
}
|
||||
|
||||
func (s alertProviderListAdapter) statusSelectorMatches(i int, conditionType, conditionStatus string) bool {
|
||||
item := s.Items[i]
|
||||
return statusMatches(conditionType, conditionStatus, item.Status.Conditions)
|
||||
}
|
||||
|
||||
@@ -56,3 +56,8 @@ func (a helmReleaseListAdapter) headers(includeNamespace bool) []string {
|
||||
}
|
||||
return headers
|
||||
}
|
||||
|
||||
func (a helmReleaseListAdapter) statusSelectorMatches(i int, conditionType, conditionStatus string) bool {
|
||||
item := a.Items[i]
|
||||
return statusMatches(conditionType, conditionStatus, item.Status.Conditions)
|
||||
}
|
||||
|
||||
@@ -21,8 +21,8 @@ import (
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
autov1 "github.com/fluxcd/image-automation-controller/api/v1alpha2"
|
||||
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1alpha2"
|
||||
autov1 "github.com/fluxcd/image-automation-controller/api/v1beta1"
|
||||
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1beta1"
|
||||
)
|
||||
|
||||
var getImageAllCmd = &cobra.Command{
|
||||
|
||||
@@ -19,7 +19,7 @@ package main
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1alpha2"
|
||||
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1beta1"
|
||||
)
|
||||
|
||||
var getImagePolicyCmd = &cobra.Command{
|
||||
@@ -54,3 +54,8 @@ func (s imagePolicyListAdapter) headers(includeNamespace bool) []string {
|
||||
}
|
||||
return headers
|
||||
}
|
||||
|
||||
func (s imagePolicyListAdapter) statusSelectorMatches(i int, conditionType, conditionStatus string) bool {
|
||||
item := s.Items[i]
|
||||
return statusMatches(conditionType, conditionStatus, item.Status.Conditions)
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ import (
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1alpha2"
|
||||
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1beta1"
|
||||
)
|
||||
|
||||
var getImageRepositoryCmd = &cobra.Command{
|
||||
@@ -63,3 +63,8 @@ func (s imageRepositoryListAdapter) headers(includeNamespace bool) []string {
|
||||
}
|
||||
return headers
|
||||
}
|
||||
|
||||
func (s imageRepositoryListAdapter) statusSelectorMatches(i int, conditionType, conditionStatus string) bool {
|
||||
item := s.Items[i]
|
||||
return statusMatches(conditionType, conditionStatus, item.Status.Conditions)
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ import (
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
autov1 "github.com/fluxcd/image-automation-controller/api/v1alpha2"
|
||||
autov1 "github.com/fluxcd/image-automation-controller/api/v1beta1"
|
||||
)
|
||||
|
||||
var getImageUpdateCmd = &cobra.Command{
|
||||
@@ -62,3 +62,8 @@ func (s imageUpdateAutomationListAdapter) headers(includeNamespace bool) []strin
|
||||
}
|
||||
return headers
|
||||
}
|
||||
|
||||
func (s imageUpdateAutomationListAdapter) statusSelectorMatches(i int, conditionType, conditionStatus string) bool {
|
||||
item := s.Items[i]
|
||||
return statusMatches(conditionType, conditionStatus, item.Status.Conditions)
|
||||
}
|
||||
|
||||
@@ -57,3 +57,8 @@ func (a kustomizationListAdapter) headers(includeNamespace bool) []string {
|
||||
}
|
||||
return headers
|
||||
}
|
||||
|
||||
func (a kustomizationListAdapter) statusSelectorMatches(i int, conditionType, conditionStatus string) bool {
|
||||
item := a.Items[i]
|
||||
return statusMatches(conditionType, conditionStatus, item.Status.Conditions)
|
||||
}
|
||||
|
||||
@@ -55,3 +55,8 @@ func (s receiverListAdapter) headers(includeNamespace bool) []string {
|
||||
}
|
||||
return headers
|
||||
}
|
||||
|
||||
func (s receiverListAdapter) statusSelectorMatches(i int, conditionType, conditionStatus string) bool {
|
||||
item := s.Items[i]
|
||||
return statusMatches(conditionType, conditionStatus, item.Status.Conditions)
|
||||
}
|
||||
|
||||
@@ -62,3 +62,8 @@ func (a bucketListAdapter) headers(includeNamespace bool) []string {
|
||||
}
|
||||
return headers
|
||||
}
|
||||
|
||||
func (a bucketListAdapter) statusSelectorMatches(i int, conditionType, conditionStatus string) bool {
|
||||
item := a.Items[i]
|
||||
return statusMatches(conditionType, conditionStatus, item.Status.Conditions)
|
||||
}
|
||||
|
||||
@@ -62,3 +62,8 @@ func (a helmChartListAdapter) headers(includeNamespace bool) []string {
|
||||
}
|
||||
return headers
|
||||
}
|
||||
|
||||
func (a helmChartListAdapter) statusSelectorMatches(i int, conditionType, conditionStatus string) bool {
|
||||
item := a.Items[i]
|
||||
return statusMatches(conditionType, conditionStatus, item.Status.Conditions)
|
||||
}
|
||||
|
||||
@@ -62,3 +62,8 @@ func (a gitRepositoryListAdapter) headers(includeNamespace bool) []string {
|
||||
}
|
||||
return headers
|
||||
}
|
||||
|
||||
func (a gitRepositoryListAdapter) statusSelectorMatches(i int, conditionType, conditionStatus string) bool {
|
||||
item := a.Items[i]
|
||||
return statusMatches(conditionType, conditionStatus, item.Status.Conditions)
|
||||
}
|
||||
|
||||
@@ -62,3 +62,8 @@ func (a helmRepositoryListAdapter) headers(includeNamespace bool) []string {
|
||||
}
|
||||
return headers
|
||||
}
|
||||
|
||||
func (a helmRepositoryListAdapter) statusSelectorMatches(i int, conditionType, conditionStatus string) bool {
|
||||
item := a.Items[i]
|
||||
return statusMatches(conditionType, conditionStatus, item.Status.Conditions)
|
||||
}
|
||||
|
||||
@@ -19,8 +19,8 @@ package main
|
||||
import (
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
autov1 "github.com/fluxcd/image-automation-controller/api/v1alpha2"
|
||||
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1alpha2"
|
||||
autov1 "github.com/fluxcd/image-automation-controller/api/v1beta1"
|
||||
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1beta1"
|
||||
)
|
||||
|
||||
// These are general-purpose adapters for attaching methods to, for
|
||||
|
||||
@@ -21,7 +21,7 @@ import (
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1alpha2"
|
||||
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1beta1"
|
||||
)
|
||||
|
||||
var reconcileImageRepositoryCmd = &cobra.Command{
|
||||
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
apimeta "k8s.io/apimachinery/pkg/api/meta"
|
||||
|
||||
autov1 "github.com/fluxcd/image-automation-controller/api/v1alpha2"
|
||||
autov1 "github.com/fluxcd/image-automation-controller/api/v1beta1"
|
||||
meta "github.com/fluxcd/pkg/apis/meta"
|
||||
)
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ package main
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1alpha2"
|
||||
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1beta1"
|
||||
)
|
||||
|
||||
var resumeImageRepositoryCmd = &cobra.Command{
|
||||
|
||||
@@ -19,7 +19,7 @@ package main
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
autov1 "github.com/fluxcd/image-automation-controller/api/v1alpha2"
|
||||
autov1 "github.com/fluxcd/image-automation-controller/api/v1beta1"
|
||||
)
|
||||
|
||||
var resumeImageUpdateCmd = &cobra.Command{
|
||||
|
||||
@@ -19,7 +19,7 @@ package main
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1alpha2"
|
||||
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1beta1"
|
||||
)
|
||||
|
||||
var suspendImageRepositoryCmd = &cobra.Command{
|
||||
|
||||
@@ -19,7 +19,7 @@ package main
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
autov1 "github.com/fluxcd/image-automation-controller/api/v1alpha2"
|
||||
autov1 "github.com/fluxcd/image-automation-controller/api/v1beta1"
|
||||
)
|
||||
|
||||
var suspendImageUpdateCmd = &cobra.Command{
|
||||
|
||||
488
cmd/flux/trace.go
Normal file
488
cmd/flux/trace.go
Normal file
@@ -0,0 +1,488 @@
|
||||
/*
|
||||
Copyright 2021 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 (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"text/template"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/fluxcd/flux2/internal/utils"
|
||||
helmv2 "github.com/fluxcd/helm-controller/api/v2beta1"
|
||||
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1"
|
||||
fluxmeta "github.com/fluxcd/pkg/apis/meta"
|
||||
sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
|
||||
)
|
||||
|
||||
var traceCmd = &cobra.Command{
|
||||
Use: "trace [name]",
|
||||
Short: "trace an in-cluster object throughout the GitOps delivery pipeline",
|
||||
Long: `The trace command shows how an object is managed by Flux,
|
||||
from which source and revision it comes, and what's the latest reconciliation status.'`,
|
||||
Example: ` # Trace a Kubernetes Deployment
|
||||
flux trace my-app --kind=deployment --api-version=apps/v1 --namespace=apps
|
||||
|
||||
# Trace a Kubernetes Pod
|
||||
flux trace redis-master-0 --kind=pod --api-version=v1 -n redis
|
||||
|
||||
# Trace a Kubernetes global object
|
||||
flux trace redis --kind=namespace --api-version=v1
|
||||
|
||||
# Trace a Kubernetes custom resource
|
||||
flux trace redis --kind=helmrelease --api-version=helm.toolkit.fluxcd.io/v2beta1 -n redis`,
|
||||
RunE: traceCmdRun,
|
||||
}
|
||||
|
||||
type traceFlags struct {
|
||||
apiVersion string
|
||||
kind string
|
||||
}
|
||||
|
||||
var traceArgs = traceFlags{}
|
||||
|
||||
func init() {
|
||||
traceCmd.Flags().StringVar(&traceArgs.kind, "kind", "",
|
||||
"the Kubernetes object kind, e.g. Deployment'")
|
||||
traceCmd.Flags().StringVar(&traceArgs.apiVersion, "api-version", "",
|
||||
"the Kubernetes object API version, e.g. 'apps/v1'")
|
||||
rootCmd.AddCommand(traceCmd)
|
||||
}
|
||||
|
||||
func traceCmdRun(cmd *cobra.Command, args []string) error {
|
||||
if len(args) < 1 {
|
||||
return fmt.Errorf("object name is required")
|
||||
}
|
||||
name := args[0]
|
||||
|
||||
if traceArgs.kind == "" {
|
||||
return fmt.Errorf("object kind is required (--kind)")
|
||||
}
|
||||
|
||||
if traceArgs.apiVersion == "" {
|
||||
return fmt.Errorf("object apiVersion is required (--api-version)")
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||
defer cancel()
|
||||
|
||||
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
gv, err := schema.ParseGroupVersion(traceArgs.apiVersion)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invaild apiVersion: %w", err)
|
||||
}
|
||||
|
||||
obj := &unstructured.Unstructured{}
|
||||
obj.SetGroupVersionKind(schema.GroupVersionKind{
|
||||
Group: gv.Group,
|
||||
Version: gv.Version,
|
||||
Kind: traceArgs.kind,
|
||||
})
|
||||
|
||||
objName := types.NamespacedName{
|
||||
Namespace: rootArgs.namespace,
|
||||
Name: name,
|
||||
}
|
||||
|
||||
err = kubeClient.Get(ctx, objName, obj)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to find object: %w", err)
|
||||
}
|
||||
|
||||
if ks, ok := isOwnerManagedByFlux(ctx, kubeClient, obj, kustomizev1.GroupVersion.Group); ok {
|
||||
report, err := traceKustomization(ctx, kubeClient, ks, obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(report)
|
||||
return nil
|
||||
}
|
||||
|
||||
if hr, ok := isOwnerManagedByFlux(ctx, kubeClient, obj, helmv2.GroupVersion.Group); ok {
|
||||
report, err := traceHelm(ctx, kubeClient, hr, obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(report)
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("object not managed by Flux")
|
||||
}
|
||||
|
||||
func traceKustomization(ctx context.Context, kubeClient client.Client, ksName types.NamespacedName, obj *unstructured.Unstructured) (string, error) {
|
||||
ks := &kustomizev1.Kustomization{}
|
||||
ksReady := &metav1.Condition{}
|
||||
err := kubeClient.Get(ctx, ksName, ks)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to find kustomization: %w", err)
|
||||
}
|
||||
ksReady = meta.FindStatusCondition(ks.Status.Conditions, fluxmeta.ReadyCondition)
|
||||
|
||||
var ksRepository *sourcev1.GitRepository
|
||||
var ksRepositoryReady *metav1.Condition
|
||||
if ks.Spec.SourceRef.Kind == sourcev1.GitRepositoryKind {
|
||||
ksRepository = &sourcev1.GitRepository{}
|
||||
sourceNamespace := ks.Namespace
|
||||
if ks.Spec.SourceRef.Namespace != "" {
|
||||
sourceNamespace = ks.Spec.SourceRef.Namespace
|
||||
}
|
||||
err = kubeClient.Get(ctx, types.NamespacedName{
|
||||
Namespace: sourceNamespace,
|
||||
Name: ks.Spec.SourceRef.Name,
|
||||
}, ksRepository)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to find GitRepository: %w", err)
|
||||
}
|
||||
ksRepositoryReady = meta.FindStatusCondition(ksRepository.Status.Conditions, fluxmeta.ReadyCondition)
|
||||
}
|
||||
|
||||
var traceTmpl = `
|
||||
Object: {{.ObjectName}}
|
||||
{{- if .ObjectNamespace }}
|
||||
Namespace: {{.ObjectNamespace}}
|
||||
{{- end }}
|
||||
Status: Managed by Flux
|
||||
{{- if .Kustomization }}
|
||||
---
|
||||
Kustomization: {{.Kustomization.Name}}
|
||||
Namespace: {{.Kustomization.Namespace}}
|
||||
{{- if .Kustomization.Spec.TargetNamespace }}
|
||||
Target: {{.Kustomization.Spec.TargetNamespace}}
|
||||
{{- end }}
|
||||
Path: {{.Kustomization.Spec.Path}}
|
||||
Revision: {{.Kustomization.Status.LastAppliedRevision}}
|
||||
{{- if .KustomizationReady }}
|
||||
Status: Last reconciled at {{.KustomizationReady.LastTransitionTime}}
|
||||
Message: {{.KustomizationReady.Message}}
|
||||
{{- else }}
|
||||
Status: Unknown
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if .GitRepository }}
|
||||
---
|
||||
GitRepository: {{.GitRepository.Name}}
|
||||
Namespace: {{.GitRepository.Namespace}}
|
||||
URL: {{.GitRepository.Spec.URL}}
|
||||
{{- if .GitRepository.Spec.Reference.Tag }}
|
||||
Tag: {{.GitRepository.Spec.Reference.Tag}}
|
||||
{{- else if .GitRepository.Spec.Reference.SemVer }}
|
||||
Tag: {{.GitRepository.Spec.Reference.SemVer}}
|
||||
{{- else if .GitRepository.Spec.Reference.Branch }}
|
||||
Branch: {{.GitRepository.Spec.Reference.Branch}}
|
||||
{{- end }}
|
||||
{{- if .GitRepository.Status.Artifact }}
|
||||
Revision: {{.GitRepository.Status.Artifact.Revision}}
|
||||
{{- end }}
|
||||
{{- if .GitRepositoryReady }}
|
||||
{{- if eq .GitRepositoryReady.Status "False" }}
|
||||
Status: Last reconciliation failed at {{.GitRepositoryReady.LastTransitionTime}}
|
||||
{{- else }}
|
||||
Status: Last reconciled at {{.GitRepositoryReady.LastTransitionTime}}
|
||||
{{- end }}
|
||||
Message: {{.GitRepositoryReady.Message}}
|
||||
{{- else }}
|
||||
Status: Unknown
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
`
|
||||
|
||||
traceResult := struct {
|
||||
ObjectName string
|
||||
ObjectNamespace string
|
||||
Kustomization *kustomizev1.Kustomization
|
||||
KustomizationReady *metav1.Condition
|
||||
GitRepository *sourcev1.GitRepository
|
||||
GitRepositoryReady *metav1.Condition
|
||||
}{
|
||||
ObjectName: obj.GetKind() + "/" + obj.GetName(),
|
||||
ObjectNamespace: obj.GetNamespace(),
|
||||
Kustomization: ks,
|
||||
KustomizationReady: ksReady,
|
||||
GitRepository: ksRepository,
|
||||
GitRepositoryReady: ksRepositoryReady,
|
||||
}
|
||||
|
||||
t, err := template.New("tmpl").Parse(traceTmpl)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var data bytes.Buffer
|
||||
writer := bufio.NewWriter(&data)
|
||||
if err := t.Execute(writer, traceResult); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if err := writer.Flush(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return data.String(), nil
|
||||
}
|
||||
|
||||
func traceHelm(ctx context.Context, kubeClient client.Client, hrName types.NamespacedName, obj *unstructured.Unstructured) (string, error) {
|
||||
hr := &helmv2.HelmRelease{}
|
||||
hrReady := &metav1.Condition{}
|
||||
err := kubeClient.Get(ctx, hrName, hr)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to find HelmRelease: %w", err)
|
||||
}
|
||||
hrReady = meta.FindStatusCondition(hr.Status.Conditions, fluxmeta.ReadyCondition)
|
||||
|
||||
var hrChart *sourcev1.HelmChart
|
||||
var hrChartReady *metav1.Condition
|
||||
if chart := hr.Status.HelmChart; chart != "" {
|
||||
hrChart = &sourcev1.HelmChart{}
|
||||
err = kubeClient.Get(ctx, utils.ParseNamespacedName(chart), hrChart)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to find HelmChart: %w", err)
|
||||
}
|
||||
hrChartReady = meta.FindStatusCondition(hrChart.Status.Conditions, fluxmeta.ReadyCondition)
|
||||
}
|
||||
|
||||
var hrGitRepository *sourcev1.GitRepository
|
||||
var hrGitRepositoryReady *metav1.Condition
|
||||
if hr.Spec.Chart.Spec.SourceRef.Kind == sourcev1.GitRepositoryKind {
|
||||
hrGitRepository = &sourcev1.GitRepository{}
|
||||
sourceNamespace := hr.Namespace
|
||||
if hr.Spec.Chart.Spec.SourceRef.Namespace != "" {
|
||||
sourceNamespace = hr.Spec.Chart.Spec.SourceRef.Namespace
|
||||
}
|
||||
err = kubeClient.Get(ctx, types.NamespacedName{
|
||||
Namespace: sourceNamespace,
|
||||
Name: hr.Spec.Chart.Spec.SourceRef.Name,
|
||||
}, hrGitRepository)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to find GitRepository: %w", err)
|
||||
}
|
||||
hrGitRepositoryReady = meta.FindStatusCondition(hrGitRepository.Status.Conditions, fluxmeta.ReadyCondition)
|
||||
}
|
||||
|
||||
var hrHelmRepository *sourcev1.HelmRepository
|
||||
var hrHelmRepositoryReady *metav1.Condition
|
||||
if hr.Spec.Chart.Spec.SourceRef.Kind == sourcev1.HelmRepositoryKind {
|
||||
hrHelmRepository = &sourcev1.HelmRepository{}
|
||||
sourceNamespace := hr.Namespace
|
||||
if hr.Spec.Chart.Spec.SourceRef.Namespace != "" {
|
||||
sourceNamespace = hr.Spec.Chart.Spec.SourceRef.Namespace
|
||||
}
|
||||
err = kubeClient.Get(ctx, types.NamespacedName{
|
||||
Namespace: sourceNamespace,
|
||||
Name: hr.Spec.Chart.Spec.SourceRef.Name,
|
||||
}, hrHelmRepository)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to find HelmRepository: %w", err)
|
||||
}
|
||||
hrHelmRepositoryReady = meta.FindStatusCondition(hrHelmRepository.Status.Conditions, fluxmeta.ReadyCondition)
|
||||
}
|
||||
|
||||
var traceTmpl = `
|
||||
Object: {{.ObjectName}}
|
||||
{{- if .ObjectNamespace }}
|
||||
Namespace: {{.ObjectNamespace}}
|
||||
{{- end }}
|
||||
Status: Managed by Flux
|
||||
{{- if .HelmRelease }}
|
||||
---
|
||||
HelmRelease: {{.HelmRelease.Name}}
|
||||
Namespace: {{.HelmRelease.Namespace}}
|
||||
{{- if .HelmRelease.Spec.TargetNamespace }}
|
||||
Target: {{.HelmRelease.Spec.TargetNamespace}}
|
||||
{{- end }}
|
||||
Revision: {{.HelmRelease.Status.LastAppliedRevision}}
|
||||
{{- if .HelmReleaseReady }}
|
||||
Status: Last reconciled at {{.HelmReleaseReady.LastTransitionTime}}
|
||||
Message: {{.HelmReleaseReady.Message}}
|
||||
{{- else }}
|
||||
Status: Unknown
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if .HelmChart }}
|
||||
---
|
||||
HelmChart: {{.HelmChart.Name}}
|
||||
Namespace: {{.HelmChart.Namespace}}
|
||||
Chart: {{.HelmChart.Spec.Chart}}
|
||||
Version: {{.HelmChart.Spec.Version}}
|
||||
{{- if .HelmChart.Status.Artifact }}
|
||||
Revision: {{.HelmChart.Status.Artifact.Revision}}
|
||||
{{- end }}
|
||||
{{- if .HelmChartReady }}
|
||||
Status: Last reconciled at {{.HelmChartReady.LastTransitionTime}}
|
||||
Message: {{.HelmChartReady.Message}}
|
||||
{{- else }}
|
||||
Status: Unknown
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if .HelmRepository }}
|
||||
---
|
||||
HelmRepository: {{.HelmRepository.Name}}
|
||||
Namespace: {{.HelmRepository.Namespace}}
|
||||
URL: {{.HelmRepository.Spec.URL}}
|
||||
{{- if .HelmRepository.Status.Artifact }}
|
||||
Revision: {{.HelmRepository.Status.Artifact.Revision}}
|
||||
{{- end }}
|
||||
{{- if .HelmRepositoryReady }}
|
||||
Status: Last reconciled at {{.HelmRepositoryReady.LastTransitionTime}}
|
||||
Message: {{.HelmRepositoryReady.Message}}
|
||||
{{- else }}
|
||||
Status: Unknown
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if .GitRepository }}
|
||||
---
|
||||
GitRepository: {{.GitRepository.Name}}
|
||||
Namespace: {{.GitRepository.Namespace}}
|
||||
URL: {{.GitRepository.Spec.URL}}
|
||||
{{- if .GitRepository.Spec.Reference.Tag }}
|
||||
Tag: {{.GitRepository.Spec.Reference.Tag}}
|
||||
{{- else if .GitRepository.Spec.Reference.SemVer }}
|
||||
Tag: {{.GitRepository.Spec.Reference.SemVer}}
|
||||
{{- else if .GitRepository.Spec.Reference.Branch }}
|
||||
Branch: {{.GitRepository.Spec.Reference.Branch}}
|
||||
{{- end }}
|
||||
{{- if .GitRepository.Status.Artifact }}
|
||||
Revision: {{.GitRepository.Status.Artifact.Revision}}
|
||||
{{- end }}
|
||||
{{- if .GitRepositoryReady }}
|
||||
{{- if eq .GitRepositoryReady.Status "False" }}
|
||||
Status: Last reconciliation failed at {{.GitRepositoryReady.LastTransitionTime}}
|
||||
{{- else }}
|
||||
Status: Last reconciled at {{.GitRepositoryReady.LastTransitionTime}}
|
||||
{{- end }}
|
||||
Message: {{.GitRepositoryReady.Message}}
|
||||
{{- else }}
|
||||
Status: Unknown
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
`
|
||||
|
||||
traceResult := struct {
|
||||
ObjectName string
|
||||
ObjectNamespace string
|
||||
HelmRelease *helmv2.HelmRelease
|
||||
HelmReleaseReady *metav1.Condition
|
||||
HelmChart *sourcev1.HelmChart
|
||||
HelmChartReady *metav1.Condition
|
||||
GitRepository *sourcev1.GitRepository
|
||||
GitRepositoryReady *metav1.Condition
|
||||
HelmRepository *sourcev1.HelmRepository
|
||||
HelmRepositoryReady *metav1.Condition
|
||||
}{
|
||||
ObjectName: obj.GetKind() + "/" + obj.GetName(),
|
||||
ObjectNamespace: obj.GetNamespace(),
|
||||
HelmRelease: hr,
|
||||
HelmReleaseReady: hrReady,
|
||||
HelmChart: hrChart,
|
||||
HelmChartReady: hrChartReady,
|
||||
GitRepository: hrGitRepository,
|
||||
GitRepositoryReady: hrGitRepositoryReady,
|
||||
HelmRepository: hrHelmRepository,
|
||||
HelmRepositoryReady: hrHelmRepositoryReady,
|
||||
}
|
||||
|
||||
t, err := template.New("tmpl").Parse(traceTmpl)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var data bytes.Buffer
|
||||
writer := bufio.NewWriter(&data)
|
||||
if err := t.Execute(writer, traceResult); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if err := writer.Flush(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return data.String(), nil
|
||||
}
|
||||
|
||||
func isManagedByFlux(obj *unstructured.Unstructured, group string) (types.NamespacedName, bool) {
|
||||
nameKey := fmt.Sprintf("%s/name", group)
|
||||
namespaceKey := fmt.Sprintf("%s/namespace", group)
|
||||
namespacedName := types.NamespacedName{}
|
||||
|
||||
for k, v := range obj.GetLabels() {
|
||||
if k == nameKey {
|
||||
namespacedName.Name = v
|
||||
}
|
||||
if k == namespaceKey {
|
||||
namespacedName.Namespace = v
|
||||
}
|
||||
}
|
||||
|
||||
if namespacedName.Name == "" {
|
||||
return namespacedName, false
|
||||
}
|
||||
return namespacedName, true
|
||||
}
|
||||
|
||||
func isOwnerManagedByFlux(ctx context.Context, kubeClient client.Client, obj *unstructured.Unstructured, group string) (types.NamespacedName, bool) {
|
||||
if n, ok := isManagedByFlux(obj, group); ok {
|
||||
return n, true
|
||||
}
|
||||
|
||||
namespacedName := types.NamespacedName{}
|
||||
for _, reference := range obj.GetOwnerReferences() {
|
||||
owner := &unstructured.Unstructured{}
|
||||
gv, err := schema.ParseGroupVersion(reference.APIVersion)
|
||||
if err != nil {
|
||||
return namespacedName, false
|
||||
}
|
||||
|
||||
owner.SetGroupVersionKind(schema.GroupVersionKind{
|
||||
Group: gv.Group,
|
||||
Version: gv.Version,
|
||||
Kind: reference.Kind,
|
||||
})
|
||||
|
||||
ownerName := types.NamespacedName{
|
||||
Namespace: obj.GetNamespace(),
|
||||
Name: reference.Name,
|
||||
}
|
||||
|
||||
err = kubeClient.Get(ctx, ownerName, owner)
|
||||
if err != nil {
|
||||
return namespacedName, false
|
||||
}
|
||||
|
||||
if n, ok := isManagedByFlux(owner, group); ok {
|
||||
return n, true
|
||||
}
|
||||
|
||||
if len(owner.GetOwnerReferences()) > 0 {
|
||||
return isOwnerManagedByFlux(ctx, kubeClient, owner, group)
|
||||
}
|
||||
}
|
||||
|
||||
return namespacedName, false
|
||||
}
|
||||
8
go.mod
8
go.mod
@@ -7,16 +7,16 @@ require (
|
||||
github.com/cyphar/filepath-securejoin v0.2.2
|
||||
github.com/fluxcd/go-git-providers v0.1.1
|
||||
github.com/fluxcd/helm-controller/api v0.11.1
|
||||
github.com/fluxcd/image-automation-controller/api v0.12.0
|
||||
github.com/fluxcd/image-reflector-controller/api v0.10.0
|
||||
github.com/fluxcd/kustomize-controller/api v0.13.0
|
||||
github.com/fluxcd/image-automation-controller/api v0.14.0
|
||||
github.com/fluxcd/image-reflector-controller/api v0.11.0
|
||||
github.com/fluxcd/kustomize-controller/api v0.13.2
|
||||
github.com/fluxcd/notification-controller/api v0.15.0
|
||||
github.com/fluxcd/pkg/apis/meta v0.10.0
|
||||
github.com/fluxcd/pkg/runtime v0.12.0
|
||||
github.com/fluxcd/pkg/ssh v0.0.5
|
||||
github.com/fluxcd/pkg/untar v0.0.5
|
||||
github.com/fluxcd/pkg/version v0.0.1
|
||||
github.com/fluxcd/source-controller/api v0.15.1
|
||||
github.com/fluxcd/source-controller/api v0.15.3
|
||||
github.com/go-git/go-git/v5 v5.4.2
|
||||
github.com/google/go-containerregistry v0.2.0
|
||||
github.com/manifoldco/promptui v0.7.0
|
||||
|
||||
18
go.sum
18
go.sum
@@ -203,12 +203,12 @@ github.com/fluxcd/go-git-providers v0.1.1 h1:R4VafMOo1IlfEZcImApCeElge/HajhFvRzD
|
||||
github.com/fluxcd/go-git-providers v0.1.1/go.mod h1:nRgNpHZmZhrsyNSma1JcAhjUG9xrqMGJcIUr9K7M7vk=
|
||||
github.com/fluxcd/helm-controller/api v0.11.1 h1:7oanAnhcRdqrnALDGpZcg5iuDqwCv+jNTmGvSrgDyCo=
|
||||
github.com/fluxcd/helm-controller/api v0.11.1/go.mod h1:nt5YdVS+jWXDSbP3gAX3HII6oX+8ahrHD6og2ZVsnN4=
|
||||
github.com/fluxcd/image-automation-controller/api v0.12.0 h1:TM37onbW9vqcwPZgcavrXka9OF+JmK2+m69V8GYRWIM=
|
||||
github.com/fluxcd/image-automation-controller/api v0.12.0/go.mod h1:f4KeYUdaQD8hfANsEOAdIxoloIBIY7UUHKM99h/swqg=
|
||||
github.com/fluxcd/image-reflector-controller/api v0.10.0 h1:uZsf5X0Djko2yJMNdKn516nKCiSBFecE8c+O66lrgyI=
|
||||
github.com/fluxcd/image-reflector-controller/api v0.10.0/go.mod h1:X4qZ11pfA5w1ajbkYbWmQ3hBW3gzCyIjhU87AvV6o2A=
|
||||
github.com/fluxcd/kustomize-controller/api v0.13.0 h1:bAbaNinlgxu7xflQHR/DLyf3u8V98pyT+U+d1+VM67c=
|
||||
github.com/fluxcd/kustomize-controller/api v0.13.0/go.mod h1:hh8LG9D89cLeXJJv3z78aoFh03X9hn2FSiibofX3UBk=
|
||||
github.com/fluxcd/image-automation-controller/api v0.14.0 h1:8/mv1KUaXDzXq+TSJWLaPaswjNH7PgzJf6aZyg9vIYw=
|
||||
github.com/fluxcd/image-automation-controller/api v0.14.0/go.mod h1:WDBKSufHazCf065F9qPWtVPUN8kU4MdM5rVC1MoZtpk=
|
||||
github.com/fluxcd/image-reflector-controller/api v0.11.0 h1:Pz9GuUQvmJO5nJPEtGBRQnIHvcY+ITqI4LdSiW11toE=
|
||||
github.com/fluxcd/image-reflector-controller/api v0.11.0/go.mod h1:X4qZ11pfA5w1ajbkYbWmQ3hBW3gzCyIjhU87AvV6o2A=
|
||||
github.com/fluxcd/kustomize-controller/api v0.13.2 h1:Dd+gryMtV1J6TuFvbHj50VFauUNOtC3Uowa5yxgZ+l0=
|
||||
github.com/fluxcd/kustomize-controller/api v0.13.2/go.mod h1:hh8LG9D89cLeXJJv3z78aoFh03X9hn2FSiibofX3UBk=
|
||||
github.com/fluxcd/notification-controller/api v0.15.0 h1:NWBnggAd07vQP90HwRZHv+z4hzE/sC03/knLrw2OJdY=
|
||||
github.com/fluxcd/notification-controller/api v0.15.0/go.mod h1:fh5AgXtcceoTpqVTHrISIVLcb3Z/qK8F9cysyhuAkfI=
|
||||
github.com/fluxcd/pkg/apis/kustomize v0.1.0/go.mod h1:gEl+W5cVykCC3RfrCaqe+Pz+j4lKl2aeR4dxsom/zII=
|
||||
@@ -224,9 +224,9 @@ github.com/fluxcd/pkg/untar v0.0.5 h1:UGI3Ch1UIEIaqQvMicmImL1s9npQa64DJ/ozqHKB7g
|
||||
github.com/fluxcd/pkg/untar v0.0.5/go.mod h1:O6V9+rtl8c1mHBafgqFlJN6zkF1HS5SSYn7RpQJ/nfw=
|
||||
github.com/fluxcd/pkg/version v0.0.1 h1:/8asQoDXSThz3csiwi4Qo8Zb6blAxLXbtxNgeMJ9bCg=
|
||||
github.com/fluxcd/pkg/version v0.0.1/go.mod h1:WAF4FEEA9xyhngF8TDxg3UPu5fA1qhEYV8Pmi2Il01Q=
|
||||
github.com/fluxcd/source-controller/api v0.14.0/go.mod h1:P1pIkaoIsiCJ/NLC7IBXPb9XEime9NvA1WN4hZu2Of4=
|
||||
github.com/fluxcd/source-controller/api v0.15.1 h1:ajJHCP3e3AST13nOJrM2ax2mqTS2vSjj7jkedhbMds0=
|
||||
github.com/fluxcd/source-controller/api v0.15.1/go.mod h1:P1pIkaoIsiCJ/NLC7IBXPb9XEime9NvA1WN4hZu2Of4=
|
||||
github.com/fluxcd/source-controller/api v0.15.2/go.mod h1:P1pIkaoIsiCJ/NLC7IBXPb9XEime9NvA1WN4hZu2Of4=
|
||||
github.com/fluxcd/source-controller/api v0.15.3 h1:xJodSIQr/pAlUhVsmaiPNLV+tabSYLjr+93remjI3WI=
|
||||
github.com/fluxcd/source-controller/api v0.15.3/go.mod h1:P1pIkaoIsiCJ/NLC7IBXPb9XEime9NvA1WN4hZu2Of4=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
github.com/form3tech-oss/jwt-go v3.2.2+incompatible h1:TcekIExNqud5crz4xD2pavyTgWiPvpYe4Xau31I0PRk=
|
||||
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
|
||||
|
||||
@@ -17,7 +17,6 @@ limitations under the License.
|
||||
package utils
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
@@ -28,7 +27,6 @@ import (
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/olekukonko/tablewriter"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
@@ -38,6 +36,7 @@ import (
|
||||
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
apiruntime "k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
sigyaml "k8s.io/apimachinery/pkg/util/yaml"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
@@ -45,8 +44,8 @@ import (
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
helmv2 "github.com/fluxcd/helm-controller/api/v2beta1"
|
||||
imageautov1 "github.com/fluxcd/image-automation-controller/api/v1alpha2"
|
||||
imagereflectv1 "github.com/fluxcd/image-reflector-controller/api/v1alpha2"
|
||||
imageautov1 "github.com/fluxcd/image-automation-controller/api/v1beta1"
|
||||
imagereflectv1 "github.com/fluxcd/image-reflector-controller/api/v1beta1"
|
||||
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1beta1"
|
||||
notificationv1 "github.com/fluxcd/notification-controller/api/v1beta1"
|
||||
"github.com/fluxcd/pkg/runtime/dependency"
|
||||
@@ -109,36 +108,6 @@ func ExecKubectlCommand(ctx context.Context, mode ExecMode, kubeConfigPath strin
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func ExecTemplate(obj interface{}, tmpl, filename string) error {
|
||||
t, err := template.New("tmpl").Parse(tmpl)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var data bytes.Buffer
|
||||
writer := bufio.NewWriter(&data)
|
||||
if err := t.Execute(writer, obj); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := writer.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
file, err := os.Create(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
_, err = io.WriteString(file, data.String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return file.Sync()
|
||||
}
|
||||
|
||||
func KubeConfig(kubeConfigPath string, kubeContext string) (*rest.Config, error) {
|
||||
configFiles := SplitKubeConfigPath(kubeConfigPath)
|
||||
configOverrides := clientcmd.ConfigOverrides{}
|
||||
@@ -225,6 +194,21 @@ func ContainsEqualFoldItemString(s []string, e string) (string, bool) {
|
||||
return "", false
|
||||
}
|
||||
|
||||
// ParseNamespacedName extracts the NamespacedName of a resource
|
||||
// based on the '<namespace>/<name>' format
|
||||
func ParseNamespacedName(input string) types.NamespacedName {
|
||||
parts := strings.Split(input, "/")
|
||||
if len(parts) == 2 {
|
||||
return types.NamespacedName{
|
||||
Namespace: parts[0],
|
||||
Name: parts[1],
|
||||
}
|
||||
}
|
||||
return types.NamespacedName{
|
||||
Name: input,
|
||||
}
|
||||
}
|
||||
|
||||
// ParseObjectKindName extracts the kind and name of a resource
|
||||
// based on the '<kind>/<name>' format
|
||||
func ParseObjectKindName(input string) (kind, name string) {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- https://github.com/fluxcd/image-automation-controller/releases/download/v0.12.0/image-automation-controller.crds.yaml
|
||||
- https://github.com/fluxcd/image-automation-controller/releases/download/v0.12.0/image-automation-controller.deployment.yaml
|
||||
- https://github.com/fluxcd/image-automation-controller/releases/download/v0.14.0/image-automation-controller.crds.yaml
|
||||
- https://github.com/fluxcd/image-automation-controller/releases/download/v0.14.0/image-automation-controller.deployment.yaml
|
||||
- account.yaml
|
||||
patchesJson6902:
|
||||
- target:
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- https://github.com/fluxcd/image-reflector-controller/releases/download/v0.10.0/image-reflector-controller.crds.yaml
|
||||
- https://github.com/fluxcd/image-reflector-controller/releases/download/v0.10.0/image-reflector-controller.deployment.yaml
|
||||
- https://github.com/fluxcd/image-reflector-controller/releases/download/v0.11.0/image-reflector-controller.crds.yaml
|
||||
- https://github.com/fluxcd/image-reflector-controller/releases/download/v0.11.0/image-reflector-controller.deployment.yaml
|
||||
- account.yaml
|
||||
patchesJson6902:
|
||||
- target:
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- https://github.com/fluxcd/kustomize-controller/releases/download/v0.13.0/kustomize-controller.crds.yaml
|
||||
- https://github.com/fluxcd/kustomize-controller/releases/download/v0.13.0/kustomize-controller.deployment.yaml
|
||||
- https://github.com/fluxcd/kustomize-controller/releases/download/v0.13.2/kustomize-controller.crds.yaml
|
||||
- https://github.com/fluxcd/kustomize-controller/releases/download/v0.13.2/kustomize-controller.deployment.yaml
|
||||
- account.yaml
|
||||
patchesJson6902:
|
||||
- target:
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- https://github.com/fluxcd/source-controller/releases/download/v0.15.1/source-controller.crds.yaml
|
||||
- https://github.com/fluxcd/source-controller/releases/download/v0.15.1/source-controller.deployment.yaml
|
||||
- https://github.com/fluxcd/source-controller/releases/download/v0.15.3/source-controller.crds.yaml
|
||||
- https://github.com/fluxcd/source-controller/releases/download/v0.15.3/source-controller.deployment.yaml
|
||||
- account.yaml
|
||||
patchesJson6902:
|
||||
- target:
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
resources:
|
||||
- https://github.com/fluxcd/source-controller/releases/download/v0.15.1/source-controller.crds.yaml
|
||||
- https://github.com/fluxcd/kustomize-controller/releases/download/v0.13.0/kustomize-controller.crds.yaml
|
||||
- https://github.com/fluxcd/source-controller/releases/download/v0.15.3/source-controller.crds.yaml
|
||||
- https://github.com/fluxcd/kustomize-controller/releases/download/v0.13.2/kustomize-controller.crds.yaml
|
||||
- https://github.com/fluxcd/helm-controller/releases/download/v0.11.1/helm-controller.crds.yaml
|
||||
- https://github.com/fluxcd/notification-controller/releases/download/v0.15.0/notification-controller.crds.yaml
|
||||
- https://github.com/fluxcd/image-reflector-controller/releases/download/v0.10.0/image-reflector-controller.crds.yaml
|
||||
- https://github.com/fluxcd/image-automation-controller/releases/download/v0.12.0/image-automation-controller.crds.yaml
|
||||
- https://github.com/fluxcd/image-reflector-controller/releases/download/v0.11.0/image-reflector-controller.crds.yaml
|
||||
- https://github.com/fluxcd/image-automation-controller/releases/download/v0.14.0/image-automation-controller.crds.yaml
|
||||
|
||||
@@ -547,7 +547,7 @@
|
||||
{
|
||||
"expr": "rate(process_cpu_seconds_total{namespace=\"$namespace\",pod=~\".*-controller-.*\"}[1m])",
|
||||
"interval": "",
|
||||
"legendFormat": "{{kubernetes_pod_name}}",
|
||||
"legendFormat": "{{pod}}",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
@@ -643,7 +643,7 @@
|
||||
"expr": "rate(go_memstats_alloc_bytes_total{namespace=\"$namespace\",pod=~\".*-controller-.*\"}[1m])",
|
||||
"hide": false,
|
||||
"interval": "",
|
||||
"legendFormat": "{{kubernetes_pod_name}}",
|
||||
"legendFormat": "{{pod}}",
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -21,4 +21,4 @@ spec:
|
||||
- image-automation-controller
|
||||
- image-reflector-controller
|
||||
podMetricsEndpoints:
|
||||
- targetPort: http-prom
|
||||
- port: http-prom
|
||||
|
||||
Reference in New Issue
Block a user