show cluster instance name and version in flux check and flux version
Signed-off-by: Somtochi Onyekwere <somtochionyekwere@gmail.com>
This commit is contained in:
@@ -18,6 +18,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -26,6 +27,7 @@ import (
|
|||||||
v1 "k8s.io/api/apps/v1"
|
v1 "k8s.io/api/apps/v1"
|
||||||
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||||
"k8s.io/client-go/kubernetes"
|
"k8s.io/client-go/kubernetes"
|
||||||
|
"k8s.io/client-go/rest"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
|
||||||
"github.com/fluxcd/pkg/version"
|
"github.com/fluxcd/pkg/version"
|
||||||
@@ -80,7 +82,20 @@ func runCheckCmd(cmd *cobra.Command, args []string) error {
|
|||||||
|
|
||||||
fluxCheck()
|
fluxCheck()
|
||||||
|
|
||||||
if !kubernetesCheck(kubernetesConstraints) {
|
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
cfg, err := utils.KubeConfig(kubeconfigArgs, kubeclientOptions)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Kubernetes client initialization failed: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
kubeClient, err := client.New(cfg, client.Options{Scheme: utils.NewScheme()})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !kubernetesCheck(cfg, kubernetesConstraints) {
|
||||||
checkFailed = true
|
checkFailed = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,13 +107,18 @@ func runCheckCmd(cmd *cobra.Command, args []string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.Actionf("checking version in cluster")
|
||||||
|
if !fluxClusterVersionCheck(ctx, kubeClient) {
|
||||||
|
checkFailed = true
|
||||||
|
}
|
||||||
|
|
||||||
logger.Actionf("checking controllers")
|
logger.Actionf("checking controllers")
|
||||||
if !componentsCheck() {
|
if !componentsCheck(ctx, kubeClient) {
|
||||||
checkFailed = true
|
checkFailed = true
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Actionf("checking crds")
|
logger.Actionf("checking crds")
|
||||||
if !crdsCheck() {
|
if !crdsCheck(ctx, kubeClient) {
|
||||||
checkFailed = true
|
checkFailed = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,17 +149,11 @@ func fluxCheck() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if latestSv.GreaterThan(curSv) {
|
if latestSv.GreaterThan(curSv) {
|
||||||
logger.Failuref("flux %s <%s (new version is available, please upgrade)", curSv, latestSv)
|
logger.Failuref("flux %s <%s (new CLI version is available, please upgrade)", curSv, latestSv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func kubernetesCheck(constraints []string) bool {
|
func kubernetesCheck(cfg *rest.Config, constraints []string) bool {
|
||||||
cfg, err := utils.KubeConfig(kubeconfigArgs, kubeclientOptions)
|
|
||||||
if err != nil {
|
|
||||||
logger.Failuref("Kubernetes client initialization failed: %s", err.Error())
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
clientSet, err := kubernetes.NewForConfig(cfg)
|
clientSet, err := kubernetes.NewForConfig(cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Failuref("Kubernetes client initialization failed: %s", err.Error())
|
logger.Failuref("Kubernetes client initialization failed: %s", err.Error())
|
||||||
@@ -178,21 +192,8 @@ func kubernetesCheck(constraints []string) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func componentsCheck() bool {
|
func componentsCheck(ctx context.Context, kubeClient client.Client) bool {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
statusChecker, err := status.NewStatusCheckerWithClient(kubeClient, checkArgs.pollInterval, rootArgs.timeout, logger)
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
kubeConfig, err := utils.KubeConfig(kubeconfigArgs, kubeclientOptions)
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
statusChecker, err := status.NewStatusChecker(kubeConfig, checkArgs.pollInterval, rootArgs.timeout, logger)
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(kubeconfigArgs, kubeclientOptions)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -222,15 +223,7 @@ func componentsCheck() bool {
|
|||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
func crdsCheck() bool {
|
func crdsCheck(ctx context.Context, kubeClient client.Client) bool {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout)
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
kubeClient, err := utils.KubeClient(kubeconfigArgs, kubeclientOptions)
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
ok := true
|
ok := true
|
||||||
selector := client.MatchingLabels{manifestgen.PartOfLabelKey: manifestgen.PartOfLabelValue}
|
selector := client.MatchingLabels{manifestgen.PartOfLabelKey: manifestgen.PartOfLabelValue}
|
||||||
var list apiextensionsv1.CustomResourceDefinitionList
|
var list apiextensionsv1.CustomResourceDefinitionList
|
||||||
@@ -253,3 +246,17 @@ func crdsCheck() bool {
|
|||||||
}
|
}
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func fluxClusterVersionCheck(ctx context.Context, kubeClient client.Client) bool {
|
||||||
|
clusterInfo, err := getFluxClusterInfo(ctx, kubeClient)
|
||||||
|
if err != nil {
|
||||||
|
logger.Failuref("checking failed: %s", err.Error())
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if clusterInfo.distribution() != "" {
|
||||||
|
logger.Successf("distribution: %s", clusterInfo.distribution())
|
||||||
|
}
|
||||||
|
logger.Successf("bootstrapped: %t", clusterInfo.bootstrapped)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ import (
|
|||||||
|
|
||||||
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
|
kustomizev1 "github.com/fluxcd/kustomize-controller/api/v1"
|
||||||
sourcev1 "github.com/fluxcd/source-controller/api/v1"
|
sourcev1 "github.com/fluxcd/source-controller/api/v1"
|
||||||
|
|
||||||
|
"github.com/fluxcd/flux2/v2/pkg/manifestgen"
|
||||||
)
|
)
|
||||||
|
|
||||||
// bootstrapLabels are labels put on a resource by kustomize-controller. These labels on the CRD indicates
|
// bootstrapLabels are labels put on a resource by kustomize-controller. These labels on the CRD indicates
|
||||||
@@ -42,6 +44,8 @@ type fluxClusterInfo struct {
|
|||||||
bootstrapped bool
|
bootstrapped bool
|
||||||
// managedBy is the name of the tool being used to manage the installation of Flux.
|
// managedBy is the name of the tool being used to manage the installation of Flux.
|
||||||
managedBy string
|
managedBy string
|
||||||
|
// partOf indicates which distribution the instance is a part of.
|
||||||
|
partOf string
|
||||||
// version is the Flux version number in semver format.
|
// version is the Flux version number in semver format.
|
||||||
version string
|
version string
|
||||||
}
|
}
|
||||||
@@ -68,7 +72,7 @@ func getFluxClusterInfo(ctx context.Context, c client.Client) (fluxClusterInfo,
|
|||||||
return info, err
|
return info, err
|
||||||
}
|
}
|
||||||
|
|
||||||
info.version = crdMetadata.Labels["app.kubernetes.io/version"]
|
info.version = crdMetadata.Labels[manifestgen.VersionLabelKey]
|
||||||
|
|
||||||
var present bool
|
var present bool
|
||||||
for _, l := range bootstrapLabels {
|
for _, l := range bootstrapLabels {
|
||||||
@@ -78,11 +82,15 @@ func getFluxClusterInfo(ctx context.Context, c client.Client) (fluxClusterInfo,
|
|||||||
info.bootstrapped = true
|
info.bootstrapped = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// the `app.kubernetes.io` label is not set by flux but might be set by other
|
// the `app.kubernetes.io/managed-by` label is not set by flux but might be set by other
|
||||||
// tools used to install Flux e.g Helm.
|
// tools used to install Flux e.g Helm.
|
||||||
if manager, ok := crdMetadata.Labels["app.kubernetes.io/managed-by"]; ok {
|
if manager, ok := crdMetadata.Labels["app.kubernetes.io/managed-by"]; ok {
|
||||||
info.managedBy = manager
|
info.managedBy = manager
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if partOf, ok := crdMetadata.Labels[manifestgen.PartOfLabelKey]; ok {
|
||||||
|
info.partOf = partOf
|
||||||
|
}
|
||||||
return info, nil
|
return info, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,6 +113,14 @@ func confirmFluxInstallOverride(info fluxClusterInfo) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (info fluxClusterInfo) distribution() string {
|
||||||
|
distribution := info.version
|
||||||
|
if info.partOf != "" {
|
||||||
|
distribution = fmt.Sprintf("%s-%s", info.partOf, info.version)
|
||||||
|
}
|
||||||
|
return distribution
|
||||||
|
}
|
||||||
|
|
||||||
func installManagedByFlux(manager string) bool {
|
func installManagedByFlux(manager string) bool {
|
||||||
return manager == "" || manager == "flux"
|
return manager == "" || manager == "flux"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,6 +102,17 @@ func Test_getFluxClusterInfo(t *testing.T) {
|
|||||||
version: "v2.1.0",
|
version: "v2.1.0",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "CRD with version and part-of labels",
|
||||||
|
labels: map[string]string{
|
||||||
|
"app.kubernetes.io/version": "v2.1.0",
|
||||||
|
"app.kubernetes.io/part-of": "flux",
|
||||||
|
},
|
||||||
|
wantInfo: fluxClusterInfo{
|
||||||
|
version: "v2.1.0",
|
||||||
|
partOf: "flux",
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
|
|||||||
@@ -25,8 +25,9 @@ import (
|
|||||||
"github.com/google/go-containerregistry/pkg/name"
|
"github.com/google/go-containerregistry/pkg/name"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
v1 "k8s.io/api/apps/v1"
|
v1 "k8s.io/api/apps/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
"sigs.k8s.io/yaml"
|
"sigs.k8s.io/yaml/goyaml.v2"
|
||||||
|
|
||||||
"github.com/fluxcd/flux2/v2/internal/utils"
|
"github.com/fluxcd/flux2/v2/internal/utils"
|
||||||
"github.com/fluxcd/flux2/v2/pkg/manifestgen"
|
"github.com/fluxcd/flux2/v2/pkg/manifestgen"
|
||||||
@@ -55,6 +56,12 @@ type versionFlags struct {
|
|||||||
|
|
||||||
var versionArgs versionFlags
|
var versionArgs versionFlags
|
||||||
|
|
||||||
|
type versionInfo struct {
|
||||||
|
Flux string `yaml:"flux"`
|
||||||
|
Distribution string `yaml:"distribution,omitempty"`
|
||||||
|
Controller map[string]string `yaml:"controller,inline"`
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
versionCmd.Flags().BoolVar(&versionArgs.client, "client", false,
|
versionCmd.Flags().BoolVar(&versionArgs.client, "client", false,
|
||||||
"print only client version")
|
"print only client version")
|
||||||
@@ -71,8 +78,12 @@ func versionCmdRun(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()
|
||||||
|
|
||||||
info := map[string]string{}
|
// versionInfo struct and goyaml is used because we care about the order.
|
||||||
info["flux"] = rootArgs.defaults.Version
|
// Without this `distribution` is printed before `flux` when the struct is marshalled.
|
||||||
|
info := &versionInfo{
|
||||||
|
Controller: map[string]string{},
|
||||||
|
}
|
||||||
|
info.Flux = rootArgs.defaults.Version
|
||||||
|
|
||||||
if !versionArgs.client {
|
if !versionArgs.client {
|
||||||
kubeClient, err := utils.KubeClient(kubeconfigArgs, kubeclientOptions)
|
kubeClient, err := utils.KubeClient(kubeconfigArgs, kubeclientOptions)
|
||||||
@@ -80,6 +91,16 @@ func versionCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clusterInfo, err := getFluxClusterInfo(ctx, kubeClient)
|
||||||
|
// ignoring not found errors because it means that the GitRepository CRD isn't installed but a user might
|
||||||
|
// have other controllers(e.g notification-controller), and we want to still return information for them.
|
||||||
|
if err != nil && !errors.IsNotFound(err) {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if clusterInfo.distribution() != "" {
|
||||||
|
info.Distribution = clusterInfo.distribution()
|
||||||
|
}
|
||||||
|
|
||||||
selector := client.MatchingLabels{manifestgen.PartOfLabelKey: manifestgen.PartOfLabelValue}
|
selector := client.MatchingLabels{manifestgen.PartOfLabelKey: manifestgen.PartOfLabelValue}
|
||||||
var list v1.DeploymentList
|
var list v1.DeploymentList
|
||||||
if err := kubeClient.List(ctx, &list, client.InNamespace(*kubeconfigArgs.Namespace), selector); err != nil {
|
if err := kubeClient.List(ctx, &list, client.InNamespace(*kubeconfigArgs.Namespace), selector); err != nil {
|
||||||
@@ -96,7 +117,7 @@ func versionCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
info[name] = tag
|
info.Controller[name] = tag
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -105,7 +126,7 @@ func versionCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
var err error
|
var err error
|
||||||
|
|
||||||
if versionArgs.output == "json" {
|
if versionArgs.output == "json" {
|
||||||
marshalled, err = json.MarshalIndent(&info, "", " ")
|
marshalled, err = info.toJSON()
|
||||||
marshalled = append(marshalled, "\n"...)
|
marshalled = append(marshalled, "\n"...)
|
||||||
} else {
|
} else {
|
||||||
marshalled, err = yaml.Marshal(&info)
|
marshalled, err = yaml.Marshal(&info)
|
||||||
@@ -119,6 +140,20 @@ func versionCmdRun(cmd *cobra.Command, args []string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (info versionInfo) toJSON() ([]byte, error) {
|
||||||
|
mapInfo := map[string]string{
|
||||||
|
"flux": info.Flux,
|
||||||
|
}
|
||||||
|
|
||||||
|
if info.Distribution != "" {
|
||||||
|
mapInfo["distribution"] = info.Distribution
|
||||||
|
}
|
||||||
|
for k, v := range info.Controller {
|
||||||
|
mapInfo[k] = v
|
||||||
|
}
|
||||||
|
return json.MarshalIndent(&mapInfo, "", " ")
|
||||||
|
}
|
||||||
|
|
||||||
func splitImageStr(image string) (string, string, error) {
|
func splitImageStr(image string) (string, string, error) {
|
||||||
ref, err := name.ParseReference(image)
|
ref, err := name.ParseReference(image)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -45,6 +45,16 @@ type StatusChecker struct {
|
|||||||
logger log.Logger
|
logger log.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewStatusCheckerWithClient(c client.Client, pollInterval time.Duration, timeout time.Duration, log log.Logger) (*StatusChecker, error) {
|
||||||
|
return &StatusChecker{
|
||||||
|
pollInterval: pollInterval,
|
||||||
|
timeout: timeout,
|
||||||
|
client: c,
|
||||||
|
statusPoller: polling.NewStatusPoller(c, c.RESTMapper(), polling.Options{}),
|
||||||
|
logger: log,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func NewStatusChecker(kubeConfig *rest.Config, pollInterval time.Duration, timeout time.Duration, log log.Logger) (*StatusChecker, error) {
|
func NewStatusChecker(kubeConfig *rest.Config, pollInterval time.Duration, timeout time.Duration, log log.Logger) (*StatusChecker, error) {
|
||||||
restMapper, err := runtimeclient.NewDynamicRESTMapper(kubeConfig)
|
restMapper, err := runtimeclient.NewDynamicRESTMapper(kubeConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -55,13 +65,7 @@ func NewStatusChecker(kubeConfig *rest.Config, pollInterval time.Duration, timeo
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &StatusChecker{
|
return NewStatusCheckerWithClient(c, pollInterval, timeout, log)
|
||||||
pollInterval: pollInterval,
|
|
||||||
timeout: timeout,
|
|
||||||
client: c,
|
|
||||||
statusPoller: polling.NewStatusPoller(c, restMapper, polling.Options{}),
|
|
||||||
logger: log,
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sc *StatusChecker) Assess(identifiers ...object.ObjMetadata) error {
|
func (sc *StatusChecker) Assess(identifiers ...object.ObjMetadata) error {
|
||||||
|
|||||||
Reference in New Issue
Block a user