Skip to content
Open
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
49 changes: 8 additions & 41 deletions cmd/crossplane/simulate/help/simulate.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@ claims, use `crossplane xr simulate`; to simulate Compositions, use
`crossplane composition simulate`; to simulate a project, use
`crossplane project simulate`.

The command connects to the cluster in your current Kubernetes context, or the
one `--context` names. Use `--as`, `--as-group`, and `--as-uid` to simulate as
another user.

`-f` (`--filename`) names a file, or a directory of YAML files, of managed
resources to simulate, and is required. Give a comma-separated list for more;
`-f -` reads standard input.

Which providers run as diff servers comes from the current kubeconfig context
by default: the CLI follows each resource's kind to the provider that
installed it on the cluster, so the preview matches the provider versions
Expand Down Expand Up @@ -88,44 +96,3 @@ the result:
replace a resource.
- 80: the flags were invalid, so nothing was simulated.
- 130: the simulation was interrupted.

## Examples

Preview what applying resources.yaml would do:

```shell
crossplane resource simulate -f resources.yaml
```

Preview against specific provider versions instead of the installed ones,
from a checked-in file of Provider manifests:

```shell
crossplane resource simulate -f resources.yaml --providers providers.yaml
```

Keep diff servers running so later runs start faster, via a provider manifest
annotated with `simulate.crossplane.io/runtime-docker-cleanup: Orphan`:

```shell
crossplane resource simulate -f resources.yaml --providers providers.yaml
```

Iterate on a provider's diff server from source, with no package to build or
push: run `go run ./cmd/provider internal diff-server` in the provider
repository, then simulate with a Provider manifest annotated with
`simulate.crossplane.io/runtime: Development` and
`simulate.crossplane.io/runtime-development-api-groups: ec2.aws.upbound.io,ec2.aws.m.upbound.io`:

```shell
crossplane resource simulate -f resources.yaml --providers providers.yaml
```

Emit machine-readable results for CI gating. Each plan carries the live
object as `before` (absent for a create) and the desired manifest as `after`,
both without status, server-managed metadata and ignored paths, and with
Secret values redacted:

```shell
crossplane resource simulate -f resources.yaml -o json
```
40 changes: 40 additions & 0 deletions cmd/crossplane/simulate/help/simulate_examples.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
## Examples

Preview what applying resources.yaml would do:

```shell
crossplane resource simulate -f resources.yaml
```

Preview against specific provider versions instead of the installed ones,
from a checked-in file of Provider manifests:

```shell
crossplane resource simulate -f resources.yaml --providers providers.yaml
```

Keep diff servers running so later runs start faster, via a provider manifest
annotated with `simulate.crossplane.io/runtime-docker-cleanup: Orphan`:

```shell
crossplane resource simulate -f resources.yaml --providers providers.yaml
```

Iterate on a provider's diff server from source, with no package to build or
push: run `go run ./cmd/provider internal diff-server` in the provider
repository, then simulate with a Provider manifest annotated with
`simulate.crossplane.io/runtime: Development` and
`simulate.crossplane.io/runtime-development-api-groups: ec2.aws.upbound.io,ec2.aws.m.upbound.io`:

```shell
crossplane resource simulate -f resources.yaml --providers providers.yaml
```

Emit machine-readable results for CI gating. Each plan carries the live
object as `before` (absent for a create) and the desired manifest as `after`,
both without status and server-managed metadata, and with Secret values
redacted:

