From 2bdcbb3e3d6ecc470468e89097853a016c6a45e6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 27 Jun 2025 06:37:45 +0000 Subject: [PATCH 01/10] Initial plan From 5e75b1e8e040a7c7a487070a22914d1b1c3bb146 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 27 Jun 2025 06:55:37 +0000 Subject: [PATCH 02/10] Create ClusterResourcePlacement template with tests Co-authored-by: sjwaight <4828246+sjwaight@users.noreply.github.com> --- .../pickall/clusterresourceplacement.yaml | 16 +++++ .../pickfixed/clusterresourceplacement.yaml | 19 ++++++ ...manifests_clusterresourceplacement_test.go | 46 ++++++++++++++ .../clusterresourceplacement.yaml | 19 ++++++ .../clusterresourceplacement/draft.yaml | 62 +++++++++++++++++++ 5 files changed, 162 insertions(+) create mode 100644 pkg/fixtures/manifests/clusterresourceplacement/pickall/clusterresourceplacement.yaml create mode 100644 pkg/fixtures/manifests/clusterresourceplacement/pickfixed/clusterresourceplacement.yaml create mode 100644 pkg/handlers/templatetests/manifests_clusterresourceplacement_test.go create mode 100644 template/addons/kubefleet/clusterresourceplacement/clusterresourceplacement.yaml create mode 100644 template/addons/kubefleet/clusterresourceplacement/draft.yaml diff --git a/pkg/fixtures/manifests/clusterresourceplacement/pickall/clusterresourceplacement.yaml b/pkg/fixtures/manifests/clusterresourceplacement/pickall/clusterresourceplacement.yaml new file mode 100644 index 000000000..22cb59993 --- /dev/null +++ b/pkg/fixtures/manifests/clusterresourceplacement/pickall/clusterresourceplacement.yaml @@ -0,0 +1,16 @@ +apiVersion: placement.kubernetes-fleet.io/v1 +kind: ClusterResourcePlacement +metadata: + name: demo-crp + labels: + app.kubernetes.io/name: demo-crp + app.kubernetes.io/part-of: test-app-project + kubernetes.azure.com/generator: draft +spec: + resourceSelectors: + - group: "" + kind: Namespace + name: fmad-demo + version: v1 + policy: + placementType: PickAll \ No newline at end of file diff --git a/pkg/fixtures/manifests/clusterresourceplacement/pickfixed/clusterresourceplacement.yaml b/pkg/fixtures/manifests/clusterresourceplacement/pickfixed/clusterresourceplacement.yaml new file mode 100644 index 000000000..f863494c8 --- /dev/null +++ b/pkg/fixtures/manifests/clusterresourceplacement/pickfixed/clusterresourceplacement.yaml @@ -0,0 +1,19 @@ +apiVersion: placement.kubernetes-fleet.io/v1 +kind: ClusterResourcePlacement +metadata: + name: fmad-demo-crp + labels: + app.kubernetes.io/name: fmad-demo-crp + app.kubernetes.io/part-of: test-app-project + kubernetes.azure.com/generator: draft +spec: + resourceSelectors: + - group: "" + kind: Namespace + name: fmad-demo + version: v1 + policy: + placementType: PickFixed + clusterNames: + - cluster-name-01 + - cluster-name-02 \ No newline at end of file diff --git a/pkg/handlers/templatetests/manifests_clusterresourceplacement_test.go b/pkg/handlers/templatetests/manifests_clusterresourceplacement_test.go new file mode 100644 index 000000000..f80af5fc3 --- /dev/null +++ b/pkg/handlers/templatetests/manifests_clusterresourceplacement_test.go @@ -0,0 +1,46 @@ +package templatetests + +import ( + "testing" + + "github.com/Azure/draft/pkg/templatewriter/writers" +) + +func TestManifestsClusterResourcePlacementTemplates(t *testing.T) { + tests := []TestInput{ + { + Name: "valid clusterresourceplacement manifest with PickAll", + TemplateName: "clusterresourceplacement-manifests", + FixturesBaseDir: "../../fixtures/manifests/clusterresourceplacement/pickall", + Version: "0.0.1", + Dest: ".", + TemplateWriter: &writers.FileMapWriter{}, + VarMap: map[string]string{ + "CRP_NAME": "demo-crp", + "RESOURCE_SELECTOR_NAME": "fmad-demo", + "PLACEMENT_TYPE": "PickAll", + "PARTOF": "test-app-project", + }, + }, + { + Name: "valid clusterresourceplacement manifest with PickFixed", + TemplateName: "clusterresourceplacement-manifests", + FixturesBaseDir: "../../fixtures/manifests/clusterresourceplacement/pickfixed", + Version: "0.0.1", + Dest: ".", + TemplateWriter: &writers.FileMapWriter{}, + VarMap: map[string]string{ + "CRP_NAME": "fmad-demo-crp", + "RESOURCE_SELECTOR_NAME": "fmad-demo", + "PLACEMENT_TYPE": "PickFixed", + "CLUSTER_NAME_1": "cluster-name-01", + "CLUSTER_NAME_2": "cluster-name-02", + "PARTOF": "test-app-project", + }, + }, + } + + for _, test := range tests { + RunTemplateTest(t, test) + } +} \ No newline at end of file diff --git a/template/addons/kubefleet/clusterresourceplacement/clusterresourceplacement.yaml b/template/addons/kubefleet/clusterresourceplacement/clusterresourceplacement.yaml new file mode 100644 index 000000000..8ba8e0e83 --- /dev/null +++ b/template/addons/kubefleet/clusterresourceplacement/clusterresourceplacement.yaml @@ -0,0 +1,19 @@ +apiVersion: placement.kubernetes-fleet.io/v1 +kind: ClusterResourcePlacement +metadata: + name: {{ .Config.GetVariableValue "CRP_NAME" }} + labels: + app.kubernetes.io/name: {{ .Config.GetVariableValue "CRP_NAME" }} + app.kubernetes.io/part-of: {{ .Config.GetVariableValue "PARTOF" }} + kubernetes.azure.com/generator: {{ .Config.GetVariableValue "GENERATORLABEL" }} +spec: + resourceSelectors: + - group: "" + kind: Namespace + name: {{ .Config.GetVariableValue "RESOURCE_SELECTOR_NAME" }} + version: v1 + policy: + placementType: {{ .Config.GetVariableValue "PLACEMENT_TYPE" }}{{- if eq (.Config.GetVariableValue "PLACEMENT_TYPE") "PickFixed" }} + clusterNames:{{- if ne (.Config.GetVariableValue "CLUSTER_NAME_1") "" }} + - {{ .Config.GetVariableValue "CLUSTER_NAME_1" }}{{- end }}{{- if ne (.Config.GetVariableValue "CLUSTER_NAME_2") "" }} + - {{ .Config.GetVariableValue "CLUSTER_NAME_2" }}{{- end }}{{- end }} \ No newline at end of file diff --git a/template/addons/kubefleet/clusterresourceplacement/draft.yaml b/template/addons/kubefleet/clusterresourceplacement/draft.yaml new file mode 100644 index 000000000..6b032d1f0 --- /dev/null +++ b/template/addons/kubefleet/clusterresourceplacement/draft.yaml @@ -0,0 +1,62 @@ +templateName: "kubefleet-clusterresourceplacement" +description: "This template is used to create a Kubefleet ClusterResourcePlacement for managing resource placement across clusters" +versions: ["0.0.1"] +defaultVersion: "0.0.1" +type: "manifest" +variables: + - name: "CRP_NAME" + type: "string" + kind: "kubernetesResourceName" + description: "the name of the ClusterResourcePlacement" + versions: ">=0.0.1" + - name: "RESOURCE_SELECTOR_NAME" + type: "string" + kind: "kubernetesResourceName" + description: "the name of the resource to select for placement" + versions: ">=0.0.1" + - name: "PLACEMENT_TYPE" + type: "string" + kind: "label" + description: "the placement type for the policy (PickAll or PickFixed)" + versions: ">=0.0.1" + default: + value: "PickAll" + allowedValues: + - "PickAll" + - "PickFixed" + - name: "CLUSTER_NAME_1" + type: "string" + kind: "kubernetesResourceName" + description: "first cluster name for PickFixed placement type (optional)" + versions: ">=0.0.1" + default: + disablePrompt: true + value: "" + activeWhen: + - variableName: "PLACEMENT_TYPE" + value: "PickFixed" + condition: "equals" + - name: "CLUSTER_NAME_2" + type: "string" + kind: "kubernetesResourceName" + description: "second cluster name for PickFixed placement type (optional)" + versions: ">=0.0.1" + default: + disablePrompt: true + value: "" + activeWhen: + - variableName: "PLACEMENT_TYPE" + value: "PickFixed" + condition: "equals" + - name: "PARTOF" + type: "string" + kind: "label" + description: "the label to identify which project the resource belong to" + versions: ">=0.0.1" + - name: "GENERATORLABEL" + type: "string" + kind: "label" + description: "the label to identify who generated the resource" + versions: ">=0.0.1" + default: + value: "draft" \ No newline at end of file From 396368eb56083f104e7746721a0fd8d5ae0ce2cb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 27 Jun 2025 07:08:17 +0000 Subject: [PATCH 03/10] Implement Kubefleet ClusterResourcePlacement support and fix addon system Co-authored-by: sjwaight <4828246+sjwaight@users.noreply.github.com> --- cmd/update.go | 22 ++++++++++++------- ...manifests_clusterresourceplacement_test.go | 4 ++-- pkg/prompts/prompts.go | 18 +++++++-------- 3 files changed, 25 insertions(+), 19 deletions(-) diff --git a/cmd/update.go b/cmd/update.go index 1230ee55b..9f126301d 100644 --- a/cmd/update.go +++ b/cmd/update.go @@ -70,31 +70,37 @@ func (uc *updateCmd) run() error { return err } - ingressTemplate, err := handlers.GetTemplate("app-routing-ingress", "", updatedDest, uc.templateWriter) + // Use the specified addon template, default to app-routing-ingress for backward compatibility + templateName := "app-routing-ingress" + if uc.addon != "" { + templateName = uc.addon + } + + addonTemplate, err := handlers.GetTemplate(templateName, "", updatedDest, uc.templateWriter) if err != nil { - log.Errorf("error getting ingress template: %s", err.Error()) + log.Errorf("error getting addon template: %s", err.Error()) return err } - if ingressTemplate == nil { + if addonTemplate == nil { return errors.New("DraftConfig is nil") } - ingressTemplate.Config.VariableMapToDraftConfig(flagVariablesMap) + addonTemplate.Config.VariableMapToDraftConfig(flagVariablesMap) - err = cmdhelpers.PromptAddonValues(uc.dest, ingressTemplate.Config) + err = cmdhelpers.PromptAddonValues(uc.dest, addonTemplate.Config) if err != nil { return err } if dryRun { - for _, variable := range ingressTemplate.Config.Variables { + for _, variable := range addonTemplate.Config.Variables { uc.templateVariableRecorder.Record(variable.Name, variable.Value) } } - err = ingressTemplate.Generate() + err = addonTemplate.Generate() if err != nil { - log.Errorf("error generating ingress template: %s", err.Error()) + log.Errorf("error generating addon template: %s", err.Error()) return err } diff --git a/pkg/handlers/templatetests/manifests_clusterresourceplacement_test.go b/pkg/handlers/templatetests/manifests_clusterresourceplacement_test.go index f80af5fc3..dde29a7c0 100644 --- a/pkg/handlers/templatetests/manifests_clusterresourceplacement_test.go +++ b/pkg/handlers/templatetests/manifests_clusterresourceplacement_test.go @@ -10,7 +10,7 @@ func TestManifestsClusterResourcePlacementTemplates(t *testing.T) { tests := []TestInput{ { Name: "valid clusterresourceplacement manifest with PickAll", - TemplateName: "clusterresourceplacement-manifests", + TemplateName: "kubefleet-clusterresourceplacement", FixturesBaseDir: "../../fixtures/manifests/clusterresourceplacement/pickall", Version: "0.0.1", Dest: ".", @@ -24,7 +24,7 @@ func TestManifestsClusterResourcePlacementTemplates(t *testing.T) { }, { Name: "valid clusterresourceplacement manifest with PickFixed", - TemplateName: "clusterresourceplacement-manifests", + TemplateName: "kubefleet-clusterresourceplacement", FixturesBaseDir: "../../fixtures/manifests/clusterresourceplacement/pickfixed", Version: "0.0.1", Dest: ".", diff --git a/pkg/prompts/prompts.go b/pkg/prompts/prompts.go index c889b770a..91740dd9d 100644 --- a/pkg/prompts/prompts.go +++ b/pkg/prompts/prompts.go @@ -43,6 +43,15 @@ func RunPromptsFromConfigWithSkipsIO(draftConfig *config.DraftConfig, Stdin io.R continue } + isVarActive, err := draftConfig.CheckActiveWhenConstraint(variable) + if err != nil { + return fmt.Errorf("unable to check ActiveWhen constraint: %w", err) + } + + if !isVarActive { + continue + } + if variable.Default.IsPromptDisabled { log.Debugf("Skipping prompt for %s as it has IsPromptDisabled=true", variable.Name) noPromptDefaultValue := GetVariableDefaultValue(draftConfig, variable) @@ -54,15 +63,6 @@ func RunPromptsFromConfigWithSkipsIO(draftConfig *config.DraftConfig, Stdin io.R continue } - isVarActive, err := draftConfig.CheckActiveWhenConstraint(variable) - if err != nil { - return fmt.Errorf("unable to check ActiveWhen constraint: %w", err) - } - - if !isVarActive { - continue - } - log.Debugf("constructing prompt for: %s", variable.Name) if variable.Type == "bool" { input, err := RunBoolPrompt(variable, Stdin, Stdout) From b7a6e2c87f40ba22b12d3d6c6e8b3e8e01733d3d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 27 Jun 2025 07:09:07 +0000 Subject: [PATCH 04/10] Add documentation for Kubefleet ClusterResourcePlacement template Co-authored-by: sjwaight <4828246+sjwaight@users.noreply.github.com> --- docs/kubefleet-clusterresourceplacement.md | 122 +++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 docs/kubefleet-clusterresourceplacement.md diff --git a/docs/kubefleet-clusterresourceplacement.md b/docs/kubefleet-clusterresourceplacement.md new file mode 100644 index 000000000..7f7ed734e --- /dev/null +++ b/docs/kubefleet-clusterresourceplacement.md @@ -0,0 +1,122 @@ +# Kubefleet ClusterResourcePlacement Support + +Draft now supports generating Kubefleet ClusterResourcePlacement manifests through the `kubefleet-clusterresourceplacement` addon template. + +## Prerequisites + +1. Have an existing Draft project with deployment files (run `draft create` first) +2. Have the Draft CLI installed and built + +## Usage + +The ClusterResourcePlacement addon supports both PickAll and PickFixed placement types as described in the [Kubefleet documentation](https://fleet.azure.com/). + +### PickAll Placement Type + +For distributing resources to all matching clusters: + +```bash +draft update --addon kubefleet-clusterresourceplacement \ + --variable CRP_NAME=demo-crp \ + --variable RESOURCE_SELECTOR_NAME=fmad-demo \ + --variable PLACEMENT_TYPE=PickAll \ + --variable PARTOF=my-project +``` + +This generates: + +```yaml +apiVersion: placement.kubernetes-fleet.io/v1 +kind: ClusterResourcePlacement +metadata: + name: demo-crp + labels: + app.kubernetes.io/name: demo-crp + app.kubernetes.io/part-of: my-project + kubernetes.azure.com/generator: draft +spec: + resourceSelectors: + - group: "" + kind: Namespace + name: fmad-demo + version: v1 + policy: + placementType: PickAll +``` + +### PickFixed Placement Type + +For distributing resources to specific clusters: + +```bash +draft update --addon kubefleet-clusterresourceplacement \ + --variable CRP_NAME=fmad-demo-crp \ + --variable RESOURCE_SELECTOR_NAME=fmad-demo \ + --variable PLACEMENT_TYPE=PickFixed \ + --variable CLUSTER_NAME_1=cluster-name-01 \ + --variable CLUSTER_NAME_2=cluster-name-02 \ + --variable PARTOF=my-project +``` + +This generates: + +```yaml +apiVersion: placement.kubernetes-fleet.io/v1 +kind: ClusterResourcePlacement +metadata: + name: fmad-demo-crp + labels: + app.kubernetes.io/name: fmad-demo-crp + app.kubernetes.io/part-of: my-project + kubernetes.azure.com/generator: draft +spec: + resourceSelectors: + - group: "" + kind: Namespace + name: fmad-demo + version: v1 + policy: + placementType: PickFixed + clusterNames: + - cluster-name-01 + - cluster-name-02 +``` + +## Template Variables + +| Variable | Type | Description | Required | Default | +|----------|------|-------------|----------|---------| +| `CRP_NAME` | string | Name of the ClusterResourcePlacement | Yes | - | +| `RESOURCE_SELECTOR_NAME` | string | Name of the resource to select for placement | Yes | - | +| `PLACEMENT_TYPE` | string | Placement policy type (PickAll or PickFixed) | No | "PickAll" | +| `CLUSTER_NAME_1` | string | First cluster name (for PickFixed only) | No | "" | +| `CLUSTER_NAME_2` | string | Second cluster name (for PickFixed only) | No | "" | +| `PARTOF` | string | Label to identify which project the resource belongs to | Yes | - | +| `GENERATORLABEL` | string | Label to identify who generated the resource | No | "draft" | + +## Interactive Mode + +You can also run the command interactively without specifying all variables: + +```bash +draft update --addon kubefleet-clusterresourceplacement +``` + +Draft will prompt you for the required values. + +## Non-interactive Mode + +For automation and CI/CD pipelines, use `--interactive=false` and provide all required variables: + +```bash +draft update --addon kubefleet-clusterresourceplacement \ + --interactive=false \ + --variable CRP_NAME=my-crp \ + --variable RESOURCE_SELECTOR_NAME=my-namespace \ + --variable PLACEMENT_TYPE=PickAll \ + --variable PARTOF=my-project +``` + +## Output + +The generated ClusterResourcePlacement manifest will be created at `manifests/clusterresourceplacement.yaml` in your project directory. \ No newline at end of file From 82b02b7b166589ada53375c98d06492ee1d47215 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 27 Jun 2025 07:27:44 +0000 Subject: [PATCH 05/10] Replace CLUSTER_NAME_1 and CLUSTER_NAME_2 with single CLUSTER_NAMES variable - Replaced two separate cluster name variables with a single comma-separated list variable - Added custom template functions (split and trim) to parse comma-separated values - Updated template logic to handle dynamic list of cluster names - Updated documentation with three-cluster example as requested - All tests updated and passing Co-authored-by: sjwaight <4828246+sjwaight@users.noreply.github.com> --- docs/kubefleet-clusterresourceplacement.md | 54 +++++++++++++++++-- pkg/handlers/template.go | 15 +++++- ...manifests_clusterresourceplacement_test.go | 3 +- .../clusterresourceplacement.yaml | 7 ++- .../clusterresourceplacement/draft.yaml | 18 ++----- 5 files changed, 71 insertions(+), 26 deletions(-) diff --git a/docs/kubefleet-clusterresourceplacement.md b/docs/kubefleet-clusterresourceplacement.md index 7f7ed734e..8476eec1f 100644 --- a/docs/kubefleet-clusterresourceplacement.md +++ b/docs/kubefleet-clusterresourceplacement.md @@ -53,8 +53,7 @@ draft update --addon kubefleet-clusterresourceplacement \ --variable CRP_NAME=fmad-demo-crp \ --variable RESOURCE_SELECTOR_NAME=fmad-demo \ --variable PLACEMENT_TYPE=PickFixed \ - --variable CLUSTER_NAME_1=cluster-name-01 \ - --variable CLUSTER_NAME_2=cluster-name-02 \ + --variable CLUSTER_NAMES=cluster-name-01,cluster-name-02 \ --variable PARTOF=my-project ``` @@ -82,6 +81,42 @@ spec: - cluster-name-02 ``` +#### Example with Three Clusters + +```bash +draft update --addon kubefleet-clusterresourceplacement \ + --variable CRP_NAME=multi-cluster-demo \ + --variable RESOURCE_SELECTOR_NAME=demo-namespace \ + --variable PLACEMENT_TYPE=PickFixed \ + --variable CLUSTER_NAMES=cluster-east,cluster-west,cluster-central \ + --variable PARTOF=my-project +``` + +This generates: + +```yaml +apiVersion: placement.kubernetes-fleet.io/v1 +kind: ClusterResourcePlacement +metadata: + name: multi-cluster-demo + labels: + app.kubernetes.io/name: multi-cluster-demo + app.kubernetes.io/part-of: my-project + kubernetes.azure.com/generator: draft +spec: + resourceSelectors: + - group: "" + kind: Namespace + name: demo-namespace + version: v1 + policy: + placementType: PickFixed + clusterNames: + - cluster-east + - cluster-west + - cluster-central +``` + ## Template Variables | Variable | Type | Description | Required | Default | @@ -89,8 +124,7 @@ spec: | `CRP_NAME` | string | Name of the ClusterResourcePlacement | Yes | - | | `RESOURCE_SELECTOR_NAME` | string | Name of the resource to select for placement | Yes | - | | `PLACEMENT_TYPE` | string | Placement policy type (PickAll or PickFixed) | No | "PickAll" | -| `CLUSTER_NAME_1` | string | First cluster name (for PickFixed only) | No | "" | -| `CLUSTER_NAME_2` | string | Second cluster name (for PickFixed only) | No | "" | +| `CLUSTER_NAMES` | string | Comma-separated list of cluster names (for PickFixed only) | No | "" | | `PARTOF` | string | Label to identify which project the resource belongs to | Yes | - | | `GENERATORLABEL` | string | Label to identify who generated the resource | No | "draft" | @@ -109,6 +143,7 @@ Draft will prompt you for the required values. For automation and CI/CD pipelines, use `--interactive=false` and provide all required variables: ```bash +# PickAll example draft update --addon kubefleet-clusterresourceplacement \ --interactive=false \ --variable CRP_NAME=my-crp \ @@ -117,6 +152,17 @@ draft update --addon kubefleet-clusterresourceplacement \ --variable PARTOF=my-project ``` +```bash +# PickFixed example +draft update --addon kubefleet-clusterresourceplacement \ + --interactive=false \ + --variable CRP_NAME=my-fixed-crp \ + --variable RESOURCE_SELECTOR_NAME=my-namespace \ + --variable PLACEMENT_TYPE=PickFixed \ + --variable CLUSTER_NAMES=cluster1,cluster2,cluster3 \ + --variable PARTOF=my-project +``` + ## Output The generated ClusterResourcePlacement manifest will be created at `manifests/clusterresourceplacement.yaml` in your project directory. \ No newline at end of file diff --git a/pkg/handlers/template.go b/pkg/handlers/template.go index cf0472d40..f413678d6 100644 --- a/pkg/handlers/template.go +++ b/pkg/handlers/template.go @@ -166,8 +166,21 @@ func writeTemplate(draftTemplate *Template, inputFile string) error { return err } + // Define custom template functions + funcMap := tmpl.FuncMap{ + "split": func(delimiter, s string) []string { + if s == "" { + return []string{} + } + return strings.Split(s, delimiter) + }, + "trim": func(s string) string { + return strings.TrimSpace(s) + }, + } + // Parse the template file, missingkey=error ensures an error will be returned if any variable is missing during template execution. - tmpl, err := tmpl.New("template").Option("missingkey=error").Parse(string(file)) + tmpl, err := tmpl.New("template").Funcs(funcMap).Option("missingkey=error").Parse(string(file)) if err != nil { return err } diff --git a/pkg/handlers/templatetests/manifests_clusterresourceplacement_test.go b/pkg/handlers/templatetests/manifests_clusterresourceplacement_test.go index dde29a7c0..410a098ac 100644 --- a/pkg/handlers/templatetests/manifests_clusterresourceplacement_test.go +++ b/pkg/handlers/templatetests/manifests_clusterresourceplacement_test.go @@ -33,8 +33,7 @@ func TestManifestsClusterResourcePlacementTemplates(t *testing.T) { "CRP_NAME": "fmad-demo-crp", "RESOURCE_SELECTOR_NAME": "fmad-demo", "PLACEMENT_TYPE": "PickFixed", - "CLUSTER_NAME_1": "cluster-name-01", - "CLUSTER_NAME_2": "cluster-name-02", + "CLUSTER_NAMES": "cluster-name-01,cluster-name-02", "PARTOF": "test-app-project", }, }, diff --git a/template/addons/kubefleet/clusterresourceplacement/clusterresourceplacement.yaml b/template/addons/kubefleet/clusterresourceplacement/clusterresourceplacement.yaml index 8ba8e0e83..790eb60ac 100644 --- a/template/addons/kubefleet/clusterresourceplacement/clusterresourceplacement.yaml +++ b/template/addons/kubefleet/clusterresourceplacement/clusterresourceplacement.yaml @@ -13,7 +13,6 @@ spec: name: {{ .Config.GetVariableValue "RESOURCE_SELECTOR_NAME" }} version: v1 policy: - placementType: {{ .Config.GetVariableValue "PLACEMENT_TYPE" }}{{- if eq (.Config.GetVariableValue "PLACEMENT_TYPE") "PickFixed" }} - clusterNames:{{- if ne (.Config.GetVariableValue "CLUSTER_NAME_1") "" }} - - {{ .Config.GetVariableValue "CLUSTER_NAME_1" }}{{- end }}{{- if ne (.Config.GetVariableValue "CLUSTER_NAME_2") "" }} - - {{ .Config.GetVariableValue "CLUSTER_NAME_2" }}{{- end }}{{- end }} \ No newline at end of file + placementType: {{ .Config.GetVariableValue "PLACEMENT_TYPE" }}{{- if eq (.Config.GetVariableValue "PLACEMENT_TYPE") "PickFixed" }}{{- $clusterNames := .Config.GetVariableValue "CLUSTER_NAMES" }}{{- if ne $clusterNames "" }} + clusterNames:{{- range (split "," $clusterNames) }}{{- $cluster := . | trim }}{{- if ne $cluster "" }} + - {{ $cluster }}{{- end }}{{- end }}{{- end }}{{- end }} \ No newline at end of file diff --git a/template/addons/kubefleet/clusterresourceplacement/draft.yaml b/template/addons/kubefleet/clusterresourceplacement/draft.yaml index 6b032d1f0..7206a63ab 100644 --- a/template/addons/kubefleet/clusterresourceplacement/draft.yaml +++ b/template/addons/kubefleet/clusterresourceplacement/draft.yaml @@ -24,22 +24,10 @@ variables: allowedValues: - "PickAll" - "PickFixed" - - name: "CLUSTER_NAME_1" + - name: "CLUSTER_NAMES" type: "string" - kind: "kubernetesResourceName" - description: "first cluster name for PickFixed placement type (optional)" - versions: ">=0.0.1" - default: - disablePrompt: true - value: "" - activeWhen: - - variableName: "PLACEMENT_TYPE" - value: "PickFixed" - condition: "equals" - - name: "CLUSTER_NAME_2" - type: "string" - kind: "kubernetesResourceName" - description: "second cluster name for PickFixed placement type (optional)" + kind: "label" + description: "comma-separated list of cluster names for PickFixed placement type (optional)" versions: ">=0.0.1" default: disablePrompt: true From dd91762ae3fade98a96fe51eb4229098a589f9df Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 7 Jul 2025 00:04:43 +0000 Subject: [PATCH 06/10] Add new 'distribute' command for Kubefleet ClusterResourcePlacement Co-authored-by: sjwaight <4828246+sjwaight@users.noreply.github.com> --- cmd/distribute.go | 131 +++++++++++++++++++++ docs/kubefleet-clusterresourceplacement.md | 10 +- 2 files changed, 136 insertions(+), 5 deletions(-) create mode 100644 cmd/distribute.go diff --git a/cmd/distribute.go b/cmd/distribute.go new file mode 100644 index 000000000..58882ada3 --- /dev/null +++ b/cmd/distribute.go @@ -0,0 +1,131 @@ +package cmd + +import ( + "encoding/json" + "errors" + "fmt" + "os" + + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + + "github.com/Azure/draft/pkg/cmdhelpers" + "github.com/Azure/draft/pkg/config" + dryrunpkg "github.com/Azure/draft/pkg/dryrun" + "github.com/Azure/draft/pkg/handlers" + "github.com/Azure/draft/pkg/templatewriter" + "github.com/Azure/draft/pkg/templatewriter/writers" +) + +type distributeCmd struct { + dest string + provider string + addon string + flagVariables []string + templateWriter templatewriter.TemplateWriter + templateVariableRecorder config.TemplateVariableRecorder +} + +var distributeDryRunRecorder *dryrunpkg.DryRunRecorder + +func newDistributeCmd() *cobra.Command { + dc := &distributeCmd{} + // distributeCmd represents the distribute command + var cmd = &cobra.Command{ + Use: "distribute", + Short: "Distributes your application resources across Kubernetes clusters using Kubefleet", + Long: `This command generates Kubefleet ClusterResourcePlacement manifests to distribute your application + resources across multiple Kubernetes clusters managed by Kubefleet.`, + RunE: func(cmd *cobra.Command, args []string) error { + if err := dc.run(); err != nil { + return err + } + log.Info("Draft has successfully created your Kubefleet ClusterResourcePlacement manifest for resource distribution 😃") + return nil + }, + } + f := cmd.Flags() + f.StringVarP(&dc.dest, "destination", "d", ".", "specify the path to the project directory") + f.StringVarP(&dc.provider, "provider", "p", "azure", "cloud provider") + f.StringVarP(&dc.addon, "addon", "a", "kubefleet-clusterresourceplacement", "kubefleet addon name") + f.StringArrayVarP(&dc.flagVariables, "variable", "", []string{}, "pass template variables (e.g. --variable CRP_NAME=demo-crp --variable PLACEMENT_TYPE=PickAll)") + + dc.templateWriter = &writers.LocalFSWriter{} + + return cmd +} + +func (dc *distributeCmd) run() error { + flagVariablesMap = flagVariablesToMap(dc.flagVariables) + + if dryRun { + distributeDryRunRecorder = dryrunpkg.NewDryRunRecorder() + dc.templateVariableRecorder = distributeDryRunRecorder + dc.templateWriter = distributeDryRunRecorder + } + + updatedDest, err := cmdhelpers.GetAddonDestPath(dc.dest) + if err != nil { + log.Errorf("error getting addon destination path: %s", err.Error()) + return err + } + + // Default to kubefleet-clusterresourceplacement addon, but allow other kubefleet addons + templateName := "kubefleet-clusterresourceplacement" + if dc.addon != "" { + templateName = dc.addon + } + + // Validate that the addon is a kubefleet addon + if templateName != "kubefleet-clusterresourceplacement" { + return fmt.Errorf("distribute command only supports kubefleet addons, got: %s", templateName) + } + + addonTemplate, err := handlers.GetTemplate(templateName, "", updatedDest, dc.templateWriter) + if err != nil { + log.Errorf("error getting kubefleet addon template: %s", err.Error()) + return err + } + if addonTemplate == nil { + return errors.New("DraftConfig is nil") + } + + addonTemplate.Config.VariableMapToDraftConfig(flagVariablesMap) + + err = cmdhelpers.PromptAddonValues(dc.dest, addonTemplate.Config) + if err != nil { + return err + } + + if dryRun { + for _, variable := range addonTemplate.Config.Variables { + dc.templateVariableRecorder.Record(variable.Name, variable.Value) + } + } + + err = addonTemplate.Generate() + if err != nil { + log.Errorf("error generating kubefleet addon template: %s", err.Error()) + return err + } + + if dryRun { + dryRunText, err := json.MarshalIndent(distributeDryRunRecorder.DryRunInfo, "", TWO_SPACES) + if err != nil { + return err + } + fmt.Println(string(dryRunText)) + if dryRunFile != "" { + log.Printf("writing dry run info to file %s", dryRunFile) + err = os.WriteFile(dryRunFile, dryRunText, 0644) + if err != nil { + return err + } + } + } + return err +} + +func init() { + rootCmd.AddCommand(newDistributeCmd()) +} \ No newline at end of file diff --git a/docs/kubefleet-clusterresourceplacement.md b/docs/kubefleet-clusterresourceplacement.md index 8476eec1f..e9d278d53 100644 --- a/docs/kubefleet-clusterresourceplacement.md +++ b/docs/kubefleet-clusterresourceplacement.md @@ -16,7 +16,7 @@ The ClusterResourcePlacement addon supports both PickAll and PickFixed placement For distributing resources to all matching clusters: ```bash -draft update --addon kubefleet-clusterresourceplacement \ +draft distribute \ --variable CRP_NAME=demo-crp \ --variable RESOURCE_SELECTOR_NAME=fmad-demo \ --variable PLACEMENT_TYPE=PickAll \ @@ -49,7 +49,7 @@ spec: For distributing resources to specific clusters: ```bash -draft update --addon kubefleet-clusterresourceplacement \ +draft distribute \ --variable CRP_NAME=fmad-demo-crp \ --variable RESOURCE_SELECTOR_NAME=fmad-demo \ --variable PLACEMENT_TYPE=PickFixed \ @@ -84,7 +84,7 @@ spec: #### Example with Three Clusters ```bash -draft update --addon kubefleet-clusterresourceplacement \ +draft distribute \ --variable CRP_NAME=multi-cluster-demo \ --variable RESOURCE_SELECTOR_NAME=demo-namespace \ --variable PLACEMENT_TYPE=PickFixed \ @@ -144,7 +144,7 @@ For automation and CI/CD pipelines, use `--interactive=false` and provide all re ```bash # PickAll example -draft update --addon kubefleet-clusterresourceplacement \ +draft distribute \ --interactive=false \ --variable CRP_NAME=my-crp \ --variable RESOURCE_SELECTOR_NAME=my-namespace \ @@ -154,7 +154,7 @@ draft update --addon kubefleet-clusterresourceplacement \ ```bash # PickFixed example -draft update --addon kubefleet-clusterresourceplacement \ +draft distribute \ --interactive=false \ --variable CRP_NAME=my-fixed-crp \ --variable RESOURCE_SELECTOR_NAME=my-namespace \ From dd5d2e444846ab9f390f358c2d49a1660589fbdc Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 7 Jul 2025 00:21:30 +0000 Subject: [PATCH 07/10] Add ClusterResourcePlacement example files for Kubefleet template Co-authored-by: sjwaight <4828246+sjwaight@users.noreply.github.com> --- example/clusterresourceplacement.go | 66 ++++++++++++++++++++++++ example/clusterresourceplacement_test.go | 13 +++++ 2 files changed, 79 insertions(+) create mode 100644 example/clusterresourceplacement.go create mode 100644 example/clusterresourceplacement_test.go diff --git a/example/clusterresourceplacement.go b/example/clusterresourceplacement.go new file mode 100644 index 000000000..9d27f2dfe --- /dev/null +++ b/example/clusterresourceplacement.go @@ -0,0 +1,66 @@ +package example + +import ( + "fmt" + + "github.com/Azure/draft/pkg/handlers" + "github.com/Azure/draft/pkg/templatewriter/writers" +) + +// WriteClusterResourcePlacementFilesExample shows how to set up a fileWriter and generate a fileMap using WriteClusterResourcePlacementFiles for Kubefleet +func WriteClusterResourcePlacementFilesExample() error { + // Create a file map + fileMap := make(map[string][]byte) + + // Create a template writer that writes to the file map + w := writers.FileMapWriter{ + FileMap: fileMap, + } + + // Select the kubefleet addon template type + templateType := "kubefleet-clusterresourceplacement" + + // Create a map of inputs to the template (must correspond to the inputs in the template/addons/kubefleet/clusterresourceplacement/draft.yaml file) + templateVars := map[string]string{ + "CRP_NAME": "example-crp", + "RESOURCE_SELECTOR_NAME": "example-namespace", + "PLACEMENT_TYPE": "PickFixed", + "CLUSTER_NAMES": "cluster-01,cluster-02,cluster-03", + "PARTOF": "example-project", + "GENERATORLABEL": "draft", + } + + // Set the output path for the ClusterResourcePlacement files + outputPath := "./" + + // Get the kubefleet template + template, err := handlers.GetTemplate(templateType, "", outputPath, &w) + if err != nil { + return fmt.Errorf("failed to get template: %e", err) + } + if template == nil { + return fmt.Errorf("template is nil") + } + + // Set the variable values within the template + for k, v := range templateVars { + template.Config.SetVariable(k, v) + } + + // Generate the ClusterResourcePlacement files + err = template.Generate() + if err != nil { + return fmt.Errorf("failed to generate manifest: %e", err) + } + + // Read written files from the file map + fmt.Printf("Files written in WriteClusterResourcePlacementFilesExample:\n") + for filePath, fileContents := range fileMap { + if fileContents == nil { + return fmt.Errorf("file contents for %s is nil", filePath) + } + fmt.Printf(" %s\n", filePath) // Print the file path + } + + return nil +} \ No newline at end of file diff --git a/example/clusterresourceplacement_test.go b/example/clusterresourceplacement_test.go new file mode 100644 index 000000000..0a674980b --- /dev/null +++ b/example/clusterresourceplacement_test.go @@ -0,0 +1,13 @@ +package example + +import ( + "testing" +) + +func TestWriteClusterResourcePlacementFilesExample(t *testing.T) { + err := WriteClusterResourcePlacementFilesExample() + if err != nil { + t.Errorf("WriteClusterResourcePlacementFilesExample failed: %e", err) + t.Fail() + } +} \ No newline at end of file From 9e45982d64077806241b231662a465a346153ad3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 7 Jul 2025 00:28:59 +0000 Subject: [PATCH 08/10] Update README.md with distribute command and correct Contoso Air URL Co-authored-by: sjwaight <4828246+sjwaight@users.noreply.github.com> --- README.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1027abdba..fd328b154 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ Draft is a tool made for users who are just getting started with Kubernetes or w ### `draft create` -In our directory that holds our application, we can run the CLI command ‘draft create’. Draft create will walk you through a series of questions prompting you on your application specification. At the end of it, you will have a Dockerfile as well as Kubernetes manifests to deploy your application. Below is a picture of running the Draft create command on our [Contoso Air repository](https://github.com/microsoft/ContosoAir). +In our directory that holds our application, we can run the CLI command ‘draft create’. Draft create will walk you through a series of questions prompting you on your application specification. At the end of it, you will have a Dockerfile as well as Kubernetes manifests to deploy your application. Below is a picture of running the Draft create command on our [Contoso Air repository](https://github.com/Azure-Samples/contoso-air). ![example of draft create command showing the prompt "select k8s deployment type" with three options "helm", "kustomize", and "manifests"](./ghAssets/draft-create.png) @@ -71,6 +71,15 @@ Draft validate scans your manifests and populates warnings messages in your code ![screenshot of draft-validate](./ghAssets/draft-validate.png) +### `draft distribute` + +The `draft distribute` command generates Kubefleet ClusterResourcePlacement manifests to distribute your application resources across multiple Kubernetes clusters managed by Kubefleet. This command is specifically designed for multi-cluster resource placement scenarios. + +Example usage: +```bash +draft distribute --variable CRP_NAME=demo-crp --variable RESOURCE_SELECTOR_NAME=fmad-demo --variable PLACEMENT_TYPE=PickAll --variable PARTOF=my-project +``` + ### `draft info` The `draft info` command prints information about supported languages and deployment types. @@ -110,6 +119,7 @@ Draft makes it easier for developers to get started building apps that run on Ku - `draft setup-gh` automates the GitHub OIDC setup process for your project. - `draft generate-workflow` generates a GitHub Actions workflow for automatic build and deploy to a Kubernetes cluster. - `draft update` automatically make your application to be internet accessible. +- `draft distribute` distributes your application resources across Kubernetes clusters using Kubefleet ClusterResourcePlacement manifests. - `draft validate` scan your manifests to see if they are following Kubernetes best practices. - `draft info` print supported language and field information in json format. From 0b481668c64f7b7de5d0c76fd0fd5d28c3e5717e Mon Sep 17 00:00:00 2001 From: Simon Waight Date: Mon, 7 Jul 2025 10:51:57 +1000 Subject: [PATCH 09/10] Updated readme.md to fix a few items. --- README.md | 48 +++++++++++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index fd328b154..0881acec7 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ ![Draft logo](./ghAssets/Draft-Gradient@3x.png) +

