mirror of
https://github.com/fluxcd/flux2.git
synced 2026-02-22 07:31:47 +00:00
Merge pull request #1671 from allenporter/flux-trace
Add tests for flux trace command
This commit is contained in:
commit
2290880389
13 changed files with 577 additions and 12 deletions
|
|
@ -25,6 +25,7 @@ import (
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
_ "k8s.io/client-go/plugin/pkg/client/auth"
|
_ "k8s.io/client-go/plugin/pkg/client/auth"
|
||||||
|
|
||||||
|
"github.com/fluxcd/flux2/internal/utils"
|
||||||
"github.com/fluxcd/flux2/pkg/manifestgen/install"
|
"github.com/fluxcd/flux2/pkg/manifestgen/install"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -126,6 +127,18 @@ func NewRootFlags() rootFlags {
|
||||||
return rf
|
return rf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type rootContext struct {
|
||||||
|
kubeManager utils.KubeManager
|
||||||
|
}
|
||||||
|
|
||||||
|
var rootCtx = NewRootContext()
|
||||||
|
|
||||||
|
func NewRootContext() rootContext {
|
||||||
|
var rc rootContext
|
||||||
|
rc.kubeManager = utils.DefaultKubeManager()
|
||||||
|
return rc
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
log.SetFlags(0)
|
log.SetFlags(0)
|
||||||
configureKubeconfig()
|
configureKubeconfig()
|
||||||
|
|
|
||||||
26
cmd/flux/testdata/trace/deployment.txt
vendored
Normal file
26
cmd/flux/testdata/trace/deployment.txt
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
|
||||||
|
Object: deployment/podinfo
|
||||||
|
Namespace: podinfo
|
||||||
|
Status: Managed by Flux
|
||||||
|
---
|
||||||
|
HelmRelease: podinfo
|
||||||
|
Namespace: podinfo
|
||||||
|
Revision: 6.0.0
|
||||||
|
Status: Last reconciled at 2021-07-16 15:42:20 +0000 UTC
|
||||||
|
Message: Release reconciliation succeeded
|
||||||
|
---
|
||||||
|
HelmChart: podinfo-podinfo
|
||||||
|
Namespace: flux-system
|
||||||
|
Chart: podinfo
|
||||||
|
Version: 6.0.0
|
||||||
|
Revision: 6.0.0
|
||||||
|
Status: Last reconciled at 2021-07-16 15:32:09 +0000 UTC
|
||||||
|
Message: Fetched revision: 6.0.0
|
||||||
|
---
|
||||||
|
HelmRepository: podinfo
|
||||||
|
Namespace: flux-system
|
||||||
|
URL: https://stefanprodan.github.io/podinfo
|
||||||
|
Revision: 8411f23d07d3701f0e96e7d9e503b7936d7e1d56
|
||||||
|
Status: Last reconciled at 2021-07-11 00:25:46 +0000 UTC
|
||||||
|
Message: Fetched revision: 8411f23d07d3701f0e96e7d9e503b7936d7e1d56
|
||||||
|
|
||||||
129
cmd/flux/testdata/trace/deployment.yaml
vendored
Normal file
129
cmd/flux/testdata/trace/deployment.yaml
vendored
Normal file
|
|
@ -0,0 +1,129 @@
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/managed-by: Helm
|
||||||
|
app.kubernetes.io/name: podinfo
|
||||||
|
helm.toolkit.fluxcd.io/name: podinfo
|
||||||
|
helm.toolkit.fluxcd.io/namespace: podinfo
|
||||||
|
name: podinfo
|
||||||
|
namespace: podinfo
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: podinfo
|
||||||
|
spec:
|
||||||
|
---
|
||||||
|
apiVersion: helm.toolkit.fluxcd.io/v2beta1
|
||||||
|
kind: HelmRelease
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
kustomize.toolkit.fluxcd.io/name: infrastructure
|
||||||
|
kustomize.toolkit.fluxcd.io/namespace: flux-system
|
||||||
|
name: podinfo
|
||||||
|
namespace: podinfo
|
||||||
|
spec:
|
||||||
|
chart:
|
||||||
|
spec:
|
||||||
|
chart: podinfo
|
||||||
|
sourceRef:
|
||||||
|
kind: HelmRepository
|
||||||
|
name: podinfo
|
||||||
|
namespace: flux-system
|
||||||
|
status:
|
||||||
|
conditions:
|
||||||
|
- lastTransitionTime: "2021-07-16T15:42:20Z"
|
||||||
|
message: Release reconciliation succeeded
|
||||||
|
reason: ReconciliationSucceeded
|
||||||
|
status: "True"
|
||||||
|
type: Ready
|
||||||
|
helmChart: flux-system/podinfo-podinfo
|
||||||
|
lastAppliedRevision: 6.0.0
|
||||||
|
lastAttemptedRevision: 6.0.0
|
||||||
|
lastAttemptedValuesChecksum: c31db75d05b7515eba2eef47bd71038c74b2e531
|
||||||
|
---
|
||||||
|
apiVersion: source.toolkit.fluxcd.io/v1beta1
|
||||||
|
kind: HelmChart
|
||||||
|
metadata:
|
||||||
|
name: podinfo-podinfo
|
||||||
|
namespace: flux-system
|
||||||
|
spec:
|
||||||
|
chart: podinfo
|
||||||
|
sourceRef:
|
||||||
|
kind: HelmRepository
|
||||||
|
name: podinfo
|
||||||
|
version: 6.0.0
|
||||||
|
status:
|
||||||
|
artifact:
|
||||||
|
checksum: cf13ba96773d9a879cd052c86e73199b3f96c854
|
||||||
|
lastUpdateTime: "2021-08-01T04:42:55Z"
|
||||||
|
revision: 6.0.0
|
||||||
|
conditions:
|
||||||
|
- lastTransitionTime: "2021-07-16T15:32:09Z"
|
||||||
|
message: 'Fetched revision: 6.0.0'
|
||||||
|
reason: ChartPullSucceeded
|
||||||
|
status: "True"
|
||||||
|
type: Ready
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: source.toolkit.fluxcd.io/v1beta1
|
||||||
|
kind: HelmRepository
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
kustomize.toolkit.fluxcd.io/name: infrastructure
|
||||||
|
kustomize.toolkit.fluxcd.io/namespace: flux-system
|
||||||
|
name: podinfo
|
||||||
|
namespace: flux-system
|
||||||
|
spec:
|
||||||
|
interval: 5m
|
||||||
|
timeout: 1m0s
|
||||||
|
url: https://stefanprodan.github.io/podinfo
|
||||||
|
status:
|
||||||
|
artifact:
|
||||||
|
checksum: 8411f23d07d3701f0e96e7d9e503b7936d7e1d56
|
||||||
|
lastUpdateTime: "2021-07-11T00:25:46Z"
|
||||||
|
revision: 8411f23d07d3701f0e96e7d9e503b7936d7e1d56
|
||||||
|
conditions:
|
||||||
|
- lastTransitionTime: "2021-07-11T00:25:46Z"
|
||||||
|
message: 'Fetched revision: 8411f23d07d3701f0e96e7d9e503b7936d7e1d56'
|
||||||
|
reason: IndexationSucceed
|
||||||
|
status: "True"
|
||||||
|
type: Ready
|
||||||
|
---
|
||||||
|
apiVersion: kustomize.toolkit.fluxcd.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
metadata:
|
||||||
|
name: infrastructure
|
||||||
|
namespace: flux-system
|
||||||
|
spec:
|
||||||
|
path: ./infrastructure/
|
||||||
|
sourceRef:
|
||||||
|
kind: GitRepository
|
||||||
|
name: flux-system
|
||||||
|
validation: client
|
||||||
|
status:
|
||||||
|
conditions:
|
||||||
|
- lastTransitionTime: "2021-08-01T04:52:56Z"
|
||||||
|
message: 'Applied revision: main/696f056df216eea4f9401adbee0ff744d4df390f'
|
||||||
|
reason: ReconciliationSucceeded
|
||||||
|
status: "True"
|
||||||
|
type: Ready
|
||||||
|
---
|
||||||
|
apiVersion: source.toolkit.fluxcd.io/v1beta1
|
||||||
|
kind: GitRepository
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
kustomize.toolkit.fluxcd.io/name: flux-system
|
||||||
|
kustomize.toolkit.fluxcd.io/namespace: flux-system
|
||||||
|
name: flux-system
|
||||||
|
namespace: flux-system
|
||||||
|
spec:
|
||||||
|
gitImplementation: go-git
|
||||||
|
ref:
|
||||||
|
branch: main
|
||||||
|
secretRef:
|
||||||
|
name: flux-system
|
||||||
|
|
||||||
19
cmd/flux/testdata/trace/helmrelease-missing-git-ref.txt
vendored
Normal file
19
cmd/flux/testdata/trace/helmrelease-missing-git-ref.txt
vendored
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
|
||||||
|
Object: HelmRelease/podinfo
|
||||||
|
Namespace: podinfo
|
||||||
|
Status: Managed by Flux
|
||||||
|
---
|
||||||
|
Kustomization: infrastructure
|
||||||
|
Namespace: flux-system
|
||||||
|
Path: ./infrastructure
|
||||||
|
Revision: main/696f056df216eea4f9401adbee0ff744d4df390f
|
||||||
|
Status: Last reconciled at 2021-08-01 04:52:56 +0000 UTC
|
||||||
|
Message: Applied revision: main/696f056df216eea4f9401adbee0ff744d4df390f
|
||||||
|
---
|
||||||
|
GitRepository: flux-system
|
||||||
|
Namespace: flux-system
|
||||||
|
URL: ssh://git@github.com/example/repo
|
||||||
|
Revision: main/696f056df216eea4f9401adbee0ff744d4df390f
|
||||||
|
Status: Last reconciled at 2021-07-20 00:48:16 +0000 UTC
|
||||||
|
Message: Fetched revision: main/696f056df216eea4f9401adbee0ff744d4df390f
|
||||||
|
|
||||||
73
cmd/flux/testdata/trace/helmrelease-missing-git-ref.yaml
vendored
Normal file
73
cmd/flux/testdata/trace/helmrelease-missing-git-ref.yaml
vendored
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
---
|
||||||
|
apiVersion: helm.toolkit.fluxcd.io/v2beta1
|
||||||
|
kind: HelmRelease
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
kustomize.toolkit.fluxcd.io/name: infrastructure
|
||||||
|
kustomize.toolkit.fluxcd.io/namespace: flux-system
|
||||||
|
name: podinfo
|
||||||
|
namespace: podinfo
|
||||||
|
spec:
|
||||||
|
chart:
|
||||||
|
spec:
|
||||||
|
chart: podinfo
|
||||||
|
sourceRef:
|
||||||
|
kind: HelmRepository
|
||||||
|
name: podinfo
|
||||||
|
namespace: flux-system
|
||||||
|
status:
|
||||||
|
conditions:
|
||||||
|
- lastTransitionTime: "2021-07-16T15:42:20Z"
|
||||||
|
message: Release reconciliation succeeded
|
||||||
|
reason: ReconciliationSucceeded
|
||||||
|
status: "True"
|
||||||
|
type: Ready
|
||||||
|
helmChart: flux-system/podinfo-podinfo
|
||||||
|
lastAppliedRevision: 6.0.0
|
||||||
|
lastAttemptedRevision: 6.0.0
|
||||||
|
lastAttemptedValuesChecksum: c31db75d05b7515eba2eef47bd71038c74b2e531
|
||||||
|
---
|
||||||
|
apiVersion: kustomize.toolkit.fluxcd.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
metadata:
|
||||||
|
name: infrastructure
|
||||||
|
namespace: flux-system
|
||||||
|
spec:
|
||||||
|
path: ./infrastructure
|
||||||
|
sourceRef:
|
||||||
|
kind: GitRepository
|
||||||
|
name: flux-system
|
||||||
|
validation: client
|
||||||
|
status:
|
||||||
|
conditions:
|
||||||
|
- lastTransitionTime: "2021-08-01T04:52:56Z"
|
||||||
|
message: 'Applied revision: main/696f056df216eea4f9401adbee0ff744d4df390f'
|
||||||
|
reason: ReconciliationSucceeded
|
||||||
|
status: "True"
|
||||||
|
type: Ready
|
||||||
|
lastAppliedRevision: main/696f056df216eea4f9401adbee0ff744d4df390f
|
||||||
|
---
|
||||||
|
apiVersion: source.toolkit.fluxcd.io/v1beta1
|
||||||
|
kind: GitRepository
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
kustomize.toolkit.fluxcd.io/name: flux-system
|
||||||
|
kustomize.toolkit.fluxcd.io/namespace: flux-system
|
||||||
|
name: flux-system
|
||||||
|
namespace: flux-system
|
||||||
|
spec:
|
||||||
|
gitImplementation: go-git
|
||||||
|
secretRef:
|
||||||
|
name: flux-system
|
||||||
|
url: ssh://git@github.com/example/repo
|
||||||
|
status:
|
||||||
|
artifact:
|
||||||
|
lastUpdateTime: "2021-08-01T04:28:42Z"
|
||||||
|
revision: main/696f056df216eea4f9401adbee0ff744d4df390f
|
||||||
|
conditions:
|
||||||
|
- lastTransitionTime: "2021-07-20T00:48:16Z"
|
||||||
|
message: 'Fetched revision: main/696f056df216eea4f9401adbee0ff744d4df390f'
|
||||||
|
reason: GitOperationSucceed
|
||||||
|
status: "True"
|
||||||
|
type: Ready
|
||||||
|
|
||||||
20
cmd/flux/testdata/trace/helmrelease.txt
vendored
Normal file
20
cmd/flux/testdata/trace/helmrelease.txt
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
|
||||||
|
Object: HelmRelease/podinfo
|
||||||
|
Namespace: podinfo
|
||||||
|
Status: Managed by Flux
|
||||||
|
---
|
||||||
|
Kustomization: infrastructure
|
||||||
|
Namespace: flux-system
|
||||||
|
Path: ./infrastructure
|
||||||
|
Revision: main/696f056df216eea4f9401adbee0ff744d4df390f
|
||||||
|
Status: Last reconciled at 2021-08-01 04:52:56 +0000 UTC
|
||||||
|
Message: Applied revision: main/696f056df216eea4f9401adbee0ff744d4df390f
|
||||||
|
---
|
||||||
|
GitRepository: flux-system
|
||||||
|
Namespace: flux-system
|
||||||
|
URL: ssh://git@github.com/example/repo
|
||||||
|
Branch: main
|
||||||
|
Revision: main/696f056df216eea4f9401adbee0ff744d4df390f
|
||||||
|
Status: Last reconciled at 2021-07-20 00:48:16 +0000 UTC
|
||||||
|
Message: Fetched revision: main/696f056df216eea4f9401adbee0ff744d4df390f
|
||||||
|
|
||||||
75
cmd/flux/testdata/trace/helmrelease.yaml
vendored
Normal file
75
cmd/flux/testdata/trace/helmrelease.yaml
vendored
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
---
|
||||||
|
apiVersion: helm.toolkit.fluxcd.io/v2beta1
|
||||||
|
kind: HelmRelease
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
kustomize.toolkit.fluxcd.io/name: infrastructure
|
||||||
|
kustomize.toolkit.fluxcd.io/namespace: flux-system
|
||||||
|
name: podinfo
|
||||||
|
namespace: podinfo
|
||||||
|
spec:
|
||||||
|
chart:
|
||||||
|
spec:
|
||||||
|
chart: podinfo
|
||||||
|
sourceRef:
|
||||||
|
kind: HelmRepository
|
||||||
|
name: podinfo
|
||||||
|
namespace: flux-system
|
||||||
|
status:
|
||||||
|
conditions:
|
||||||
|
- lastTransitionTime: "2021-07-16T15:42:20Z"
|
||||||
|
message: Release reconciliation succeeded
|
||||||
|
reason: ReconciliationSucceeded
|
||||||
|
status: "True"
|
||||||
|
type: Ready
|
||||||
|
helmChart: flux-system/podinfo-podinfo
|
||||||
|
lastAppliedRevision: 6.0.0
|
||||||
|
lastAttemptedRevision: 6.0.0
|
||||||
|
lastAttemptedValuesChecksum: c31db75d05b7515eba2eef47bd71038c74b2e531
|
||||||
|
---
|
||||||
|
apiVersion: kustomize.toolkit.fluxcd.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
metadata:
|
||||||
|
name: infrastructure
|
||||||
|
namespace: flux-system
|
||||||
|
spec:
|
||||||
|
path: ./infrastructure
|
||||||
|
sourceRef:
|
||||||
|
kind: GitRepository
|
||||||
|
name: flux-system
|
||||||
|
validation: client
|
||||||
|
status:
|
||||||
|
conditions:
|
||||||
|
- lastTransitionTime: "2021-08-01T04:52:56Z"
|
||||||
|
message: 'Applied revision: main/696f056df216eea4f9401adbee0ff744d4df390f'
|
||||||
|
reason: ReconciliationSucceeded
|
||||||
|
status: "True"
|
||||||
|
type: Ready
|
||||||
|
lastAppliedRevision: main/696f056df216eea4f9401adbee0ff744d4df390f
|
||||||
|
---
|
||||||
|
apiVersion: source.toolkit.fluxcd.io/v1beta1
|
||||||
|
kind: GitRepository
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
kustomize.toolkit.fluxcd.io/name: flux-system
|
||||||
|
kustomize.toolkit.fluxcd.io/namespace: flux-system
|
||||||
|
name: flux-system
|
||||||
|
namespace: flux-system
|
||||||
|
spec:
|
||||||
|
gitImplementation: go-git
|
||||||
|
ref:
|
||||||
|
branch: main
|
||||||
|
secretRef:
|
||||||
|
name: flux-system
|
||||||
|
url: ssh://git@github.com/example/repo
|
||||||
|
status:
|
||||||
|
artifact:
|
||||||
|
lastUpdateTime: "2021-08-01T04:28:42Z"
|
||||||
|
revision: main/696f056df216eea4f9401adbee0ff744d4df390f
|
||||||
|
conditions:
|
||||||
|
- lastTransitionTime: "2021-07-20T00:48:16Z"
|
||||||
|
message: 'Fetched revision: main/696f056df216eea4f9401adbee0ff744d4df390f'
|
||||||
|
reason: GitOperationSucceed
|
||||||
|
status: "True"
|
||||||
|
type: Ready
|
||||||
|
|
||||||
1
cmd/flux/testdata/trace/no-args.txt
vendored
Normal file
1
cmd/flux/testdata/trace/no-args.txt
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
object name is required
|
||||||
|
|
@ -89,7 +89,7 @@ func traceCmdRun(cmd *cobra.Command, args []string) error {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(rootArgs.kubeconfig, rootArgs.kubecontext)
|
kubeClient, err := rootCtx.kubeManager.NewClient(rootArgs.kubeconfig, rootArgs.kubecontext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -121,7 +121,7 @@ func traceCmdRun(cmd *cobra.Command, args []string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Println(report)
|
rootCmd.Print(report)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -130,7 +130,7 @@ func traceCmdRun(cmd *cobra.Command, args []string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Println(report)
|
rootCmd.Print(report)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
180
cmd/flux/trace_test.go
Normal file
180
cmd/flux/trace_test.go
Normal file
|
|
@ -0,0 +1,180 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/fluxcd/flux2/internal/utils"
|
||||||
|
"github.com/google/go-cmp/cmp"
|
||||||
|
shellwords "github.com/mattn/go-shellwords"
|
||||||
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
|
k8syaml "k8s.io/apimachinery/pkg/util/yaml"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
fakeclient "sigs.k8s.io/controller-runtime/pkg/client/fake"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// Ensure tests print consistent timestamps regardless of timezone
|
||||||
|
os.Setenv("TZ", "UTC")
|
||||||
|
}
|
||||||
|
|
||||||
|
func readYamlObjects(objectFile string) ([]client.Object, error) {
|
||||||
|
obj, err := ioutil.ReadFile(objectFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
objects := []client.Object{}
|
||||||
|
reader := k8syaml.NewYAMLReader(bufio.NewReader(bytes.NewReader(obj)))
|
||||||
|
for {
|
||||||
|
doc, err := reader.Read()
|
||||||
|
if err != nil {
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unstructuredObj := &unstructured.Unstructured{}
|
||||||
|
decoder := k8syaml.NewYAMLOrJSONDecoder(bytes.NewBuffer(doc), len(doc))
|
||||||
|
err = decoder.Decode(unstructuredObj)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
objects = append(objects, unstructuredObj)
|
||||||
|
}
|
||||||
|
return objects, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// A KubeManager that can create objects that are subject to a test.
|
||||||
|
type fakeKubeManager struct {
|
||||||
|
fakeClient client.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *fakeKubeManager) NewClient(kubeconfig string, kubecontext string) (client.Client, error) {
|
||||||
|
return m.fakeClient, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *fakeKubeManager) CreateObjects(clientObjects []client.Object) error {
|
||||||
|
for _, obj := range clientObjects {
|
||||||
|
err := m.fakeClient.Create(context.Background(), obj)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFakeKubeManager() *fakeKubeManager {
|
||||||
|
c := fakeclient.NewClientBuilder().WithScheme(utils.NewScheme()).Build()
|
||||||
|
return &fakeKubeManager{
|
||||||
|
fakeClient: c,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the command and return the captured output.
|
||||||
|
func executeCommand(cmd string) (string, error) {
|
||||||
|
args, err := shellwords.Parse(cmd)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
|
||||||
|
rootCmd.SetOut(buf)
|
||||||
|
rootCmd.SetErr(buf)
|
||||||
|
rootCmd.SetArgs(args)
|
||||||
|
|
||||||
|
_, err = rootCmd.ExecuteC()
|
||||||
|
result := buf.String()
|
||||||
|
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Structure used for each test to load objects into kubernetes, run
|
||||||
|
// commands and assert on the expected output.
|
||||||
|
type cmdTestCase struct {
|
||||||
|
// The command line arguments to test.
|
||||||
|
args string
|
||||||
|
// When true, the test expects the command to fail.
|
||||||
|
wantError bool
|
||||||
|
// Filename that contains the expected test output.
|
||||||
|
goldenFile string
|
||||||
|
// Filename that contains yaml objects to load into Kubernetes
|
||||||
|
objectFile string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cmd *cmdTestCase) runTestCmd(t *testing.T) {
|
||||||
|
km := NewFakeKubeManager()
|
||||||
|
rootCtx.kubeManager = km
|
||||||
|
|
||||||
|
if cmd.objectFile != "" {
|
||||||
|
clientObjects, err := readYamlObjects(cmd.objectFile)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error loading yaml: '%v'", err)
|
||||||
|
}
|
||||||
|
err = km.CreateObjects(clientObjects)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error creating test objects: '%v'", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
actual, err := executeCommand(cmd.args)
|
||||||
|
if (err != nil) != cmd.wantError {
|
||||||
|
t.Fatalf("Expected error='%v', Got: %v", cmd.wantError, err)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
actual = err.Error()
|
||||||
|
}
|
||||||
|
contents, err := ioutil.ReadFile(cmd.goldenFile)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error reading golden file: '%s'", err)
|
||||||
|
}
|
||||||
|
expected := strings.TrimSuffix(string(contents), "\n")
|
||||||
|
diff := cmp.Diff(expected, actual)
|
||||||
|
if diff != "" {
|
||||||
|
t.Errorf("Mismatch from '%s' (-want +got):\n%s", cmd.goldenFile, diff)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTraceNoArgs(t *testing.T) {
|
||||||
|
cmd := cmdTestCase{
|
||||||
|
args: "trace",
|
||||||
|
wantError: true,
|
||||||
|
goldenFile: "testdata/trace/no-args.txt",
|
||||||
|
}
|
||||||
|
cmd.runTestCmd(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTraceDeployment(t *testing.T) {
|
||||||
|
cmd := cmdTestCase{
|
||||||
|
args: "trace podinfo -n podinfo --kind deployment --api-version=apps/v1",
|
||||||
|
wantError: false,
|
||||||
|
goldenFile: "testdata/trace/deployment.txt",
|
||||||
|
objectFile: "testdata/trace/deployment.yaml",
|
||||||
|
}
|
||||||
|
cmd.runTestCmd(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTraceHelmRelease(t *testing.T) {
|
||||||
|
cmd := cmdTestCase{
|
||||||
|
args: "trace podinfo -n podinfo --kind HelmRelease --api-version=helm.toolkit.fluxcd.io/v2beta1",
|
||||||
|
wantError: false,
|
||||||
|
goldenFile: "testdata/trace/helmrelease.txt",
|
||||||
|
objectFile: "testdata/trace/helmrelease.yaml",
|
||||||
|
}
|
||||||
|
cmd.runTestCmd(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTraceHelmReleaseMissingGitRef(t *testing.T) {
|
||||||
|
cmd := cmdTestCase{
|
||||||
|
args: "trace podinfo -n podinfo --kind HelmRelease --api-version=helm.toolkit.fluxcd.io/v2beta1",
|
||||||
|
wantError: false,
|
||||||
|
goldenFile: "testdata/trace/helmrelease-missing-git-ref.txt",
|
||||||
|
objectFile: "testdata/trace/helmrelease-missing-git-ref.yaml",
|
||||||
|
}
|
||||||
|
cmd.runTestCmd(t)
|
||||||
|
}
|
||||||
2
go.mod
2
go.mod
|
|
@ -18,8 +18,10 @@ require (
|
||||||
github.com/fluxcd/pkg/version v0.0.1
|
github.com/fluxcd/pkg/version v0.0.1
|
||||||
github.com/fluxcd/source-controller/api v0.15.3
|
github.com/fluxcd/source-controller/api v0.15.3
|
||||||
github.com/go-git/go-git/v5 v5.4.2
|
github.com/go-git/go-git/v5 v5.4.2
|
||||||
|
github.com/google/go-cmp v0.5.5
|
||||||
github.com/google/go-containerregistry v0.2.0
|
github.com/google/go-containerregistry v0.2.0
|
||||||
github.com/manifoldco/promptui v0.7.0
|
github.com/manifoldco/promptui v0.7.0
|
||||||
|
github.com/mattn/go-shellwords v1.0.12
|
||||||
github.com/olekukonko/tablewriter v0.0.4
|
github.com/olekukonko/tablewriter v0.0.4
|
||||||
github.com/spf13/cobra v1.1.3
|
github.com/spf13/cobra v1.1.3
|
||||||
github.com/spf13/pflag v1.0.5
|
github.com/spf13/pflag v1.0.5
|
||||||
|
|
|
||||||
2
go.sum
2
go.sum
|
|
@ -537,6 +537,8 @@ github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNx
|
||||||
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||||
github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54=
|
github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54=
|
||||||
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||||
|
github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk=
|
||||||
|
github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||||
github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY=
|
github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY=
|
||||||
|
|
|
||||||
|
|
@ -131,12 +131,39 @@ func KubeConfig(kubeConfigPath string, kubeContext string) (*rest.Config, error)
|
||||||
return cfg, nil
|
return cfg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func KubeClient(kubeConfigPath string, kubeContext string) (client.Client, error) {
|
// KubeManger creates a Kubernetes client.Client. This interface exists to
|
||||||
|
// facilitate unit testing and provide a fake client.
|
||||||
|
type KubeManager interface {
|
||||||
|
NewClient(string, string) (client.Client, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type defaultKubeManager struct{}
|
||||||
|
|
||||||
|
func DefaultKubeManager() KubeManager {
|
||||||
|
var manager defaultKubeManager
|
||||||
|
return manager
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m defaultKubeManager) NewClient(kubeConfigPath string, kubeContext string) (client.Client, error) {
|
||||||
cfg, err := KubeConfig(kubeConfigPath, kubeContext)
|
cfg, err := KubeConfig(kubeConfigPath, kubeContext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("kubernetes client initialization failed: %w", err)
|
return nil, fmt.Errorf("kubernetes client initialization failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scheme := NewScheme()
|
||||||
|
kubeClient, err := client.New(cfg, client.Options{
|
||||||
|
Scheme: scheme,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("kubernetes client initialization failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return kubeClient, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the Scheme, methods for serializing and deserializing API objects
|
||||||
|
// which can be shared by tests.
|
||||||
|
func NewScheme() *apiruntime.Scheme {
|
||||||
scheme := apiruntime.NewScheme()
|
scheme := apiruntime.NewScheme()
|
||||||
_ = apiextensionsv1.AddToScheme(scheme)
|
_ = apiextensionsv1.AddToScheme(scheme)
|
||||||
_ = corev1.AddToScheme(scheme)
|
_ = corev1.AddToScheme(scheme)
|
||||||
|
|
@ -149,15 +176,13 @@ func KubeClient(kubeConfigPath string, kubeContext string) (client.Client, error
|
||||||
_ = notificationv1.AddToScheme(scheme)
|
_ = notificationv1.AddToScheme(scheme)
|
||||||
_ = imagereflectv1.AddToScheme(scheme)
|
_ = imagereflectv1.AddToScheme(scheme)
|
||||||
_ = imageautov1.AddToScheme(scheme)
|
_ = imageautov1.AddToScheme(scheme)
|
||||||
|
return scheme
|
||||||
|
}
|
||||||
|
|
||||||
kubeClient, err := client.New(cfg, client.Options{
|
func KubeClient(kubeConfigPath string, kubeContext string) (client.Client, error) {
|
||||||
Scheme: scheme,
|
m := DefaultKubeManager()
|
||||||
})
|
kubeClient, err := m.NewClient(kubeConfigPath, kubeContext)
|
||||||
if err != nil {
|
return kubeClient, err
|
||||||
return nil, fmt.Errorf("kubernetes client initialization failed: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return kubeClient, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SplitKubeConfigPath splits the given KUBECONFIG path based on the runtime OS
|
// SplitKubeConfigPath splits the given KUBECONFIG path based on the runtime OS
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue