Repository navigation
feat(project): add KinD configuration options and DinD support #395
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
cb50109
41899ce
0df8e74
268f037
34d3658
e272f26
d534e74
ba0f07e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,6 +22,7 @@ import ( | |
| "maps" | ||
| "os" | ||
| "path/filepath" | ||
| "strings" | ||
| "time" | ||
|
|
||
| "github.com/google/go-containerregistry/pkg/name" | ||
|
|
@@ -31,6 +32,7 @@ import ( | |
| "k8s.io/client-go/tools/clientcmd" | ||
| clientcmdapi "k8s.io/client-go/tools/clientcmd/api" | ||
| "sigs.k8s.io/controller-runtime/pkg/scheme" | ||
| "sigs.k8s.io/kind/pkg/apis/config/v1alpha4" | ||
| "sigs.k8s.io/yaml" | ||
|
|
||
| "github.com/crossplane/crossplane-runtime/v2/pkg/errors" | ||
|
|
@@ -44,6 +46,7 @@ import ( | |
| "github.com/crossplane/cli/v2/internal/async" | ||
| "github.com/crossplane/cli/v2/internal/config" | ||
| "github.com/crossplane/cli/v2/internal/dependency" | ||
| "github.com/crossplane/cli/v2/internal/docker" | ||
| "github.com/crossplane/cli/v2/internal/project" | ||
| "github.com/crossplane/cli/v2/internal/project/controlplane" | ||
| "github.com/crossplane/cli/v2/internal/project/functions" | ||
|
|
@@ -69,18 +72,23 @@ type runCmd struct { | |
|
|
||
| ControlPlaneName string `help:"Name of the dev control plane. Defaults to project name."` | ||
| CrossplaneVersion string `help:"Version of Crossplane to install."` | ||
| DockerNetwork string `help:"The docker network to start up the dev control plane in. Defaults to kind. This is an experimental feature in KinD."` | ||
| Internal bool `help:"Use internal addresses in the exported kubeconfig. Enable if running crossplane project in a container."` | ||
| KindConfig string `help:"The path to the KinD configuration which should be used to create the local development cluster."` | ||
| RegistryDir string `help:"Directory for local registry images."` | ||
| ClusterAdmin bool `default:"true" help:"Grant Crossplane the cluster-admin role." negatable:""` | ||
| DefaultMRAP bool `default:"true" help:"Install the default wildcard ManagedResourceActivationPolicy in the dev control plane." negatable:""` | ||
| Timeout time.Duration `default:"5m" help:"Max wait for project readiness."` | ||
| InitResources []string `help:"Resources to apply before installing." type:"path"` | ||
| ExtraResources []string `help:"Resources to apply after installing." type:"path"` | ||
| ClusterAdmin bool `default:"true" help:"Grant Crossplane the cluster-admin role." negatable:""` | ||
| DefaultMRAP bool `default:"true" help:"Install the default wildcard ManagedResourceActivationPolicy in the dev control plane." negatable:""` | ||
| Timeout time.Duration `default:"5m" help:"Max wait for project readiness."` | ||
| InitResources []string `help:"Resources to apply before installing." type:"path"` | ||
| ExtraResources []string `help:"Resources to apply after installing." type:"path"` | ||
|
|
||
| proj *devv1alpha1.Project | ||
| projFS afero.Fs | ||
|
|
||
| initResources []runtime.RawExtension | ||
| extraResources []runtime.RawExtension | ||
| kindConfig *v1alpha4.Cluster | ||
| storageType docker.StorageType | ||
| } | ||
|
|
||
| func (c *runCmd) Help() string { | ||
|
|
@@ -130,12 +138,36 @@ func (c *runCmd) AfterApply() error { | |
| } | ||
| } | ||
|
|
||
| if len(strings.TrimSpace(c.KindConfig)) == 0 { | ||
| c.KindConfig = c.proj.Spec.Runtime.Kind.Config.Path | ||
| } | ||
|
|
||
| if len(strings.TrimSpace(c.KindConfig)) > 0 { | ||
| kindCfgBytes, err := afero.ReadFile(c.projFS, c.KindConfig) | ||
| if err != nil { | ||
| return errors.Wrapf(err, "failed to load kind configuration from %q", c.KindConfig) | ||
| } | ||
|
|
||
| kindCfg := &v1alpha4.Cluster{} | ||
| if err := yaml.Unmarshal(kindCfgBytes, kindCfg); err != nil { | ||
| return errors.Wrapf(err, "failed to unmarshal KinD configuration from %q", c.KindConfig) | ||
| } | ||
|
|
||
| c.kindConfig = kindCfg | ||
| } | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
| // Run executes the run command. | ||
| func (c *runCmd) Run(logger logging.Logger, sp terminal.SpinnerPrinter, cfg *config.Config) error { //nolint:gocyclo // Main command orchestration. | ||
| ctx := context.Background() | ||
| // resolveRunOptions applies command overrides and project runtime defaults. | ||
| func (c *runCmd) resolveRunOptions() error { | ||
| if !c.Internal { | ||
| c.Internal = c.proj.Spec.Runtime.Kind.Internal | ||
| } | ||
|
|
||
| if c.DockerNetwork == "" && len(strings.TrimSpace(c.proj.Spec.Runtime.Kind.Network.Name)) > 0 { | ||
| c.DockerNetwork = c.proj.Spec.Runtime.Kind.Network.Name | ||
| } | ||
|
Comment on lines
+162
to
+170
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win 🔎 Supported by static analysis🏁 Script executed: sed -n '65,100p;130,205p;260,285p' cmd/crossplane/project/run.go
rg -n 'Internal|internal|resolveRunOptions' cmd/crossplane/project apis/dev/v1alpha1/project_types.goRepository: crossplane/cli Length of output: 9845 🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- PR diff for run.go ---'
git diff --unified=40 29316fea54f2ede9d2c039d9c54f0c29cbad4b65 ba0f07e72e1d3e6caeb61321aa3f8b53e894fc1c -- cmd/crossplane/project/run.go
printf '%s\n' '--- runHelp and flag parser references ---'
rg -n -F -- 'runHelp' cmd/crossplane/project
rg -n -F -- 'kong' go.mod cmd/crossplane
printf '%s\n' '--- related help, precedence, and negatable flag usages ---'
rg -n 'runtime\.kind\.internal|--internal|Internal.*negatable|negatable:""|command.*override|overrides.*project|project.*defaults|defaults.*flag' cmd apis docs
printf '%s\n' '--- run command tests and documentation candidates ---'
rg --files cmd/crossplane/project docs | rg '(run|project).*(test|md)$|project.*(test|md)$' || trueRepository: crossplane/cli Length of output: 26813 🏁 Script executed: #!/bin/bash
set -u
printf '%s\n' '--- project subtree files ---'
rg --files cmd/crossplane/project | sort
printf '%s\n' '--- embedded run help ---'
sed -n '1,240p' cmd/crossplane/project/help/run.md
printf '%s\n' '--- run option tests/references ---'
rg -n -C 4 'resolveRunOptions|runCmd\{|WithInternal|Internal:|internal:' cmd/crossplane/project cmd/crossplane/project/help apis/dev
printf '%s\n' '--- module cache path and Kong bool parser source ---'
if command -v go >/dev/null 2>&1; then
gomodcache="$(go env GOMODCACHE 2>/dev/null)"
printf 'GOMODCACHE=%s\n' "$gomodcache"
kongdir="$gomodcache/github.com/alecthomas/kong@v1.16.1"
if test -d "$kongdir"; then
rg -n -C 3 'Negatable|negatable|Parse.*bool|Bool|bool' "$kongdir" --glob '*.go' | head -240
else
printf 'Kong module source not present at %s\n' "$kongdir"
fi
else
printf '%s\n' 'go executable unavailable'
fiRepository: crossplane/cli Length of output: 5195 🔍 Additional research query:
💡 Result: 🌐 Web query:
💡 Result: 🌐 Web query:
💡 Result: 🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- internal option definition and consumers ---'
rg -n -C 5 'func WithInternal|WithInternal|internalAddress|Internal' internal/project/controlplaneRepository: crossplane/cli Length of output: 1185 🏁 Script executed: #!/bin/bash
set -eu
rg -n -C 4 'internal|kubeconfig|KubeConfig' internal/project/controlplane --glob '*.go'Repository: crossplane/cli Length of output: 11293 Preserve an explicit Thanks for adding the project runtime default. Could we track whether 🤖 Prompt for AI Agents |
||
|
|
||
| if c.Repository != "" { | ||
| ref, err := name.NewRepository(c.Repository) | ||
|
|
@@ -149,6 +181,22 @@ func (c *runCmd) Run(logger logging.Logger, sp terminal.SpinnerPrinter, cfg *con | |
| c.ControlPlaneName = "crossplane-" + c.proj.Name | ||
| } | ||
|
|
||
| c.storageType = docker.StorageTypeBindMount | ||
| if c.proj.Spec.Runtime.Registry.Storage.Type == string(docker.StorageTypeVolume) { | ||
| c.storageType = docker.StorageTypeVolume | ||
| } | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
| // Run executes the run command. | ||
| func (c *runCmd) Run(logger logging.Logger, sp terminal.SpinnerPrinter, cfg *config.Config) error { //nolint:gocyclo // Main command orchestration. | ||
| ctx := context.Background() | ||
|
|
||
| if err := c.resolveRunOptions(); err != nil { | ||
| return err | ||
| } | ||
|
|
||
| concurrency := max(1, c.MaxConcurrency) | ||
|
|
||
| schemasFS := afero.NewBasePathFs(c.projFS, c.proj.Spec.Paths.Schemas) | ||
|
|
@@ -222,6 +270,10 @@ func (c *runCmd) Run(logger logging.Logger, sp terminal.SpinnerPrinter, cfg *con | |
| controlplane.WithClusterAdmin(c.ClusterAdmin), | ||
| controlplane.WithDefaultMRAP(c.DefaultMRAP), | ||
| controlplane.WithLogger(logger), | ||
| controlplane.WithDockerNetwork(c.DockerNetwork), | ||
| controlplane.WithInternal(c.Internal), | ||
| controlplane.WithKindConfig(c.kindConfig), | ||
| controlplane.WithStorageType(c.storageType), | ||
| ) | ||
| if ctpErr != nil { | ||
| ch.SendEvent("Setting up control plane", async.EventStatusFailure) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Add enum validation to
StorageConfig.Type. A misspelled value currently falls back to bind mounts without any warning.Thanks for adding this option. In
cmd/crossplane/project/run.go,resolveRunOptionsselects volume storage only when the value equals"volume"exactly. Any other value, such as"Volume"or"volumes", falls back to bind mounts without an error. A DinD user with a typo gets bind mounts, and the registry then fails in a confusing way. Thedefaulterror branch incontrolplane.gonever runs for this input.Could you add a
+kubebuilder:validation:Enum=bindMount;volumemarker? Could you also reject unknown non-empty values inresolveRunOptions?Proposed fix
📝 Committable suggestion
🤖 Prompt for AI Agents
Source: Path instructions