Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .golangci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,17 @@ issues:
formatters:
enable:
- gofmt
- gci
settings:
gci:
sections:
- standard
- default
- prefix(github.com/kube-bind)
- prefix(github.com/kube-bind/sdk)
- blank
- dot
custom-order: true
exclusions:
generated: lax
paths:
Expand Down
82 changes: 46 additions & 36 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,6 @@ GOLANGCI_LINT_VER := v2.1.6
GOLANGCI_LINT_BIN := golangci-lint
GOLANGCI_LINT := $(TOOLS_GOBIN_DIR)/$(GOLANGCI_LINT_BIN)-$(GOLANGCI_LINT_VER)

GOIMPORTS_VER := v0.35.0
GOIMPORTS_BIN := goimports
GOIMPORTS := $(TOOLS_GOBIN_DIR)/$(GOIMPORTS_BIN)-$(GOIMPORTS_VER)

GOTESTSUM_VER := v1.8.1
GOTESTSUM_BIN := gotestsum
GOTESTSUM := $(abspath $(TOOLS_DIR))/$(GOTESTSUM_BIN)-$(GOTESTSUM_VER)
Expand All @@ -76,7 +72,7 @@ LOGCHECK_BIN := logcheck
LOGCHECK := $(TOOLS_GOBIN_DIR)/$(LOGCHECK_BIN)-$(LOGCHECK_VER)
export LOGCHECK # so hack scripts can use it

CODE_GENERATOR_VER := v2.3.1
CODE_GENERATOR_VER := v2.4.0
CODE_GENERATOR_BIN := code-generator
CODE_GENERATOR := $(TOOLS_GOBIN_DIR)/$(CODE_GENERATOR_BIN)-$(CODE_GENERATOR_VER)
export CODE_GENERATOR # so hack scripts can use it
Expand Down Expand Up @@ -115,6 +111,11 @@ LDFLAGS := \
all: build
.PHONY: all

check: verify lint test test-e2e
.PHONY: check

GOMODS := $(shell find . -name 'go.mod' -exec dirname {} \; | grep -v hack/tools)

ldflags:
@echo $(LDFLAGS)

Expand All @@ -141,20 +142,23 @@ install: ## install binaries to GOBIN
$(GOLANGCI_LINT):
GOBIN=$(TOOLS_GOBIN_DIR) $(GO_INSTALL) github.com/golangci/golangci-lint/v2/cmd/golangci-lint $(GOLANGCI_LINT_BIN) $(GOLANGCI_LINT_VER)

$(GOIMPORTS):
GOBIN=$(TOOLS_GOBIN_DIR) $(GO_INSTALL) golang.org/x/tools/cmd/goimports $(GOIMPORTS_BIN) $(GOIMPORTS_VER)

$(LOGCHECK):
GOBIN=$(TOOLS_GOBIN_DIR) $(GO_INSTALL) sigs.k8s.io/logtools/logcheck $(LOGCHECK_BIN) $(LOGCHECK_VER)

$(CODE_GENERATOR):
GOBIN=$(TOOLS_GOBIN_DIR) $(GO_INSTALL) github.com/kcp-dev/code-generator/v2 $(CODE_GENERATOR_BIN) $(CODE_GENERATOR_VER)

lint: $(GOLANGCI_LINT) $(LOGCHECK) ## Run linters
$(GOLANGCI_LINT) run $(GOLANGCI_LINT_FLAGS) -c $(ROOT_DIR)/.golangci.yaml --timeout 20m
lint: $(GOLANGCI_LINT) $(LOGCHECK) ## Run golangci-lint
@if [ -n "$(WHAT)" ]; then \
$(GOLANGCI_LINT) run $(GOLANGCI_LINT_FLAGS) -c $(ROOT_DIR)/.golangci.yaml --timeout 20m $(WHAT); \
else \
for MOD in $(GOMODS); do \
(cd $$MOD; echo "Linting $$MOD"; $(GOLANGCI_LINT) run $(GOLANGCI_LINT_FLAGS) -c $(ROOT_DIR)/.golangci.yaml --timeout 20m); \
done; \
fi
.PHONY: lint

fix-lint: $(GOLANGCI_LINT)
fix-lint: $(GOLANGCI_LINT) ## Run golangci-lint with --fix
GOLANGCI_LINT_FLAGS="--fix" $(MAKE) lint
.PHONY: fix-lint

Expand All @@ -163,7 +167,7 @@ vendor: ## Vendor the dependencies
go mod vendor
.PHONY: vendor

