diff --git a/pkg/controller/postgres/postgres_controller.go b/pkg/controller/postgres/postgres_controller.go index 35641b3b..8fda12a5 100644 --- a/pkg/controller/postgres/postgres_controller.go +++ b/pkg/controller/postgres/postgres_controller.go @@ -230,6 +230,11 @@ func (r *ReconcilePostgres) Reconcile(request reconcile.Request) (_ reconcile.Re reqLogger.Error(err, fmt.Sprintf("Could not give %s permissions \"%s\"", writer, writerPrivs)) continue } + err = r.pg.SetSchemaPrivilegesCreate(database, owner, writer, schema, writerPrivs, reqLogger) + if err != nil { + reqLogger.Error(err, fmt.Sprintf("Could not give %s permissions \"%s\"", writer, writerPrivs)) + continue + } instance.Status.Schemas = append(instance.Status.Schemas, schema) } diff --git a/pkg/controller/postgres/postgres_controller_test.go b/pkg/controller/postgres/postgres_controller_test.go index efe900ea..685aae41 100644 --- a/pkg/controller/postgres/postgres_controller_test.go +++ b/pkg/controller/postgres/postgres_controller_test.go @@ -683,9 +683,11 @@ var _ = Describe("ReconcilePostgres", func() { // customers schema pg.EXPECT().CreateSchema(name, name+"-group", "customers", gomock.Any()).Return(nil).Times(1) pg.EXPECT().SetSchemaPrivileges(name, name+"-group", gomock.Any(), "customers", gomock.Any(), gomock.Any()).Return(nil).Times(2) + pg.EXPECT().SetSchemaPrivilegesCreate(name, name+"-group", name+"-writer", "customers", gomock.Any(), gomock.Any()).Return(nil).Times(1) // stores schema pg.EXPECT().CreateSchema(name, name+"-group", "stores", gomock.Any()).Return(nil).Times(1) pg.EXPECT().SetSchemaPrivileges(name, name+"-group", gomock.Any(), "stores", gomock.Any(), gomock.Any()).Return(nil).Times(2) + pg.EXPECT().SetSchemaPrivilegesCreate(name, name+"-group", name+"-writer", "stores", gomock.Any(), gomock.Any()).Return(nil).Times(1) }) It("should update status", func() { @@ -708,9 +710,11 @@ var _ = Describe("ReconcilePostgres", func() { // customers schema errors pg.EXPECT().CreateSchema(name, name+"-group", "customers", gomock.Any()).Return(fmt.Errorf("Could not create schema")).Times(1) pg.EXPECT().SetSchemaPrivileges(name, name+"-group", gomock.Any(), "customers", gomock.Any(), gomock.Any()).Return(nil).Times(0) + pg.EXPECT().SetSchemaPrivilegesCreate(name, name+"-group", name+"-writer", "customers", gomock.Any(), gomock.Any()).Return(nil).Times(0) // stores schema pg.EXPECT().CreateSchema(name, name+"-group", "stores", gomock.Any()).Return(nil).Times(1) pg.EXPECT().SetSchemaPrivileges(name, name+"-group", gomock.Any(), "stores", gomock.Any(), gomock.Any()).Return(nil).Times(2) + pg.EXPECT().SetSchemaPrivilegesCreate(name, name+"-group", name+"-writer", "stores", gomock.Any(), gomock.Any()).Return(nil).Times(1) }) It("should update status", func() { @@ -752,6 +756,7 @@ var _ = Describe("ReconcilePostgres", func() { // customers schema pg.EXPECT().CreateSchema(name, name+"-group", "customers", gomock.Any()).Return(nil).Times(1) pg.EXPECT().SetSchemaPrivileges(name, name+"-group", gomock.Any(), "customers", gomock.Any(), gomock.Any()).Return(nil).Times(2) + pg.EXPECT().SetSchemaPrivilegesCreate(name, name+"-group", name+"-writer", "customers", gomock.Any(), gomock.Any()).Return(nil).Times(1) // stores schema already exists pg.EXPECT().CreateSchema(name, name+"-group", "stores", gomock.Any()).Times(0) // Call reconcile diff --git a/pkg/postgres/database.go b/pkg/postgres/database.go index 649e3513..ad16a8d2 100644 --- a/pkg/postgres/database.go +++ b/pkg/postgres/database.go @@ -14,6 +14,7 @@ const ( ALTER_DB_OWNER = `ALTER DATABASE "%s" OWNER TO "%s"` DROP_DATABASE = `DROP DATABASE "%s"` GRANT_USAGE_SCHEMA = `GRANT USAGE ON SCHEMA "%s" TO "%s"` + GRANT_CREATE_TABLE = `GRANT CREATE ON SCHEMA "%s" TO "%s"` GRANT_ALL_TABLES = `GRANT %s ON ALL TABLES IN SCHEMA "%s" TO "%s"` DEFAULT_PRIVS_SCHEMA = `ALTER DEFAULT PRIVILEGES FOR ROLE "%s" IN SCHEMA "%s" GRANT %s ON TABLES TO "%s"` REVOKE_CONNECT = `REVOKE CONNECT ON DATABASE "%s" FROM public` @@ -109,3 +110,18 @@ func (c *pg) SetSchemaPrivileges(db, creator, role, schema, privs string, logger } return nil } + +func (c *pg) SetSchemaPrivilegesCreate(db, creator, role, schema, privs string, logger logr.Logger) error { + tmpDb, err := GetConnection(c.user, c.pass, c.host, db, c.args, logger) + if err != nil { + return err + } + defer tmpDb.Close() + + // Grant role usage on schema + _, err = tmpDb.Exec(fmt.Sprintf(GRANT_CREATE_TABLE, schema, role)) + if err != nil { + return err + } + return nil +} diff --git a/pkg/postgres/mock/postgres.go b/pkg/postgres/mock/postgres.go index 6cd73efb..47386eab 100644 --- a/pkg/postgres/mock/postgres.go +++ b/pkg/postgres/mock/postgres.go @@ -146,6 +146,20 @@ func (mr *MockPGMockRecorder) SetSchemaPrivileges(db, creator, role, schema, pri return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetSchemaPrivileges", reflect.TypeOf((*MockPG)(nil).SetSchemaPrivileges), db, creator, role, schema, privs, logger) } +// SetSchemaPrivilegesCreate mocks base method +func (m *MockPG) SetSchemaPrivilegesCreate(db, creator, role, schema, privs string, logger logr.Logger) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetSchemaPrivilegesCreate", db, creator, role, schema, privs, logger) + ret0, _ := ret[0].(error) + return ret0 +} + +// SetSchemaPrivilegesCreate indicates an expected call of SetSchemaPrivilegesCreate +func (mr *MockPGMockRecorder) SetSchemaPrivilegesCreate(db, creator, role, schema, privs, logger interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetSchemaPrivilegesCreate", reflect.TypeOf((*MockPG)(nil).SetSchemaPrivilegesCreate), db, creator, role, schema, privs, logger) +} + // RevokeRole mocks base method func (m *MockPG) RevokeRole(role, revoked string) error { m.ctrl.T.Helper() diff --git a/pkg/postgres/postgres.go b/pkg/postgres/postgres.go index 22f8f56e..f8fa0f88 100644 --- a/pkg/postgres/postgres.go +++ b/pkg/postgres/postgres.go @@ -17,6 +17,7 @@ type PG interface { UpdatePassword(role, password string) error GrantRole(role, grantee string) error SetSchemaPrivileges(db, creator, role, schema, privs string, logger logr.Logger) error + SetSchemaPrivilegesCreate(db, creator, role, schema, privs string, logger logr.Logger) error RevokeRole(role, revoked string) error AlterDefaultLoginRole(role, setRole string) error DropDatabase(db string, logger logr.Logger) error