Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
cb50109
feat(project): support custom Kind configuration and Docker network
nkzk Oct 1, 2026
41899ce
fix(project): copy registry data instead of bind-mounting it
nkzk Oct 1, 2026
0df8e74
fix: default to kind network if networkName is empty
nkzk Oct 1, 2026
268f037
chore: use go-archive instead of manually tarring
nkzk Oct 1, 2026
34d3658
chore: simplify the internal flag check
nkzk Oct 1, 2026
e272f26
chore: update StartWithVolume comment
nkzk Oct 1, 2026
d534e74
fix(project): copy registry data into docker volume
nkzk Oct 1, 2026
ba0f07e
refactor: add storage interface for registry storage and configflag t…
nkzk Oct 2, 2026
916b31e
fix(project): validate storage type input
nkzk Oct 7, 2026
84f8d6d
fix(project): use bool ptr for --internal flag
nkzk Oct 7, 2026
285722a
fix(project): recreate local registry when its CA changes
nkzk Oct 8, 2026
ef6ead9
fix(project): ensure that existing project cluster joins a new specif…
nkzk Oct 8, 2026
d1ff8bd
fix(project): ensure existing registry container is connected to the…
nkzk Oct 8, 2026
c6c3cfc
fix(project): reconcile existing registry storage backend
nkzk Oct 8, 2026
28ed65d
fix(project/storage): change StorageTypeBindMount to 'bind'
nkzk Oct 8, 2026
4adff77
fix(project): restore/unset KIND_EXPERIMENTAL_DOCKER_NETWORK after use
nkzk Oct 8, 2026
e828fea
refactor(project): configure container connectivity with attachContai…
nkzk Oct 9, 2026
710231a
fix(project): only include certs when initializing volume storage
nkzk Oct 9, 2026
cfdb2d6
fix(project): dont override node image if kind-config is provided
nkzk Oct 9, 2026
814bc7f
fix(project): wrap error
nkzk Oct 9, 2026
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
47 changes: 47 additions & 0 deletions apis/dev/v1alpha1/project_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,53 @@ type ProjectSpec struct {
// any necessary ImageConfigs for deployment into a cluster must be created
// separately at deployment time.
ImageConfigs []pkgv1beta1.ImageConfig `json:"imageConfigs,omitempty"`

// Runtime configures the local development cluster.
Runtime Runtime `json:"runtime,omitempty"`
}

// Runtime is the spec for project runtime configuration.
type Runtime struct {
Kind RuntimeKind `json:"kind,omitempty"`
Registry RegistryConfig `json:"registry,omitempty"`
}

// RuntimeKind is the runtime configuration options for KinD.
type RuntimeKind struct {
// The KinD configuration to use for local development cluster.
Config RuntimeConfig `json:"config,omitempty"`
// Use internal addresses in the exported kubeconfig.
// Enable if running crossplane project in a container.
Internal bool `json:"internal,omitempty"`
// Network configuration options
Network RuntimeNetwork `json:"network,omitempty"`
}

// RuntimeConfig is the spec for a runtime configuration.
type RuntimeConfig struct {
// The path to the configuration file.
Path string `json:"path,omitempty"`
}

// RuntimeNetwork is the spec for runtime network configuration.
type RuntimeNetwork struct {
// AttachContainers lists existing containers to attach to the KinD network.
// Each entry accepts a Docker container name or ID. Containers already
// attached are left unchanged. Use this when running crossplane project
// in a container to give it access to the local development cluster.
AttachContainers []string `json:"attachContainers,omitempty"`
}

// RegistryConfig is the configuration options for the local registry.
type RegistryConfig struct {
Storage StorageConfig `json:"storage,omitempty"`
}

// StorageConfig is the configuration options for storage.
type StorageConfig struct {
// The type of storage to use.
// Options: "bind" (default), "volume".
Type string `json:"type,omitempty"`
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}

// ProjectPackageMetadata holds metadata about the project, which will become
Expand Down
101 changes: 101 additions & 0 deletions apis/dev/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

67 changes: 59 additions & 8 deletions cmd/crossplane/project/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"maps"
"os"
"path/filepath"
"strings"
"time"

