-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
PostgreSQL user creation logic was implemented #542
Conversation
7b03af4
to
0fc2d03
Compare
event = models.Created | ||
u.Status.ClustersEvents[namespacedName] = event |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can omit to assign to event
var and just do u.Status.ClustersEvents[namespacedName] = models.Created
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree, fixed
} | ||
|
||
l.Info("User has been created", "username", newUsername) | ||
fmt.Println("userName and ns:", u.Name, namespacedName) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please delete this log
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed
Name: parts[1], | ||
Namespace: parts[0], | ||
} | ||
err := r.Get(context.TODO(), userSecretNamespacedName, defaultUserSecret) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe you should you the context that is passed into your Reconcile
method?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is reconcile, not controller
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But this func is used in reconcile func, so you just can pass it's context in createUser func trought signature
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree, fixed in all such cases
createUserQuery := fmt.Sprintf(`CREATE USER "%s" WITH PASSWORD '%s'`, newUserName, newPassword) | ||
_, err = conn.Exec(context.Background(), createUserQuery) | ||
if err != nil { | ||
return fmt.Errorf("cannot execute creation user query in postgresql err, err: %w", err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cannot execute creation user query in postgresql err, err
-> cannot execute creation user query in postgresql, err: %w
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Renamed
createUserQuery := fmt.Sprintf(`CREATE USER "%s" WITH PASSWORD '%s'`, newUserName, newPassword) | ||
_, err = conn.Exec(context.Background(), createUserQuery) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
conn.Exec
requires query and optinal arguments. I think you should omit to create the whole query by yourself. Just do
createUserQuery := `CREATE USER '$1' WITH PASSWORD '$2'`
_, err = conn.Exec(ctx, createUserQuery, newUserName, newPassword)
I hope pgx driver also validates passed arguments to avoid SQL injections, which are possible in your case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We cannot do this because it is important to have " " and ' ' in query
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Uhm, I didn't get what you meant. I gave the example with those '' in the query.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean that example that you provided won't work. In the comment above, I described why
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, I see. You have to use the quotes for the SQL.
If you put those " "
and ' '
quotes to the example of mine, does the problem still occur? Because it looks a bit strange, so I'm asking about it.
Edited example:
createUserQuery := `CREATE USER "$1" WITH PASSWORD '$2'`
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I already tested your solution and it does not work. That's why I wrote this query in fmt.Sprintf
APIVersion: models.ClusterresourcesV1beta1APIVersion, | ||
}, | ||
ObjectMeta: ctrl.ObjectMeta{ | ||
Name: fmt.Sprintf("%s-%s-%s", models.ClusterNetworkFirewallRulePrefix, clusterID, nodeName), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use the previously created var firewallRuleName
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
Status: clusterresourcesv1beta1.ClusterNetworkFirewallRuleStatus{ | ||
FirewallRuleStatus: clusterresourcesv1beta1.FirewallRuleStatus{ | ||
ID: "", | ||
DeferredReason: "", | ||
Status: "", | ||
}, | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I'm not wrong there is no any pointer value, so you can omit this Status
initialization
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed
return false, err | ||
} | ||
|
||
return true, err |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return true, err
-> return true, nil
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
0fc2d03
to
bea26b8
Compare
|
||
if len(username) == 0 || len(password) == 0 { | ||
return "", "", models.ErrMissingSecretKeys | ||
} | ||
|
||
return username[:len(username)-1], password[:len(password)-1], nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How can we handle the case if the customer will encode creds without removing the last character?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added validation for such things, If the user adds an indent, we will handle it and remove it
|
||
for namespacedName, event := range u.Status.ClustersEvents { | ||
if event == models.CreatingEvent { | ||
l.Info("Creating user", "user", u, "namespacedName", namespacedName) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
namespacedName -> userSecretNamespacedName or secretNamespacedName
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Refactored, changed this to ClusterID
and add new field in status DefaultSecretNamespacedName
@@ -622,3 +601,22 @@ func (pgs *PgStatus) DCsFromInstAPI(iDCs []*models.PGDataCentre) (dcs []*DataCen | |||
} | |||
return | |||
} | |||
|
|||
func GetDefaultPgUserSecret( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can implement it as reconciler method, wdyt?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because it is a separate function that does not use postgresql cluster fields and gets the name and namespace for the secret. So I think we can leave this as just a function and not a method.
7b4b068
to
625feaf
Compare
625feaf
to
d129a66
Compare
// The keys of the map represent the cluster IDs, while the corresponding values represent the events themselves. | ||
ClustersEvents map[string]string `json:"clustersEvents,omitempty"` | ||
DefaultSecretNamespacedName string `json:"defaultSecretNamespacedName,omitempty"` | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can store NamespacedName as struct wdyt?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, we can, changed
} | ||
|
||
clusterName := defaultUserSecret.Labels[models.ControlledByLabel] | ||
clusterID := defaultUserSecret.Labels[models.ClusterIDLabel] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can pass ClusterID trought func signature when you iterate by cluster events
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
} | ||
|
||
defaultUserSecret := &k8sCore.Secret{} | ||
userSecretNamespacedName := types.NamespacedName{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
userSecretNamespacedName -> defaultUserSecretNamespacedName
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
renamed
if err != nil { | ||
if k8sErrors.IsNotFound(err) { | ||
return fmt.Errorf("cannot get default PostgreSQL user secret, username: %s , err: %w", parts[1], err) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can use userName as userSecretNamespacedName.Name instead of parts[1] for more readability. If you agree fix in all similar cases
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
exposeServiceList, err := exposeservice.GetExposeService(r.Client, clusterName, parts[0]) | ||
if err != nil { | ||
return fmt.Errorf("cannot list expose services for cluster: %s, err: %w", parts[0], err) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess parts[0] is a secret namespace not a cluster name(also we can use here already created clusterName variable)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
logic changed, refactored
return err | ||
} | ||
|
||
secret, err := v1beta1.GetDefaultPgUserSecret(context.TODO(), c.Name, c.Namespace, r.Client) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why you dont use ctx that we have in func signature?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
u.Status.ClustersEvents = make(map[string]string) | ||
} | ||
|
||
u.Status.DefaultSecretNamespacedName = defaultSecretNamespacedName.String() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will it work on multiple cluster?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice catch, fixed and tested
ClusterID: clusterID, | ||
Type: models.PgAppType, | ||
}, | ||
Network: fmt.Sprintf("%s/%s", nodeAddress, "32"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can just do
fmt.Sprintf("%s/32", nodeAddress)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It also can be, but I prefer my variant to move it in const in future
u.Status.ClustersEvents = make(map[string]string) | ||
} | ||
|
||
u.Status.DefaultSecretNamespacedName = defaultSecretNamespacedName.String() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You need the reference to the default user in the PostgreSQLUserController
to create a new one. But what if there is more than 1 cluster reference to the given user resource?
I think it would be better if we save the reference in another map like map[ClusterID]DefaultSecretNamespacedName
. Or modify ClusterEvents
to something like that:
type ClusterEvent struct {
Event string `json:"event,omitempty"`
DefaultSecretRef types.NamespacedName `json:"defautSecretRef,omitempty"`
}
type PostgreSQLUserStatus struct {
ClusterEvents map[ClusterID]ClusterEvent `json:"clusterEvents,omitempty"
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice catch, fixed and tested
d129a66
to
564a055
Compare
import ( | ||
"context" | ||
"errors" | ||
"fmt" | ||
"github.com/jackc/pgx/v5" | ||
k8sCore "k8s.io/api/core/v1" | ||
k8sErrors "k8s.io/apimachinery/pkg/api/errors" | ||
"k8s.io/apimachinery/pkg/runtime" | ||
"k8s.io/apimachinery/pkg/types" | ||
"k8s.io/client-go/tools/record" | ||
ctrl "sigs.k8s.io/controller-runtime" | ||
"sigs.k8s.io/controller-runtime/pkg/client" | ||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" | ||
"sigs.k8s.io/controller-runtime/pkg/log" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sort imports please
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
|
||
l.Error(err, "Cannot get PostgreSQL user", "user", u.Spec) | ||
r.EventRecorder.Eventf(c, models.Warning, models.CreationFailed, | ||
"Cannot get PostgreSQL user. user reference: %v", uRef) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cannot get PostgreSQL user. user reference -> Cannot get PostgreSQL user. User reference
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
564a055
to
4854c32
Compare
@@ -89,6 +89,7 @@ type PgSpec struct { | |||
ClusterConfigurations map[string]string `json:"clusterConfigurations,omitempty"` | |||
Description string `json:"description,omitempty"` | |||
SynchronousModeStrict bool `json:"synchronousModeStrict,omitempty"` | |||
UserRefs []*UserReference `json:"userRef,omitempty"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
json:userRefs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
type NamespacedName struct { | ||
Namespace string `json:"namespace"` | ||
Name string `json:"name"` | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think there is no need to create this struct, please just use the existing types.NamespacedName
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here we need to create ours because types.NamespacedName
does not have json representation
newUsername, newPassword, err := getUserCreds(s) | ||
if err != nil { | ||
l.Error(err, "Cannot get the PostgreSQL user credentials from the secret", | ||
"secret name", s.Name, | ||
"secret namespace", s.Namespace) | ||
r.EventRecorder.Eventf(u, models.Warning, models.CreatingEvent, | ||
"Cannot get the PostgreSQL user credentials from the secret. Reason: %v", err) | ||
|
||
return models.ReconcileRequeue, nil | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please move this block of code before adding finalizers
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and name vars just username and password
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved this block before finalazers, we have default username and password and new password. We need to clearly distinguish them for better readability
err = r.Status().Patch(ctx, u, patch) | ||
if err != nil { | ||
l.Error(err, "Cannot patch PostgreSQL user status") | ||
r.EventRecorder.Eventf(u, models.Warning, models.PatchFailed, | ||
"Resource patch is failed. Reason: %v", err) | ||
|
||
return models.ReconcileRequeue, nil | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please make messages more detailed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added details
4854c32
to
4e030b4
Compare
Closes #428