diff --git a/Makefile b/Makefile index 32ab52c..a434d8c 100644 --- a/Makefile +++ b/Makefile @@ -59,39 +59,11 @@ test: fmt vet ## Run tests. .PHONY: build build: fmt vet ## Build manager binary. - go build -o bin/manager cmd/main.go + go build -o bin/kubectl-dpm cmd/kubectl-dpm.go .PHONY: run run: fmt vet ## Run a controller from your host. - go run ./cmd/main.go - -# If you wish built the manager image targeting other platforms you can use the --platform flag. -# (i.e. docker build --platform linux/arm64 ). However, you must enable docker buildKit for it. -# More info: https://docs.docker.com/develop/develop-images/build_enhancements/ -.PHONY: docker-build -docker-build: test ## Build docker image with the manager. - $(CONTAINER_TOOL) build -t ${IMG} . - -.PHONY: docker-push -docker-push: ## Push docker image with the manager. - $(CONTAINER_TOOL) push ${IMG} - -# PLATFORMS defines the target platforms for the manager image be build to provide support to multiple -# architectures. (i.e. make docker-buildx IMG=myregistry/mypoperator:0.0.1). To use this option you need to: -# - able to use docker buildx . More info: https://docs.docker.com/build/buildx/ -# - have enable BuildKit, More info: https://docs.docker.com/develop/develop-images/build_enhancements/ -# - be able to push the image for your registry (i.e. if you do not inform a valid value via IMG=> then the export will fail) -# To properly provided solutions that supports more than one platform you should use this option. -PLATFORMS ?= linux/arm64,linux/amd64,linux/s390x,linux/ppc64le -.PHONY: docker-buildx -docker-buildx: test ## Build and push docker image for the manager for cross-platform support - # copy existing Dockerfile and insert --platform=${BUILDPLATFORM} into Dockerfile.cross, and preserve the original Dockerfile - sed -e '1 s/\(^FROM\)/FROM --platform=\$$\{BUILDPLATFORM\}/; t' -e ' 1,// s//FROM --platform=\$$\{BUILDPLATFORM\}/' Dockerfile > Dockerfile.cross - - $(CONTAINER_TOOL) buildx create --name project-v3-builder - $(CONTAINER_TOOL) buildx use project-v3-builder - - $(CONTAINER_TOOL) buildx build --push --platform=$(PLATFORMS) --tag ${IMG} -f Dockerfile.cross . - - $(CONTAINER_TOOL) buildx rm project-v3-builder - rm Dockerfile.cross + go run ./cmd/kubectl-dpm.go ##@ SBOM diff --git a/demo/debug-profiles/debug-profiles.yaml b/demo/debug-profiles/debug-profiles.yaml index be0f0fa..96fe680 100644 --- a/demo/debug-profiles/debug-profiles.yaml +++ b/demo/debug-profiles/debug-profiles.yaml @@ -1,3 +1,4 @@ +kubectlPath: ${HOME}/bin/kubectl profiles: - name: prometheus profile: /home/comario/go/src/github.com/bavarianbidi/kubectl-dpm/demo/debug-profiles/prom-profile-config.json @@ -6,7 +7,7 @@ profiles: matchLabels: app.kubernetes.io/name: prometheus - name: webapp - profile: /home/comario/go/src/github.com/bavarianbidi/kubectl-dpm/demo/debug-profiles/app-profile-config.json + profile: $HOME/go/src/github.com/bavarianbidi/kubectl-dpm/demo/debug-profiles/app-profile-config.json image: nicolaka/netshoot:v0.13 namespace: default matchLabels: diff --git a/pkg/command/debug.go b/pkg/command/debug.go index fa83d96..18510b3 100644 --- a/pkg/command/debug.go +++ b/pkg/command/debug.go @@ -124,10 +124,10 @@ func (o *CustomDebugOptions) run(streams genericiooptions.IOStreams, args []stri func(c profile.Profile) bool { return c.ProfileName == flagProfileName }, ) - fmt.Printf("Profile: %+v\n", debugProfile) - debugProfile = profile.Config.Profiles[idx] + fmt.Printf("Profile: %+v\n", debugProfile) + // this is not needed atm as we want support kubectl versions < 1.30 // // to just wrap the kubectl-debug command, we have to change a few things in here @@ -144,7 +144,7 @@ func (o *CustomDebugOptions) run(streams genericiooptions.IOStreams, args []stri } func (o *CustomDebugOptions) prepareEphemeralContainer(streams genericiooptions.IOStreams, args []string) error { - o.DebugOptions.CustomProfileFile = debugProfile.CustomProfileFile + o.DebugOptions.CustomProfileFile = os.ExpandEnv(debugProfile.CustomProfileFile) o.DebugOptions.Profile = kubectldebug.ProfileLegacy // use image from profile diff --git a/pkg/command/validate.go b/pkg/command/validate.go index a8db777..3bf63b7 100644 --- a/pkg/command/validate.go +++ b/pkg/command/validate.go @@ -3,7 +3,7 @@ package command import ( - "log" + "fmt" "github.com/spf13/cobra" @@ -25,9 +25,7 @@ func ValidateDebugProfileFile() *cobra.Command { return err } - log.Printf("all profiles are valid\n") - log.Printf("kubectl path: %s\n", profile.Config.KubectlPath) - log.Printf("profiles: %v\n", profile.Config.Profiles) + fmt.Printf("all profiles are valid\n") return nil }, diff --git a/pkg/profile/test_data/profile1.json b/pkg/profile/test_data/profile1.json new file mode 100644 index 0000000..d42030d --- /dev/null +++ b/pkg/profile/test_data/profile1.json @@ -0,0 +1,22 @@ +{ + "volumeMounts": [ + { + "mountPath": "/app/config", + "name": "app-config", + "readOnly": true + } + ], + "securityContext": { + "capabilities": { + "add": [ + "CAP_NET_ADMIN" + ] + } + }, + "env": [ + { + "name": "APP_ENV", + "value": "test" + } + ] +} \ No newline at end of file diff --git a/pkg/profile/test_data/profile2.json b/pkg/profile/test_data/profile2.json new file mode 100644 index 0000000..0107c24 --- /dev/null +++ b/pkg/profile/test_data/profile2.json @@ -0,0 +1,26 @@ +{ + "volumeMounts": [ + { + "mountPath": "/app/config", + "name": "app-config", + "readOnly": true + } + ], + "securityContext": { + "capabilities": { + "add": [ + "CAP_NET_ADMIN" + ] + } + }, + "env": [ + { + "name": "APP_ENV", + "value": "prod" + }, + { + "name": "APP_DB", + "value": "sql://prod" + } + ] +} \ No newline at end of file diff --git a/pkg/profile/validate.go b/pkg/profile/validate.go index 6808593..17ea4a8 100644 --- a/pkg/profile/validate.go +++ b/pkg/profile/validate.go @@ -4,6 +4,7 @@ package profile import ( "cmp" + "encoding/json" "fmt" "log" "os" @@ -35,7 +36,7 @@ func ValidateKubectlPath() error { Config.KubectlPath = os.Getenv("_") } else { // check if configured kubectl path is valid - info, err := os.Stat(Config.KubectlPath) + info, err := os.Stat(os.ExpandEnv(Config.KubectlPath)) if os.IsNotExist(err) { return fmt.Errorf("kubectl %s does not exist", Config.KubectlPath) } @@ -88,18 +89,41 @@ func ValidateAllProfiles() error { // This function is not implemented yet // future ideas: check if the profile file exists and // it's a valid pod.spec -func ValidateProfile(_ string) error { +func ValidateProfile(profileName string) error { + idx := slices.IndexFunc(Config.Profiles, + func(c Profile) bool { return c.ProfileName == profileName }, + ) + + if err := validatePodSpec(Config.Profiles[idx].CustomProfileFile); err != nil { + return err + } + return nil } -func ValidateAndCompleteProfile(profileName string) error { - if err := ValidateProfile(profileName); err != nil { +func validatePodSpec(podSpec string) error { + podSpecByte, err := os.ReadFile(os.ExpandEnv(podSpec)) + if err != nil { return err } + pod := corev1.PodSpec{} + + if err := json.Unmarshal(podSpecByte, &pod); err != nil { + return err + } + + return nil +} + +func ValidateAndCompleteProfile(profileName string) error { if err := CompleteProfile(profileName); err != nil { return err } + + if err := ValidateProfile(profileName); err != nil { + return err + } return nil } diff --git a/pkg/profile/validate_test.go b/pkg/profile/validate_test.go index 91ee1b6..0ff6974 100644 --- a/pkg/profile/validate_test.go +++ b/pkg/profile/validate_test.go @@ -67,19 +67,19 @@ func TestValidateAllProfiles(t *testing.T) { Profiles: []Profile{ { ProfileName: "profile1", - CustomProfileFile: "profile1.yaml", + CustomProfileFile: "test_data/profile1.json", Image: "busybox", Namespace: "default", ImagePullPolicy: "Always", }, { ProfileName: "profile2", - CustomProfileFile: "profile2.yaml", + CustomProfileFile: "test_data/profile2.json", Image: "busybox", }, { ProfileName: "profile2", - CustomProfileFile: "profile2.yaml", + CustomProfileFile: "test_data/profile2.json", }, }, }, @@ -87,14 +87,14 @@ func TestValidateAllProfiles(t *testing.T) { Profiles: []Profile{ { ProfileName: "profile1", - CustomProfileFile: "profile1.yaml", + CustomProfileFile: "test_data/profile1.json", Image: "busybox", Namespace: "default", ImagePullPolicy: "Always", }, { ProfileName: "profile2", - CustomProfileFile: "profile2.yaml", + CustomProfileFile: "test_data/profile2.json", Image: "busybox", }, }, @@ -106,7 +106,7 @@ func TestValidateAllProfiles(t *testing.T) { Profiles: []Profile{ { ProfileName: "profile1", - CustomProfileFile: "profile1.yaml", + CustomProfileFile: "test_data/profile1.json", Image: "busybox", Namespace: "default", ImagePullPolicy: "Always", @@ -124,13 +124,13 @@ func TestValidateAllProfiles(t *testing.T) { Profiles: []Profile{ { ProfileName: "profile1", - CustomProfileFile: "profile1.yaml", + CustomProfileFile: "test_data/profile1.json", Image: "busybox", Namespace: "default", ImagePullPolicy: "Always", }, { - CustomProfileFile: "profile2.yaml", + CustomProfileFile: "test_data/profile2.json", }, }, },