@@ -21,6 +22,7 @@
## Installation + ### Homebrew 1. Run the following commands @@ -76,15 +78,21 @@ Draft validate scans your manifests and populates warnings messages in your code The `draft distribute` command generates Kubefleet ClusterResourcePlacement manifests to distribute your application resources across multiple Kubernetes clusters managed by Kubefleet. This command is specifically designed for multi-cluster resource placement scenarios. Example usage: + ```bash -draft distribute --variable CRP_NAME=demo-crp --variable RESOURCE_SELECTOR_NAME=fmad-demo --variable PLACEMENT_TYPE=PickAll --variable PARTOF=my-project +draft distribute --variable CRP_NAME=demo-crp \ + --variable RESOURCE_SELECTOR_NAME=demo-namespace \ + --variable PLACEMENT_TYPE=PickAll \ + --variable PARTOF=my-project ``` ### `draft info` + The `draft info` command prints information about supported languages and deployment types. Example output (for brevity, only the first supported language is shown): -``` + +```json { "supportedLanguages": [ { @@ -106,6 +114,7 @@ Example output (for brevity, only the first supported language is shown): ] } ``` + ## About The Project @@ -114,21 +123,23 @@ Draft makes it easier for developers to get started building apps that run on Ku ### Commands -- `draft create` adds the minimum required Dockerfile and manifest files for your deployment to the project directory. - - Supported deployment types: Helm, Kustomize, Kubernetes manifest. -- `draft setup-gh` automates the GitHub OIDC setup process for your project. -- `draft generate-workflow` generates a GitHub Actions workflow for automatic build and deploy to a Kubernetes cluster. -- `draft update` automatically make your application to be internet accessible. -- `draft distribute` distributes your application resources across Kubernetes clusters using Kubefleet ClusterResourcePlacement manifests. -- `draft validate` scan your manifests to see if they are following Kubernetes best practices. -- `draft info` print supported language and field information in json format. +* `draft create` adds the minimum required Dockerfile and manifest files for your deployment to the project directory. + * Supported deployment types: Helm, Kustomize, Kubernetes manifest. +* `draft setup-gh` automates the GitHub OIDC setup process for your project. +* `draft generate-workflow` generates a GitHub Actions workflow for automatic build and deploy to a Kubernetes cluster. +* `draft update` automatically make your application to be internet accessible. +* `draft distribute` distributes your application resources across Kubernetes clusters using Kubefleet ClusterResourcePlacement manifests. +* `draft validate` scan your manifests to see if they are following Kubernetes best practices. +* `draft info` print supported language and field information in json format. Use `draft [command] --help` for more information about a command. ### Dry Run + The following flags can be used for enabling dry running, which is currently supported by the following commands: `create` -- ` --dry-run` enables dry run mode in which no files are written to disk -- `--dry-run-file` specifies a file to write the dry run summary in json format into + +* `--dry-run` enables dry run mode in which no files are written to disk +* `--dry-run-file` specifies a file to write the dry run summary in json format into ```json // Example dry run output @@ -156,6 +167,7 @@ The following flags can be used for enabling dry running, which is currently sup ] } ``` + ## Install from Source ### Prerequisites @@ -187,12 +199,12 @@ go version mv draft $HOME/go/bin/ ``` - ## Draft as a Dependency If you are looking to leverage Draft's file generation capabilities and templating within another project instead of using the CLI, you have two options: importing the Draft go packages, and wrapping the binary ### Importing Draft Go Packages + This option will provide the cleanest integration, as it directly builds Draft into your project. However, it requires that your project is written in Go. Dockerfiles can be generated following the example in [examples/dockerfile.go](https://github.com/Azure/draft/blob/main/example/dockerfile.go) @@ -200,13 +212,15 @@ Dockerfiles can be generated following the example in [examples/dockerfile.go](h Deployment files can be generated following the example in [examples/deployment.go](https://github.com/Azure/draft/blob/main/example/deployment.go) ### Wrapping the Binary + For projects written in languages other than Go, or for projects that prefer to not import the packages directly, you can wrap the Draft binary. Several features have been implemented to make consuming draft as easy as possible: -- `draft info` prints supported language and field information in json format for easy parsing -- `--dry-run` and `--dry-run-file` flags can be used on the `create` and `update` commands to generate a summary of the files that would be written to disk, and the variables that would be used in the templates -- `draft update` and `draft create` accept a repeatable `--variable` flag that can be used to set template variables -- `draft create` takes a `--create-config` flag that can be used to input variables through a yaml file instead of interactively + +* `draft info` prints supported language and field information in json format for easy parsing +* `--dry-run` and `--dry-run-file` flags can be used on the `create`, `update` and `ditribute` commands to generate a summary of the files that would be written to disk, and the variables that would be used in the templates +* `draft update`, `draft create` and `draft distribute` accept a repeatable `--variable` flag that can be used to set template variables +* `draft create` takes a `--create-config` flag that can be used to input variables through a yaml file instead of interactively ## Introduction Videos From 9c2453d8424e336da0fbdcc558cdb6421dc95358 Mon Sep 17 00:00:00 2001 From: Simon Waight Date: Mon, 7 Jul 2025 11:19:35 +1000 Subject: [PATCH 10/10] Update docs. --- README.md | 4 +- docs/kubefleet-clusterresourceplacement.md | 53 ++++------------------ 2 files changed, 12 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index 0881acec7..b85752cb1 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ Draft validate scans your manifests and populates warnings messages in your code ### `draft distribute` -The `draft distribute` command generates Kubefleet ClusterResourcePlacement manifests to distribute your application resources across multiple Kubernetes clusters managed by Kubefleet. This command is specifically designed for multi-cluster resource placement scenarios. +The `draft distribute` command generates [KubeFleet](https://kubefleet.dev) ClusterResourcePlacement manifests to distribute your application resources across multiple Kubernetes clusters managed by KubeFleet. This command is specifically designed for multi-cluster resource placement scenarios and requires existing files created using `draft create`. [Read the documentation for this command](docs/kubefleet-clusterresourceplacement.md) for more details. Example usage: @@ -128,7 +128,7 @@ Draft makes it easier for developers to get started building apps that run on Ku * `draft setup-gh` automates the GitHub OIDC setup process for your project. * `draft generate-workflow` generates a GitHub Actions workflow for automatic build and deploy to a Kubernetes cluster. * `draft update` automatically make your application to be internet accessible. -* `draft distribute` distributes your application resources across Kubernetes clusters using Kubefleet ClusterResourcePlacement manifests. +* `draft distribute` distributes your application resources across Kubernetes clusters using [KubeFleet](https://kubefleet.dev/) ClusterResourcePlacement manifests. * `draft validate` scan your manifests to see if they are following Kubernetes best practices. * `draft info` print supported language and field information in json format. diff --git a/docs/kubefleet-clusterresourceplacement.md b/docs/kubefleet-clusterresourceplacement.md index e9d278d53..c0dd89507 100644 --- a/docs/kubefleet-clusterresourceplacement.md +++ b/docs/kubefleet-clusterresourceplacement.md @@ -1,6 +1,6 @@ -# Kubefleet ClusterResourcePlacement Support +# KubeFleet ClusterResourcePlacement Support -Draft now supports generating Kubefleet ClusterResourcePlacement manifests through the `kubefleet-clusterresourceplacement` addon template. +Draft now supports generating KubeFleet ClusterResourcePlacement manifests through the `kubefleet-clusterresourceplacement` addon template. ## Prerequisites @@ -9,7 +9,7 @@ Draft now supports generating Kubefleet ClusterResourcePlacement manifests throu ## Usage -The ClusterResourcePlacement addon supports both PickAll and PickFixed placement types as described in the [Kubefleet documentation](https://fleet.azure.com/). +The ClusterResourcePlacement addon supports both PickAll and PickFixed placement types as described in the [KubeFleet documentation](https://kubefleet.dev/docs/concepts/crp/). ### PickAll Placement Type @@ -18,7 +18,7 @@ For distributing resources to all matching clusters: ```bash draft distribute \ --variable CRP_NAME=demo-crp \ - --variable RESOURCE_SELECTOR_NAME=fmad-demo \ + --variable RESOURCE_SELECTOR_NAME=ns-demo \ --variable PLACEMENT_TYPE=PickAll \ --variable PARTOF=my-project ``` @@ -38,7 +38,7 @@ spec: resourceSelectors: - group: "" kind: Namespace - name: fmad-demo + name: ns-demo version: v1 policy: placementType: PickAll @@ -50,7 +50,7 @@ For distributing resources to specific clusters: ```bash draft distribute \ - --variable CRP_NAME=fmad-demo-crp \ + --variable CRP_NAME=ns-demo-crp \ --variable RESOURCE_SELECTOR_NAME=fmad-demo \ --variable PLACEMENT_TYPE=PickFixed \ --variable CLUSTER_NAMES=cluster-name-01,cluster-name-02 \ @@ -63,16 +63,16 @@ This generates: apiVersion: placement.kubernetes-fleet.io/v1 kind: ClusterResourcePlacement metadata: - name: fmad-demo-crp + name: ns-demo-crp labels: - app.kubernetes.io/name: fmad-demo-crp + app.kubernetes.io/name: ns-demo-crp app.kubernetes.io/part-of: my-project kubernetes.azure.com/generator: draft spec: resourceSelectors: - group: "" kind: Namespace - name: fmad-demo + name: ns-demo version: v1 policy: placementType: PickFixed @@ -128,41 +128,8 @@ spec: | `PARTOF` | string | Label to identify which project the resource belongs to | Yes | - | | `GENERATORLABEL` | string | Label to identify who generated the resource | No | "draft" | -## Interactive Mode - -You can also run the command interactively without specifying all variables: - -```bash -draft update --addon kubefleet-clusterresourceplacement -``` - Draft will prompt you for the required values. -## Non-interactive Mode - -For automation and CI/CD pipelines, use `--interactive=false` and provide all required variables: - -```bash -# PickAll example -draft distribute \ - --interactive=false \ - --variable CRP_NAME=my-crp \ - --variable RESOURCE_SELECTOR_NAME=my-namespace \ - --variable PLACEMENT_TYPE=PickAll \ - --variable PARTOF=my-project -``` - -```bash -# PickFixed example -draft distribute \ - --interactive=false \ - --variable CRP_NAME=my-fixed-crp \ - --variable RESOURCE_SELECTOR_NAME=my-namespace \ - --variable PLACEMENT_TYPE=PickFixed \ - --variable CLUSTER_NAMES=cluster1,cluster2,cluster3 \ - --variable PARTOF=my-project -``` - ## Output -The generated ClusterResourcePlacement manifest will be created at `manifests/clusterresourceplacement.yaml` in your project directory. \ No newline at end of file +The generated ClusterResourcePlacement manifest will be created at `manifests/clusterresourceplacement.yaml` in your project directory.