tools: $(GOLANGCI_LINT) $(CONTROLLER_GEN) $(YAML_PATCH) $(GOTESTSUM) $(CODE_GENERATOR)
tools: $(GOLANGCI_LINT) $(CONTROLLER_GEN) $(YAML_PATCH) $(GOTESTSUM) $(CODE_GENERATOR) ## Install tools
.PHONY: tools

$(CONTROLLER_GEN):
Expand All @@ -185,8 +189,7 @@ $(KUBE_APPLYCONFIGURATION_GEN):
GOBIN=$(GOBIN_DIR) $(GO_INSTALL) k8s.io/code-generator/cmd/$(KUBE_APPLYCONFIGURATION_GEN_BIN) $(KUBE_APPLYCONFIGURATION_GEN_BIN) $(KUBE_APPLYCONFIGURATION_GEN_VER)


codegen: WHAT ?= ./sdk/client
codegen: $(CONTROLLER_GEN) $(YAML_PATCH) $(CODE_GENERATOR) $(KUBE_CLIENT_GEN) $(KUBE_LISTER_GEN) $(KUBE_INFORMER_GEN) $(KUBE_APPLYCONFIGURATION_GEN)
codegen: $(CONTROLLER_GEN) $(YAML_PATCH) $(CODE_GENERATOR) $(KUBE_CLIENT_GEN) $(KUBE_LISTER_GEN) $(KUBE_INFORMER_GEN) $(KUBE_APPLYCONFIGURATION_GEN) ## Generate code
go mod download
./hack/update-codegen.sh
$(MAKE) imports
Expand All @@ -210,15 +213,13 @@ verify-codegen:
fi

.PHONY: imports
imports: $(GOLANGCI_LINT) $(GOIMPORTS) verify-go-versions
if [ -n "$(WHAT)" ]; then \
$(GOLANGCI_LINT) fmt --enable gci -c $(ROOT_DIR)/.golangci.yaml $(WHAT); \
$(GOIMPORTS) -local github.com/kube-bind/kube-bind -w $(WHAT); \
imports: $(GOLANGCI_LINT) verify-go-versions ## Fix imports and format code
@if [ -n "$(WHAT)" ]; then \
$(GOLANGCI_LINT) fmt --enable gci -c $(ROOT_DIR)/.golangci.yaml $(WHAT); \
else \
for MOD in . $$(git ls-files '**/go.mod' | sed 's,/go.mod,,'); do \
(set -x; cd $$MOD; $(GOLANGCI_LINT) fmt --enable gci -c $(ROOT_DIR)/.golangci.yaml); \
$(GOIMPORTS) -local github.com/kube-bind/kube-bind -w .; \
done; \
for MOD in $(GOMODS); do \
( cd $$MOD; $(GOLANGCI_LINT) fmt --enable gci -c $(ROOT_DIR)/.golangci.yaml; ) \
done; \
fi

$(TOOLS_DIR)/verify_boilerplate.py:
Expand Down Expand Up @@ -269,7 +270,7 @@ endif
test-e2e: TEST_ARGS ?=
test-e2e: WORK_DIR ?= .
test-e2e: WHAT ?= ./test/e2e...
test-e2e: $(KCP) $(DEX) build
test-e2e: $(KCP) $(DEX) build ## Run e2e tests
mkdir .kcp
$(DEX) serve hack/dex-config-dev.yaml 2>&1 & DEX_PID=$$!; \
$(KCP) start &>.kcp/kcp.log & KCP_PID=$$!; \
Expand All @@ -283,36 +284,45 @@ test: $(GOTESTSUM)
endif
test: WHAT ?= ./...
# We will need to move into the sub package, of pkg/apis to run those tests.
test: ## run unit tests
$(GO_TEST) -race -count $(COUNT) -coverprofile=coverage.txt -covermode=atomic $(TEST_ARGS) $$(go list "$(WHAT)" | grep -v ./test/e2e/ | grep -v ./kcp)
cd sdk/apis && $(GO_TEST) -race -count $(COUNT) -coverprofile=coverage.txt -covermode=atomic $(TEST_ARGS) $(WHAT)
test: ## Run unit tests
@if [ -n "$(WHAT)" ]; then \
$(GO_TEST) -race -count $(COUNT) -coverprofile=coverage.txt -covermode=atomic $(TEST_ARGS) $$(go list "$(WHAT)" | grep -v ./test/e2e/); \
else \
for MOD in $(GOMODS); do \
( cd $$MOD; $(GO_TEST) -race -count $(COUNT) -coverprofile=coverage.txt -covermode=atomic $(TEST_ARGS) ) \
done; \
fi