```shell
crossplane resource simulate -f resources.yaml -o json
```
23 changes: 13 additions & 10 deletions cmd/crossplane/simulate/simulate.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,25 +51,28 @@ import (
//go:embed help/simulate.md
var helpDetail string

//go:embed help/simulate_examples.md
var helpExamples string

// Cmd previews what applying managed resources would do.
type Cmd struct {
Filename string `help:"YAML files or directory with managed resources, or '-' for stdin (comma-separated)." predictor:"yaml_file_or_directory" required:"" short:"f"`
Filename string `help:"File or directory of managed resources to simulate. Takes a comma-separated list of paths. - reads standard input." predictor:"yaml_file_or_directory" required:"" short:"f"`

Providers string `help:"YAML file or directory with Provider manifests to run as diff servers, overriding discovery from the cluster. Supports per-provider runtime annotations." name:"providers" optional:"" predictor:"yaml_file_or_directory" type:"path"`
ImageConfigs string `help:"YAML file with ImageConfig manifests that rewrite provider image paths for local pulls. Defaults to the project's imageConfigs when a project file is present." name:"image-configs" optional:"" predictor:"yaml_file" type:"existingfile"`
ProjectFile string `help:"Path to a project definition file to read imageConfigs from. Defaults to ${project_file} when present." name:"project-file" optional:""`
SessionID string `help:"Session ID to apply as the simulate.crossplane.io/session label on diff server containers. Defaults to a random per-run ID. A supplied ID isn't leased, so its containers aren't reclaimed after a crash." placeholder:"ID"`
Context string `default:"" help:"Kubernetes context." name:"context" predictor:"context" short:"c"`
CacheDir string `env:"CROSSPLANE_XPKG_CACHE" help:"Cache directory for downloaded provider packages." name:"cache-dir" predictor:"directory"`
Timeout time.Duration `default:"2m" help:"Per-resource plan timeout."`
Output string `default:"plan" enum:"plan,json,yaml" help:"Output format. One of: plan, json, yaml." name:"output" short:"o"`
Providers string `help:"YAML file or directory of Provider manifests to run as diff servers, instead of discovering them from the cluster." name:"providers" optional:"" predictor:"yaml_file_or_directory" type:"path"`
ImageConfigs string `help:"YAML file of ImageConfig manifests that rewrite package paths for pulls. Defaults to the project's imageConfigs when a project file is present." name:"image-configs" optional:"" predictor:"yaml_file" type:"existingfile"`
ProjectFile string `help:"Project file to read imageConfigs from. Defaults to ${project_file} when present." name:"project-file" optional:""`
SessionID string `help:"Session ID to apply as the simulate.crossplane.io/session label on diff server containers. Defaults to a random per-process ID. A supplied ID isn't leased, so its containers aren't reclaimed after a crash." placeholder:"ID"`
Context string `default:"" help:"Kubernetes context to simulate against. Defaults to the current context." name:"context" predictor:"context" short:"c"`
CacheDir string `env:"CROSSPLANE_XPKG_CACHE" help:"Directory for cached xpkg package contents (providers)." name:"cache-dir" predictor:"directory"`
Timeout time.Duration `default:"2m" help:"Max time to plan one managed resource."`
Output string `default:"plan" enum:"plan,json,yaml" help:"Output format. One of: plan, json, yaml." name:"output" short:"o"`

Impersonation kube.ImpersonationFlags `embed:""`
}

// Help returns the help message for the simulate command.
func (c *Cmd) Help() string {
return helpDetail
return helpDetail + "\n" + helpExamples
}

// Run runs the simulate command. ctx is the signal-bound command context from
Expand Down
31 changes: 31 additions & 0 deletions cmd/crossplane/simulate/simulate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ limitations under the License.
package simulate

import (
"strings"
"testing"

"github.com/google/go-cmp/cmp"
Expand Down Expand Up @@ -72,3 +73,33 @@ func TestExitStatus(t *testing.T) {
})
}
}

func TestHelp(t *testing.T) {
type args struct {
want string
}
cases := map[string]struct {
reason string
args args
want bool
}{
"Detail": {
reason: "Help should include the command description.",
args: args{want: "-f` (`--filename`)"},
want: true,
},
"Examples": {
reason: "Help should include the examples section.",
args: args{want: "## Examples"},
want: true,
},
}
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
got := strings.Contains((&Cmd{}).Help(), tc.args.want)
if diff := cmp.Diff(tc.want, got); diff != "" {
t.Errorf("\n%s\nHelp() contains %q: -want, +got:\n%s", tc.reason, tc.args.want, diff)
}
})
}
}
Loading