diff --git a/pkg/karmadactl/promote/promote.go b/pkg/karmadactl/promote/promote.go index f9d8beafa..0390637c4 100644 --- a/pkg/karmadactl/promote/promote.go +++ b/pkg/karmadactl/promote/promote.go @@ -114,6 +114,16 @@ type CommandPromoteOption struct { // DryRun tells if run the command in dry-run mode, without making any server requests. DryRun bool + // AutoCreatePolicy tells if the promote command should create the + // PropagationPolicy(or ClusterPropagationPolicy) by default. + // It default to true. + AutoCreatePolicy bool + + // PolicyName is the name of the PropagationPolicy(or ClusterPropagationPolicy), + // It defaults to the promoting resource name with a random hash suffix. + // It will be ingnored if AutoCreatePolicy is false. + PolicyName string + resource.FilenameOptions JSONYamlPrintFlags *genericclioptions.JSONYamlPrintFlags @@ -127,6 +137,10 @@ type CommandPromoteOption struct { // AddFlags adds flags to the specified FlagSet. func (o *CommandPromoteOption) AddFlags(flags *pflag.FlagSet) { + flags.BoolVar(&o.AutoCreatePolicy, "auto-create-policy", true, + "Automatically create a PropagationPolicy for namespace-scoped resources or create a ClusterPropagationPolicy for cluster-scoped resources.") + flags.StringVar(&o.PolicyName, "policy-name", "", + "The name of the PropagationPolicy(or ClusterPropagationPolicy) that is automatically created after promotion. If not specified, the name will be the resource name with a hash suffix that is generated by resource metadata.") flags.StringVarP(&o.OutputFormat, "output", "o", "", "Output format. One of: json|yaml") flags.StringVarP(&o.Namespace, "namespace", "n", o.Namespace, "If present, the namespace scope for this CLI request") @@ -275,9 +289,11 @@ func (o *CommandPromoteOption) promote(controlPlaneRestConfig *rest.Config, obj return fmt.Errorf("failed to create resource %q(%s) in control plane: %v", gvr, o.name, err) } - err = o.createClusterPropagationPolicy(karmadaClient, gvr) - if err != nil { - return err + if o.AutoCreatePolicy { + err = o.createClusterPropagationPolicy(karmadaClient, gvr) + if err != nil { + return err + } } fmt.Printf("Resource %q(%s) is promoted successfully\n", gvr, o.name) @@ -298,9 +314,11 @@ func (o *CommandPromoteOption) promote(controlPlaneRestConfig *rest.Config, obj return fmt.Errorf("failed to create resource %q(%s/%s) in control plane: %v", gvr, o.Namespace, o.name, err) } - err = o.createPropagationPolicy(karmadaClient, gvr) - if err != nil { - return err + if o.AutoCreatePolicy { + err = o.createPropagationPolicy(karmadaClient, gvr) + if err != nil { + return err + } } fmt.Printf("Resource %q(%s/%s) is promoted successfully\n", gvr, o.Namespace, o.name) @@ -351,16 +369,23 @@ func (o *CommandPromoteOption) printObjectAndPolicy(obj *unstructured.Unstructur if err = printer.PrintObj(obj, os.Stdout); err != nil { return fmt.Errorf("failed to print the resource template. err: %v", err) } - - if len(obj.GetNamespace()) == 0 { - cpp := buildClusterPropagationPolicy(o.name, o.Cluster, gvr, o.gvk) - if err = printer.PrintObj(cpp, os.Stdout); err != nil { - return fmt.Errorf("failed to print the ClusterPropagationPolicy. err: %v", err) + if o.AutoCreatePolicy { + var policyName string + if o.PolicyName == "" { + policyName = names.GeneratePolicyName(o.Namespace, o.name, o.gvk.String()) + } else { + policyName = o.PolicyName } - } else { - pp := buildPropagationPolicy(o.name, o.Namespace, o.Cluster, gvr, o.gvk) - if err = printer.PrintObj(pp, os.Stdout); err != nil { - return fmt.Errorf("failed to print the PropagationPolicy. err: %v", err) + if len(obj.GetNamespace()) == 0 { + cpp := buildClusterPropagationPolicy(o.name, policyName, o.Cluster, gvr, o.gvk) + if err = printer.PrintObj(cpp, os.Stdout); err != nil { + return fmt.Errorf("failed to print the ClusterPropagationPolicy. err: %v", err) + } + } else { + pp := buildPropagationPolicy(o.name, policyName, o.Namespace, o.Cluster, gvr, o.gvk) + if err = printer.PrintObj(pp, os.Stdout); err != nil { + return fmt.Errorf("failed to print the PropagationPolicy. err: %v", err) + } } } @@ -369,40 +394,50 @@ func (o *CommandPromoteOption) printObjectAndPolicy(obj *unstructured.Unstructur // createPropagationPolicy create PropagationPolicy in karmada control plane func (o *CommandPromoteOption) createPropagationPolicy(karmadaClient *karmadaclientset.Clientset, gvr schema.GroupVersionResource) error { - name := names.GeneratePolicyName(o.Namespace, o.name, o.gvk.String()) + var policyName string + if o.PolicyName == "" { + policyName = names.GeneratePolicyName(o.Namespace, o.name, o.gvk.String()) + } else { + policyName = o.PolicyName + } - _, err := karmadaClient.PolicyV1alpha1().PropagationPolicies(o.Namespace).Get(context.TODO(), name, metav1.GetOptions{}) + _, err := karmadaClient.PolicyV1alpha1().PropagationPolicies(o.Namespace).Get(context.TODO(), policyName, metav1.GetOptions{}) if err != nil && apierrors.IsNotFound(err) { - pp := buildPropagationPolicy(o.name, o.Namespace, o.Cluster, gvr, o.gvk) + pp := buildPropagationPolicy(o.name, policyName, o.Namespace, o.Cluster, gvr, o.gvk) _, err = karmadaClient.PolicyV1alpha1().PropagationPolicies(o.Namespace).Create(context.TODO(), pp, metav1.CreateOptions{}) return err } if err != nil { - return fmt.Errorf("failed to get PropagationPolicy(%s/%s) in control plane: %v", o.Namespace, name, err) + return fmt.Errorf("failed to get PropagationPolicy(%s/%s) in control plane: %v", o.Namespace, policyName, err) } // PropagationPolicy already exists, not to create it - return fmt.Errorf("the PropagationPolicy(%s/%s) already exist, please edit it to propagate resource", o.Namespace, name) + return fmt.Errorf("the PropagationPolicy(%s/%s) already exist, please edit it to propagate resource", o.Namespace, policyName) } // createClusterPropagationPolicy create ClusterPropagationPolicy in karmada control plane func (o *CommandPromoteOption) createClusterPropagationPolicy(karmadaClient *karmadaclientset.Clientset, gvr schema.GroupVersionResource) error { - name := names.GeneratePolicyName("", o.name, o.gvk.String()) + var policyName string + if o.PolicyName == "" { + policyName = names.GeneratePolicyName("", o.name, o.gvk.String()) + } else { + policyName = o.PolicyName + } - _, err := karmadaClient.PolicyV1alpha1().ClusterPropagationPolicies().Get(context.TODO(), name, metav1.GetOptions{}) + _, err := karmadaClient.PolicyV1alpha1().ClusterPropagationPolicies().Get(context.TODO(), policyName, metav1.GetOptions{}) if err != nil && apierrors.IsNotFound(err) { - cpp := buildClusterPropagationPolicy(o.name, o.Cluster, gvr, o.gvk) + cpp := buildClusterPropagationPolicy(o.name, policyName, o.Cluster, gvr, o.gvk) _, err = karmadaClient.PolicyV1alpha1().ClusterPropagationPolicies().Create(context.TODO(), cpp, metav1.CreateOptions{}) return err } if err != nil { - return fmt.Errorf("failed to get ClusterPropagationPolicy(%s) in control plane: %v", name, err) + return fmt.Errorf("failed to get ClusterPropagationPolicy(%s) in control plane: %v", policyName, err) } // ClusterPropagationPolicy already exists, not to create it - return fmt.Errorf("the ClusterPropagationPolicy(%s) already exist, please edit it to propagate resource", name) + return fmt.Errorf("the ClusterPropagationPolicy(%s) already exist, please edit it to propagate resource", policyName) } // preprocessResource delete redundant fields to convert resource as template @@ -430,9 +465,7 @@ func addOverwriteAnnotation(obj *unstructured.Unstructured) { } // buildPropagationPolicy build PropagationPolicy according to resource and cluster -func buildPropagationPolicy(resourceName, namespace, cluster string, gvr schema.GroupVersionResource, gvk schema.GroupVersionKind) *policyv1alpha1.PropagationPolicy { - policyName := names.GeneratePolicyName(namespace, resourceName, gvk.String()) - +func buildPropagationPolicy(resourceName, policyName, namespace, cluster string, gvr schema.GroupVersionResource, gvk schema.GroupVersionKind) *policyv1alpha1.PropagationPolicy { pp := &policyv1alpha1.PropagationPolicy{ ObjectMeta: metav1.ObjectMeta{ Name: policyName, @@ -453,14 +486,11 @@ func buildPropagationPolicy(resourceName, namespace, cluster string, gvr schema. }, }, } - return pp } // buildClusterPropagationPolicy build ClusterPropagationPolicy according to resource and cluster -func buildClusterPropagationPolicy(resourceName, cluster string, gvr schema.GroupVersionResource, gvk schema.GroupVersionKind) *policyv1alpha1.ClusterPropagationPolicy { - policyName := names.GeneratePolicyName("", resourceName, gvk.String()) - +func buildClusterPropagationPolicy(resourceName, policyName, cluster string, gvr schema.GroupVersionResource, gvk schema.GroupVersionKind) *policyv1alpha1.ClusterPropagationPolicy { cpp := &policyv1alpha1.ClusterPropagationPolicy{ ObjectMeta: metav1.ObjectMeta{ Name: policyName, diff --git a/test/e2e/karmadactl_test.go b/test/e2e/karmadactl_test.go index b3e8f7605..4bc04bc2b 100644 --- a/test/e2e/karmadactl_test.go +++ b/test/e2e/karmadactl_test.go @@ -90,7 +90,8 @@ var _ = ginkgo.Describe("Karmadactl promote testing", func() { // Step 2, promote namespace used by the deployment from member1 to karmada ginkgo.By(fmt.Sprintf("Promoting namespace %s from member: %s to karmada control plane", deploymentNamespace, member1), func() { namespaceOpts = promote.CommandPromoteOption{ - Cluster: member1, + Cluster: member1, + AutoCreatePolicy: true, } args := []string{"namespace", deploymentNamespace} // init args: place namespace name to CommandPromoteOption.name @@ -107,8 +108,9 @@ var _ = ginkgo.Describe("Karmadactl promote testing", func() { // Step 3, promote deployment from cluster member1 to karmada ginkgo.By(fmt.Sprintf("Promoting deployment %s from member: %s to karmada", deploymentName, member1), func() { deploymentOpts = promote.CommandPromoteOption{ - Namespace: deploymentNamespace, - Cluster: member1, + Namespace: deploymentNamespace, + Cluster: member1, + AutoCreatePolicy: true, } args := []string{"deployment", deploymentName} // init args: place deployment name to CommandPromoteOption.name @@ -195,7 +197,8 @@ var _ = ginkgo.Describe("Karmadactl promote testing", func() { // Step2, promote clusterrole and clusterrolebinding from member1 ginkgo.By(fmt.Sprintf("Promoting clusterrole %s and clusterrolebindings %s from member to karmada", clusterRoleName, clusterRoleBindingName), func() { clusterRoleOpts = promote.CommandPromoteOption{ - Cluster: member1, + Cluster: member1, + AutoCreatePolicy: true, } args := []string{"clusterrole", clusterRoleName} @@ -208,7 +211,8 @@ var _ = ginkgo.Describe("Karmadactl promote testing", func() { gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) clusterRoleBindingOpts = promote.CommandPromoteOption{ - Cluster: member1, + Cluster: member1, + AutoCreatePolicy: true, } args = []string{"clusterrolebinding", clusterRoleBindingName} @@ -260,7 +264,8 @@ var _ = ginkgo.Describe("Karmadactl promote testing", func() { ginkgo.By(fmt.Sprintf("Promoting namespace %s from member: %s to karmada control plane", serviceNamespace, member1), func() { opts := promote.CommandPromoteOption{ - Cluster: member1, + Cluster: member1, + AutoCreatePolicy: true, } args := []string{"namespace", serviceNamespace} err := opts.Complete(f, args) @@ -274,8 +279,9 @@ var _ = ginkgo.Describe("Karmadactl promote testing", func() { ginkgo.By(fmt.Sprintf("Promoting service %s from member: %s to karmada control plane", serviceName, member1), func() { opts := promote.CommandPromoteOption{ - Namespace: serviceNamespace, - Cluster: member1, + Namespace: serviceNamespace, + Cluster: member1, + AutoCreatePolicy: true, } args := []string{"service", serviceName} err := opts.Complete(f, args)