.PHONY: verify-imports
verify-imports:
hack/verify-imports.sh
verify-imports: imports
if ! git diff --quiet HEAD; then \
git diff; \
echo "You need to run 'make imports' to update the immport statement ordering and commit them"; \
exit 1; \
fi

.PHONY: verify-go-versions
verify-go-versions:
hack/verify-go-versions.sh

.PHONY: modules
modules: ## Run go mod tidy to ensure modules are up to date
go mod tidy
cd sdk/apis; go mod tidy
for MOD in $(GOMODS); do \
(cd $$MOD; echo "Tidying $$MOD"; go mod tidy); \
done

.PHONY: verify-modules
verify-modules: modules # Verify go modules are up to date
@if !(git diff --quiet HEAD -- go.sum go.mod pkg/apis/go.mod pkg/apis/go.sum); then \
git diff; \
echo "go module files are out of date"; exit 1; \
fi
@for MOD in $(GOMODS); do \
(cd $$MOD; echo "Verifying $$MOD"; if ! git diff --quiet HEAD -- go.mod go.sum; then echo "[$$MOD] go modules are out of date, please run 'make modules'"; exit 1; fi; ) \
done

.PHONY: verify
verify: verify-modules verify-go-versions verify-imports verify-codegen verify-boilerplate ## verify formal properties of the code

.PHONY: help
help: ## Show this help.
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
help: ## Show this help
@awk 'BEGIN { fs="## " } { FS=fs } /:.*##/ { doc=$$2; FS=":"; $$0=$$0; printf "\033[36m%-30s\033[0m %s\n", $$1, doc; }' $(MAKEFILE_LIST) | sort | grep -v fs=

.PHONY: generate-cli-docs
generate-cli-docs: ## Generate cli docs
Expand Down
6 changes: 2 additions & 4 deletions cli/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,15 @@ go 1.24.0

replace (
github.com/kube-bind/kube-bind => ../
github.com/kube-bind/kube-bind/sdk/apis => ../sdk/apis
github.com/kube-bind/kube-bind/sdk/client => ../sdk/client
github.com/kube-bind/kube-bind/sdk => ../sdk
)

