diff --git a/Makefile b/Makefile index 516b859531..600ab9a021 100644 --- a/Makefile +++ b/Makefile @@ -223,7 +223,7 @@ help: # Display this help .PHONY: generate generate: ## Run all generate targets - $(MAKE) generate-modules generate-manifests generate-go-deepcopy generate-go-conversions + $(MAKE) generate-modules generate-manifests generate-go-deepcopy generate-go-conversions generate-flavors .PHONY: generate-manifests generate-manifests: $(CONTROLLER_GEN) ## Generate manifests e.g. CRD, RBAC etc. @@ -335,7 +335,7 @@ APIDIFF_OLD_COMMIT ?= $(shell git rev-parse origin/main) apidiff: $(GO_APIDIFF) ## Check for API differences $(GO_APIDIFF) $(APIDIFF_OLD_COMMIT) --print-compatible -ALL_VERIFY_CHECKS = boilerplate modules gen conversions +ALL_VERIFY_CHECKS = boilerplate modules gen conversions flavor .PHONY: verify verify: $(addprefix verify-,$(ALL_VERIFY_CHECKS)) lint-markdown lint-shell ## Run all verify-* targets @@ -561,12 +561,15 @@ dev-flavors: $(OVERRIDES_DIR) .PHONY: generate-flavors generate-flavors: $(FLAVOR_DIR) - go run ./packaging/flavorgen -f vip > $(FLAVOR_DIR)/cluster-template.yaml - go run ./packaging/flavorgen -f external-loadbalancer > $(FLAVOR_DIR)/cluster-template-external-loadbalancer.yaml - go run ./packaging/flavorgen -f cluster-class > $(FLAVOR_DIR)/clusterclass-template.yaml - go run ./packaging/flavorgen -f cluster-topology > $(FLAVOR_DIR)/cluster-template-topology.yaml - go run ./packaging/flavorgen -f ignition > $(FLAVOR_DIR)/cluster-template-ignition.yaml - go run ./packaging/flavorgen -f node-ipam > $(FLAVOR_DIR)/cluster-template-node-ipam.yaml + go run ./packaging/flavorgen --output-dir $(FLAVOR_DIR) + +.PHONY: verify-flavors +verify-flavors: $(FLAVOR_DIR) + go run ./packaging/flavorgen --output-dir $(FLAVOR_DIR) + @if !(git diff --quiet HEAD -- templates); then \ + git diff; \ + echo "flavor files in templates directory are out of date"; exit 1; \ + fi .PHONY: release-staging release-staging: ## Build and push container images to the staging registry diff --git a/packaging/flavorgen/cmd/root.go b/packaging/flavorgen/cmd/root.go index a327b91627..478d326adf 100644 --- a/packaging/flavorgen/cmd/root.go +++ b/packaging/flavorgen/cmd/root.go @@ -17,10 +17,13 @@ limitations under the License. package cmd import ( + "fmt" "os" + "path/filepath" "github.com/pkg/errors" "github.com/spf13/cobra" + "k8s.io/apimachinery/pkg/runtime" "sigs.k8s.io/cluster-api-provider-vsphere/packaging/flavorgen/flavors" "sigs.k8s.io/cluster-api-provider-vsphere/packaging/flavorgen/flavors/env" @@ -28,6 +31,28 @@ import ( ) const flavorFlag = "flavor" +const outputDirFlag = "output-dir" + +var ( + flavorMappings = map[string]string{ + flavors.VIP: "cluster-template", + flavors.ExternalLoadBalancer: "cluster-template-external-loadbalancer", + flavors.ClusterClass: "clusterclass-template", + flavors.ClusterTopology: "cluster-template-topology", + flavors.Ignition: "cluster-template-ignition", + flavors.NodeIPAM: "cluster-template-node-ipam", + } + + allFlavors = []string{ + flavors.VIP, + flavors.ExternalLoadBalancer, + flavors.ClusterClass, + flavors.Ignition, + flavors.NodeIPAM, + // keep the ClusterTopology the last one + flavors.ClusterTopology, + } +) func RootCmd() *cobra.Command { rootCmd := &cobra.Command{ @@ -36,8 +61,11 @@ func RootCmd() *cobra.Command { RunE: func(command *cobra.Command, args []string) error { return RunRoot(command) }, + SilenceUsage: true, } rootCmd.Flags().StringP(flavorFlag, "f", "", "Name of flavor to compile") + rootCmd.Flags().StringP(outputDirFlag, "o", "", "Directory to store the generated flavor template") + return rootCmd } @@ -52,13 +80,50 @@ func RunRoot(command *cobra.Command) error { if err != nil { return errors.Wrapf(err, "error accessing flag %s for command %s", flavorFlag, command.Name()) } + outputDir, err := command.Flags().GetString(outputDirFlag) + if err != nil { + return errors.Wrapf(err, "error accessing flag %s for command %s", outputDirFlag, command.Name()) + } + var flavors []string + if flavor != "" { + flavors = append(flavors, flavor) + } else { + flavors = allFlavors + } + generateMultiFlavors := len(flavors) > 1 + for _, f := range flavors { + objs, err := generateSingle(f) + if err != nil { + return err + } + + yamlFileName := flavorMappings[f] + ".yaml" + if outputDir == "" { + if generateMultiFlavors { + fmt.Printf(fmt.Sprintf("### %s\n", yamlFileName)) + } + util.PrintObjects(objs) + continue + } + + yamlPath := filepath.Join(outputDir, yamlFileName) + err = util.DumpObjectsToFile(objs, yamlPath) + if err != nil { + return errors.Wrapf(err, "failed to dump manifest content to file for flavor %s", f) + } + } + + return nil +} + +func generateSingle(flavor string) ([]runtime.Object, error) { switch flavor { case flavors.VIP: - util.PrintObjects(flavors.MultiNodeTemplateWithKubeVIP()) + return flavors.MultiNodeTemplateWithKubeVIP(), nil case flavors.ExternalLoadBalancer: - util.PrintObjects(flavors.MultiNodeTemplateWithExternalLoadBalancer()) + return flavors.MultiNodeTemplateWithExternalLoadBalancer(), nil case flavors.ClusterClass: - util.PrintObjects(flavors.ClusterClassTemplateWithKubeVIP()) + return flavors.ClusterClassTemplateWithKubeVIP(), nil case flavors.ClusterTopology: additionalReplacements := []util.Replacement{ { @@ -69,13 +134,12 @@ func RunRoot(command *cobra.Command) error { }, } util.Replacements = append(util.Replacements, additionalReplacements...) - util.PrintObjects(flavors.ClusterTopologyTemplateKubeVIP()) + return flavors.ClusterTopologyTemplateKubeVIP(), nil case flavors.Ignition: - util.PrintObjects(flavors.MultiNodeTemplateWithKubeVIPIgnition()) + return flavors.MultiNodeTemplateWithKubeVIPIgnition(), nil case flavors.NodeIPAM: - util.PrintObjects(flavors.MultiNodeTemplateWithKubeVIPNodeIPAM()) + return flavors.MultiNodeTemplateWithKubeVIPNodeIPAM(), nil default: - return errors.Errorf("invalid flavor") + return nil, errors.Errorf("invalid flavor") } - return nil } diff --git a/packaging/flavorgen/flavors/util/helpers.go b/packaging/flavorgen/flavors/util/helpers.go index 3ed2f5d7bf..b931255baa 100644 --- a/packaging/flavorgen/flavors/util/helpers.go +++ b/packaging/flavorgen/flavors/util/helpers.go @@ -18,6 +18,7 @@ package util import ( "fmt" + "os" "reflect" "regexp" "strings" @@ -192,10 +193,12 @@ func GenerateManifestYaml(objs []runtime.Object) string { } func PrintObjects(objs []runtime.Object) { - for _, o := range objs { - o := o - fmt.Printf("---\n%s", GenerateObjectYAML(o, Replacements)) //nolint:forbidigo - } + fmt.Print(GenerateManifestYaml(objs)) +} + +func DumpObjectsToFile(objs []runtime.Object, path string) error { + manifest := GenerateManifestYaml(objs) + return os.WriteFile(path, []byte(manifest), 0644) } func TypeToKind(i interface{}) string {