operator/cmd/cluster/manifest.go (124 lines of code) (raw):

/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package cluster import ( "cmp" "fmt" "github.com/apache/dubbo-kubernetes/dubboctl/pkg/cli" "github.com/apache/dubbo-kubernetes/operator/pkg/manifest" "github.com/apache/dubbo-kubernetes/operator/pkg/render" "github.com/apache/dubbo-kubernetes/operator/pkg/util/clog" "github.com/apache/dubbo-kubernetes/pkg/kube" "github.com/apache/dubbo-kubernetes/pkg/util/slices" "github.com/spf13/cobra" "sigs.k8s.io/yaml" "strings" ) type manifestGenerateArgs struct { // filenames is an array of paths to input DubboOperator CR files. // filenames []string // sets is a string with the format "path=value". sets []string } func (a *manifestGenerateArgs) String() string { var b strings.Builder // b.WriteString("filenames: " + fmt.Sprint(a.filenames) + "\n") b.WriteString("sets: " + fmt.Sprint(a.sets) + "\n") return b.String() } func addManifestGenerateFlags(cmd *cobra.Command, args *manifestGenerateArgs) { // cmd.PersistentFlags().StringSliceVarP(&args.filenames, "filenames", "f", nil, ``) cmd.PersistentFlags().StringArrayVarP(&args.sets, "set", "s", nil, `Override dubboOperator values, such as selecting profiles, etc.`) } func ManifestCmd(ctx cli.Context) *cobra.Command { rootArgs := &RootArgs{} mgcArgs := &manifestGenerateArgs{} mgc := manifestGenerateCmd(ctx, rootArgs, mgcArgs) mc := &cobra.Command{ Use: "manifest", Short: "dubbo manifest related commands", Long: "The manifest command will generates dubbo manifests.", } AddFlags(mc, rootArgs) AddFlags(mgc, rootArgs) addManifestGenerateFlags(mgc, mgcArgs) mc.AddCommand(mgc) return mc } var kubeClientFunc func() (kube.CLIClient, error) func manifestGenerateCmd(ctx cli.Context, _ *RootArgs, mgArgs *manifestGenerateArgs) *cobra.Command { return &cobra.Command{ Use: "generate", Short: "Generates an Dubbo install manifest", Long: "The generate subcommand generates an Dubbo install manifest and outputs to the console by default.", Example: ` # Generate a default Dubbo installation dubboctl manifest generate # Generate the demo profile dubboctl manifest generate --set profile=demo `, RunE: func(cmd *cobra.Command, args []string) error { if kubeClientFunc == nil { kubeClientFunc = ctx.CLIClient } var kubeClient kube.CLIClient kc, err := kubeClientFunc() if err != nil { return err } kubeClient = kc cl := clog.NewConsoleLogger(cmd.OutOrStdout(), cmd.ErrOrStderr()) return manifestGenerate(kubeClient, mgArgs, cl) }, } } const ( YAMLSeparator = "\n---\n" ) func manifestGenerate(kc kube.CLIClient, mgArgs *manifestGenerateArgs, cl clog.Logger) error { setFlags := applyFlagAliases(mgArgs.sets) manifests, _, err := render.GenerateManifest(nil, setFlags, cl, kc) if err != nil { return err } for _, smf := range sortManifests(manifests) { cl.Print(smf + YAMLSeparator) } return nil } func sortManifests(raw []manifest.ManifestSet) []string { all := []manifest.Manifest{} for _, m := range raw { all = append(all, m.Manifests...) } slices.SortStableFunc(all, func(a, b manifest.Manifest) int { if r := cmp.Compare(objectKindOrder(a), objectKindOrder(b)); r != 0 { return r } if r := cmp.Compare(a.GroupVersionKind().Group, b.GroupVersionKind().Group); r != 0 { return r } if r := cmp.Compare(a.GroupVersionKind().Kind, b.GroupVersionKind().Kind); r != 0 { return r } return cmp.Compare(a.GetName(), b.GetName()) }) return slices.Map(all, func(e manifest.Manifest) string { res, _ := yaml.Marshal(e.Object) return string(res) }) } func objectKindOrder(m manifest.Manifest) int { o := m.Unstructured gk := o.GroupVersionKind().Group + "/" + o.GroupVersionKind().Kind switch { // Create CRDs asap - both because they are slow and because we will likely create instances of them soon case gk == "apiextensions.k8s.io/CustomResourceDefinition": return -1000 // We need to create ServiceAccounts, Roles before we bind them with a RoleBinding case gk == "/ServiceAccount" || gk == "rbac.authorization.k8s.io/ClusterRole": return 1 case gk == "rbac.authorization.k8s.io/ClusterRoleBinding": return 2 // Pods might need configmap or secrets - avoid backoff by creating them first case gk == "/ConfigMap" || gk == "/Secrets": return 100 // Create the pods after we've created other things they might be waiting for case gk == "extensions/Deployment" || gk == "apps/Deployment": return 1000 // Autoscalers typically act on a deployment case gk == "autoscaling/HorizontalPodAutoscaler": return 1001 // Create services late - after pods have been started case gk == "/Service": return 10000 default: return 1000 } }