require (
github.com/MakeNowJust/heredoc v1.0.0
github.com/blang/semver/v4 v4.0.0
github.com/fatih/color v1.18.0
github.com/kube-bind/kube-bind v0.0.0-00010101000000-000000000000
github.com/kube-bind/kube-bind/sdk/apis v0.4.8
github.com/kube-bind/kube-bind/sdk/client v0.0.0-20250515145715-d9f20e7c840d
github.com/kube-bind/kube-bind/sdk v0.4.1
github.com/mdp/qrterminal/v3 v3.2.0
github.com/muesli/reflow v0.3.0
github.com/spf13/cobra v1.9.1
Expand Down
2 changes: 1 addition & 1 deletion cli/pkg/kubectl/base/kubeconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import (
func ParseRemoteKubeconfig(kubeconfig []byte) (host string, ns string, err error) {
config, err := clientcmd.Load(kubeconfig)
if err != nil {
return "", "", nil
return "", "", err
}
if _, found := config.Contexts[config.CurrentContext]; !found {
return "", "", fmt.Errorf("current context %q of remote kubeconfig not found", config.CurrentContext)
Expand Down
2 changes: 1 addition & 1 deletion cli/pkg/kubectl/base/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func (o *Options) BindFlags(cmd *cobra.Command) {
cmd.Flags().StringVar(&o.Kubeconfig, "kubeconfig", o.Kubeconfig, "path to the kubeconfig file")

// We add only a subset of kubeconfig-related flags to the plugin.
// All those with with LongName == "" will be ignored.
// All those with LongName == "" will be ignored.
kubectlConfigOverrideFlags := clientcmd.RecommendedConfigOverrideFlags("")
kubectlConfigOverrideFlags.AuthOverrideFlags.ClientCertificate.LongName = ""
kubectlConfigOverrideFlags.AuthOverrideFlags.ClientKey.LongName = ""
Expand Down
7 changes: 4 additions & 3 deletions cli/pkg/kubectl/bind-apiservice/cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,12 @@ import (
"github.com/fatih/color"
"github.com/spf13/cobra"
"k8s.io/cli-runtime/pkg/genericclioptions"
_ "k8s.io/client-go/plugin/pkg/client/auth/exec"
_ "k8s.io/client-go/plugin/pkg/client/auth/oidc"
logsv1 "k8s.io/component-base/logs/api/v1"

"github.com/kube-bind/kube-bind/cli/pkg/kubectl/bind-apiservice/plugin"

_ "k8s.io/client-go/plugin/pkg/client/auth/exec"
_ "k8s.io/client-go/plugin/pkg/client/auth/oidc"
)

var (
Expand Down Expand Up @@ -67,7 +68,7 @@ func New(streams genericclioptions.IOStreams) (*cobra.Command, error) {

if !opts.NoBanner {
yellow := color.New(color.BgRed, color.FgBlack).SprintFunc()
fmt.Fprintf(streams.ErrOut, "%s\n\n", yellow("DISCLAIMER: This is a prototype. It will change in incompatible ways at any time.")) //nolint:errcheck
fmt.Fprintf(streams.ErrOut, "%s\n\n", yellow("DISCLAIMER: This is a prototype. It will change in incompatible ways at any time."))
}

return opts.Run(cmd.Context())
Expand Down
11 changes: 6 additions & 5 deletions cli/pkg/kubectl/bind-apiservice/plugin/bind.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,6 @@ func (b *BindAPIServiceOptions) Validate() error {

// Run starts the binding process.
func (b *BindAPIServiceOptions) Run(ctx context.Context) error {
//nolint:staticcheck
config, err := b.Options.ClientConfig.ClientConfig()
if err != nil {
return err
Expand Down Expand Up @@ -177,7 +176,7 @@ func (b *BindAPIServiceOptions) Run(ctx context.Context) error {
return err
}

fmt.Fprintln(b.Options.ErrOut) //nolint:errcheck
fmt.Fprintln(b.Options.ErrOut)
return b.printTable(ctx, config, bindings)
}

Expand Down Expand Up @@ -231,17 +230,19 @@ func (b *BindAPIServiceOptions) getRemoteKubeconfig(ctx context.Context, config

func (b *BindAPIServiceOptions) getRequestManifest() ([]byte, error) {
if b.url != "" {
resp, err := http.Get(b.url)
resp, err := http.Get(b.url) //nolint:noctx
if err != nil {
return nil, fmt.Errorf("failed to get %s: %w", b.url, err)
}
defer resp.Body.Close() //nolint:errcheck
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("failed to read response body: %w", err)
}
return body, nil
} else if b.file == "-" {
}

if b.file == "-" {
body, err := io.ReadAll(b.Options.IOStreams.In)
if err != nil {
return nil, fmt.Errorf("failed to read from stdin: %w", err)
Expand Down
49 changes: 25 additions & 24 deletions cli/pkg/kubectl/bind-apiservice/plugin/konnector.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ const (
konnectorImage = "ghcr.io/kube-bind/konnector"
)

//nolint:unused
func (b *BindAPIServiceOptions) deployKonnector(ctx context.Context, config *rest.Config) error {
logger := klog.FromContext(ctx)

Expand All @@ -69,7 +68,7 @@ func (b *BindAPIServiceOptions) deployKonnector(ctx context.Context, config *res
}

if b.KonnectorImageOverride != "" {
fmt.Fprintf(b.Options.ErrOut, "🚀 Deploying konnector %s to namespace kube-bind with custom image %q.\n", bindVersion, b.KonnectorImageOverride) //nolint:errcheck
fmt.Fprintf(b.Options.ErrOut, "🚀 Deploying konnector %s to namespace kube-bind with custom image %q.\n", bindVersion, b.KonnectorImageOverride)
if err := konnector.Bootstrap(ctx, discoveryClient, dynamicClient, b.KonnectorImageOverride); err != nil {
return err
}
Expand All @@ -81,28 +80,30 @@ func (b *BindAPIServiceOptions) deployKonnector(ctx context.Context, config *res

konnectorImage := fmt.Sprintf("%s:%s", konnectorImage, bindVersion)

if installed && (konnectorVersion == "unknown" || konnectorVersion == "latest") {
fmt.Fprintf(b.Options.ErrOut, "ℹ️ konnector of %s version already installed, skipping\n", konnectorVersion) //nolint:errcheck
// fall through to CRD test
} else if installed {
konnectorSemVer, err := semver.Parse(strings.TrimLeft(konnectorVersion, "v"))
if err != nil {
return fmt.Errorf("failed to parse konnector SemVer version %q: %w", konnectorVersion, err)
}
bindSemVer, err := semver.Parse(strings.TrimLeft(bindVersion, "v"))
if err != nil {
return fmt.Errorf("failed to parse kubectl-bind SemVer version %q: %w", bindVersion, err)
}
if bindSemVer.GT(konnectorSemVer) {
fmt.Fprintf(b.Options.ErrOut, "🚀 Updating konnector from %s to %s.\n", konnectorVersion, bindVersion) //nolint:errcheck
if err := konnector.Bootstrap(ctx, discoveryClient, dynamicClient, konnectorImage); err != nil {
return err
if installed {
if konnectorVersion == "unknown" || konnectorVersion == "latest" {
fmt.Fprintf(b.Options.ErrOut, "ℹ️ konnector of %s version already installed, skipping\n", konnectorVersion)
// fall through to CRD test
} else {
konnectorSemVer, err := semver.Parse(strings.TrimLeft(konnectorVersion, "v"))
if err != nil {
return fmt.Errorf("failed to parse konnector SemVer version %q: %w", konnectorVersion, err)
}
bindSemVer, err := semver.Parse(strings.TrimLeft(bindVersion, "v"))
if err != nil {
return fmt.Errorf("failed to parse kubectl-bind SemVer version %q: %w", bindVersion, err)
}
if bindSemVer.GT(konnectorSemVer) {
fmt.Fprintf(b.Options.ErrOut, "🚀 Updating konnector from %s to %s.\n", konnectorVersion, bindVersion)
if err := konnector.Bootstrap(ctx, discoveryClient, dynamicClient, konnectorImage); err != nil {
return err
}
} else if bindSemVer.LT(konnectorSemVer) {
fmt.Fprintf(b.Options.ErrOut, "⚠️ Newer konnector %s installed. To downgrade to %s use --downgrade-konnector.\n", konnectorVersion, bindVersion)
}
} else if bindSemVer.LT(konnectorSemVer) {
fmt.Fprintf(b.Options.ErrOut, "⚠️ Newer konnector %s installed. To downgrade to %s use --downgrade-konnector.\n", konnectorVersion, bindVersion) //nolint:errcheck
}
} else {
fmt.Fprintf(b.Options.ErrOut, "🚀 Deploying konnector %s to namespace kube-bind.\n", bindVersion) //nolint:errcheck
fmt.Fprintf(b.Options.ErrOut, "🚀 Deploying konnector %s to namespace kube-bind.\n", bindVersion)
if err := konnector.Bootstrap(ctx, discoveryClient, dynamicClient, konnectorImage); err != nil {
return err
}
Expand All @@ -113,17 +114,17 @@ func (b *BindAPIServiceOptions) deployKonnector(ctx context.Context, config *res
_, err := bindClient.KubeBindV1alpha2().APIServiceBindings().List(ctx, metav1.ListOptions{})
if err == nil {
if !first {
fmt.Fprintln(b.Options.IOStreams.ErrOut) //nolint:errcheck
fmt.Fprintln(b.Options.IOStreams.ErrOut)
}
return true, nil
}

logger.V(2).Info("Waiting for APIServiceBindings to be served", "error", err, "host", bindClient.RESTClient())
if first {
fmt.Fprint(b.Options.IOStreams.ErrOut, " Waiting for the konnector to be ready") //nolint:errcheck
fmt.Fprint(b.Options.IOStreams.ErrOut, " Waiting for the konnector to be ready")
first = false
} else {
fmt.Fprint(b.Options.IOStreams.ErrOut, ".") //nolint:errcheck
fmt.Fprint(b.Options.IOStreams.ErrOut, ".")
}
return false, nil
})
Expand Down
4 changes: 2 additions & 2 deletions cli/pkg/kubectl/bind-apiservice/plugin/secret.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func (b *BindAPIServiceOptions) createKubeconfigSecret(ctx context.Context, conf
}, metav1.CreateOptions{}); err != nil && !apierrors.IsAlreadyExists(err) {
return "", err
} else if err == nil {
fmt.Fprintf(b.Options.IOStreams.ErrOut, "📦 Created kube-binding namespace.\n") //nolint:errcheck
fmt.Fprintf(b.Options.IOStreams.ErrOut, "📦 Created kube-binding namespace.\n")
}

// look for secret of the given identity
Expand All @@ -54,7 +54,7 @@ func (b *BindAPIServiceOptions) createKubeconfigSecret(ctx context.Context, conf
return secretName, nil
}

fmt.Fprintf(b.Options.IOStreams.ErrOut, "🔒 Creating secret for host %s, namespace %s\n", remoteHost, remoteNamespace) //nolint:errcheck
fmt.Fprintf(b.Options.IOStreams.ErrOut, "🔒 Creating secret for host %s, namespace %s\n", remoteHost, remoteNamespace)
secretName, err = b.ensureKubeconfigSecretWithLogging(ctx, kubeconfig, "", kubeClient)
if err != nil {
return "", err
Expand Down
Loading