"github.com/google/go-containerregistry/pkg/name"
Expand All @@ -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"
Expand All @@ -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"
Expand All @@ -69,18 +72,22 @@ type runCmd struct {

ControlPlaneName string `help:"Name of the dev control plane. Defaults to project name."`
CrossplaneVersion string `help:"Version of Crossplane to install."`
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 {
Expand Down Expand Up @@ -130,12 +137,32 @@ 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 == nil {
c.Internal = &c.proj.Spec.Runtime.Kind.Internal
}

if c.Repository != "" {
ref, err := name.NewRepository(c.Repository)
Expand All @@ -149,6 +176,26 @@ func (c *runCmd) Run(logger logging.Logger, sp terminal.SpinnerPrinter, cfg *con
c.ControlPlaneName = "crossplane-" + c.proj.Name
}

c.storageType = docker.StorageTypeBindMount
storageType := c.proj.Spec.Runtime.Registry.Storage.Type
if len(strings.TrimSpace(storageType)) > 0 {
if !docker.IsValidStorageType(storageType) {
return errors.Errorf("%q is an invalid storage type. Supported storage types: %v", storageType, docker.ValidStorageTypes())
}
c.storageType = docker.StorageType(storageType)
}

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)
Expand Down Expand Up @@ -222,6 +269,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.WithAttachContainers(c.proj.Spec.Runtime.Kind.Network.AttachContainers),
controlplane.WithInternal(*c.Internal),
controlplane.WithKindConfig(c.kindConfig),
controlplane.WithStorageType(c.storageType),
)
if ctpErr != nil {
ch.SendEvent("Setting up control plane", async.EventStatusFailure)
Expand Down
5 changes: 5 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ require (
github.com/google/ko v0.18.1
github.com/invopop/jsonschema v0.14.0
github.com/kubernetes-sigs/kro v0.9.2
github.com/moby/go-archive v0.3.3
github.com/moby/moby/api v1.56.0
github.com/moby/moby/client v0.5.1
github.com/muesli/termenv v0.16.0
Expand Down Expand Up @@ -222,6 +223,10 @@ require (
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/moby/docker-image-spec v1.3.1 // indirect
github.com/moby/patternmatcher v0.6.1 // indirect
github.com/moby/sys/sequential v0.7.0 // indirect
github.com/moby/sys/user v0.4.1 // indirect
github.com/moby/sys/userns v0.1.0 // indirect
github.com/moby/term v0.5.2 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
Expand Down
14 changes: 14 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -591,10 +591,24 @@ github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zx
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/go-archive v0.3.3 h1:OxxR9paxsluYi+zDUEXTTaIxtkK3viymW+Ka7vRhhME=
github.com/moby/go-archive v0.3.3/go.mod h1:Npdv43fFqlhZW7Xo8fbm3ZMYFvAGNviUPqX21VERbcE=
github.com/moby/moby/api v1.56.0 h1:GQzua3NA599ASSIICx0iFgiJeO9YkdDARvQsm23ZZuQ=
github.com/moby/moby/api v1.56.0/go.mod h1:sZ+THbVWkjOmBPPfbnzdD/G1LuIexWhqlSHHPTDQ1Uk=
github.com/moby/moby/client v0.5.1 h1:tYNaJno4c0HXz12y5BiqEDy0rVTYkWzI26lGvnTMiJw=
github.com/moby/moby/client v0.5.1/go.mod h1:odLstlZ6uSnfvAgVxMpvgmb8SUdd+siH2T0GBuxVAlM=
github.com/moby/patternmatcher v0.6.1 h1:qlhtafmr6kgMIJjKJMDmMWq7WLkKIo23hsrpR3x084U=
github.com/moby/patternmatcher v0.6.1/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
github.com/moby/sys/mount v0.3.5 h1:eS3fsZTjHaBihwjp4/+5Z3jxqLXYsbwxqpVSfFv3M00=
github.com/moby/sys/mount v0.3.5/go.mod h1:WUQDO+/uCiCIkIztx8SrwIDVn2dtMFRBebRhpDFT71M=
github.com/moby/sys/mountinfo v0.7.2 h1:1shs6aH5s4o5H2zQLn796ADW1wMrIwHsyJ2v9KouLrg=
github.com/moby/sys/mountinfo v0.7.2/go.mod h1:1YOa8w8Ih7uW0wALDUgT1dTTSBrZ+HiBLGws92L2RU4=
github.com/moby/sys/sequential v0.7.0 h1:ASQNGNROJSuOO6LL6bPHbKvuZu6NU8P4ldPWk31zj/8=
github.com/moby/sys/sequential v0.7.0/go.mod h1:NfSTAp6V3fw4tmkD62PEcOKeZKquXT8VKCkf7aVR79o=
github.com/moby/sys/user v0.4.1 h1:RgjRlaDKi/Xmyrz4t8lyzXT6v2ooFeO/7xtchmhVWE0=
github.com/moby/sys/user v0.4.1/go.mod h1:E9QsW5WRe1kUAf7kW8hXKwu1uhsZEAdPLYHYSDudF4Y=
github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g=
github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=
github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ=
github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
Expand Down
Loading