Feature/infrastructure roles (#91)

* Add infrastructure roles configured globally.

Those are the roles defined in the operator itself. The operator's
configuration refers to the secret containing role names, passwords
and membership information. While they are referred to as roles, in
reality those are users.

In addition, improve the regex to filter out invalid users and
make sure user secret names are compatible with DNS name spec.

Add an example manifest for the infrastructure roles.
This commit is contained in:
Oleksii Kliukin
2017-05-12 11:41:33 +02:00
committed by Murat Kabilov
parent b8fba429df
commit 71b93b4cc2
13 changed files with 129 additions and 33 deletions
+25 -5
View File
@@ -30,15 +30,17 @@ import (
var (
alphaNumericRegexp = regexp.MustCompile("^[a-zA-Z][a-zA-Z0-9]*$")
userRegexp = regexp.MustCompile(`^[a-z0-9]([-_a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-_a-z0-9]*[a-z0-9])?)*$`)
)
//TODO: remove struct duplication
type Config struct {
KubeClient *kubernetes.Clientset //TODO: move clients to the better place?
RestClient *rest.RESTClient
EtcdClient etcdclient.KeysAPI
TeamsAPIClient *teams.TeamsAPI
OpConfig *config.Config
KubeClient *kubernetes.Clientset //TODO: move clients to the better place?
RestClient *rest.RESTClient
EtcdClient etcdclient.KeysAPI
TeamsAPIClient *teams.TeamsAPI
OpConfig *config.Config
InfrastructureRoles map[string]spec.PgUser // inherited from the controller
}
type kubeResources struct {
@@ -122,6 +124,11 @@ func (c *Cluster) SetStatus(status spec.PostgresStatus) {
func (c *Cluster) initUsers() error {
c.initSystemUsers()
if err := c.initInfrastructureRoles(); err != nil {
return fmt.Errorf("Can't init infrastructure roles: %s", err)
}
if err := c.initRobotUsers(); err != nil {
return fmt.Errorf("Can't init robot users: %s", err)
}
@@ -130,6 +137,8 @@ func (c *Cluster) initUsers() error {
return fmt.Errorf("Can't init human users: %s", err)
}
c.logger.Debugf("Initialized users: %# v", util.Pretty(c.pgUsers))
return nil
}
@@ -400,3 +409,14 @@ func (c *Cluster) initHumanUsers() error {
return nil
}
func (c *Cluster) initInfrastructureRoles() error {
// add infrastucture roles from the operator's definition
for username, data := range c.InfrastructureRoles {
if !isValidUsername(username) {
return fmt.Errorf("Invalid username: '%s'", username)
}
c.pgUsers[username] = data
}
return nil
}
+3 -1
View File
@@ -66,7 +66,9 @@ func (c *Cluster) createPgUser(user spec.PgUser) (isHuman bool, err error) {
if addLoginFlag {
flags = append(flags, "LOGIN")
}
if !isHuman && user.MemberOf != "" {
flags = append(flags, fmt.Sprintf("IN ROLE \"%s\"", user.MemberOf))
}
userFlags := strings.Join(flags, " ")
userPassword := fmt.Sprintf("ENCRYPTED PASSWORD '%s'", util.PGUserPassword(user))
if user.Password == "" {
+1 -1
View File
@@ -122,4 +122,4 @@ func (c *Cluster) syncStatefulSet() error {
c.logger.Infof("Pods have been recreated")
return nil
}
}
+4 -2
View File
@@ -18,7 +18,7 @@ import (
)
func isValidUsername(username string) bool {
return alphaNumericRegexp.MatchString(username)
return userRegexp.MatchString(username)
}
func normalizeUserFlags(userFlags []string) (flags []string, err error) {
@@ -218,8 +218,10 @@ func (c *Cluster) dnsName() string {
}
func (c *Cluster) credentialSecretName(username string) string {
// secret must consist of lower case alphanumeric characters, '-' or '.',
// and must start and end with an alphanumeric character
return fmt.Sprintf(constants.UserSecretTemplate,
username,
strings.Replace(username, "_", "-", -1),
c.Metadata.Name,
constants.TPRName,
constants.TPRVendor)