Repository navigation
Add clustersim command for manual MCM testing - #1152
takoverflow wants to merge 2 commits into
Conversation
Signed-off-by: Prashant Tak <prashant.tak@sap.com>
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
Signed-off-by: Prashant Tak <prashant.tak@sap.com>
62d6692 to
ebfa590
Compare
aaronfern
left a comment
There was a problem hiding this comment.
Thanks for the PR!
I have a few questions and nits
| go 1.26.2 | ||
|
|
||
| require ( | ||
| github.com/gardener/gardener/pkg/apis v1.137.0 |
There was a problem hiding this comment.
This is quite outdated. Do you want to use a later version?
There was a problem hiding this comment.
It doesn't make a difference from clustersim PoV, since we only rely on the typed data for ViewerKubeconfig and Shoot resources, and the information that we capture is very minimal from the latter (Just the seedname tbh).
I'll still bump up the version for now.
|
|
||
| ### `build` | ||
|
|
||
| Builds the specified components, fallsback to building both `machine-controller-manager` and the `simulated-provider` if unspecifed. Requires a mandatory flag `source-dir` pointing to the `machine-controller-manager` source root directory. |
There was a problem hiding this comment.
It would be nice if source-dir had a default of ../../../../ and users can override if they intend on using a different mcm
There was a problem hiding this comment.
The only problem is this depends on the path from where the binary is being invoked, if its from the clustersim directory the above works but anywhere else it'll just be incorrect. This was the reason why I turned it into a flag (initially I was automatically computing the root path relative to the file)
Do you still think we should have the default?
| } | ||
|
|
||
| func getClusterNames(cmd *cobra.Command) (clusters []string) { | ||
| clusters, _ = cmd.Flags().GetStringSlice("clusters") |
| } | ||
|
|
||
| func getClustersDir(cmd *cobra.Command) (dir string) { | ||
| dir, _ = cmd.Flags().GetString("dir") |
There was a problem hiding this comment.
Similar here too, why ignore an error?
| // CopyShoot only works with one cluster at a time, to ensure user doesn't | ||
| // pass incorrect project when specifying multiple clusters. Multiple invocations | ||
| // are to be made in case data for multiple clusters needs to be fetched. | ||
| clusterNames := getClusterNames(cmd) |
There was a problem hiding this comment.
nit: why call this var clusterNames when you expect only one cluster name to be present?
Also, maybe this constraint should also be specified in README.md under the copyshoot section
| Short: "Generates MachineClasses and MachineDeployments with the specified parameters.", | ||
| DisableFlagsInUseLine: true, | ||
| PreRunE: func(cmd *cobra.Command, _ []string) error { | ||
| if genClusterFlags.Zones == nil || genClusterFlags.Instances == nil { |
There was a problem hiding this comment.
I think you'll need a more sophisticated check here to ensure Zones or instances are not empty.
If I understood the docstring of MarkFlagRequired() correctly, it will just cause your command to report an error if invoked without the flag. So something like --zones "" would be legal.
This then passed the genClusterFlags.Zones == nil check since []Zones{""} will not be nil
Maybe something like:
for _, zone := range genClusterFlags.Zones {
if strings.TrimSpace(zone) == "" {
return fmt.Errorf("zone name cannot be empty")
}
}
| &genClusterFlags.Zones, "zones", "z", nil, | ||
| "comma separated list of zones to use (required)", | ||
| ) | ||
| _ = genClusterCmd.MarkFlagRequired("zones") |
| &genClusterFlags.Instances, "instances", "i", nil, | ||
| "comma separated list of instances to use (required)", | ||
| ) | ||
| _ = genClusterCmd.MarkFlagRequired("instances") |
| linkedConfigPath := filepath.Join(clusterPath, fileNameKubeconfig) | ||
| kubeConfig := clusterEnv.Cfg.KubeconfigFile() | ||
| // Clean up any existing, stale symlink | ||
| _ = os.Remove(linkedConfigPath) |
| } | ||
| } | ||
|
|
||
| clusterEnv := cluster.New(name, dummyNamespace) |
There was a problem hiding this comment.
Why use a dummy namespace here?
You can fetch the proper namespace using getClusterNamespace(). If namespace does not matter then a comment explaining that would be needed.
| @(cd test/integration/controller; ginkgo -v --show-node-events --poll-progress-after=300s --poll-progress-interval=60s) | ||
|
|
||
| .PHONY: build-clustersim | ||
| build-clustersim: |
There was a problem hiding this comment.
Can we please also duplicate this target (only this target in top level MCM Makefile)
| clustersim build --source-dir ../../../../ --components "mcm,mc" | ||
|
|
||
| Flags: | ||
| -c, --components strings comma separated list of components to build (default [mcm,mc]) |
There was a problem hiding this comment.
I suggest making a command build with different source directories passed --source-mcm and --source-ca. Since source directory can be different for each. Or ask user to specify env variables if this is too much work. I don't think building MC is necessary since it only builds the current simulated provider - which it should do by default for any build invocation using the --source-mcm directory and put built binaries into $source-mcm/bin.
| clustersim build {--source-dir ..} [--components mcm]... | ||
|
|
||
| Examples: | ||
| clustersim build --source-dir ../../../../ --components "mcm,mc" |
There was a problem hiding this comment.
It is not possible to build the ca tried
Error: passed invalid component "ca", supported ones are [mcm mc]
There was a problem hiding this comment.
I had mentioned in the proposal that I didn't wish to add CA support for now. Wanted to keep the current task's scope restricted to just adding IT support and basic manual testing. This can be handled later unless you feel strongly that it should also be done now.
(I'd also mentioned skipping copyshoot and gendata for current implementation but since it was somewhat necessary for testing with gardener data, I added those subcommands)
|
|
||
| .PHONY: build-clustersim | ||
| build-clustersim: | ||
| @mkdir -p bin |
There was a problem hiding this comment.
a bin directory for binaries should not go inside a pkg subdirectory in Go. You can use top level project bin directory for all binaries. There is no need to have gen/bin which is even more confusing as we now have 3 different build dirs. DOn't use cluster data directory to determine binary directory. Binaries are always at fixed location and constant.
| return err | ||
| } | ||
|
|
||
| if finfo, err := os.Stat(binPath); err != nil && finfo.IsDir() { |
There was a problem hiding this comment.
error here: if err is not nil then finfo will be nil and you will get a panic.
| } | ||
|
|
||
| func init() { | ||
| stopCmd.PersistentFlags().BoolVar( |
There was a problem hiding this comment.
Please move all flag setup code away from init. init runs at program startup BEFORE any flags are parsed. stopFlags.KillAll is always true here. Move to PersistentPreRun or alternative.
| ctx, mcc.SecretRef.Name, mcc.SecretRef.Namespace, &secret, | ||
| ) | ||
| if err != nil { | ||
| return false, err |
There was a problem hiding this comment.
This doesn't make sense. Shouldn't you do a IsNotFound check here ?
| "embed" | ||
| "encoding/json" | ||
| "fmt" | ||
| "html/template" |
There was a problem hiding this comment.
Please use text/template. html/template is meant for HTML as it does HTML decode/encode stuff which can screw up yaml.
There was a problem hiding this comment.
This was an LSP import, didn't pay attention. Thanks for the catch, will fix.
| Use: "clustersim {--clusters name}... command [--dir /tmp]", | ||
| Short: "Manages and sets up virtual cluster running simulated Machine Controller Manager.", | ||
| Example: `clustersim --clusters "test" setup`, | ||
| Args: cobra.ExactArgs(1), |
There was a problem hiding this comment.
Remove this. Has no relevance for sub-commands unless you have top-level argument for root command which you do not AFAIK.
| @@ -0,0 +1,9249 @@ | |||
| [ | |||
There was a problem hiding this comment.
This file is just too large at ~400KB. This is also not scalable when you need to simulate other provider instance types. We should not check it in. Just accept Accept capacity directly as flags. --cpu 2 --memory 8Gi --arch amd64 . Or some format. (check what other k8s projects do), instead of looking at it by instance name.
There was a problem hiding this comment.
Yes, I was hesitant to add this, alternatively I thought I'll just populate the file with top 20 instances from each CSP but what you've proposed makes sense. I can introduce additional flags for the instance parameters.
| Generates MachineClasses and MachineDeployments with the specified parameters. | ||
|
|
||
| Usage: | ||
| clustersim gencluster {--clusters name} {--zones zone}... {--instances inst}... |
There was a problem hiding this comment.
I suggest supporting multiple --instance fields each with a spec like --instance m5.xlarge:amd64:2:0:8Gi . Order is name:arch:cpu:gpu:mem. Or more verbose like --instance name=m5.xlarge,cpu=2,mem=8Gi,arch=amd64, but I think this will give problem with cobra.
| @@ -0,0 +1,130 @@ | |||
| ## Clustersim | |||
|
|
|||
There was a problem hiding this comment.
Please add pre-requisites for clustersim tool.
Error: kwok: failed to create cluster "aw1": exit status 1: exit status 1: {"time":"2026-10-06T13:51:50.793557+05:30","level":"INFO","source":{"function":"sigs.k8s.io/kwok/pkg/kwokctl/cmd/create/cluster.runE","file":"/Users/I034796/go/pkg/mod/sigs.k8s.io/kwok@v0.5.0/pkg/kwokctl/cmd/create/cluster/cluster.go","line":266},"msg":"Cluster is creating","cluster":"aw1"}
{"time":"2026-10-06T13:51:51.18667+05:30","level":"INFO","source":{"function":"sigs.k8s.io/kwok/pkg/utils/file.getCacheOrDownload","file":"/Users/I034796/go/pkg/mod/sigs.k8s.io/kwok@v0.5.0/pkg/utils/file/download.go","line":145},"msg":"Download","cluster":"aw1","uri":"https://dl.k8s.io/release/v1.35.0/bin/darwin/arm64/kube-apiserver"}
{"time":"2026-10-06T13:51:53.40609+05:30","level":"ERROR","source":{"function":"sigs.k8s.io/kwok/pkg/kwokctl/cmd/create/cluster.runE","file":"/Users/I034796/go/pkg/mod/sigs.k8s.io/kwok@v0.5.0/pkg/kwokctl/cmd/create/cluster/cluster.go","line":269},"msg":"Failed to setup config","cluster":"aw1","err":"https://dl.k8s.io/release/v1.35.0/bin/darwin/arm64/kube-apiserver: 404 Not Found"}
{"time":"2026-10-06T13:51:53.415484+05:30","level":"INFO","source":{"function":"sigs.k8s.io/kwok/pkg/kwokctl/cmd/create/cluster.runE.func2","file":"/Users/I034796/go/pkg/mod/sigs.k8s.io/kwok@v0.5.0/pkg/kwokctl/cmd/create/cluster/cluster.go","line":247},"msg":"Cluster is cleaned up","cluster":"aw1"}
{"time":"2026-10-06T13:51:53.415536+05:30","level":"ERROR","source":{"function":"main.main","file":"/Users/I034796/go/pkg/mod/sigs.k8s.io/kwok@v0.5.0/cmd/kwokctl/main.go","line":54},"msg":"Execute exit","err":"https://dl.k8s.io/release/v1.35.0/bin/darwin/arm64/kube-apiserver: 404 Not Found"}
Error: kwok: failed to create cluster "aw1": exit status 1: exit status 1: {"time":"2026-10-06T13:51:50.793557+05:30","level":"INFO","source":{"function":"sigs.k8s.io/kwok/pkg/kwokctl/cmd/create/cluster.runE","file":"/Users/I034796/go/pkg/mod/sigs.k8s.io/kwok@v0.5.0/pkg/kwokctl/cmd/create/cluster/cluster.go","line":266},"msg":"Cluster is creating","cluster":"aw1"}
{"time":"2026-10-06T13:51:51.18667+05:30","level":"INFO","source":{"function":"sigs.k8s.io/kwok/pkg/utils/file.getCacheOrDownload","file":"/Users/I034796/go/pkg/mod/sigs.k8s.io/kwok@v0.5.0/pkg/utils/file/download.go","line":145},"msg":"Download","cluster":"aw1","uri":"https://dl.k8s.io/release/v1.35.0/bin/darwin/arm64/kube-apiserver"}
{"time":"2026-10-06T13:51:53.40609+05:30","level":"ERROR","source":{"function":"sigs.k8s.io/kwok/pkg/kwokctl/cmd/create/cluster.runE","file":"/Users/I034796/go/pkg/mod/sigs.k8s.io/kwok@v0.5.0/pkg/kwokctl/cmd/create/cluster/cluster.go","line":269},"msg":"Failed to setup config","cluster":"aw1","err":"https://dl.k8s.io/release/v1.35.0/bin/darwin/arm64/kube-apiserver: 404 Not Found"}
{"time":"2026-10-06T13:51:53.415484+05:30","level":"INFO","source":{"function":"sigs.k8s.io/kwok/pkg/kwokctl/cmd/create/cluster.runE.func2","file":"/Users/I034796/go/pkg/mod/sigs.k8s.io/kwok@v0.5.0/pkg/kwokctl/cmd/create/cluster/cluster.go","line":247},"msg":"Cluster is cleaned up","cluster":"aw1"}
{"time":"2026-10-06T13:51:53.415536+05:30","level":"ERROR","source":{"function":"main.main","file":"/Users/I034796/go/pkg/mod/sigs.k8s.io/kwok@v0.5.0/cmd/kwokctl/main.go","line":54},"msg":"Execute exit","err":"https://dl.k8s.io/release/v1.35.0/bin/darwin/arm64/kube-apiserver: 404 Not Found"}
There was a problem hiding this comment.
This is because of old kwok version present on the system: 0.5.0
I'll add a note in the README to ensure that the user cleans it up and checks that the version is atleast 0.8.0.
What this PR does / why we need it:
Introduces standalone
clustersimtool to create virtual clusters with workload consisting of MachineClasses and MachineDeployments to aid in manual testing. Please check itsREADME.mdfor more details.Which issue(s) this PR fixes:
Fixes part of #1120
Special notes for your reviewer:
The line diff is bloated because of the
instances.jsonfile, which consists of capacity information for various AWS instances. If deemed overkill, it can be replaced by a list of top 20 frequently used instances for all providers./invite @elankath
Release note: