diff --git a/pkg/remote_replica/postgres.go b/pkg/remote_replica/postgres.go index 06095badc..aeb5cd882 100644 --- a/pkg/remote_replica/postgres.go +++ b/pkg/remote_replica/postgres.go @@ -52,7 +52,7 @@ import ( ) func PostgreSQlAPP(f cmdutil.Factory) *cobra.Command { - var userName, password, dns, ns string + var userName, password, dns, ns, authSecretName string var yes bool cmd := cobra.Command{ @@ -70,7 +70,7 @@ func PostgreSQlAPP(f cmdutil.Factory) *cobra.Command { } var buffer []byte - buffer, err := generateConfig(f, userName, password, dns, ns, args[0]) + buffer, err := generateConfig(f, userName, password, dns, ns, authSecretName, args[0]) if err != nil { log.Fatal(err) } @@ -107,10 +107,11 @@ func PostgreSQlAPP(f cmdutil.Factory) *cobra.Command { log.Fatal(err) } cmd.PersistentFlags().BoolVarP(&yes, "yes", "y", false, "permission for alter password for the remote replica") + cmd.PersistentFlags().StringVar(&authSecretName, "auth-secret", "", "name for the auth secret on the remote cluster (default: -remote-replica-auth)") return &cmd } -func generateConfig(f cmdutil.Factory, userName string, password string, dns string, ns string, dbname string) ([]byte, error) { +func generateConfig(f cmdutil.Factory, userName string, password string, dns string, ns string, authSecretName string, dbname string) ([]byte, error) { var buffer []byte opts, err := common.NewPostgresOpts(f, dbname, ns) if err != nil { @@ -123,31 +124,55 @@ func generateConfig(f cmdutil.Factory, userName string, password string, dns str return nil, fmt.Errorf("failed to get appbinding %v", err) } - authBuff, authSecretName, err := generateAuthSecret(userName, password, ns, opts) + authBuff, authSecretName, err := generateAuthSecret(userName, password, ns, authSecretName, opts) if err != nil { return nil, fmt.Errorf("failed to generate auth secret ,%v", err) } buffer = append(buffer, authBuff...) - // generate secret + var tlsSecretName string if apb.Spec.TLSSecret != nil { - tlsBuff, tlsSecretName, err := generateTlsSecret(userName, apb, ns, opts) + var tlsBuff []byte + tlsBuff, tlsSecretName, err = generateTlsSecret(userName, apb, ns, opts) if err != nil { return nil, fmt.Errorf("failed to generate tls secret %v", err) } buffer = append(buffer, tlsBuff...) - apb.Spec.TLSSecret.Name = tlsSecretName } - apb.APIVersion = AppcatApiVersion - apb.Kind = AppcatKind - apb.Spec.ClientConfig.Service.Name = dns - apb.Spec.Secret.Name = authSecretName - apb.Annotations = nil - apb.ManagedFields = nil - apb.OwnerReferences = nil + // Deep-copy the source AppBinding and replace only the ObjectMeta with a + // clean one. This preserves all spec fields (appRef, parameters, type, + // version, clientConfig, etc.) so nothing is silently dropped, while + // ensuring server-managed metadata (resourceVersion, uid, generation, + // labels, annotations) never leaks into the generated YAML. A clean + // ObjectMeta means the last-applied annotation stays minimal, so + // repeated kubectl apply is idempotent and the 3-way merge never tries + // to remove metadata.resourceVersion. + remoteApb := apb.DeepCopy() + remoteApb.TypeMeta = metav1.TypeMeta{ + APIVersion: AppcatApiVersion, + Kind: AppcatKind, + } + remoteApb.ObjectMeta = metav1.ObjectMeta{ + Name: apb.Name, + Namespace: ns, + } + if remoteApb.Spec.ClientConfig.Service == nil { + remoteApb.Spec.ClientConfig.Service = &appApi.ServiceReference{} + } + remoteApb.Spec.ClientConfig.Service.Name = dns + if remoteApb.Spec.Secret == nil { + remoteApb.Spec.Secret = &appApi.TypedLocalObjectReference{} + } + remoteApb.Spec.Secret.Name = authSecretName + if tlsSecretName != "" { + if remoteApb.Spec.TLSSecret == nil { + remoteApb.Spec.TLSSecret = &appApi.TypedLocalObjectReference{} + } + remoteApb.Spec.TLSSecret.Name = tlsSecretName + } - appbindingYaml, err := yaml.Marshal(apb) + appbindingYaml, err := yaml.Marshal(remoteApb) if err != nil { return nil, fmt.Errorf("failed to marshal appbind yaml %v", err) } @@ -181,7 +206,11 @@ func generateTlsSecret(userName string, apb *appApi.AppBinding, ns string, opts } tlsSecret.APIVersion = "v1" tlsSecret.Kind = "Secret" + tlsSecret.ResourceVersion = "" + tlsSecret.UID = "" + tlsSecret.CreationTimestamp = metav1.Time{} tlsSecret.Annotations = nil + tlsSecret.Labels = nil tlsSecret.ManagedFields = nil tlsSecretYaml, err := yaml.Marshal(tlsSecret) if err != nil { @@ -194,7 +223,7 @@ func generateTlsSecret(userName string, apb *appApi.AppBinding, ns string, opts return buffer, tlsSecret.Name, nil } -func generateAuthSecret(userName string, password string, ns string, opts *common.PostgresOpts) ([]byte, string, error) { +func generateAuthSecret(userName string, password string, ns string, secretName string, opts *common.PostgresOpts) ([]byte, string, error) { var buffer []byte if userName != opts.Username { // generate user if not present @@ -205,6 +234,9 @@ func generateAuthSecret(userName string, password string, ns string, opts *commo } else { password = opts.Pass } + if secretName == "" { + secretName = fmt.Sprintf("%s-remote-replica-auth", opts.DB.Name) + } // generate auth secret AuthSecret := core.Secret{ TypeMeta: metav1.TypeMeta{ @@ -212,7 +244,7 @@ func generateAuthSecret(userName string, password string, ns string, opts *commo APIVersion: ApiversionV1, }, ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf("%s-remote-replica-auth", opts.DB.Name), + Name: secretName, Namespace: ns, }, StringData: map[string]string{