Skip to content

Conversation

RafiaSabih
Copy link
Contributor

If namespace is provided with the username in manifest,
then create the secret for that user in that namespace.
Also, the name of the secret will contain the namespace.

@FxKu FxKu added the zalando label May 19, 2021
if strings.Contains(username, ".") {
splits := strings.Split(username, ".")
name = splits[1]
namespace = splits[0]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what if the username is .user? Then namespace is "" and should become the default namespace

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right now, such a username is considered invalid username and I think this should continue. I don't see a reason why this should be allowed, if no namespace is provided then username only should be provided.

Rafia Sabih added 4 commits May 19, 2021 17:39
- include namespace in secret name only when namespace is provided
- use username.namespace as key to pgUsers only when namespace is
  provided
- avoid conflict in the role creation in db by checking namespace
  alongwith the username
name := username
namespace := c.Namespace

if strings.Contains(username, ".") {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs some attention.

Also include update to regex in manifest schema.

Rafia Sabih added 4 commits May 27, 2021 13:25
- update regular expression for usernames
- add test to allow check for valid usernames
- create pg roles with namespace (if any) appended in rolename
TPR) and `{tprgroup}` with the group of the CRD. No other placeholders are
allowed. The default is
`{username}.{cluster}.credentials.{tprkind}.{tprgroup}`.
operator. `{namesapce}` is replaced with name of the namespace (if any,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: namesApce -> namespace

allowed. The default is
`{username}.{cluster}.credentials.{tprkind}.{tprgroup}`.
operator. `{namesapce}` is replaced with name of the namespace (if any,
otherwise empty), `{username}` is replaced with name of the secret,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is an ambiguous description because a secret always lives in a namespace.
My best guess is that what is meant here is

This part of the secret name is empty if the secret and a PG cluster it belongs to are in the same namespace

'''
app_namespace = "appspace"
k8s = self.k8s
k8s.api.core_v1.create_namespace(app_namespace)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am unsure if kind always creates a new namespace fast enough. It is better to have some type of timeout / waiting here to avoid spurious test failures.

}
})
self.eventuallyEqual(lambda: k8s.count_secrets_in_namespace(app_namespace),
1, "Secret not created in user namespace")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To make it more informative, please log the name of the secret and the namespace


err := cluster.initRobotUsers()
if err != nil {
t.Errorf("%s Could not create namespaced users with error: %s", testName, err)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Does namespaced user here really mean namespaced secret ?
  2. I doubt there is a need to log a test name, the golang test framework likely reports it automatically

func TestValidUsernames(t *testing.T) {
testName := "test username validity"

invalidUsernames := []string{"_", ".", ".user", "appspace.", "appspace.user.extra", "user_", "_user", "-user", "user-", ",", ",user", "user,", "namespace,user"}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the name - disallowed by other means ?

for _, cachedUser := range c.pgUsersCache {
if _, exists := c.pgUsers[cachedUser.Name]; !exists {
userNames = append(userNames, cachedUser.Name)
pg_role := u.Name
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pg_role should be pgRole because of the golang naming conventions.

Comment on lines 559 to 571
userNames = append(userNames, u.Name)
// add team member role name with rename suffix in case we need to rename it back
if u.Origin == spec.RoleOriginTeamsAPI && c.OpConfig.EnableTeamMemberDeprecation {
deletedUsers[u.Name+c.OpConfig.RoleDeletionSuffix] = u.Name
userNames = append(userNames, u.Name+c.OpConfig.RoleDeletionSuffix)
}
}

// add team members that exist only in cache
// to trigger a rename of the role in ProduceSyncRequests
for _, cachedUser := range c.pgUsersCache {
if _, exists := c.pgUsers[cachedUser.Name]; !exists {
userNames = append(userNames, cachedUser.Name)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happened to these lines ? they are still needed for renaming roles removed fro PostgresTeam CRD

if u.Namespace != c.Namespace {
// to avoid the conflict of having multiple users of same name
// but each in different namespace.
pg_role = fmt.Sprintf("%s.%s", u.Name, u.Namespace)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so the template for the secret name is namespace.username but (in case of this name conflict) the role also gets a namespace as part of its name ? Will the resultant secret contain the namespace twice ?

# template for database user secrets generated by the operator
# template for database user secrets generated by the operator,
# here username contains the namespace in the format namespace.username
# if the user is in different namespace than cluster
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is the secret in the different namespace not the user.

k8s = self.k8s
v1_appnamespace = client.V1Namespace(metadata=client.V1ObjectMeta(name=app_namespace))
try:
k8s.api.core_v1.create_namespace(v1_appnamespace)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is unlikely the actual namespace creation will timeout. What I meant in my previous review was the following:

  1. The API call to create namespace may take some time, especially on kind where we know from experience even basic k8s operations sometimes take minutes
  2. the patch at line 603 may run into problems because of that
  3. Since we run e2e tests in different environments (locally, GitHub Action, CDP etc) that may lead to unwanted spurious test failures

Earlier I used simple timeouts in such cases, but now we have function like self.k8s.wait_for_pod_start and so on. You may just add a new one named self.k8s.wait_for_namespace_creation

}
})
self.eventuallyEqual(lambda: k8s.count_secrets_with_label("cluster_name=acid-minimal-cluster,application=spilo", app_namespace),
1, "Secret not created for user in namespace", app_namespace)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To which parameter of eventuallyEqual does app_namespace correspond ?

if u.Namespace != c.Namespace {
// to avoid the conflict of having multiple users of same name
// but each in different namespace.
pgRole = fmt.Sprintf("%s.%s", u.Name, u.Namespace)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel that behavior needs to be logged and mentioned in the docs. Just because it may happen an end user unaware of the name conflict expects to get username but gets instead namespace.username

for _, u := range c.pgUsers {
userNames = append(userNames, u.Name)
pgRole := u.Name
if u.Namespace != c.Namespace {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make sure u.Namespace is always set. Currently it's missing in initTeamMembers and readPgUsersFromDatabase methods which leads to the wrong name appended here. This makes the second e2e test fail atm (it wants to create a user that already exists).

Copy link
Member

@FxKu FxKu Jun 9, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

scratch initTeamMembers and readPgUsersFromDatabase. It's easier to just add && u.Namespace != "" here to not touch more unit tests. I pushed the change now.

@Jan-M
Copy link
Member

Jan-M commented Jun 10, 2021

👍

2 similar comments
@RafiaSabih
Copy link
Contributor Author

👍

@FxKu
Copy link
Member

FxKu commented Jun 11, 2021

👍

@FxKu FxKu merged commit 75a9e2b into master Jun 11, 2021
@FxKu FxKu added this to the 1.7 milestone Jun 11, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants