From 3d42ddb7b434960f4f2234483f277f822666a829 Mon Sep 17 00:00:00 2001 From: fgaillot-qosenergy <67331418+fgaillot-qosenergy@users.noreply.github.com> Date: Mon, 24 Jun 2024 22:45:03 +0200 Subject: [PATCH 01/24] Give MySQL sql_log_bin at DSN level to take parameter into account (#171) Signed-off-by: Florian Gaillot --- pkg/clients/mysql/mysql.go | 35 +++++++------------ pkg/clients/mysql/mysql_test.go | 9 +++-- pkg/controller/mysql/database/reconciler.go | 10 +++--- .../mysql/database/reconciler_test.go | 2 +- pkg/controller/mysql/grant/reconciler.go | 21 +++++------ pkg/controller/mysql/grant/reconciler_test.go | 2 +- pkg/controller/mysql/user/reconciler.go | 20 +++++------ pkg/controller/mysql/user/reconciler_test.go | 2 +- 8 files changed, 42 insertions(+), 59 deletions(-) diff --git a/pkg/clients/mysql/mysql.go b/pkg/clients/mysql/mysql.go index f0d62063..dbcaa28f 100644 --- a/pkg/clients/mysql/mysql.go +++ b/pkg/clients/mysql/mysql.go @@ -4,6 +4,7 @@ import ( "context" "database/sql" "fmt" + "strconv" "strings" "github.com/crossplane-contrib/provider-sql/pkg/clients/xsql" @@ -16,7 +17,6 @@ import ( const ( errNotSupported = "%s not supported by mysql client" - errSetSQLLogBin = "cannot set sql_log_bin = 0" errFlushPriv = "cannot flush privileges" ) @@ -28,7 +28,7 @@ type mySQLDB struct { } // New returns a new MySQL database client. -func New(creds map[string][]byte, tls *string) xsql.DB { +func New(creds map[string][]byte, tls *string, binlog *bool) xsql.DB { // TODO(negz): Support alternative connection secret formats? endpoint := string(creds[xpv1.ResourceCredentialsSecretEndpointKey]) port := string(creds[xpv1.ResourceCredentialsSecretPortKey]) @@ -38,7 +38,11 @@ func New(creds map[string][]byte, tls *string) xsql.DB { defaultTLS := "preferred" tls = &defaultTLS } - dsn := DSN(username, password, endpoint, port, *tls) + if binlog == nil { + defaultBinlog := true + binlog = &defaultBinlog + } + dsn := DSN(username, password, endpoint, port, *tls, *binlog) return mySQLDB{ dsn: dsn, @@ -49,16 +53,17 @@ func New(creds map[string][]byte, tls *string) xsql.DB { } // DSN returns the DSN URL -func DSN(username, password, endpoint, port, tls string) string { +func DSN(username, password, endpoint, port, tls string, binlog bool) string { // Use net/url UserPassword to encode the username and password // This will ensure that any special characters in the username or password // are percent-encoded for use in the user info portion of the DSN URL - return fmt.Sprintf("%s:%s@tcp(%s:%s)/?tls=%s", + return fmt.Sprintf("%s:%s@tcp(%s:%s)/?tls=%s&sql_log_bin=%s", username, password, endpoint, port, - tls) + tls, + strconv.FormatBool(binlog)) } // ExecTx is unsupported in MySQL. @@ -143,30 +148,16 @@ type ExecQuery struct { // ExecOptions parametrizes which optional statements will be executed before or after ExecQuery.Query type ExecOptions struct { - // Binlog defines whether storing binlogs will be disabled before executing the query. Defaults to true - Binlog *bool // Flush defines whether privileges will be flushed after executing the query. Defaults to true Flush *bool } -// ExecWithBinlogAndFlush is a wrapper function for xsql.DB.Exec() that allows the execution of optional queries before and after the provided query -func ExecWithBinlogAndFlush(ctx context.Context, db xsql.DB, query ExecQuery, options ExecOptions) error { - if options.Binlog == nil { - options.Binlog = ptr.To(true) - } - +// ExecWithFlush is a wrapper function for xsql.DB.Exec() that allows the execution of optional queries before and after the provided query +func ExecWithFlush(ctx context.Context, db xsql.DB, query ExecQuery, options ExecOptions) error { if options.Flush == nil { options.Flush = ptr.To(true) } - if !*options.Binlog { - if err := db.Exec(ctx, xsql.Query{ - String: "SET sql_log_bin = 0", - }); err != nil { - return errors.Wrap(err, errSetSQLLogBin) - } - } - if err := db.Exec(ctx, xsql.Query{ String: query.Query, }); err != nil { diff --git a/pkg/clients/mysql/mysql_test.go b/pkg/clients/mysql/mysql_test.go index 60f054d1..2a9cc889 100644 --- a/pkg/clients/mysql/mysql_test.go +++ b/pkg/clients/mysql/mysql_test.go @@ -2,6 +2,7 @@ package mysql import ( "fmt" + "strconv" "testing" ) @@ -11,13 +12,15 @@ func TestDSNURLEscaping(t *testing.T) { user := "username" rawPass := "password^" tls := "true" - dsn := DSN(user, rawPass, endpoint, port, tls) - if dsn != fmt.Sprintf("%s:%s@tcp(%s:%s)/?tls=%s", + binlog := false + dsn := DSN(user, rawPass, endpoint, port, tls, binlog) + if dsn != fmt.Sprintf("%s:%s@tcp(%s:%s)/?tls=%s&sql_log_bin=%s", user, rawPass, endpoint, port, - tls) { + tls, + strconv.FormatBool(binlog)) { t.Errorf("DSN string did not match expected output with URL encoded") } } diff --git a/pkg/controller/mysql/database/reconciler.go b/pkg/controller/mysql/database/reconciler.go index 2aab4db6..9f60e786 100644 --- a/pkg/controller/mysql/database/reconciler.go +++ b/pkg/controller/mysql/database/reconciler.go @@ -77,7 +77,7 @@ func Setup(mgr ctrl.Manager, o xpcontroller.Options) error { type connector struct { kube client.Client usage resource.Tracker - newDB func(creds map[string][]byte, tls *string) xsql.DB + newDB func(creds map[string][]byte, tls *string, binlog *bool) xsql.DB } func (c *connector) Connect(ctx context.Context, mg resource.Managed) (managed.ExternalClient, error) { @@ -110,7 +110,7 @@ func (c *connector) Connect(ctx context.Context, mg resource.Managed) (managed.E return nil, errors.Wrap(err, errGetSecret) } - return &external{db: c.newDB(s.Data, pc.Spec.TLS)}, nil + return &external{db: c.newDB(s.Data, pc.Spec.TLS, cr.Spec.ForProvider.BinLog)}, nil } type external struct{ db xsql.DB } @@ -148,10 +148,9 @@ func (c *external) Create(ctx context.Context, mg resource.Managed) (managed.Ext return managed.ExternalCreation{}, errors.New(errNotDatabase) } - binlog := cr.Spec.ForProvider.BinLog query := "CREATE DATABASE " + mysql.QuoteIdentifier(meta.GetExternalName(cr)) - if err := mysql.ExecWithBinlogAndFlush(ctx, c.db, mysql.ExecQuery{Query: query, ErrorValue: errCreateDB}, mysql.ExecOptions{Binlog: binlog, Flush: ptr.To(false)}); err != nil { + if err := mysql.ExecWithFlush(ctx, c.db, mysql.ExecQuery{Query: query, ErrorValue: errCreateDB}, mysql.ExecOptions{Flush: ptr.To(false)}); err != nil { return managed.ExternalCreation{}, err } @@ -169,10 +168,9 @@ func (c *external) Delete(ctx context.Context, mg resource.Managed) error { return errors.New(errNotDatabase) } - binlog := cr.Spec.ForProvider.BinLog query := "DROP DATABASE IF EXISTS " + mysql.QuoteIdentifier(meta.GetExternalName(cr)) - if err := mysql.ExecWithBinlogAndFlush(ctx, c.db, mysql.ExecQuery{Query: query, ErrorValue: errDropDB}, mysql.ExecOptions{Binlog: binlog, Flush: ptr.To(false)}); err != nil { + if err := mysql.ExecWithFlush(ctx, c.db, mysql.ExecQuery{Query: query, ErrorValue: errDropDB}, mysql.ExecOptions{Flush: ptr.To(false)}); err != nil { return err } diff --git a/pkg/controller/mysql/database/reconciler_test.go b/pkg/controller/mysql/database/reconciler_test.go index 6ae33c78..e1a6a59a 100644 --- a/pkg/controller/mysql/database/reconciler_test.go +++ b/pkg/controller/mysql/database/reconciler_test.go @@ -64,7 +64,7 @@ func TestConnect(t *testing.T) { type fields struct { kube client.Client usage resource.Tracker - newDB func(creds map[string][]byte, tls *string) xsql.DB + newDB func(creds map[string][]byte, tls *string, binlog *bool) xsql.DB } type args struct { diff --git a/pkg/controller/mysql/grant/reconciler.go b/pkg/controller/mysql/grant/reconciler.go index a4d071b8..5d5b35c3 100644 --- a/pkg/controller/mysql/grant/reconciler.go +++ b/pkg/controller/mysql/grant/reconciler.go @@ -87,7 +87,7 @@ func Setup(mgr ctrl.Manager, o xpcontroller.Options) error { type connector struct { kube client.Client usage resource.Tracker - newDB func(creds map[string][]byte, tls *string) xsql.DB + newDB func(creds map[string][]byte, tls *string, binlog *bool) xsql.DB } func (c *connector) Connect(ctx context.Context, mg resource.Managed) (managed.ExternalClient, error) { @@ -121,7 +121,7 @@ func (c *connector) Connect(ctx context.Context, mg resource.Managed) (managed.E } return &external{ - db: c.newDB(s.Data, pc.Spec.TLS), + db: c.newDB(s.Data, pc.Spec.TLS, cr.Spec.ForProvider.BinLog), kube: c.kube, }, nil } @@ -259,10 +259,9 @@ func (c *external) Create(ctx context.Context, mg resource.Managed) (managed.Ext table := defaultIdentifier(cr.Spec.ForProvider.Table) privileges, grantOption := getPrivilegesString(cr.Spec.ForProvider.Privileges.ToStringSlice()) - binlog := cr.Spec.ForProvider.BinLog query := createGrantQuery(privileges, dbname, username, table, grantOption) - if err := mysql.ExecWithBinlogAndFlush(ctx, c.db, mysql.ExecQuery{Query: query, ErrorValue: errCreateGrant}, mysql.ExecOptions{Binlog: binlog}); err != nil { + if err := mysql.ExecWithFlush(ctx, c.db, mysql.ExecQuery{Query: query, ErrorValue: errCreateGrant}, mysql.ExecOptions{}); err != nil { return managed.ExternalCreation{}, err } return managed.ExternalCreation{}, nil @@ -277,7 +276,6 @@ func (c *external) Update(ctx context.Context, mg resource.Managed) (managed.Ext username := *cr.Spec.ForProvider.User dbname := defaultIdentifier(cr.Spec.ForProvider.Database) table := defaultIdentifier(cr.Spec.ForProvider.Table) - binlog := cr.Spec.ForProvider.BinLog observed := cr.Status.AtProvider.Privileges desired := cr.Spec.ForProvider.Privileges.ToStringSlice() @@ -287,11 +285,10 @@ func (c *external) Update(ctx context.Context, mg resource.Managed) (managed.Ext sort.Strings(toRevoke) privileges, grantOption := getPrivilegesString(toRevoke) query := createRevokeQuery(privileges, dbname, username, table, grantOption) - if err := mysql.ExecWithBinlogAndFlush(ctx, c.db, + if err := mysql.ExecWithFlush(ctx, c.db, mysql.ExecQuery{ Query: query, ErrorValue: errRevokeGrant, - }, mysql.ExecOptions{ - Binlog: binlog}); err != nil { + }, mysql.ExecOptions{}); err != nil { return managed.ExternalUpdate{}, err } } @@ -300,11 +297,10 @@ func (c *external) Update(ctx context.Context, mg resource.Managed) (managed.Ext sort.Strings(toGrant) privileges, grantOption := getPrivilegesString(toGrant) query := createGrantQuery(privileges, dbname, username, table, grantOption) - if err := mysql.ExecWithBinlogAndFlush(ctx, c.db, + if err := mysql.ExecWithFlush(ctx, c.db, mysql.ExecQuery{ Query: query, ErrorValue: errCreateGrant, - }, mysql.ExecOptions{ - Binlog: binlog}); err != nil { + }, mysql.ExecOptions{}); err != nil { return managed.ExternalUpdate{}, err } } @@ -369,12 +365,11 @@ func (c *external) Delete(ctx context.Context, mg resource.Managed) error { username := *cr.Spec.ForProvider.User dbname := defaultIdentifier(cr.Spec.ForProvider.Database) table := defaultIdentifier(cr.Spec.ForProvider.Table) - binlog := cr.Spec.ForProvider.BinLog privileges, grantOption := getPrivilegesString(cr.Spec.ForProvider.Privileges.ToStringSlice()) query := createRevokeQuery(privileges, dbname, username, table, grantOption) - if err := mysql.ExecWithBinlogAndFlush(ctx, c.db, mysql.ExecQuery{Query: query, ErrorValue: errRevokeGrant}, mysql.ExecOptions{Binlog: binlog}); err != nil { + if err := mysql.ExecWithFlush(ctx, c.db, mysql.ExecQuery{Query: query, ErrorValue: errRevokeGrant}, mysql.ExecOptions{}); err != nil { var myErr *mysqldriver.MySQLError if errors.As(err, &myErr) && myErr.Number == errCodeNoSuchGrant { // MySQL automatically deletes related grants if the user has been deleted diff --git a/pkg/controller/mysql/grant/reconciler_test.go b/pkg/controller/mysql/grant/reconciler_test.go index 2eefa995..1f54281f 100644 --- a/pkg/controller/mysql/grant/reconciler_test.go +++ b/pkg/controller/mysql/grant/reconciler_test.go @@ -74,7 +74,7 @@ func TestConnect(t *testing.T) { type fields struct { kube client.Client usage resource.Tracker - newDB func(creds map[string][]byte, tls *string) xsql.DB + newDB func(creds map[string][]byte, tls *string, binlog *bool) xsql.DB } type args struct { diff --git a/pkg/controller/mysql/user/reconciler.go b/pkg/controller/mysql/user/reconciler.go index b446e2bb..92e7e0fe 100644 --- a/pkg/controller/mysql/user/reconciler.go +++ b/pkg/controller/mysql/user/reconciler.go @@ -82,7 +82,7 @@ func Setup(mgr ctrl.Manager, o xpcontroller.Options) error { type connector struct { kube client.Client usage resource.Tracker - newDB func(creds map[string][]byte, tls *string) xsql.DB + newDB func(creds map[string][]byte, tls *string, binlog *bool) xsql.DB } func (c *connector) Connect(ctx context.Context, mg resource.Managed) (managed.ExternalClient, error) { @@ -116,7 +116,7 @@ func (c *connector) Connect(ctx context.Context, mg resource.Managed) (managed.E } return &external{ - db: c.newDB(s.Data, pc.Spec.TLS), + db: c.newDB(s.Data, pc.Spec.TLS, cr.Spec.ForProvider.BinLog), kube: c.kube, }, nil } @@ -251,8 +251,7 @@ func (c *external) Create(ctx context.Context, mg resource.Managed) (managed.Ext } ro := resourceOptionsToClauses(cr.Spec.ForProvider.ResourceOptions) - binlog := cr.Spec.ForProvider.BinLog - if err := c.executeCreateUserQuery(ctx, username, host, ro, pw, binlog); err != nil { + if err := c.executeCreateUserQuery(ctx, username, host, ro, pw); err != nil { return managed.ExternalCreation{}, err } @@ -265,7 +264,7 @@ func (c *external) Create(ctx context.Context, mg resource.Managed) (managed.Ext }, nil } -func (c *external) executeCreateUserQuery(ctx context.Context, username string, host string, resourceOptionsClauses []string, pw string, binlog *bool) error { +func (c *external) executeCreateUserQuery(ctx context.Context, username string, host string, resourceOptionsClauses []string, pw string) error { resourceOptions := "" if len(resourceOptionsClauses) != 0 { resourceOptions = fmt.Sprintf(" WITH %s", strings.Join(resourceOptionsClauses, " ")) @@ -279,7 +278,7 @@ func (c *external) executeCreateUserQuery(ctx context.Context, username string, resourceOptions, ) - if err := mysql.ExecWithBinlogAndFlush(ctx, c.db, mysql.ExecQuery{Query: query, ErrorValue: errCreateUser}, mysql.ExecOptions{Binlog: binlog}); err != nil { + if err := mysql.ExecWithFlush(ctx, c.db, mysql.ExecQuery{Query: query, ErrorValue: errCreateUser}, mysql.ExecOptions{}); err != nil { return err } @@ -303,14 +302,13 @@ func (c *external) Update(ctx context.Context, mg resource.Managed) (managed.Ext if len(rochanged) > 0 { resourceOptions := fmt.Sprintf("WITH %s", strings.Join(ro, " ")) - binlog := cr.Spec.ForProvider.BinLog query := fmt.Sprintf( "ALTER USER %s@%s %s", mysql.QuoteValue(username), mysql.QuoteValue(host), resourceOptions, ) - if err := mysql.ExecWithBinlogAndFlush(ctx, c.db, mysql.ExecQuery{Query: query, ErrorValue: errUpdateUser}, mysql.ExecOptions{Binlog: binlog}); err != nil { + if err := mysql.ExecWithFlush(ctx, c.db, mysql.ExecQuery{Query: query, ErrorValue: errUpdateUser}, mysql.ExecOptions{}); err != nil { return managed.ExternalUpdate{}, err } @@ -336,9 +334,8 @@ func (c *external) UpdatePassword(ctx context.Context, cr *v1alpha1.User, userna } if pwchanged { - binlog := cr.Spec.ForProvider.BinLog query := fmt.Sprintf("ALTER USER %s@%s IDENTIFIED BY %s", mysql.QuoteValue(username), mysql.QuoteValue(host), mysql.QuoteValue(pw)) - if err := mysql.ExecWithBinlogAndFlush(ctx, c.db, mysql.ExecQuery{Query: query, ErrorValue: errUpdateUser}, mysql.ExecOptions{Binlog: binlog}); err != nil { + if err := mysql.ExecWithFlush(ctx, c.db, mysql.ExecQuery{Query: query, ErrorValue: errUpdateUser}, mysql.ExecOptions{}); err != nil { return managed.ConnectionDetails{}, err } @@ -358,9 +355,8 @@ func (c *external) Delete(ctx context.Context, mg resource.Managed) error { username, host := mysql.SplitUserHost(meta.GetExternalName(cr)) - binlog := cr.Spec.ForProvider.BinLog query := fmt.Sprintf("DROP USER IF EXISTS %s@%s", mysql.QuoteValue(username), mysql.QuoteValue(host)) - if err := mysql.ExecWithBinlogAndFlush(ctx, c.db, mysql.ExecQuery{Query: query, ErrorValue: errDropUser}, mysql.ExecOptions{Binlog: binlog}); err != nil { + if err := mysql.ExecWithFlush(ctx, c.db, mysql.ExecQuery{Query: query, ErrorValue: errDropUser}, mysql.ExecOptions{}); err != nil { return err } diff --git a/pkg/controller/mysql/user/reconciler_test.go b/pkg/controller/mysql/user/reconciler_test.go index 17858ccf..855fe457 100644 --- a/pkg/controller/mysql/user/reconciler_test.go +++ b/pkg/controller/mysql/user/reconciler_test.go @@ -72,7 +72,7 @@ func TestConnect(t *testing.T) { type fields struct { kube client.Client usage resource.Tracker - newDB func(creds map[string][]byte, tls *string) xsql.DB + newDB func(creds map[string][]byte, tls *string, binlog *bool) xsql.DB } type args struct { From 883b9fb7e15173b1ead6f18ceb722922aed52c06 Mon Sep 17 00:00:00 2001 From: Batuhan Apaydin Date: Tue, 15 Oct 2024 23:29:47 +0300 Subject: [PATCH 02/24] change the host with endpoint to make it worked Signed-off-by: Batuhan Apaydin --- examples/postgresql/config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/postgresql/config.yaml b/examples/postgresql/config.yaml index 9205b6cb..a16129bb 100644 --- a/examples/postgresql/config.yaml +++ b/examples/postgresql/config.yaml @@ -24,5 +24,5 @@ spec: # stringData: # username: postgres # password: pass -# host: localhost +# endpoint: localhost # port: "5432" From 3d25f262230c38a128f72d8d3af5c6364e80b64c Mon Sep 17 00:00:00 2001 From: Duologic Date: Thu, 28 Nov 2024 11:57:46 +0100 Subject: [PATCH 03/24] ci: fix upload-artifact ref --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 271413a1..96a4218c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -293,7 +293,7 @@ jobs: BUILD_ARGS: "--load" - name: Publish Artifacts to GitHub - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v4 with: name: output path: _output/** From 414c2064a8d84eead4133074c510cd9b0dae0bde Mon Sep 17 00:00:00 2001 From: Marc Brugger Date: Thu, 28 Nov 2024 13:35:59 +0100 Subject: [PATCH 04/24] allow to define login db (#192) Signed-off-by: bakito --- apis/mssql/v1alpha1/user_types.go | 14 +- apis/mssql/v1alpha1/zz_generated.deepcopy.go | 15 ++ apis/mssql/v1alpha1/zz_generated.resolvers.go | 16 ++ .../crds/mssql.sql.crossplane.io_users.yaml | 89 ++++++++++- pkg/controller/mssql/user/reconciler.go | 36 +++-- pkg/controller/mssql/user/reconciler_test.go | 151 +++++++++++++++--- 6 files changed, 283 insertions(+), 38 deletions(-) diff --git a/apis/mssql/v1alpha1/user_types.go b/apis/mssql/v1alpha1/user_types.go index 846f16cd..eb74775e 100644 --- a/apis/mssql/v1alpha1/user_types.go +++ b/apis/mssql/v1alpha1/user_types.go @@ -36,18 +36,26 @@ type UserStatus struct { // UserParameters define the desired state of a MSSQL user instance. type UserParameters struct { + // Database allows you to specify the name of the Database the USER is created for. // +crossplane:generate:reference:type=Database Database *string `json:"database,omitempty"` - // DatabaseRef allows you to specify custom resource name of the Database + // DatabaseRef allows you to specify custom resource name of the Database the USER is created for. // to fill Database field. DatabaseRef *xpv1.Reference `json:"databaseRef,omitempty"` - // DatabaseSelector allows you to use selector constraints to select a - // Database. + // DatabaseSelector allows you to use selector constraints to select a Database the USER is created for. DatabaseSelector *xpv1.Selector `json:"databaseSelector,omitempty"` // PasswordSecretRef references the secret that contains the password used // for this user. If no reference is given, a password will be auto-generated. // +optional PasswordSecretRef *xpv1.SecretKeySelector `json:"passwordSecretRef,omitempty"` + // LoginDatabase allows you to specify the name of the Database to be used to create the user LOGIN in (normally master). + // +crossplane:generate:reference:type=Database + LoginDatabase *string `json:"loginDatabase,omitempty"` + // DatabaseRef allows you to specify custom resource name of the Database to be used to create the user LOGIN in (normally master). + // to fill Database field. + LoginDatabaseRef *xpv1.Reference `json:"loginDatabaseRef,omitempty"` + // DatabaseSelector allows you to use selector constraints to select a Database to be used to create the user LOGIN in (normally master). + LoginDatabaseSelector *xpv1.Selector `json:"loginDatabaseSelector,omitempty"` } // A UserObservation represents the observed state of a MSSQL user. diff --git a/apis/mssql/v1alpha1/zz_generated.deepcopy.go b/apis/mssql/v1alpha1/zz_generated.deepcopy.go index 729bad36..7ce2c561 100644 --- a/apis/mssql/v1alpha1/zz_generated.deepcopy.go +++ b/apis/mssql/v1alpha1/zz_generated.deepcopy.go @@ -543,6 +543,21 @@ func (in *UserParameters) DeepCopyInto(out *UserParameters) { *out = new(v1.SecretKeySelector) **out = **in } + if in.LoginDatabase != nil { + in, out := &in.LoginDatabase, &out.LoginDatabase + *out = new(string) + **out = **in + } + if in.LoginDatabaseRef != nil { + in, out := &in.LoginDatabaseRef, &out.LoginDatabaseRef + *out = new(v1.Reference) + (*in).DeepCopyInto(*out) + } + if in.LoginDatabaseSelector != nil { + in, out := &in.LoginDatabaseSelector, &out.LoginDatabaseSelector + *out = new(v1.Selector) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UserParameters. diff --git a/apis/mssql/v1alpha1/zz_generated.resolvers.go b/apis/mssql/v1alpha1/zz_generated.resolvers.go index 8c077a66..1be14579 100644 --- a/apis/mssql/v1alpha1/zz_generated.resolvers.go +++ b/apis/mssql/v1alpha1/zz_generated.resolvers.go @@ -89,5 +89,21 @@ func (mg *User) ResolveReferences(ctx context.Context, c client.Reader) error { mg.Spec.ForProvider.Database = reference.ToPtrValue(rsp.ResolvedValue) mg.Spec.ForProvider.DatabaseRef = rsp.ResolvedReference + rsp, err = r.Resolve(ctx, reference.ResolutionRequest{ + CurrentValue: reference.FromPtrValue(mg.Spec.ForProvider.LoginDatabase), + Extract: reference.ExternalName(), + Reference: mg.Spec.ForProvider.LoginDatabaseRef, + Selector: mg.Spec.ForProvider.LoginDatabaseSelector, + To: reference.To{ + List: &DatabaseList{}, + Managed: &Database{}, + }, + }) + if err != nil { + return errors.Wrap(err, "mg.Spec.ForProvider.LoginDatabase") + } + mg.Spec.ForProvider.LoginDatabase = reference.ToPtrValue(rsp.ResolvedValue) + mg.Spec.ForProvider.LoginDatabaseRef = rsp.ResolvedReference + return nil } diff --git a/package/crds/mssql.sql.crossplane.io_users.yaml b/package/crds/mssql.sql.crossplane.io_users.yaml index 6b6e1101..e90fcf9c 100644 --- a/package/crds/mssql.sql.crossplane.io_users.yaml +++ b/package/crds/mssql.sql.crossplane.io_users.yaml @@ -72,10 +72,12 @@ spec: instance. properties: database: + description: Database allows you to specify the name of the Database + the USER is created for. type: string databaseRef: description: |- - DatabaseRef allows you to specify custom resource name of the Database + DatabaseRef allows you to specify custom resource name of the Database the USER is created for. to fill Database field. properties: name: @@ -110,9 +112,90 @@ spec: - name type: object databaseSelector: + description: DatabaseSelector allows you to use selector constraints + to select a Database the USER is created for. + properties: + matchControllerRef: + description: |- + MatchControllerRef ensures an object with the same controller reference + as the selecting object is selected. + type: boolean + matchLabels: + additionalProperties: + type: string + description: MatchLabels ensures an object with matching labels + is selected. + type: object + policy: + description: Policies for selection. + properties: + resolution: + default: Required + description: |- + Resolution specifies whether resolution of this reference is required. + The default is 'Required', which means the reconcile will fail if the + reference cannot be resolved. 'Optional' means this reference will be + a no-op if it cannot be resolved. + enum: + - Required + - Optional + type: string + resolve: + description: |- + Resolve specifies when this reference should be resolved. The default + is 'IfNotPresent', which will attempt to resolve the reference only when + the corresponding field is not present. Use 'Always' to resolve the + reference on every reconcile. + enum: + - Always + - IfNotPresent + type: string + type: object + type: object + loginDatabase: + description: LoginDatabase allows you to specify the name of the + Database to be used to create the user LOGIN in (normally master). + type: string + loginDatabaseRef: description: |- - DatabaseSelector allows you to use selector constraints to select a - Database. + DatabaseRef allows you to specify custom resource name of the Database to be used to create the user LOGIN in (normally master). + to fill Database field. + properties: + name: + description: Name of the referenced object. + type: string + policy: + description: Policies for referencing. + properties: + resolution: + default: Required + description: |- + Resolution specifies whether resolution of this reference is required. + The default is 'Required', which means the reconcile will fail if the + reference cannot be resolved. 'Optional' means this reference will be + a no-op if it cannot be resolved. + enum: + - Required + - Optional + type: string + resolve: + description: |- + Resolve specifies when this reference should be resolved. The default + is 'IfNotPresent', which will attempt to resolve the reference only when + the corresponding field is not present. Use 'Always' to resolve the + reference on every reconcile. + enum: + - Always + - IfNotPresent + type: string + type: object + required: + - name + type: object + loginDatabaseSelector: + description: DatabaseSelector allows you to use selector constraints + to select a Database to be used to create the user LOGIN in + (normally master). properties: matchControllerRef: description: |- diff --git a/pkg/controller/mssql/user/reconciler.go b/pkg/controller/mssql/user/reconciler.go index 5ab1d202..054d3b04 100644 --- a/pkg/controller/mssql/user/reconciler.go +++ b/pkg/controller/mssql/user/reconciler.go @@ -119,15 +119,23 @@ func (c *connector) Connect(ctx context.Context, mg resource.Managed) (managed.E return nil, errors.Wrap(err, errGetSecret) } + userDB := c.newClient(s.Data, ptr.Deref(cr.Spec.ForProvider.Database, "")) + loginDB := userDB + if cr.Spec.ForProvider.LoginDatabase != nil { + loginDB = c.newClient(s.Data, ptr.Deref(cr.Spec.ForProvider.LoginDatabase, "")) + } + return &external{ - db: c.newClient(s.Data, ptr.Deref(cr.Spec.ForProvider.Database, "")), - kube: c.kube, + userDB: userDB, + loginDB: loginDB, + kube: c.kube, }, nil } type external struct { - db xsql.DB - kube client.Client + userDB xsql.DB + loginDB xsql.DB + kube client.Client } func (c *external) Observe(ctx context.Context, mg resource.Managed) (managed.ExternalObservation, error) { @@ -139,7 +147,7 @@ func (c *external) Observe(ctx context.Context, mg resource.Managed) (managed.Ex var name string query := "SELECT name FROM sys.database_principals WHERE type = 'S' AND name = @p1" - err := c.db.Scan(ctx, xsql.Query{ + err := c.userDB.Scan(ctx, xsql.Query{ String: query, Parameters: []interface{}{ meta.GetExternalName(cr), }, @@ -182,21 +190,21 @@ func (c *external) Create(ctx context.Context, mg resource.Managed) (managed.Ext } loginQuery := fmt.Sprintf("CREATE LOGIN %s WITH PASSWORD=%s", mssql.QuoteIdentifier(meta.GetExternalName(cr)), mssql.QuoteValue(pw)) - if err := c.db.Exec(ctx, xsql.Query{ + if err := c.loginDB.Exec(ctx, xsql.Query{ String: loginQuery, }); err != nil { return managed.ExternalCreation{}, errors.Wrapf(err, errCreateLogin, meta.GetExternalName(cr)) } userQuery := fmt.Sprintf("CREATE USER %s FOR LOGIN %s", mssql.QuoteIdentifier(meta.GetExternalName(cr)), mssql.QuoteIdentifier(meta.GetExternalName(cr))) - if err := c.db.Exec(ctx, xsql.Query{ + if err := c.userDB.Exec(ctx, xsql.Query{ String: userQuery, }); err != nil { return managed.ExternalCreation{}, errors.Wrapf(err, errCreateUser, meta.GetExternalName(cr)) } return managed.ExternalCreation{ - ConnectionDetails: c.db.GetConnectionDetails(meta.GetExternalName(cr), pw), + ConnectionDetails: c.userDB.GetConnectionDetails(meta.GetExternalName(cr), pw), }, nil } @@ -213,14 +221,14 @@ func (c *external) Update(ctx context.Context, mg resource.Managed) (managed.Ext if changed { query := fmt.Sprintf("ALTER LOGIN %s WITH PASSWORD=%s", mssql.QuoteIdentifier(meta.GetExternalName(cr)), mssql.QuoteValue(pw)) - if err := c.db.Exec(ctx, xsql.Query{ + if err := c.loginDB.Exec(ctx, xsql.Query{ String: query, }); err != nil { return managed.ExternalUpdate{}, errors.Wrap(err, errUpdateUser) } return managed.ExternalUpdate{ - ConnectionDetails: c.db.GetConnectionDetails(meta.GetExternalName(cr), pw), + ConnectionDetails: c.userDB.GetConnectionDetails(meta.GetExternalName(cr), pw), }, nil } return managed.ExternalUpdate{}, nil @@ -233,7 +241,7 @@ func (c *external) Delete(ctx context.Context, mg resource.Managed) error { } query := fmt.Sprintf("SELECT session_id FROM sys.dm_exec_sessions WHERE login_name = %s", mssql.QuoteValue(meta.GetExternalName(cr))) - rows, err := c.db.Query(ctx, xsql.Query{String: query}) + rows, err := c.userDB.Query(ctx, xsql.Query{String: query}) if err != nil { return errors.Wrap(err, errCannotGetLogins) } @@ -244,7 +252,7 @@ func (c *external) Delete(ctx context.Context, mg resource.Managed) error { if err := rows.Scan(&sessionID); err != nil { return errors.Wrap(err, errCannotGetLogins) } - if err := c.db.Exec(ctx, xsql.Query{String: fmt.Sprintf("KILL %d", sessionID)}); err != nil { + if err := c.userDB.Exec(ctx, xsql.Query{String: fmt.Sprintf("KILL %d", sessionID)}); err != nil { return errors.Wrapf(err, errCannotKillLoginSession, sessionID, meta.GetExternalName(cr)) } } @@ -252,13 +260,13 @@ func (c *external) Delete(ctx context.Context, mg resource.Managed) error { return errors.Wrap(err, errCannotGetLogins) } - if err := c.db.Exec(ctx, xsql.Query{ + if err := c.userDB.Exec(ctx, xsql.Query{ String: fmt.Sprintf("DROP USER IF EXISTS %s", mssql.QuoteIdentifier(meta.GetExternalName(cr))), }); err != nil { return errors.Wrapf(err, errDropUser, meta.GetExternalName(cr)) } - if err := c.db.Exec(ctx, xsql.Query{ + if err := c.loginDB.Exec(ctx, xsql.Query{ String: fmt.Sprintf("DROP LOGIN %s", mssql.QuoteIdentifier(meta.GetExternalName(cr))), }); err != nil { return errors.Wrapf(err, errDropLogin, meta.GetExternalName(cr)) diff --git a/pkg/controller/mssql/user/reconciler_test.go b/pkg/controller/mssql/user/reconciler_test.go index a0a3a74c..022eceb9 100644 --- a/pkg/controller/mssql/user/reconciler_test.go +++ b/pkg/controller/mssql/user/reconciler_test.go @@ -28,6 +28,7 @@ import ( "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/ptr" "sigs.k8s.io/controller-runtime/pkg/client" xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" @@ -40,6 +41,7 @@ import ( ) type mockDB struct { + database string MockExec func(ctx context.Context, q xsql.Query) error MockExecTx func(ctx context.Context, ql []xsql.Query) error MockScan func(ctx context.Context, q xsql.Query, dest ...interface{}) error @@ -92,18 +94,25 @@ func TestConnect(t *testing.T) { mg resource.Managed } + type want struct { + sameClient *bool + err error + } + cases := map[string]struct { reason string fields fields args args - want error + want want }{ "ErrNotUser": { reason: "An error should be returned if the managed resource is not a *User", args: args{ mg: nil, }, - want: errors.New(errNotUser), + want: want{ + err: errors.New(errNotUser), + }, }, "ErrTrackProviderConfigUsage": { reason: "An error should be returned if we can't track our ProviderConfig usage", @@ -113,7 +122,9 @@ func TestConnect(t *testing.T) { args: args{ mg: &v1alpha1.User{}, }, - want: errors.Wrap(errBoom, errTrackPCUsage), + want: want{ + err: errors.Wrap(errBoom, errTrackPCUsage), + }, }, "ErrGetProviderConfig": { reason: "An error should be returned if we can't get our ProviderConfig", @@ -132,7 +143,9 @@ func TestConnect(t *testing.T) { }, }, }, - want: errors.Wrap(errBoom, errGetPC), + want: want{ + err: errors.Wrap(errBoom, errGetPC), + }, }, "ErrMissingConnectionSecret": { reason: "An error should be returned if our ProviderConfig doesn't specify a connection secret", @@ -154,7 +167,9 @@ func TestConnect(t *testing.T) { }, }, }, - want: errors.New(errNoSecretRef), + want: want{ + err: errors.New(errNoSecretRef), + }, }, "ErrGetConnectionSecret": { reason: "An error should be returned if we can't get our ProviderConfig's connection secret", @@ -181,17 +196,106 @@ func TestConnect(t *testing.T) { }, }, }, - want: errors.Wrap(errBoom, errGetSecret), + want: want{ + err: errors.Wrap(errBoom, errGetSecret), + }, + }, + "Success": { + reason: "With NO login database defined, the clients should be the same", + fields: fields{ + kube: &test.MockClient{ + MockGet: test.NewMockGetFn(nil, func(obj client.Object) error { + switch o := obj.(type) { + case *v1alpha1.ProviderConfig: + o.Spec.Credentials.ConnectionSecretRef = &xpv1.SecretReference{} + case *corev1.Secret: + secret := corev1.Secret{ + Data: map[string][]byte{}, + } + secret.DeepCopyInto(obj.(*corev1.Secret)) + } + return nil + }), + }, + usage: resource.TrackerFn(func(ctx context.Context, mg resource.Managed) error { return nil }), + newDB: func(creds map[string][]byte, database string) xsql.DB { return mockDB{database: database} }, + }, + args: args{ + mg: &v1alpha1.User{ + Spec: v1alpha1.UserSpec{ + ResourceSpec: xpv1.ResourceSpec{ + ProviderConfigReference: &xpv1.Reference{}, + }, + ForProvider: v1alpha1.UserParameters{ + Database: ptr.To("success-database"), + }, + }, + }, + }, + want: want{ + err: nil, + sameClient: ptr.To(true), + }, + }, + "SuccessLoginDB": { + reason: "With the login database defined, the clients should differ", + fields: fields{ + kube: &test.MockClient{ + MockGet: test.NewMockGetFn(nil, func(obj client.Object) error { + switch o := obj.(type) { + case *v1alpha1.ProviderConfig: + o.Spec.Credentials.ConnectionSecretRef = &xpv1.SecretReference{} + case *corev1.Secret: + secret := corev1.Secret{ + Data: map[string][]byte{}, + } + secret.DeepCopyInto(obj.(*corev1.Secret)) + } + return nil + }), + }, + usage: resource.TrackerFn(func(ctx context.Context, mg resource.Managed) error { return nil }), + newDB: func(creds map[string][]byte, database string) xsql.DB { return mockDB{database: database} }, + }, + args: args{ + mg: &v1alpha1.User{ + Spec: v1alpha1.UserSpec{ + ResourceSpec: xpv1.ResourceSpec{ + ProviderConfigReference: &xpv1.Reference{}, + }, + ForProvider: v1alpha1.UserParameters{ + Database: ptr.To("success-database"), + LoginDatabase: ptr.To("success-login-database"), + }, + }, + }, + }, + want: want{ + err: nil, + sameClient: ptr.To(false), + }, }, } for name, tc := range cases { t.Run(name, func(t *testing.T) { e := &connector{kube: tc.fields.kube, usage: tc.fields.usage, newClient: tc.fields.newDB} - _, err := e.Connect(tc.args.ctx, tc.args.mg) - if diff := cmp.Diff(tc.want, err, test.EquateErrors()); diff != "" { + ec, err := e.Connect(tc.args.ctx, tc.args.mg) + if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" { t.Errorf("\n%s\ne.Connect(...): -want error, +got error:\n%s\n", tc.reason, diff) } + if tc.want.sameClient != nil { + ext := ec.(*external) + db1 := ext.userDB.(mockDB).database + db2 := ext.loginDB.(mockDB).database + if *tc.want.sameClient && db1 != db2 { + t.Errorf("\n%s\ne.Connect(...): want clients to be on the same database\n%s / %s\n", + tc.reason, db1, db2) + } else if !*tc.want.sameClient && db1 == db2 { + t.Errorf("\n%s\ne.Connect(...): want clients NOT to be the same instance\n%s\n", + tc.reason, db1) + } + } }) } } @@ -325,8 +429,9 @@ func TestObserve(t *testing.T) { for name, tc := range cases { t.Run(name, func(t *testing.T) { e := external{ - db: tc.fields.db, - kube: tc.fields.kube, + userDB: tc.fields.db, + loginDB: tc.fields.db, + kube: tc.fields.kube, } got, err := e.Observe(tc.args.ctx, tc.args.mg) if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" { @@ -474,8 +579,9 @@ func TestCreate(t *testing.T) { for name, tc := range cases { t.Run(name, func(t *testing.T) { e := external{ - db: tc.fields.db, - kube: tc.fields.kube, + userDB: tc.fields.db, + loginDB: tc.fields.db, + kube: tc.fields.kube, } got, err := e.Create(tc.args.ctx, tc.args.mg) if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" { @@ -692,8 +798,9 @@ func TestUpdate(t *testing.T) { for name, tc := range cases { t.Run(name, func(t *testing.T) { e := external{ - db: tc.fields.db, - kube: tc.args.kube, + userDB: tc.fields.db, + loginDB: tc.fields.db, + kube: tc.args.kube, } got, err := e.Update(tc.args.ctx, tc.args.mg) if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" { @@ -710,7 +817,8 @@ func TestDelete(t *testing.T) { errBoom := errors.New("boom") type fields struct { - db xsql.DB + userDB xsql.DB + loginDB xsql.DB } type args struct { @@ -734,7 +842,7 @@ func TestDelete(t *testing.T) { "ErrDropDB": { reason: "Errors dropping a user should be returned", fields: fields{ - db: &mockDB{ + userDB: &mockDB{ MockQuery: func(ctx context.Context, q xsql.Query) (*sql.Rows, error) { return mockRowsToSQLRows(sqlmock.NewRows([]string{})), nil }, @@ -742,6 +850,7 @@ func TestDelete(t *testing.T) { return errBoom }, }, + loginDB: &mockDB{}, }, args: args{ mg: &v1alpha1.User{}, @@ -751,7 +860,7 @@ func TestDelete(t *testing.T) { "Success": { reason: "No error should be returned", fields: fields{ - db: &mockDB{ + userDB: &mockDB{ MockQuery: func(ctx context.Context, q xsql.Query) (*sql.Rows, error) { return mockRowsToSQLRows(sqlmock.NewRows([]string{})), nil }, @@ -759,6 +868,12 @@ func TestDelete(t *testing.T) { return nil }, }, + loginDB: &mockDB{ + + MockExec: func(ctx context.Context, q xsql.Query) error { + return nil + }, + }, }, args: args{ mg: &v1alpha1.User{}, @@ -768,7 +883,7 @@ func TestDelete(t *testing.T) { for name, tc := range cases { t.Run(name, func(t *testing.T) { - e := external{db: tc.fields.db} + e := external{userDB: tc.fields.userDB, loginDB: tc.fields.loginDB} err := e.Delete(tc.args.ctx, tc.args.mg) if diff := cmp.Diff(tc.want, err, test.EquateErrors()); diff != "" { t.Errorf("\n%s\ne.Delete(...): -want error, +got error:\n%s\n", tc.reason, diff) From fc01ede9d856cf8436ab52b44a730f56eed2f4c2 Mon Sep 17 00:00:00 2001 From: Marc Brugger Date: Thu, 28 Nov 2024 13:36:33 +0100 Subject: [PATCH 05/24] add support for mssql schema in grants (#193) Signed-off-by: bakito --- apis/mssql/v1alpha1/grant_types.go | 6 + apis/mssql/v1alpha1/zz_generated.deepcopy.go | 5 + .../crds/mssql.sql.crossplane.io_grants.yaml | 6 + pkg/controller/mssql/grant/reconciler.go | 65 +++++--- pkg/controller/mssql/grant/reconciler_test.go | 144 +++++++++++++++++- 5 files changed, 207 insertions(+), 19 deletions(-) diff --git a/apis/mssql/v1alpha1/grant_types.go b/apis/mssql/v1alpha1/grant_types.go index 7e2aa4e5..d717c2ae 100644 --- a/apis/mssql/v1alpha1/grant_types.go +++ b/apis/mssql/v1alpha1/grant_types.go @@ -55,6 +55,11 @@ type GrantParameters struct { // for available privileges. Permissions GrantPermissions `json:"permissions"` + // Schema for the permissions to be granted for. + // +immutable + // +optional + Schema *string `json:"schema,omitempty"` + // User this grant is for. // +optional // +crossplane:generate:reference:type=User @@ -100,6 +105,7 @@ type GrantStatus struct { // +kubebuilder:printcolumn:name="AGE",type="date",JSONPath=".metadata.creationTimestamp" // +kubebuilder:printcolumn:name="ROLE",type="string",JSONPath=".spec.forProvider.user" // +kubebuilder:printcolumn:name="DATABASE",type="string",JSONPath=".spec.forProvider.database" +// +kubebuilder:printcolumn:name="SCHEMA",type="string",JSONPath=".spec.forProvider.schema" // +kubebuilder:printcolumn:name="PERMISSIONS",type="string",JSONPath=".spec.forProvider.permissions" // +kubebuilder:resource:scope=Cluster,categories={crossplane,managed,sql} type Grant struct { diff --git a/apis/mssql/v1alpha1/zz_generated.deepcopy.go b/apis/mssql/v1alpha1/zz_generated.deepcopy.go index 7ce2c561..bcaee39a 100644 --- a/apis/mssql/v1alpha1/zz_generated.deepcopy.go +++ b/apis/mssql/v1alpha1/zz_generated.deepcopy.go @@ -183,6 +183,11 @@ func (in *GrantParameters) DeepCopyInto(out *GrantParameters) { *out = make(GrantPermissions, len(*in)) copy(*out, *in) } + if in.Schema != nil { + in, out := &in.Schema, &out.Schema + *out = new(string) + **out = **in + } if in.User != nil { in, out := &in.User, &out.User *out = new(string) diff --git a/package/crds/mssql.sql.crossplane.io_grants.yaml b/package/crds/mssql.sql.crossplane.io_grants.yaml index 342e74d2..2c70d591 100644 --- a/package/crds/mssql.sql.crossplane.io_grants.yaml +++ b/package/crds/mssql.sql.crossplane.io_grants.yaml @@ -34,6 +34,9 @@ spec: - jsonPath: .spec.forProvider.database name: DATABASE type: string + - jsonPath: .spec.forProvider.schema + name: SCHEMA + type: string - jsonPath: .spec.forProvider.permissions name: PERMISSIONS type: string @@ -170,6 +173,9 @@ spec: type: string minItems: 1 type: array + schema: + description: Schema for the permissions to be granted for. + type: string user: description: User this grant is for. type: string diff --git a/pkg/controller/mssql/grant/reconciler.go b/pkg/controller/mssql/grant/reconciler.go index 35620a70..7566446d 100644 --- a/pkg/controller/mssql/grant/reconciler.go +++ b/pkg/controller/mssql/grant/reconciler.go @@ -130,7 +130,7 @@ func (c *external) Observe(ctx context.Context, mg resource.Managed) (managed.Ex return managed.ExternalObservation{}, errors.New(errNotGrant) } - permissions, err := c.getPermissions(ctx, *cr.Spec.ForProvider.User) + permissions, err := c.getPermissions(ctx, cr) if err != nil { return managed.ExternalObservation{}, err } @@ -156,7 +156,7 @@ func (c *external) Create(ctx context.Context, mg resource.Managed) (managed.Ext username := *cr.Spec.ForProvider.User permissions := strings.Join(cr.Spec.ForProvider.Permissions.ToStringSlice(), ", ") - query := fmt.Sprintf("GRANT %s TO %s", permissions, mssql.QuoteIdentifier(username)) + query := fmt.Sprintf("GRANT %s %s TO %s", permissions, onSchemaQuery(cr), mssql.QuoteIdentifier(username)) return managed.ExternalCreation{}, errors.Wrap(c.db.Exec(ctx, xsql.Query{String: query}), errGrant) } @@ -166,7 +166,7 @@ func (c *external) Update(ctx context.Context, mg resource.Managed) (managed.Ext return managed.ExternalUpdate{}, errors.New(errNotGrant) } - observed, err := c.getPermissions(ctx, *cr.Spec.ForProvider.User) + observed, err := c.getPermissions(ctx, cr) if err != nil { return managed.ExternalUpdate{}, err } @@ -175,16 +175,16 @@ func (c *external) Update(ctx context.Context, mg resource.Managed) (managed.Ext if len(toRevoke) > 0 { sort.Strings(toRevoke) - query := fmt.Sprintf("REVOKE %s FROM %s", - strings.Join(toRevoke, ", "), mssql.QuoteIdentifier(*cr.Spec.ForProvider.User)) + query := fmt.Sprintf("REVOKE %s %s FROM %s", + strings.Join(toRevoke, ", "), onSchemaQuery(cr), mssql.QuoteIdentifier(*cr.Spec.ForProvider.User)) if err = c.db.Exec(ctx, xsql.Query{String: query}); err != nil { return managed.ExternalUpdate{}, errors.Wrap(err, errRevoke) } } if len(toGrant) > 0 { sort.Strings(toGrant) - query := fmt.Sprintf("GRANT %s TO %s", - strings.Join(toGrant, ", "), mssql.QuoteIdentifier(*cr.Spec.ForProvider.User)) + query := fmt.Sprintf("GRANT %s %s TO %s", + strings.Join(toGrant, ", "), onSchemaQuery(cr), mssql.QuoteIdentifier(*cr.Spec.ForProvider.User)) if err = c.db.Exec(ctx, xsql.Query{String: query}); err != nil { return managed.ExternalUpdate{}, errors.Wrap(err, errGrant) } @@ -200,23 +200,47 @@ func (c *external) Delete(ctx context.Context, mg resource.Managed) error { username := *cr.Spec.ForProvider.User - query := fmt.Sprintf("REVOKE %s FROM %s", + query := fmt.Sprintf("REVOKE %s %s FROM %s", strings.Join(cr.Spec.ForProvider.Permissions.ToStringSlice(), ", "), + onSchemaQuery(cr), mssql.QuoteIdentifier(username), ) return errors.Wrap(c.db.Exec(ctx, xsql.Query{String: query}), errRevoke) } -func (c *external) getPermissions(ctx context.Context, username string) ([]string, error) { - // TODO(turkenh/ulucinar): Possible performance improvement. We first - // calculate the Cartesian product, and then filter. It would be more - // efficient to first filter principals by name, and then join. - query := fmt.Sprintf(`SELECT pe.permission_name - FROM sys.database_principals AS pr - JOIN sys.database_permissions AS pe - ON pe.grantee_principal_id = pr.principal_id +// TODO(turkenh/ulucinar): Possible performance improvement. We first +// +// calculate the Cartesian product, and then filter. It would be more +// efficient to first filter principals by name, and then join. +const queryPermissionDefault = `SELECT pe.permission_name + FROM sys.database_principals AS pr + JOIN sys.database_permissions AS pe + ON pe.grantee_principal_id = pr.principal_id WHERE - pr.name = %s`, mssql.QuoteValue(username)) + pe.class = 0 /* DATABASE (default) */ + AND pr.name = %s` + +const queryPermissionSchema = `SELECT pe.permission_name + FROM sys.database_principals AS pr + JOIN sys.database_permissions AS pe + ON pe.grantee_principal_id = pr.principal_id + JOIN sys.schemas AS s + ON s.schema_id = pe.major_id + WHERE + pe.class = 3 /* SCHEMA */ + AND s.name = %s + AND pr.name = %s` + +func (c *external) getPermissions(ctx context.Context, cr *v1alpha1.Grant) ([]string, error) { + var query string + if cr.Spec.ForProvider.Schema == nil { + query = fmt.Sprintf(queryPermissionDefault, mssql.QuoteValue(*cr.Spec.ForProvider.User)) + } else { + query = fmt.Sprintf(queryPermissionSchema, + mssql.QuoteValue(*cr.Spec.ForProvider.Schema), + mssql.QuoteValue(*cr.Spec.ForProvider.User), + ) + } rows, err := c.db.Query(ctx, xsql.Query{String: query}) if err != nil { return nil, errors.Wrap(err, errCannotGetGrants) @@ -237,6 +261,13 @@ func (c *external) getPermissions(ctx context.Context, username string) ([]strin return permissions, nil } +func onSchemaQuery(cr *v1alpha1.Grant) (schema string) { + if cr.Spec.ForProvider.Schema != nil { + schema = fmt.Sprintf("ON SCHEMA::%s", *cr.Spec.ForProvider.Schema) + } + return +} + func diffPermissions(desired, observed []string) ([]string, []string) { md := make(map[string]struct{}, len(desired)) mo := make(map[string]struct{}, len(observed)) diff --git a/pkg/controller/mssql/grant/reconciler_test.go b/pkg/controller/mssql/grant/reconciler_test.go index 7227f100..65aba6f1 100644 --- a/pkg/controller/mssql/grant/reconciler_test.go +++ b/pkg/controller/mssql/grant/reconciler_test.go @@ -266,6 +266,9 @@ func TestObserve(t *testing.T) { fields: fields{ db: mockDB{ MockQuery: func(ctx context.Context, q xsql.Query) (*sql.Rows, error) { + if strings.Contains(q.String, "sys.schemas") { + return nil, errBoom + } return mockRowsToSQLRows( sqlmock.NewRows( []string{"Grants"}, @@ -293,6 +296,42 @@ func TestObserve(t *testing.T) { err: nil, }, }, + "SuccessSchema": { + reason: "We should return no error if we can successfully get our permissions", + fields: fields{ + db: mockDB{ + MockQuery: func(ctx context.Context, q xsql.Query) (*sql.Rows, error) { + if !strings.Contains(q.String, "sys.schemas") { + return nil, errBoom + } + return mockRowsToSQLRows( + sqlmock.NewRows( + []string{"Grants"}, + ).AddRow("ALTER"), + ), nil + }, + }, + }, + args: args{ + mg: &v1alpha1.Grant{ + Spec: v1alpha1.GrantSpec{ + ForProvider: v1alpha1.GrantParameters{ + Database: ptr.To("success-db"), + User: ptr.To("success-user"), + Schema: ptr.To("success-schema"), + Permissions: v1alpha1.GrantPermissions{"ALTER"}, + }, + }, + }, + }, + want: want{ + o: managed.ExternalObservation{ + ResourceExists: true, + ResourceUpToDate: true, + }, + err: nil, + }, + }, "SuccessDiffPermissions": { reason: "We should return no error if different permissions exist", fields: fields{ @@ -430,7 +469,12 @@ func TestCreate(t *testing.T) { reason: "No error should be returned when we successfully create a grant", fields: fields{ db: &mockDB{ - MockExec: func(ctx context.Context, q xsql.Query) error { return nil }, + MockExec: func(ctx context.Context, q xsql.Query) error { + if strings.Contains(q.String, "ON SCHEMA::") { + return errBoom + } + return nil + }, }, }, args: args{ @@ -448,6 +492,34 @@ func TestCreate(t *testing.T) { err: nil, }, }, + "SuccessSchema": { + reason: "No error should be returned when we successfully create a grant", + fields: fields{ + db: &mockDB{ + MockExec: func(ctx context.Context, q xsql.Query) error { + if !strings.Contains(q.String, "ON SCHEMA::") { + return errBoom + } + return nil + }, + }, + }, + args: args{ + mg: &v1alpha1.Grant{ + Spec: v1alpha1.GrantSpec{ + ForProvider: v1alpha1.GrantParameters{ + Database: ptr.To("test-example"), + User: ptr.To("test-example"), + Schema: ptr.To("success-schema"), + Permissions: v1alpha1.GrantPermissions{"ALTER"}, + }, + }, + }, + }, + want: want{ + err: nil, + }, + }, } for name, tc := range cases { @@ -529,6 +601,9 @@ func TestUpdate(t *testing.T) { return mockRowsToSQLRows(sqlmock.NewRows([]string{})), nil }, MockExec: func(ctx context.Context, q xsql.Query) error { + if strings.Contains(q.String, "ON SCHEMA::") { + return errBoom + } if strings.Contains(q.String, "CREATE, DELETE") { return nil } @@ -552,6 +627,41 @@ func TestUpdate(t *testing.T) { c: managed.ExternalUpdate{}, }, }, + "SuccessSchema": { + reason: "No error should be returned when we update a grant", + fields: fields{ + db: &mockDB{ + MockQuery: func(ctx context.Context, q xsql.Query) (*sql.Rows, error) { + return mockRowsToSQLRows(sqlmock.NewRows([]string{})), nil + }, + MockExec: func(ctx context.Context, q xsql.Query) error { + if !strings.Contains(q.String, "ON SCHEMA::") { + return errBoom + } + if strings.Contains(q.String, "ALTER") { + return nil + } + return errBoom + }, + }, + }, + args: args{ + mg: &v1alpha1.Grant{ + Spec: v1alpha1.GrantSpec{ + ForProvider: v1alpha1.GrantParameters{ + Database: ptr.To("test-example"), + User: ptr.To("test-example"), + Schema: ptr.To("success-schema"), + Permissions: v1alpha1.GrantPermissions{"ALTER"}, + }, + }, + }, + }, + want: want{ + err: nil, + c: managed.ExternalUpdate{}, + }, + }, } for name, tc := range cases { @@ -630,7 +740,37 @@ func TestDelete(t *testing.T) { }, fields: fields{ db: &mockDB{ - MockExec: func(ctx context.Context, q xsql.Query) error { return nil }, + MockExec: func(ctx context.Context, q xsql.Query) error { + if strings.Contains(q.String, "ON SCHEMA::") { + return errBoom + } + return nil + }, + }, + }, + want: nil, + }, + "SuccessSchema": { + reason: "No error should be returned if the grant was revoked", + args: args{ + mg: &v1alpha1.Grant{ + Spec: v1alpha1.GrantSpec{ + ForProvider: v1alpha1.GrantParameters{ + Database: ptr.To("test-example"), + User: ptr.To("test-example"), + Schema: ptr.To("success-schema"), + }, + }, + }, + }, + fields: fields{ + db: &mockDB{ + MockExec: func(ctx context.Context, q xsql.Query) error { + if !strings.Contains(q.String, "ON SCHEMA::") { + return errBoom + } + return nil + }, }, }, want: nil, From 0890de04b084a0d533d15b3bd898c4a60f14f136 Mon Sep 17 00:00:00 2001 From: Marius Leahu <11443917+mleahu@users.noreply.github.com> Date: Thu, 28 Nov 2024 14:37:51 +0100 Subject: [PATCH 06/24] optional binlog parameters in mysql connection string to allow the use of DB default setting (#201) Signed-off-by: Marius Leahu --- apis/mysql/v1alpha1/database_types.go | 2 +- apis/mysql/v1alpha1/grant_types.go | 2 +- apis/mysql/v1alpha1/user_types.go | 2 +- pkg/clients/mysql/mysql.go | 22 +++++++++++++--------- pkg/clients/mysql/mysql_test.go | 19 ++++++++++++++++++- 5 files changed, 34 insertions(+), 13 deletions(-) diff --git a/apis/mysql/v1alpha1/database_types.go b/apis/mysql/v1alpha1/database_types.go index 3b6fd865..ef6aac2c 100644 --- a/apis/mysql/v1alpha1/database_types.go +++ b/apis/mysql/v1alpha1/database_types.go @@ -37,7 +37,7 @@ type DatabaseStatus struct { type DatabaseParameters struct { // BinLog defines whether the create, delete, update operations of this database are propagated to replicas. Defaults to true // +optional - BinLog *bool `json:"binlog,omitempty" default:"true"` + BinLog *bool `json:"binlog,omitempty"` } // +kubebuilder:object:root=true diff --git a/apis/mysql/v1alpha1/grant_types.go b/apis/mysql/v1alpha1/grant_types.go index a3c5f12e..4c5dc4c5 100644 --- a/apis/mysql/v1alpha1/grant_types.go +++ b/apis/mysql/v1alpha1/grant_types.go @@ -95,7 +95,7 @@ type GrantParameters struct { // BinLog defines whether the create, delete, update operations of this grant are propagated to replicas. Defaults to true // +optional - BinLog *bool `json:"binlog,omitempty" default:"true"` + BinLog *bool `json:"binlog,omitempty"` } // A GrantStatus represents the observed state of a Grant. diff --git a/apis/mysql/v1alpha1/user_types.go b/apis/mysql/v1alpha1/user_types.go index 89fe9d98..069d34e9 100644 --- a/apis/mysql/v1alpha1/user_types.go +++ b/apis/mysql/v1alpha1/user_types.go @@ -48,7 +48,7 @@ type UserParameters struct { // BinLog defines whether the create, delete, update operations of this user are propagated to replicas. Defaults to true // +optional - BinLog *bool `json:"binlog,omitempty" default:"true"` + BinLog *bool `json:"binlog,omitempty"` } // ResourceOptions define the account specific resource limits. diff --git a/pkg/clients/mysql/mysql.go b/pkg/clients/mysql/mysql.go index dbcaa28f..5e462383 100644 --- a/pkg/clients/mysql/mysql.go +++ b/pkg/clients/mysql/mysql.go @@ -38,11 +38,7 @@ func New(creds map[string][]byte, tls *string, binlog *bool) xsql.DB { defaultTLS := "preferred" tls = &defaultTLS } - if binlog == nil { - defaultBinlog := true - binlog = &defaultBinlog - } - dsn := DSN(username, password, endpoint, port, *tls, *binlog) + dsn := DSN(username, password, endpoint, port, *tls, binlog) return mySQLDB{ dsn: dsn, @@ -53,17 +49,25 @@ func New(creds map[string][]byte, tls *string, binlog *bool) xsql.DB { } // DSN returns the DSN URL -func DSN(username, password, endpoint, port, tls string, binlog bool) string { +func DSN(username, password, endpoint, port, tls string, binlog *bool) string { // Use net/url UserPassword to encode the username and password // This will ensure that any special characters in the username or password // are percent-encoded for use in the user info portion of the DSN URL - return fmt.Sprintf("%s:%s@tcp(%s:%s)/?tls=%s&sql_log_bin=%s", + if binlog != nil { + return fmt.Sprintf("%s:%s@tcp(%s:%s)/?tls=%s&sql_log_bin=%s", + username, + password, + endpoint, + port, + tls, + strconv.FormatBool(*binlog)) + } + return fmt.Sprintf("%s:%s@tcp(%s:%s)/?tls=%s", username, password, endpoint, port, - tls, - strconv.FormatBool(binlog)) + tls) } // ExecTx is unsupported in MySQL. diff --git a/pkg/clients/mysql/mysql_test.go b/pkg/clients/mysql/mysql_test.go index 2a9cc889..13aacdc6 100644 --- a/pkg/clients/mysql/mysql_test.go +++ b/pkg/clients/mysql/mysql_test.go @@ -13,7 +13,7 @@ func TestDSNURLEscaping(t *testing.T) { rawPass := "password^" tls := "true" binlog := false - dsn := DSN(user, rawPass, endpoint, port, tls, binlog) + dsn := DSN(user, rawPass, endpoint, port, tls, &binlog) if dsn != fmt.Sprintf("%s:%s@tcp(%s:%s)/?tls=%s&sql_log_bin=%s", user, rawPass, @@ -21,6 +21,23 @@ func TestDSNURLEscaping(t *testing.T) { port, tls, strconv.FormatBool(binlog)) { + t.Errorf("DSN string did not match expected output with URL encoded and binlog") + } +} + +func TestDSNURLEscapingWithoutBinLog(t *testing.T) { + endpoint := "endpoint" + port := "3306" + user := "username" + rawPass := "password^" + tls := "true" + dsn := DSN(user, rawPass, endpoint, port, tls, nil) + if dsn != fmt.Sprintf("%s:%s@tcp(%s:%s)/?tls=%s", + user, + rawPass, + endpoint, + port, + tls) { t.Errorf("DSN string did not match expected output with URL encoded") } } From 49c9535fe449ca69f2a228f5b2545321db348b9d Mon Sep 17 00:00:00 2001 From: Jeroen Op 't Eynde Date: Thu, 28 Nov 2024 14:42:03 +0100 Subject: [PATCH 07/24] fix: remove unneeded flush privileges call for mysql (#202) Signed-off-by: Marius Ziemke Co-authored-by: Marius Ziemke --- pkg/clients/mysql/mysql.go | 24 ++------------------- pkg/controller/mysql/database/reconciler.go | 5 ++--- pkg/controller/mysql/grant/reconciler.go | 12 +++++------ pkg/controller/mysql/user/reconciler.go | 8 +++---- 4 files changed, 14 insertions(+), 35 deletions(-) diff --git a/pkg/clients/mysql/mysql.go b/pkg/clients/mysql/mysql.go index 5e462383..3a9e02d9 100644 --- a/pkg/clients/mysql/mysql.go +++ b/pkg/clients/mysql/mysql.go @@ -9,7 +9,6 @@ import ( "github.com/crossplane-contrib/provider-sql/pkg/clients/xsql" "github.com/pkg/errors" - "k8s.io/utils/ptr" xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" "github.com/crossplane/crossplane-runtime/pkg/reconciler/managed" @@ -17,7 +16,6 @@ import ( const ( errNotSupported = "%s not supported by mysql client" - errFlushPriv = "cannot flush privileges" ) type mySQLDB struct { @@ -150,31 +148,13 @@ type ExecQuery struct { ErrorValue string } -// ExecOptions parametrizes which optional statements will be executed before or after ExecQuery.Query -type ExecOptions struct { - // Flush defines whether privileges will be flushed after executing the query. Defaults to true - Flush *bool -} - -// ExecWithFlush is a wrapper function for xsql.DB.Exec() that allows the execution of optional queries before and after the provided query -func ExecWithFlush(ctx context.Context, db xsql.DB, query ExecQuery, options ExecOptions) error { - if options.Flush == nil { - options.Flush = ptr.To(true) - } - +// ExecWrapper is a wrapper function for xsql.DB.Exec() that allows the execution of optional queries before and after the provided query +func ExecWrapper(ctx context.Context, db xsql.DB, query ExecQuery) error { if err := db.Exec(ctx, xsql.Query{ String: query.Query, }); err != nil { return errors.Wrap(err, query.ErrorValue) } - if *options.Flush { - if err := db.Exec(ctx, xsql.Query{ - String: "FLUSH PRIVILEGES", - }); err != nil { - return errors.Wrap(err, errFlushPriv) - } - } - return nil } diff --git a/pkg/controller/mysql/database/reconciler.go b/pkg/controller/mysql/database/reconciler.go index 9f60e786..c7cbdf8b 100644 --- a/pkg/controller/mysql/database/reconciler.go +++ b/pkg/controller/mysql/database/reconciler.go @@ -22,7 +22,6 @@ import ( "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/types" - "k8s.io/utils/ptr" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller" @@ -150,7 +149,7 @@ func (c *external) Create(ctx context.Context, mg resource.Managed) (managed.Ext query := "CREATE DATABASE " + mysql.QuoteIdentifier(meta.GetExternalName(cr)) - if err := mysql.ExecWithFlush(ctx, c.db, mysql.ExecQuery{Query: query, ErrorValue: errCreateDB}, mysql.ExecOptions{Flush: ptr.To(false)}); err != nil { + if err := mysql.ExecWrapper(ctx, c.db, mysql.ExecQuery{Query: query, ErrorValue: errCreateDB}); err != nil { return managed.ExternalCreation{}, err } @@ -170,7 +169,7 @@ func (c *external) Delete(ctx context.Context, mg resource.Managed) error { query := "DROP DATABASE IF EXISTS " + mysql.QuoteIdentifier(meta.GetExternalName(cr)) - if err := mysql.ExecWithFlush(ctx, c.db, mysql.ExecQuery{Query: query, ErrorValue: errDropDB}, mysql.ExecOptions{Flush: ptr.To(false)}); err != nil { + if err := mysql.ExecWrapper(ctx, c.db, mysql.ExecQuery{Query: query, ErrorValue: errDropDB}); err != nil { return err } diff --git a/pkg/controller/mysql/grant/reconciler.go b/pkg/controller/mysql/grant/reconciler.go index 5d5b35c3..2753e13e 100644 --- a/pkg/controller/mysql/grant/reconciler.go +++ b/pkg/controller/mysql/grant/reconciler.go @@ -261,7 +261,7 @@ func (c *external) Create(ctx context.Context, mg resource.Managed) (managed.Ext privileges, grantOption := getPrivilegesString(cr.Spec.ForProvider.Privileges.ToStringSlice()) query := createGrantQuery(privileges, dbname, username, table, grantOption) - if err := mysql.ExecWithFlush(ctx, c.db, mysql.ExecQuery{Query: query, ErrorValue: errCreateGrant}, mysql.ExecOptions{}); err != nil { + if err := mysql.ExecWrapper(ctx, c.db, mysql.ExecQuery{Query: query, ErrorValue: errCreateGrant}); err != nil { return managed.ExternalCreation{}, err } return managed.ExternalCreation{}, nil @@ -285,10 +285,10 @@ func (c *external) Update(ctx context.Context, mg resource.Managed) (managed.Ext sort.Strings(toRevoke) privileges, grantOption := getPrivilegesString(toRevoke) query := createRevokeQuery(privileges, dbname, username, table, grantOption) - if err := mysql.ExecWithFlush(ctx, c.db, + if err := mysql.ExecWrapper(ctx, c.db, mysql.ExecQuery{ Query: query, ErrorValue: errRevokeGrant, - }, mysql.ExecOptions{}); err != nil { + }); err != nil { return managed.ExternalUpdate{}, err } } @@ -297,10 +297,10 @@ func (c *external) Update(ctx context.Context, mg resource.Managed) (managed.Ext sort.Strings(toGrant) privileges, grantOption := getPrivilegesString(toGrant) query := createGrantQuery(privileges, dbname, username, table, grantOption) - if err := mysql.ExecWithFlush(ctx, c.db, + if err := mysql.ExecWrapper(ctx, c.db, mysql.ExecQuery{ Query: query, ErrorValue: errCreateGrant, - }, mysql.ExecOptions{}); err != nil { + }); err != nil { return managed.ExternalUpdate{}, err } } @@ -369,7 +369,7 @@ func (c *external) Delete(ctx context.Context, mg resource.Managed) error { privileges, grantOption := getPrivilegesString(cr.Spec.ForProvider.Privileges.ToStringSlice()) query := createRevokeQuery(privileges, dbname, username, table, grantOption) - if err := mysql.ExecWithFlush(ctx, c.db, mysql.ExecQuery{Query: query, ErrorValue: errRevokeGrant}, mysql.ExecOptions{}); err != nil { + if err := mysql.ExecWrapper(ctx, c.db, mysql.ExecQuery{Query: query, ErrorValue: errRevokeGrant}); err != nil { var myErr *mysqldriver.MySQLError if errors.As(err, &myErr) && myErr.Number == errCodeNoSuchGrant { // MySQL automatically deletes related grants if the user has been deleted diff --git a/pkg/controller/mysql/user/reconciler.go b/pkg/controller/mysql/user/reconciler.go index 92e7e0fe..693f5276 100644 --- a/pkg/controller/mysql/user/reconciler.go +++ b/pkg/controller/mysql/user/reconciler.go @@ -278,7 +278,7 @@ func (c *external) executeCreateUserQuery(ctx context.Context, username string, resourceOptions, ) - if err := mysql.ExecWithFlush(ctx, c.db, mysql.ExecQuery{Query: query, ErrorValue: errCreateUser}, mysql.ExecOptions{}); err != nil { + if err := mysql.ExecWrapper(ctx, c.db, mysql.ExecQuery{Query: query, ErrorValue: errCreateUser}); err != nil { return err } @@ -308,7 +308,7 @@ func (c *external) Update(ctx context.Context, mg resource.Managed) (managed.Ext mysql.QuoteValue(host), resourceOptions, ) - if err := mysql.ExecWithFlush(ctx, c.db, mysql.ExecQuery{Query: query, ErrorValue: errUpdateUser}, mysql.ExecOptions{}); err != nil { + if err := mysql.ExecWrapper(ctx, c.db, mysql.ExecQuery{Query: query, ErrorValue: errUpdateUser}); err != nil { return managed.ExternalUpdate{}, err } @@ -335,7 +335,7 @@ func (c *external) UpdatePassword(ctx context.Context, cr *v1alpha1.User, userna if pwchanged { query := fmt.Sprintf("ALTER USER %s@%s IDENTIFIED BY %s", mysql.QuoteValue(username), mysql.QuoteValue(host), mysql.QuoteValue(pw)) - if err := mysql.ExecWithFlush(ctx, c.db, mysql.ExecQuery{Query: query, ErrorValue: errUpdateUser}, mysql.ExecOptions{}); err != nil { + if err := mysql.ExecWrapper(ctx, c.db, mysql.ExecQuery{Query: query, ErrorValue: errUpdateUser}); err != nil { return managed.ConnectionDetails{}, err } @@ -356,7 +356,7 @@ func (c *external) Delete(ctx context.Context, mg resource.Managed) error { username, host := mysql.SplitUserHost(meta.GetExternalName(cr)) query := fmt.Sprintf("DROP USER IF EXISTS %s@%s", mysql.QuoteValue(username), mysql.QuoteValue(host)) - if err := mysql.ExecWithFlush(ctx, c.db, mysql.ExecQuery{Query: query, ErrorValue: errDropUser}, mysql.ExecOptions{}); err != nil { + if err := mysql.ExecWrapper(ctx, c.db, mysql.ExecQuery{Query: query, ErrorValue: errDropUser}); err != nil { return err } From 9189b596154575576a41943164a64540c632de2b Mon Sep 17 00:00:00 2001 From: Mathieu Frenette <1917993+silphid@users.noreply.github.com> Date: Thu, 28 Nov 2024 08:44:51 -0500 Subject: [PATCH 08/24] feat: add custom tls config support to mysql (#184) * feat: add custom tls config support Signed-off-by: Mathieu Frenette * use provider config name to make tls name unique Signed-off-by: Mathieu Frenette * refactor integration tests into modular functions Signed-off-by: Mathieu Frenette --------- Signed-off-by: Mathieu Frenette Co-authored-by: Mathieu Frenette --- apis/mysql/v1alpha1/provider_types.go | 20 +- apis/mysql/v1alpha1/zz_generated.deepcopy.go | 39 ++ cluster/local/integration_tests.sh | 479 ++++++++++++------ examples/mysql/config.yaml | 2 +- examples/mysql/config_tls.yaml | 29 ++ ...sql.sql.crossplane.io_providerconfigs.yaml | 81 +++ pkg/controller/mysql/database/reconciler.go | 12 +- pkg/controller/mysql/grant/reconciler.go | 12 +- pkg/controller/mysql/tls/tls.go | 112 ++++ pkg/controller/mysql/user/reconciler.go | 12 +- 10 files changed, 646 insertions(+), 152 deletions(-) create mode 100644 examples/mysql/config_tls.yaml create mode 100644 pkg/controller/mysql/tls/tls.go diff --git a/apis/mysql/v1alpha1/provider_types.go b/apis/mysql/v1alpha1/provider_types.go index b193f657..0b8c892d 100644 --- a/apis/mysql/v1alpha1/provider_types.go +++ b/apis/mysql/v1alpha1/provider_types.go @@ -31,9 +31,27 @@ type ProviderConfigSpec struct { // or use preferred to use TLS only when advertised by the server. This is similar // to skip-verify, but additionally allows a fallback to a connection which is // not encrypted. Neither skip-verify nor preferred add any reliable security. - // +kubebuilder:validation:Enum="true";skip-verify;preferred + // Alternatively, set tls=custom and provide a custom TLS configuration via the tlsConfig field. + // +kubebuilder:validation:Enum="true";skip-verify;preferred;custom // +optional TLS *string `json:"tls"` + + // Optional TLS configuration for sql driver. Setting this field also requires the tls field to be set to custom. + // +optional + TLSConfig *TLSConfig `json:"tlsConfig"` +} + +// TLSConfig defines the TLS configuration for the provider when tls=custom. +type TLSConfig struct { + CACert TLSSecret `json:"caCert,omitempty"` + ClientCert TLSSecret `json:"clientCert,omitempty"` + ClientKey TLSSecret `json:"clientKey,omitempty"` + InsecureSkipVerify bool `json:"insecureSkipVerify,omitempty"` +} + +// TLSSecret defines a reference to a K8s secret and its specific internal key that contains the TLS cert/keys in PEM format. +type TLSSecret struct { + SecretRef xpv1.SecretKeySelector `json:"secretRef,omitempty"` } const ( diff --git a/apis/mysql/v1alpha1/zz_generated.deepcopy.go b/apis/mysql/v1alpha1/zz_generated.deepcopy.go index 2f813766..4dfc6379 100644 --- a/apis/mysql/v1alpha1/zz_generated.deepcopy.go +++ b/apis/mysql/v1alpha1/zz_generated.deepcopy.go @@ -397,6 +397,11 @@ func (in *ProviderConfigSpec) DeepCopyInto(out *ProviderConfigSpec) { *out = new(string) **out = **in } + if in.TLSConfig != nil { + in, out := &in.TLSConfig, &out.TLSConfig + *out = new(TLSConfig) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderConfigSpec. @@ -538,6 +543,40 @@ func (in *ResourceOptions) DeepCopy() *ResourceOptions { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TLSConfig) DeepCopyInto(out *TLSConfig) { + *out = *in + out.CACert = in.CACert + out.ClientCert = in.ClientCert + out.ClientKey = in.ClientKey +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TLSConfig. +func (in *TLSConfig) DeepCopy() *TLSConfig { + if in == nil { + return nil + } + out := new(TLSConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TLSSecret) DeepCopyInto(out *TLSSecret) { + *out = *in + out.SecretRef = in.SecretRef +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TLSSecret. +func (in *TLSSecret) DeepCopy() *TLSSecret { + if in == nil { + return nil + } + out := new(TLSSecret) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *User) DeepCopyInto(out *User) { *out = *in diff --git a/cluster/local/integration_tests.sh b/cluster/local/integration_tests.sh index 06661871..17ed43e1 100755 --- a/cluster/local/integration_tests.sh +++ b/cluster/local/integration_tests.sh @@ -7,27 +7,27 @@ YLW='\033[0;33m' GRN='\033[0;32m' RED='\033[0;31m' NOC='\033[0m' # No Color -echo_info(){ +echo_info() { printf "\n${BLU}%s${NOC}" "$1" } -echo_step(){ +echo_step() { printf "\n${BLU}>>>>>>> %s${NOC}\n" "$1" } -echo_sub_step(){ +echo_sub_step() { printf "\n${BLU}>>> %s${NOC}\n" "$1" } -echo_step_completed(){ +echo_step_completed() { printf "${GRN} [✔]${NOC}" } -echo_success(){ +echo_success() { printf "\n${GRN}%s${NOC}\n" "$1" } -echo_warn(){ +echo_warn() { printf "\n${YLW}%s${NOC}" "$1" } -echo_error(){ +echo_error() { printf "\n${RED}%s${NOC}" "$1" exit 1 } @@ -47,51 +47,57 @@ version_tag="$(cat ${projectdir}/_output/version)" # tag as latest version to load into kind cluster K8S_CLUSTER="${K8S_CLUSTER:-${BUILD_REGISTRY}-inttests}" -CROSSPLANE_NAMESPACE="crossplane-system" PACKAGE_NAME="provider-sql" +MARIADB_ROOT_PW=$(openssl rand -base64 32) +MARIADB_TEST_PW=$(openssl rand -base64 32) # cleanup on exit if [ "$skipcleanup" != true ]; then function cleanup { echo_step "Cleaning up..." export KUBECONFIG= - "${KIND}" delete cluster --name="${K8S_CLUSTER}" + cleanup_cluster } trap cleanup EXIT fi -# setup package cache -echo_step "setting up local package cache" -CACHE_PATH="${projectdir}/.work/inttest-package-cache" -mkdir -p "${CACHE_PATH}" -echo "created cache dir at ${CACHE_PATH}" -"${UP}" alpha xpkg xp-extract --from-xpkg "${OUTPUT_DIR}"/xpkg/linux_"${SAFEHOSTARCH}"/"${PACKAGE_NAME}"-"${VERSION}".xpkg -o "${CACHE_PATH}/${PACKAGE_NAME}.gz" && chmod 644 "${CACHE_PATH}/${PACKAGE_NAME}.gz" - -# create kind cluster with extra mounts -KIND_NODE_IMAGE="kindest/node:${KIND_NODE_IMAGE_TAG}" -echo_step "creating k8s cluster using kind ${KIND_VERSION} and node image ${KIND_NODE_IMAGE}" -KIND_CONFIG="$( cat < $current ]]; then - echo_error "timeout of ${timeout}s has been reached" - fi - sleep $step; -done + )" + + echo "${yaml}" | "${KUBECTL}" apply -f - +} + +cleanup_provider_config() { + echo_step "cleaning up ProviderConfig" + "${KUBECTL}" delete providerconfig.mysql.sql.crossplane.io default +} + +setup_mariadb_no_tls() { + echo_step "installing MariaDB with no TLS" + "${KUBECTL}" create secret generic mariadb-creds \ + --from-literal username="root" \ + --from-literal password="${MARIADB_ROOT_PW}" \ + --from-literal endpoint="mariadb.default.svc.cluster.local" \ + --from-literal port="3306" + + "${HELM3}" repo add bitnami https://charts.bitnami.com/bitnami >/dev/null + "${HELM3}" install mariadb bitnami/mariadb \ + --version 11.3.0 \ + --set auth.rootPassword="${MARIADB_ROOT_PW}" \ + --wait +} + +setup_mariadb_tls() { + echo_step "installing MariaDB with TLS" + "${KUBECTL}" create secret generic mariadb-creds \ + --from-literal username="test" \ + --from-literal password="${MARIADB_TEST_PW}" \ + --from-literal endpoint="mariadb.default.svc.cluster.local" \ + --from-literal port="3306" \ + --from-file=ca-cert.pem \ + --from-file=client-cert.pem \ + --from-file=client-key.pem + + local values=$(cat </dev/null + "${HELM3}" install mariadb bitnami/mariadb \ + --version 11.3.0 \ + --values <(echo "$values") \ + --wait +} + +cleanup_mariadb() { + echo_step "uninstalling MariaDB" + "${HELM3}" uninstall mariadb + "${KUBECTL}" delete secret mariadb-creds +} + +test_create_database() { + echo_step "test creating MySQL Database resource" + "${KUBECTL}" apply -f ${projectdir}/examples/mysql/database.yaml + + echo_info "check if is ready" + "${KUBECTL}" wait --timeout 2m --for condition=Ready -f ${projectdir}/examples/mysql/database.yaml + echo_step_completed +} + +test_create_user() { + echo_step "test creating MySQL User resource" + local user_pw="asdf1234" + "${KUBECTL}" create secret generic example-pw --from-literal password="${user_pw}" + "${KUBECTL}" apply -f ${projectdir}/examples/mysql/user.yaml + + echo_info "check if is ready" + "${KUBECTL}" wait --timeout 2m --for condition=Ready -f ${projectdir}/examples/mysql/user.yaml + echo_step_completed + + echo_info "check if connection secret exists" + local pw=$("${KUBECTL}" get secret example-connection-secret -ojsonpath='{.data.password}' | base64 --decode) + [ "${pw}" == "${user_pw}" ] + echo_step_completed +} + +test_update_user_password() { + echo_step "test updating MySQL User password" + local user_pw="newpassword" + "${KUBECTL}" create secret generic example-pw --from-literal password="${user_pw}" --dry-run -oyaml | \ + "${KUBECTL}" apply -f - + + # trigger reconcile + "${KUBECTL}" annotate -f ${projectdir}/examples/mysql/user.yaml reconcile=now + + sleep 3 + + echo_info "check if connection secret has been updated" + local pw=$("${KUBECTL}" get secret example-connection-secret -ojsonpath='{.data.password}' | base64 --decode) + [ "${pw}" == "${user_pw}" ] + echo_step_completed +} + +test_create_grant() { + echo_step "test creating MySQL Grant resource" + "${KUBECTL}" apply -f ${projectdir}/examples/mysql/grant_database.yaml + + echo_info "check if is ready" + "${KUBECTL}" wait --timeout 2m --for condition=Ready -f ${projectdir}/examples/mysql/grant_database.yaml + echo_step_completed +} + +test_all() { + test_create_database + test_create_user + test_update_user_password + test_create_grant +} + +cleanup_test_resources() { + echo_step "cleaning up test resources" + "${KUBECTL}" delete -f ${projectdir}/examples/mysql/grant_database.yaml + "${KUBECTL}" delete -f ${projectdir}/examples/mysql/database.yaml + "${KUBECTL}" delete -f ${projectdir}/examples/mysql/user.yaml + "${KUBECTL}" delete secret example-pw +} + +setup_cluster +setup_crossplane +setup_provider + +echo_step "--- INTEGRATION TESTS - NO TLS ---" + +setup_mariadb_no_tls +setup_provider_config_no_tls + +test_all + +cleanup_test_resources +cleanup_provider_config +cleanup_mariadb + +echo_step "--- INTEGRATION TESTS - TLS ---" + +setup_tls_certs +setup_mariadb_tls +setup_provider_config_tls + +test_all + +cleanup_test_resources +cleanup_provider_config +cleanup_mariadb +cleanup_tls_certs + +echo_step "--- CLEAN-UP ---" +cleanup_provider echo_success "Integration tests succeeded!" diff --git a/examples/mysql/config.yaml b/examples/mysql/config.yaml index 005ded02..717a5998 100644 --- a/examples/mysql/config.yaml +++ b/examples/mysql/config.yaml @@ -9,5 +9,5 @@ spec: connectionSecretRef: namespace: default name: db-conn - # tls one of preferred(default), skip-verify, or true + # tls one of preferred(default), skip-verify, true, or custom tls: preferred diff --git a/examples/mysql/config_tls.yaml b/examples/mysql/config_tls.yaml new file mode 100644 index 00000000..b7edb53a --- /dev/null +++ b/examples/mysql/config_tls.yaml @@ -0,0 +1,29 @@ +--- +apiVersion: mysql.sql.crossplane.io/v1alpha1 +kind: ProviderConfig +metadata: + name: default +spec: + credentials: + source: MySQLConnectionSecret + connectionSecretRef: + namespace: default + name: credentials + # setting tls to custom will configure mysql driver with custom tls configuration specified in tlsConfig + tls: custom + tlsConfig: + caCert: + secretRef: + namespace: default + name: tls-creds + key: ca-cert.pem + clientCert: + secretRef: + namespace: default + name: tls-creds + key: client-cert.pem + clientKey: + secretRef: + namespace: default + name: tls-creds + key: client-key.pem diff --git a/package/crds/mysql.sql.crossplane.io_providerconfigs.yaml b/package/crds/mysql.sql.crossplane.io_providerconfigs.yaml index ea5aed14..1e52c0ee 100644 --- a/package/crds/mysql.sql.crossplane.io_providerconfigs.yaml +++ b/package/crds/mysql.sql.crossplane.io_providerconfigs.yaml @@ -85,11 +85,92 @@ spec: or use preferred to use TLS only when advertised by the server. This is similar to skip-verify, but additionally allows a fallback to a connection which is not encrypted. Neither skip-verify nor preferred add any reliable security. + Alternatively, set tls=custom and provide a custom TLS configuration via the tlsConfig field. enum: - "true" - skip-verify - preferred + - custom type: string + tlsConfig: + description: Optional TLS configuration for sql driver. Setting this + field also requires the tls field to be set to custom. + properties: + caCert: + description: TLSSecret defines a reference to a K8s secret and + its specific internal key that contains the TLS cert/keys in + PEM format. + properties: + secretRef: + description: A SecretKeySelector is a reference to a secret + key in an arbitrary namespace. + properties: + key: + description: The key to select. + type: string + name: + description: Name of the secret. + type: string + namespace: + description: Namespace of the secret. + type: string + required: + - key + - name + - namespace + type: object + type: object + clientCert: + description: TLSSecret defines a reference to a K8s secret and + its specific internal key that contains the TLS cert/keys in + PEM format. + properties: + secretRef: + description: A SecretKeySelector is a reference to a secret + key in an arbitrary namespace. + properties: + key: + description: The key to select. + type: string + name: + description: Name of the secret. + type: string + namespace: + description: Namespace of the secret. + type: string + required: + - key + - name + - namespace + type: object + type: object + clientKey: + description: TLSSecret defines a reference to a K8s secret and + its specific internal key that contains the TLS cert/keys in + PEM format. + properties: + secretRef: + description: A SecretKeySelector is a reference to a secret + key in an arbitrary namespace. + properties: + key: + description: The key to select. + type: string + name: + description: Name of the secret. + type: string + namespace: + description: Namespace of the secret. + type: string + required: + - key + - name + - namespace + type: object + type: object + insecureSkipVerify: + type: boolean + type: object required: - credentials type: object diff --git a/pkg/controller/mysql/database/reconciler.go b/pkg/controller/mysql/database/reconciler.go index c7cbdf8b..1c8c3687 100644 --- a/pkg/controller/mysql/database/reconciler.go +++ b/pkg/controller/mysql/database/reconciler.go @@ -36,6 +36,7 @@ import ( "github.com/crossplane-contrib/provider-sql/apis/mysql/v1alpha1" "github.com/crossplane-contrib/provider-sql/pkg/clients/mysql" "github.com/crossplane-contrib/provider-sql/pkg/clients/xsql" + "github.com/crossplane-contrib/provider-sql/pkg/controller/mysql/tls" ) const ( @@ -43,6 +44,7 @@ const ( errGetPC = "cannot get ProviderConfig" errNoSecretRef = "ProviderConfig does not reference a credentials Secret" errGetSecret = "cannot get credentials Secret" + errTLSConfig = "cannot load TLS config" errNotDatabase = "managed resource is not a Database custom resource" errSelectDB = "cannot select database" @@ -91,8 +93,9 @@ func (c *connector) Connect(ctx context.Context, mg resource.Managed) (managed.E // ProviderConfigReference could theoretically be nil, but in practice the // DefaultProviderConfig initializer will set it before we get here. + providerConfigName := cr.GetProviderConfigReference().Name pc := &v1alpha1.ProviderConfig{} - if err := c.kube.Get(ctx, types.NamespacedName{Name: cr.GetProviderConfigReference().Name}, pc); err != nil { + if err := c.kube.Get(ctx, types.NamespacedName{Name: providerConfigName}, pc); err != nil { return nil, errors.Wrap(err, errGetPC) } @@ -109,7 +112,12 @@ func (c *connector) Connect(ctx context.Context, mg resource.Managed) (managed.E return nil, errors.Wrap(err, errGetSecret) } - return &external{db: c.newDB(s.Data, pc.Spec.TLS, cr.Spec.ForProvider.BinLog)}, nil + tlsName, err := tls.LoadConfig(ctx, c.kube, providerConfigName, pc.Spec.TLS, pc.Spec.TLSConfig) + if err != nil { + return nil, errors.Wrap(err, errTLSConfig) + } + + return &external{db: c.newDB(s.Data, tlsName, cr.Spec.ForProvider.BinLog)}, nil } type external struct{ db xsql.DB } diff --git a/pkg/controller/mysql/grant/reconciler.go b/pkg/controller/mysql/grant/reconciler.go index 2753e13e..1e13d8f5 100644 --- a/pkg/controller/mysql/grant/reconciler.go +++ b/pkg/controller/mysql/grant/reconciler.go @@ -40,6 +40,7 @@ import ( "github.com/crossplane-contrib/provider-sql/apis/mysql/v1alpha1" "github.com/crossplane-contrib/provider-sql/pkg/clients/mysql" "github.com/crossplane-contrib/provider-sql/pkg/clients/xsql" + "github.com/crossplane-contrib/provider-sql/pkg/controller/mysql/tls" ) const ( @@ -47,6 +48,7 @@ const ( errGetPC = "cannot get ProviderConfig" errNoSecretRef = "ProviderConfig does not reference a credentials Secret" errGetSecret = "cannot get credentials Secret" + errTLSConfig = "cannot load TLS config" errNotGrant = "managed resource is not a Grant custom resource" errCreateGrant = "cannot create grant" @@ -102,8 +104,9 @@ func (c *connector) Connect(ctx context.Context, mg resource.Managed) (managed.E // ProviderConfigReference could theoretically be nil, but in practice the // DefaultProviderConfig initializer will set it before we get here. + providerConfigName := cr.GetProviderConfigReference().Name pc := &v1alpha1.ProviderConfig{} - if err := c.kube.Get(ctx, types.NamespacedName{Name: cr.GetProviderConfigReference().Name}, pc); err != nil { + if err := c.kube.Get(ctx, types.NamespacedName{Name: providerConfigName}, pc); err != nil { return nil, errors.Wrap(err, errGetPC) } @@ -120,8 +123,13 @@ func (c *connector) Connect(ctx context.Context, mg resource.Managed) (managed.E return nil, errors.Wrap(err, errGetSecret) } + tlsName, err := tls.LoadConfig(ctx, c.kube, providerConfigName, pc.Spec.TLS, pc.Spec.TLSConfig) + if err != nil { + return nil, errors.Wrap(err, errTLSConfig) + } + return &external{ - db: c.newDB(s.Data, pc.Spec.TLS, cr.Spec.ForProvider.BinLog), + db: c.newDB(s.Data, tlsName, cr.Spec.ForProvider.BinLog), kube: c.kube, }, nil } diff --git a/pkg/controller/mysql/tls/tls.go b/pkg/controller/mysql/tls/tls.go new file mode 100644 index 00000000..f4a6315a --- /dev/null +++ b/pkg/controller/mysql/tls/tls.go @@ -0,0 +1,112 @@ +package tls + +import ( + "context" + "crypto/tls" + "crypto/x509" + "fmt" + + "github.com/crossplane-contrib/provider-sql/apis/mysql/v1alpha1" + xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" + "github.com/go-sql-driver/mysql" + "github.com/pkg/errors" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +// LoadConfig loads the TLS configuration when tls mode is set to custom and +// returns the tls name of registered configuration. +func LoadConfig(ctx context.Context, kube client.Client, providerConfigName string, mode *string, cfg *v1alpha1.TLSConfig) (*string, error) { + if mode == nil || *mode != "custom" { + if cfg != nil { + return nil, fmt.Errorf("tlsConfig is allowed only when tls=custom") + } + return mode, nil + } + + if err := validateTLSConfig(cfg); err != nil { + return nil, err + } + + tlsName := fmt.Sprintf("custom-%s", providerConfigName) + err := registerTLS(ctx, kube, tlsName, cfg) + if err != nil { + return nil, err + } + return &tlsName, nil +} + +func validateTLSConfig(cfg *v1alpha1.TLSConfig) error { + if cfg == nil || + cfg.CACert.SecretRef.Name == "" || + cfg.CACert.SecretRef.Key == "" || + cfg.ClientCert.SecretRef.Name == "" || + cfg.ClientCert.SecretRef.Key == "" || + cfg.ClientKey.SecretRef.Name == "" || + cfg.ClientKey.SecretRef.Key == "" { + return fmt.Errorf("tlsConfig is required when tls=custom") + } + return nil +} + +func registerTLS(ctx context.Context, kube client.Client, tlsName string, cfg *v1alpha1.TLSConfig) error { + if cfg == nil { + return nil + } + + caCert, err := getSecret(ctx, kube, cfg.CACert.SecretRef) + if err != nil { + return fmt.Errorf("cannot get CA certificate: %w", err) + } + + pool := x509.NewCertPool() + if ok := pool.AppendCertsFromPEM(caCert); !ok { + return fmt.Errorf("cannot append CA certificate to pool") + } + + keyPair, err := getClientKeyPair(ctx, kube, cfg) + if err != nil { + return err + } + + return mysql.RegisterTLSConfig(tlsName, &tls.Config{ + RootCAs: pool, + Certificates: []tls.Certificate{keyPair}, + InsecureSkipVerify: cfg.InsecureSkipVerify, //nolint:gosec // This is only required by integration tests and should never be used in production + }) +} + +func getClientKeyPair(ctx context.Context, kube client.Client, cfg *v1alpha1.TLSConfig) (tls.Certificate, error) { + cert, err := getSecret(ctx, kube, cfg.ClientCert.SecretRef) + if err != nil { + return tls.Certificate{}, fmt.Errorf("cannot get client certificate: %w", err) + } + + key, err := getSecret(ctx, kube, cfg.ClientKey.SecretRef) + if err != nil { + return tls.Certificate{}, fmt.Errorf("cannot get client key: %w", err) + } + + keyPair, err := tls.X509KeyPair(cert, key) + if err != nil { + return tls.Certificate{}, errors.Wrap(err, "cannot make client certificate") + } + return keyPair, nil +} + +func getSecret(ctx context.Context, kube client.Client, sel xpv1.SecretKeySelector) ([]byte, error) { + secret := &corev1.Secret{} + if err := kube.Get(ctx, types.NamespacedName{ + Namespace: sel.Namespace, + Name: sel.Name}, secret); err != nil { + return nil, fmt.Errorf("cannot get Secret %q in namespace %q: %w", sel.Name, sel.Namespace, err) + } + + data, ok := secret.Data[sel.Key] + if !ok { + return nil, fmt.Errorf("key %q not found in Secret %q", sel.Key, sel.Name) + } + + return data, nil +} diff --git a/pkg/controller/mysql/user/reconciler.go b/pkg/controller/mysql/user/reconciler.go index 693f5276..532e63c3 100644 --- a/pkg/controller/mysql/user/reconciler.go +++ b/pkg/controller/mysql/user/reconciler.go @@ -39,6 +39,7 @@ import ( "github.com/crossplane-contrib/provider-sql/apis/mysql/v1alpha1" "github.com/crossplane-contrib/provider-sql/pkg/clients/mysql" "github.com/crossplane-contrib/provider-sql/pkg/clients/xsql" + "github.com/crossplane-contrib/provider-sql/pkg/controller/mysql/tls" ) const ( @@ -46,6 +47,7 @@ const ( errGetPC = "cannot get ProviderConfig" errNoSecretRef = "ProviderConfig does not reference a credentials Secret" errGetSecret = "cannot get credentials Secret" + errTLSConfig = "cannot load TLS config" errNotUser = "managed resource is not a User custom resource" errSelectUser = "cannot select user" @@ -97,8 +99,9 @@ func (c *connector) Connect(ctx context.Context, mg resource.Managed) (managed.E // ProviderConfigReference could theoretically be nil, but in practice the // DefaultProviderConfig initializer will set it before we get here. + providerConfigName := cr.GetProviderConfigReference().Name pc := &v1alpha1.ProviderConfig{} - if err := c.kube.Get(ctx, types.NamespacedName{Name: cr.GetProviderConfigReference().Name}, pc); err != nil { + if err := c.kube.Get(ctx, types.NamespacedName{Name: providerConfigName}, pc); err != nil { return nil, errors.Wrap(err, errGetPC) } @@ -115,8 +118,13 @@ func (c *connector) Connect(ctx context.Context, mg resource.Managed) (managed.E return nil, errors.Wrap(err, errGetSecret) } + tlsName, err := tls.LoadConfig(ctx, c.kube, providerConfigName, pc.Spec.TLS, pc.Spec.TLSConfig) + if err != nil { + return nil, errors.Wrap(err, errTLSConfig) + } + return &external{ - db: c.newDB(s.Data, pc.Spec.TLS, cr.Spec.ForProvider.BinLog), + db: c.newDB(s.Data, tlsName, cr.Spec.ForProvider.BinLog), kube: c.kube, }, nil } From 9f1195ba57ddf92caa82b4580769edece6e9c799 Mon Sep 17 00:00:00 2001 From: Jeroen Op 't Eynde Date: Fri, 13 Dec 2024 14:15:41 +0100 Subject: [PATCH 09/24] refactor(mysql): consistent username/host parameters (#205) Signed-off-by: Duologic --- pkg/controller/mysql/grant/reconciler.go | 30 ++++++++++-------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/pkg/controller/mysql/grant/reconciler.go b/pkg/controller/mysql/grant/reconciler.go index 1e13d8f5..7e643cd2 100644 --- a/pkg/controller/mysql/grant/reconciler.go +++ b/pkg/controller/mysql/grant/reconciler.go @@ -145,11 +145,11 @@ func (c *external) Observe(ctx context.Context, mg resource.Managed) (managed.Ex return managed.ExternalObservation{}, errors.New(errNotGrant) } - username := *cr.Spec.ForProvider.User + username, host := mysql.SplitUserHost(*cr.Spec.ForProvider.User) dbname := defaultIdentifier(cr.Spec.ForProvider.Database) table := defaultIdentifier(cr.Spec.ForProvider.Table) - observedPrivileges, result, err := c.getPrivileges(ctx, username, dbname, table) + observedPrivileges, result, err := c.getPrivileges(ctx, username, host, dbname, table) if err != nil { return managed.ExternalObservation{}, err } @@ -193,9 +193,7 @@ func parseGrant(grant, dbname string, table string) (privileges []string) { return nil } -func (c *external) getPrivileges(ctx context.Context, username, dbname string, table string) ([]string, *managed.ExternalObservation, error) { - username, host := mysql.SplitUserHost(username) - +func (c *external) getPrivileges(ctx context.Context, username, host, dbname, table string) ([]string, *managed.ExternalObservation, error) { privileges, err := c.parseGrantRows(ctx, username, host, dbname, table) if err != nil { var myErr *mysqldriver.MySQLError @@ -225,7 +223,7 @@ func (c *external) getPrivileges(ctx context.Context, username, dbname string, t return ret, nil, nil } -func (c *external) parseGrantRows(ctx context.Context, username string, host string, dbname string, table string) ([]string, error) { +func (c *external) parseGrantRows(ctx context.Context, username, host, dbname, table string) ([]string, error) { query := fmt.Sprintf("SHOW GRANTS FOR %s@%s", mysql.QuoteValue(username), mysql.QuoteValue(host)) rows, err := c.db.Query(ctx, xsql.Query{String: query}) @@ -262,12 +260,12 @@ func (c *external) Create(ctx context.Context, mg resource.Managed) (managed.Ext return managed.ExternalCreation{}, errors.New(errNotGrant) } - username := *cr.Spec.ForProvider.User + username, host := mysql.SplitUserHost(*cr.Spec.ForProvider.User) dbname := defaultIdentifier(cr.Spec.ForProvider.Database) table := defaultIdentifier(cr.Spec.ForProvider.Table) privileges, grantOption := getPrivilegesString(cr.Spec.ForProvider.Privileges.ToStringSlice()) - query := createGrantQuery(privileges, dbname, username, table, grantOption) + query := createGrantQuery(privileges, dbname, username, host, table, grantOption) if err := mysql.ExecWrapper(ctx, c.db, mysql.ExecQuery{Query: query, ErrorValue: errCreateGrant}); err != nil { return managed.ExternalCreation{}, err @@ -281,7 +279,7 @@ func (c *external) Update(ctx context.Context, mg resource.Managed) (managed.Ext return managed.ExternalUpdate{}, errors.New(errNotGrant) } - username := *cr.Spec.ForProvider.User + username, host := mysql.SplitUserHost(*cr.Spec.ForProvider.User) dbname := defaultIdentifier(cr.Spec.ForProvider.Database) table := defaultIdentifier(cr.Spec.ForProvider.Table) @@ -292,7 +290,7 @@ func (c *external) Update(ctx context.Context, mg resource.Managed) (managed.Ext if len(toRevoke) > 0 { sort.Strings(toRevoke) privileges, grantOption := getPrivilegesString(toRevoke) - query := createRevokeQuery(privileges, dbname, username, table, grantOption) + query := createRevokeQuery(privileges, dbname, username, host, table, grantOption) if err := mysql.ExecWrapper(ctx, c.db, mysql.ExecQuery{ Query: query, ErrorValue: errRevokeGrant, @@ -304,7 +302,7 @@ func (c *external) Update(ctx context.Context, mg resource.Managed) (managed.Ext if len(toGrant) > 0 { sort.Strings(toGrant) privileges, grantOption := getPrivilegesString(toGrant) - query := createGrantQuery(privileges, dbname, username, table, grantOption) + query := createGrantQuery(privileges, dbname, username, host, table, grantOption) if err := mysql.ExecWrapper(ctx, c.db, mysql.ExecQuery{ Query: query, ErrorValue: errCreateGrant, @@ -330,8 +328,7 @@ func getPrivilegesString(privileges []string) (string, bool) { return out, grantOption } -func createRevokeQuery(privileges, dbname, username string, table string, grantOption bool) string { - username, host := mysql.SplitUserHost(username) +func createRevokeQuery(privileges, dbname, username, host, table string, grantOption bool) string { result := fmt.Sprintf("REVOKE %s ON %s.%s FROM %s@%s", privileges, dbname, @@ -347,8 +344,7 @@ func createRevokeQuery(privileges, dbname, username string, table string, grantO return result } -func createGrantQuery(privileges, dbname, username string, table string, grantOption bool) string { - username, host := mysql.SplitUserHost(username) +func createGrantQuery(privileges, dbname, username, host, table string, grantOption bool) string { result := fmt.Sprintf("GRANT %s ON %s.%s TO %s@%s", privileges, dbname, @@ -370,12 +366,12 @@ func (c *external) Delete(ctx context.Context, mg resource.Managed) error { return errors.New(errNotGrant) } - username := *cr.Spec.ForProvider.User + username, host := mysql.SplitUserHost(*cr.Spec.ForProvider.User) dbname := defaultIdentifier(cr.Spec.ForProvider.Database) table := defaultIdentifier(cr.Spec.ForProvider.Table) privileges, grantOption := getPrivilegesString(cr.Spec.ForProvider.Privileges.ToStringSlice()) - query := createRevokeQuery(privileges, dbname, username, table, grantOption) + query := createRevokeQuery(privileges, dbname, username, host, table, grantOption) if err := mysql.ExecWrapper(ctx, c.db, mysql.ExecQuery{Query: query, ErrorValue: errRevokeGrant}); err != nil { var myErr *mysqldriver.MySQLError From cee2aea51f9340bbecfdac025ed959e09e3f6d7d Mon Sep 17 00:00:00 2001 From: Jeroen Op 't Eynde Date: Fri, 13 Dec 2024 15:03:18 +0100 Subject: [PATCH 10/24] chore: update build/, Makefile and integration test script (#204) Signed-off-by: Duologic --- .github/workflows/backport.yml | 28 +++++ .github/workflows/ci.yml | 159 +++++++++++++++-------------- .github/workflows/codeql.yml | 42 ++++++++ .github/workflows/commands.yml | 86 ++++++++++++++++ .github/workflows/promote.yml | 9 +- .github/workflows/tag.yml | 4 +- .gitmodules | 2 +- Makefile | 14 +-- build | 2 +- cluster/local/integration_tests.sh | 35 ++++--- 10 files changed, 272 insertions(+), 109 deletions(-) create mode 100644 .github/workflows/backport.yml create mode 100644 .github/workflows/codeql.yml create mode 100644 .github/workflows/commands.yml diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml new file mode 100644 index 00000000..1ee4208e --- /dev/null +++ b/.github/workflows/backport.yml @@ -0,0 +1,28 @@ +name: Backport + +on: + # NOTE(negz): This is a risky target, but we run this action only when and if + # a PR is closed, then filter down to specifically merged PRs. We also don't + # invoke any scripts, etc from within the repo. I believe the fact that we'll + # be able to review PRs before this runs makes this fairly safe. + # https://securitylab.github.com/research/github-actions-preventing-pwn-requests/ + pull_request_target: + types: [closed] + # See also commands.yml for the /backport triggered variant of this workflow. + +jobs: + # NOTE(negz): I tested many backport GitHub actions before landing on this + # one. Many do not support merge commits, or do not support pull requests with + # more than one commit. This one does. It also handily links backport PRs with + # new PRs, and provides commentary and instructions when it can't backport. + # The main gotcha with this action is that PRs _must_ be labelled before they're + # merged to trigger a backport. + open-pr: + runs-on: ubuntu-22.04 + if: github.event.pull_request.merged + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Open Backport PR + uses: korthout/backport-action@v1 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 96a4218c..f78a81d6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,7 @@ env: # Common versions GO_VERSION: '1.21' GOLANGCI_VERSION: 'v1.54.0' - DOCKER_BUILDX_VERSION: 'v0.8.2' + DOCKER_BUILDX_VERSION: 'v0.9.1' # Common users. We can't run a step 'if secrets.AWS_USR != ""' but we can run # a step 'if env.AWS_USR' != ""', so we copy these to succinctly test whether @@ -23,13 +23,13 @@ env: jobs: detect-noop: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 outputs: noop: ${{ steps.noop.outputs.should_skip }} steps: - name: Detect No-op Changes id: noop - uses: fkirc/skip-duplicate-actions@v2.1.0 + uses: fkirc/skip-duplicate-actions@v5.2.0 with: github_token: ${{ secrets.GITHUB_TOKEN }} paths_ignore: '["**.md", "**.png", "**.jpg"]' @@ -38,45 +38,44 @@ jobs: lint: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 needs: detect-noop if: needs.detect-noop.outputs.noop != 'true' steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: submodules: true - name: Setup Go - uses: actions/setup-go@v2 + uses: actions/setup-go@v3 with: go-version: ${{ env.GO_VERSION }} - name: Find the Go Build Cache id: go - run: echo "::set-output name=cache::$(make go.cachedir)" + run: echo "cachedir=$(make go.cachedir)" >> $GITHUB_ENV - name: Cache the Go Build Cache - uses: actions/cache@v2 + uses: actions/cache@v3 with: - path: ${{ steps.go.outputs.cache }} + path: ${{ env.cachedir }} key: ${{ runner.os }}-build-lint-${{ hashFiles('**/go.sum') }} restore-keys: ${{ runner.os }}-build-lint- - name: Cache Go Dependencies - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: .work/pkg key: ${{ runner.os }}-pkg-${{ hashFiles('**/go.sum') }} restore-keys: ${{ runner.os }}-pkg- - - name: Vendor Dependencies - run: make vendor vendor.check + - name: Download Go Modules + run: make modules.download modules.check - # We could run 'make lint' to ensure our desired Go version, but we prefer - # this action because it leaves 'annotations' (i.e. it comments on PRs to - # point out linter violations). + # We could run 'make lint' but we prefer this action because it leaves + # 'annotations' (i.e. it comments on PRs to point out linter violations). - name: Lint uses: golangci/golangci-lint-action@v3 with: @@ -84,53 +83,60 @@ jobs: skip-go-installation: true check-diff: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 needs: detect-noop if: needs.detect-noop.outputs.noop != 'true' steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: submodules: true - name: Setup Go - uses: actions/setup-go@v2 + uses: actions/setup-go@v3 with: go-version: ${{ env.GO_VERSION }} - name: Find the Go Build Cache id: go - run: echo "::set-output name=cache::$(make go.cachedir)" + run: echo "cachedir=$(make go.cachedir)" >> $GITHUB_ENV - name: Cache the Go Build Cache - uses: actions/cache@v2 + uses: actions/cache@v3 with: - path: ${{ steps.go.outputs.cache }} + path: ${{ env.cachedir }} key: ${{ runner.os }}-build-check-diff-${{ hashFiles('**/go.sum') }} restore-keys: ${{ runner.os }}-build-check-diff- - name: Cache Go Dependencies - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: .work/pkg key: ${{ runner.os }}-pkg-${{ hashFiles('**/go.sum') }} restore-keys: ${{ runner.os }}-pkg- - - name: Vendor Dependencies - run: make vendor vendor.check + - name: Download Go Modules + run: make modules.download modules.check - name: Check Diff - run: make check-diff + id: check-diff + run: | + mkdir _output + make check-diff + + - name: Show diff + if: failure() && steps.check-diff.outcome == 'failure' + run: git diff unit-tests: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 needs: detect-noop if: needs.detect-noop.outputs.noop != 'true' steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: submodules: true @@ -138,59 +144,59 @@ jobs: run: git fetch --prune --unshallow - name: Setup Go - uses: actions/setup-go@v2 + uses: actions/setup-go@v3 with: go-version: ${{ env.GO_VERSION }} - name: Find the Go Build Cache id: go - run: echo "::set-output name=cache::$(make go.cachedir)" + run: echo "cachedir=$(make go.cachedir)" >> $GITHUB_ENV - name: Cache the Go Build Cache - uses: actions/cache@v2 + uses: actions/cache@v3 with: - path: ${{ steps.go.outputs.cache }} + path: ${{ env.cachedir }} key: ${{ runner.os }}-build-unit-tests-${{ hashFiles('**/go.sum') }} restore-keys: ${{ runner.os }}-build-unit-tests- - name: Cache Go Dependencies - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: .work/pkg key: ${{ runner.os }}-pkg-${{ hashFiles('**/go.sum') }} restore-keys: ${{ runner.os }}-pkg- - - name: Vendor Dependencies - run: make vendor vendor.check + - name: Download Go Modules + run: make modules.download modules.check - name: Run Unit Tests run: make -j2 test - name: Publish Unit Test Coverage - uses: codecov/codecov-action@v1 + uses: codecov/codecov-action@v3 with: flags: unittests file: _output/tests/linux_amd64/coverage.txt e2e-tests: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 needs: detect-noop if: needs.detect-noop.outputs.noop != 'true' steps: - name: Setup QEMU - uses: docker/setup-qemu-action@v1 + uses: docker/setup-qemu-action@v2 with: platforms: all - name: Setup Docker Buildx - uses: docker/setup-buildx-action@v1 + uses: docker/setup-buildx-action@v2 with: version: ${{ env.DOCKER_BUILDX_VERSION }} install: true - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: submodules: true @@ -198,61 +204,68 @@ jobs: run: git fetch --prune --unshallow - name: Setup Go - uses: actions/setup-go@v2 + uses: actions/setup-go@v3 with: go-version: ${{ env.GO_VERSION }} - name: Find the Go Build Cache id: go - run: echo "::set-output name=cache::$(make go.cachedir)" + run: echo "cachedir=$(make go.cachedir)" >> $GITHUB_ENV - name: Cache the Go Build Cache - uses: actions/cache@v2 + uses: actions/cache@v3 with: - path: ${{ steps.go.outputs.cache }} - key: ${{ runner.os }}-build-e2e-tests-${{ hashFiles('**/go.sum') }} - restore-keys: ${{ runner.os }}-build-e2e-tests- + path: ${{ env.cachedir }} + key: ${{ runner.os }}-build-unit-tests-${{ hashFiles('**/go.sum') }} + restore-keys: ${{ runner.os }}-build-unit-tests- - name: Cache Go Dependencies - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: .work/pkg key: ${{ runner.os }}-pkg-${{ hashFiles('**/go.sum') }} - restore-keys: | - ${{ runner.os }}-pkg- + restore-keys: ${{ runner.os }}-pkg- - - name: Vendor Dependencies - run: make vendor vendor.check + - name: Download Go Modules + run: make modules.download modules.check - name: Build Helm Chart run: make -j2 build - env: - # We're using docker buildx, which doesn't actually load the images it - # builds by default. Specifying --load does so. - BUILD_ARGS: "--load" + #env: + # # We're using docker buildx, which doesn't actually load the images it + # # builds by default. Specifying --load does so. + # BUILD_ARGS: "--load" - name: Run E2E Tests - run: make e2e USE_HELM3=true + run: make e2e USE_HELM=true publish-artifacts: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 needs: detect-noop if: needs.detect-noop.outputs.noop != 'true' steps: - name: Setup QEMU - uses: docker/setup-qemu-action@v1 + uses: docker/setup-qemu-action@v2 with: platforms: all - name: Setup Docker Buildx - uses: docker/setup-buildx-action@v1 + uses: docker/setup-buildx-action@v2 with: version: ${{ env.DOCKER_BUILDX_VERSION }} install: true + - name: Login to Upbound + uses: docker/login-action@v1 + if: env.XPKG_ACCESS_ID != '' + with: + registry: xpkg.upbound.io + username: ${{ secrets.XPKG_ACCESS_ID }} + password: ${{ secrets.XPKG_TOKEN }} + - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: submodules: true @@ -260,30 +273,30 @@ jobs: run: git fetch --prune --unshallow - name: Setup Go - uses: actions/setup-go@v2 + uses: actions/setup-go@v3 with: go-version: ${{ env.GO_VERSION }} - name: Find the Go Build Cache id: go - run: echo "::set-output name=cache::$(make go.cachedir)" + run: echo "cachedir=$(make go.cachedir)" >> $GITHUB_ENV - name: Cache the Go Build Cache - uses: actions/cache@v2 + uses: actions/cache@v3 with: - path: ${{ steps.go.outputs.cache }} + path: ${{ env.cachedir }} key: ${{ runner.os }}-build-publish-artifacts-${{ hashFiles('**/go.sum') }} restore-keys: ${{ runner.os }}-build-publish-artifacts- - name: Cache Go Dependencies - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: .work/pkg key: ${{ runner.os }}-pkg-${{ hashFiles('**/go.sum') }} restore-keys: ${{ runner.os }}-pkg- - - name: Vendor Dependencies - run: make vendor vendor.check + - name: Download Go Modules + run: make modules.download modules.check - name: Build Artifacts run: make -j2 build.all @@ -293,11 +306,15 @@ jobs: BUILD_ARGS: "--load" - name: Publish Artifacts to GitHub - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v3 with: name: output path: _output/** + - name: Publish Artifacts + if: env.XPKG_ACCESS_ID != '' + run: make publish BRANCH_NAME=${GITHUB_REF##*/} + - name: Login to Docker uses: docker/login-action@v1 if: env.CONTRIB_DOCKER_USR != '' @@ -305,14 +322,6 @@ jobs: username: ${{ secrets.CONTRIB_DOCKER_USR }} password: ${{ secrets.CONTRIB_DOCKER_PSW }} - - name: Login to Upbound - uses: docker/login-action@v1 - if: env.XPKG_ACCESS_ID != '' - with: - registry: xpkg.upbound.io - username: ${{ secrets.XPKG_ACCESS_ID }} - password: ${{ secrets.XPKG_TOKEN }} - - name: Publish Artifacts to S3 and Docker Hub run: make -j2 publish BRANCH_NAME=${GITHUB_REF##*/} if: env.AWS_USR != '' && env.CONTRIB_DOCKER_USR != '' diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 00000000..6b077c85 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,42 @@ +name: CodeQL + +on: + push: + branches: + - master + - release-* + workflow_dispatch: {} + +jobs: + detect-noop: + runs-on: ubuntu-22.04 + outputs: + noop: ${{ steps.noop.outputs.should_skip }} + steps: + - name: Detect No-op Changes + id: noop + uses: fkirc/skip-duplicate-actions@v5.2.0 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + paths_ignore: '["**.md", "**.png", "**.jpg"]' + do_not_skip: '["workflow_dispatch", "schedule", "push"]' + concurrent_skipping: false + + analyze: + runs-on: ubuntu-22.04 + needs: detect-noop + if: needs.detect-noop.outputs.noop != 'true' + + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + submodules: true + + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: go + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/commands.yml b/.github/workflows/commands.yml new file mode 100644 index 00000000..df101a8e --- /dev/null +++ b/.github/workflows/commands.yml @@ -0,0 +1,86 @@ +name: Comment Commands + +on: issue_comment + +jobs: + points: + runs-on: ubuntu-22.04 + if: startsWith(github.event.comment.body, '/points') + + steps: + - name: Extract Command + id: command + uses: xt0rted/slash-command-action@v1 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + command: points + reaction: "true" + reaction-type: "eyes" + allow-edits: "false" + permission-level: write + - name: Handle Command + uses: actions/github-script@v4 + env: + POINTS: ${{ steps.command.outputs.command-arguments }} + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const points = process.env.POINTS + + if (isNaN(parseInt(points))) { + console.log("Malformed command - expected '/points '") + github.reactions.createForIssueComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: context.payload.comment.id, + content: "confused" + }) + return + } + const label = "points/" + points + + // Delete our needs-points-label label. + try { + await github.issues.deleteLabel({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + name: ['needs-points-label'] + }) + console.log("Deleted 'needs-points-label' label.") + } + catch(e) { + console.log("Label 'needs-points-label' probably didn't exist.") + } + + // Add our points label. + github.issues.addLabels({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + labels: [label] + }) + console.log("Added '" + label + "' label.") + + # NOTE(negz): See also backport.yml, which is the variant that triggers on PR + # merge rather than on comment. + backport: + runs-on: ubuntu-22.04 + if: github.event.issue.pull_request && startsWith(github.event.comment.body, '/backport') + steps: + - name: Extract Command + id: command + uses: xt0rted/slash-command-action@v1 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + command: backport + reaction: "true" + reaction-type: "eyes" + allow-edits: "false" + permission-level: write + + - name: Checkout + uses: actions/checkout@v3 + + - name: Open Backport PR + uses: korthout/backport-action@v1 diff --git a/.github/workflows/promote.yml b/.github/workflows/promote.yml index e297e8ed..680c0f9e 100644 --- a/.github/workflows/promote.yml +++ b/.github/workflows/promote.yml @@ -9,12 +9,9 @@ on: channel: description: 'Release channel' required: true - default: 'alpha' + default: 'stable' env: - # Common versions - GO_VERSION: '1.18' - # Common users. We can't run a step 'if secrets.AWS_USR != ""' but we can run # a step 'if env.AWS_USR' != ""', so we copy these to succinctly test whether # credentials have been provided before trying to run steps that need them. @@ -24,11 +21,11 @@ env: jobs: promote-artifacts: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: submodules: true diff --git a/.github/workflows/tag.yml b/.github/workflows/tag.yml index 3b272eaf..db32dd0f 100644 --- a/.github/workflows/tag.yml +++ b/.github/workflows/tag.yml @@ -12,11 +12,11 @@ on: jobs: create-tag: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Create Tag uses: negz/create-tag@v1 diff --git a/.gitmodules b/.gitmodules index c2fad470..8f84209c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "build"] path = build - url = https://github.com/upbound/build + url = https://github.com/crossplane/build diff --git a/Makefile b/Makefile index 6b532fb2..ff3a0507 100644 --- a/Makefile +++ b/Makefile @@ -29,15 +29,10 @@ GO_SUBDIRS += cmd pkg apis GO111MODULE = on -include build/makelib/golang.mk -# kind-related versions -KIND_VERSION ?= v0.12.0 -KIND_NODE_IMAGE_TAG ?= v1.23.4 - # ==================================================================================== # Setup Kubernetes tools - -UP_VERSION = v0.31.0 -UP_CHANNEL = stable +KIND_NODE_IMAGE_TAG ?= v1.23.4 +DOCKER_REGISTRY ?= "xpkg.upbound.io" -include build/makelib/k8s_tools.mk # ==================================================================================== @@ -46,7 +41,6 @@ UP_CHANNEL = stable IMAGES = provider-sql -include build/makelib/imagelight.mk - # ==================================================================================== # Setup XPKG @@ -87,7 +81,7 @@ generate: crds.clean e2e.run: test-integration # Run integration tests. -test-integration: $(KIND) $(KUBECTL) $(UP) $(HELM3) +test-integration: $(KIND) $(KUBECTL) $(UP) $(HELM) @$(INFO) running integration tests using kind $(KIND_VERSION) @KIND_NODE_IMAGE_TAG=${KIND_NODE_IMAGE_TAG} $(ROOT_DIR)/cluster/local/integration_tests.sh || $(FAIL) @$(OK) integration tests passed @@ -124,7 +118,7 @@ dev: $(KIND) $(KUBECTL) @$(KIND) create cluster --name=$(PROJECT_NAME)-dev @$(KUBECTL) cluster-info --context kind-$(PROJECT_NAME)-dev @$(INFO) Installing Crossplane CRDs - @$(KUBECTL) apply -k https://github.com/crossplane/crossplane//cluster?ref=master + @$(KUBECTL) apply --server-side -k https://github.com/crossplane/crossplane//cluster?ref=master @$(INFO) Installing Provider SQL CRDs @$(KUBECTL) apply -R -f package/crds @$(INFO) Starting Provider SQL controllers diff --git a/build b/build index 3b994632..231258db 160000 --- a/build +++ b/build @@ -1 +1 @@ -Subproject commit 3b99463225581259ce39c7d7a45290be12515abb +Subproject commit 231258db281237379d8ec0c6e4af9d7c1ae5cc4a diff --git a/cluster/local/integration_tests.sh b/cluster/local/integration_tests.sh index 17ed43e1..fc19b1d5 100755 --- a/cluster/local/integration_tests.sh +++ b/cluster/local/integration_tests.sh @@ -146,33 +146,40 @@ cleanup_cluster() { setup_crossplane() { echo_step "installing crossplane from stable channel" - "${HELM3}" repo add crossplane-stable https://charts.crossplane.io/stable/ --force-update - local chart_version="$("${HELM3}" search repo crossplane-stable/crossplane | awk 'FNR == 2 {print $2}')" + "${HELM}" repo add crossplane-stable https://charts.crossplane.io/stable/ --force-update + local chart_version="$("${HELM}" search repo crossplane-stable/crossplane | awk 'FNR == 2 {print $2}')" echo_info "using crossplane version ${chart_version}" echo # we replace empty dir with our PVC so that the /cache dir in the kind node # container is exposed to the crossplane pod - "${HELM3}" install crossplane --namespace crossplane-system crossplane-stable/crossplane --version ${chart_version} --wait --set packageCache.pvc=package-cache + "${HELM}" install crossplane --namespace crossplane-system crossplane-stable/crossplane --version ${chart_version} --wait --set packageCache.pvc=package-cache } setup_provider() { echo_step "installing provider" local yaml="$( cat </dev/null - "${HELM3}" install mariadb bitnami/mariadb \ + "${HELM}" repo add bitnami https://charts.bitnami.com/bitnami >/dev/null + "${HELM}" install mariadb bitnami/mariadb \ --version 11.3.0 \ --set auth.rootPassword="${MARIADB_ROOT_PW}" \ --wait @@ -355,8 +362,8 @@ initdbScripts: EOF ) - "${HELM3}" repo add bitnami https://charts.bitnami.com/bitnami >/dev/null - "${HELM3}" install mariadb bitnami/mariadb \ + "${HELM}" repo add bitnami https://charts.bitnami.com/bitnami >/dev/null + "${HELM}" install mariadb bitnami/mariadb \ --version 11.3.0 \ --values <(echo "$values") \ --wait @@ -364,7 +371,7 @@ EOF cleanup_mariadb() { echo_step "uninstalling MariaDB" - "${HELM3}" uninstall mariadb + "${HELM}" uninstall mariadb "${KUBECTL}" delete secret mariadb-creds } From fcd50ac4c7de3276f5dab4dbed1739dc9ea84bf7 Mon Sep 17 00:00:00 2001 From: olikyr Date: Mon, 13 Jan 2025 11:53:48 +0100 Subject: [PATCH 11/24] feat(postgresql): add revoke public logic to grant and schema resources (#207) - added a field called revokePublicOnDb in grant resource; if true, it will revoke from public access to DB; This usually a DBA requirement. - added a field called revokePublicOnSchema in schema resource; if true, it will revoke from public access to a schema; This usually a DBA requirement. Signed-off-by: oliver.zokra --- apis/postgresql/v1alpha1/grant_types.go | 4 ++ apis/postgresql/v1alpha1/schema_types.go | 4 ++ .../v1alpha1/zz_generated.deepcopy.go | 10 +++ .../postgresql.sql.crossplane.io_grants.yaml | 5 ++ .../postgresql.sql.crossplane.io_schemas.yaml | 4 ++ pkg/controller/postgresql/grant/reconciler.go | 8 +++ .../postgresql/schema/reconciler.go | 66 +++++++++++++++---- .../postgresql/schema/reconciler_test.go | 6 +- 8 files changed, 90 insertions(+), 17 deletions(-) diff --git a/apis/postgresql/v1alpha1/grant_types.go b/apis/postgresql/v1alpha1/grant_types.go index 6d4c982d..1bf6fc7c 100644 --- a/apis/postgresql/v1alpha1/grant_types.go +++ b/apis/postgresql/v1alpha1/grant_types.go @@ -154,6 +154,10 @@ type GrantParameters struct { // +immutable // +optional MemberOfSelector *xpv1.Selector `json:"memberOfSelector,omitempty"` + + // RevokePublicOnDb apply the statement "REVOKE ALL ON DATABASE %s FROM PUBLIC" to make database unreachable from public + // +optional + RevokePublicOnDb *bool `json:"revokePublicOnDb,omitempty" default:"false"` } // A GrantStatus represents the observed state of a Grant. diff --git a/apis/postgresql/v1alpha1/schema_types.go b/apis/postgresql/v1alpha1/schema_types.go index a9a1a7a4..8f9a9d7f 100644 --- a/apis/postgresql/v1alpha1/schema_types.go +++ b/apis/postgresql/v1alpha1/schema_types.go @@ -59,6 +59,10 @@ type SchemaParameters struct { // +immutable // +optional DatabaseSelector *xpv1.Selector `json:"databaseSelector,omitempty"` + + // RevokePublicOnSchema apply a "REVOKE ALL ON SCHEMA public FROM public" statement + // +optional + RevokePublicOnSchema *bool `json:"revokePublicOnSchema,omitempty" default:"false"` } // A SchemaStatus represents the observed state of a Schema. diff --git a/apis/postgresql/v1alpha1/zz_generated.deepcopy.go b/apis/postgresql/v1alpha1/zz_generated.deepcopy.go index 09ae90b7..70d15187 100644 --- a/apis/postgresql/v1alpha1/zz_generated.deepcopy.go +++ b/apis/postgresql/v1alpha1/zz_generated.deepcopy.go @@ -426,6 +426,11 @@ func (in *GrantParameters) DeepCopyInto(out *GrantParameters) { *out = new(v1.Selector) (*in).DeepCopyInto(*out) } + if in.RevokePublicOnDb != nil { + in, out := &in.RevokePublicOnDb, &out.RevokePublicOnDb + *out = new(bool) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GrantParameters. @@ -978,6 +983,11 @@ func (in *SchemaParameters) DeepCopyInto(out *SchemaParameters) { *out = new(v1.Selector) (*in).DeepCopyInto(*out) } + if in.RevokePublicOnSchema != nil { + in, out := &in.RevokePublicOnSchema, &out.RevokePublicOnSchema + *out = new(bool) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SchemaParameters. diff --git a/package/crds/postgresql.sql.crossplane.io_grants.yaml b/package/crds/postgresql.sql.crossplane.io_grants.yaml index a7c19812..f9849f71 100644 --- a/package/crds/postgresql.sql.crossplane.io_grants.yaml +++ b/package/crds/postgresql.sql.crossplane.io_grants.yaml @@ -252,6 +252,11 @@ spec: type: string minItems: 1 type: array + revokePublicOnDb: + description: RevokePublicOnDb apply the statement "REVOKE ALL + ON DATABASE %s FROM PUBLIC" to make database unreachable from + public + type: boolean role: description: Role this grant is for. type: string diff --git a/package/crds/postgresql.sql.crossplane.io_schemas.yaml b/package/crds/postgresql.sql.crossplane.io_schemas.yaml index 0aedddcd..8b70d7fd 100644 --- a/package/crds/postgresql.sql.crossplane.io_schemas.yaml +++ b/package/crds/postgresql.sql.crossplane.io_schemas.yaml @@ -156,6 +156,10 @@ spec: type: string type: object type: object + revokePublicOnSchema: + description: RevokePublicOnSchema apply a "REVOKE ALL ON SCHEMA + public FROM public" statement + type: boolean role: description: Role for ownership of this schema. type: string diff --git a/pkg/controller/postgresql/grant/reconciler.go b/pkg/controller/postgresql/grant/reconciler.go index 85d0175c..d73c3943 100644 --- a/pkg/controller/postgresql/grant/reconciler.go +++ b/pkg/controller/postgresql/grant/reconciler.go @@ -276,6 +276,14 @@ func createGrantQueries(gp v1alpha1.GrantParameters, ql *[]xsql.Query) error { / withOption(gp.WithOption), )}, ) + if gp.RevokePublicOnDb != nil && *gp.RevokePublicOnDb { + *ql = append(*ql, + // REVOKE FROM PUBLIC + xsql.Query{String: fmt.Sprintf("REVOKE ALL ON DATABASE %s FROM PUBLIC", + db, + )}, + ) + } return nil } return errors.New(errUnknownGrant) diff --git a/pkg/controller/postgresql/schema/reconciler.go b/pkg/controller/postgresql/schema/reconciler.go index 6209f60b..d3d3515e 100644 --- a/pkg/controller/postgresql/schema/reconciler.go +++ b/pkg/controller/postgresql/schema/reconciler.go @@ -167,16 +167,14 @@ func (c *external) Create(ctx context.Context, mg resource.Managed) (managed.Ext return managed.ExternalCreation{}, errors.New(errNotSchema) } - var b strings.Builder - b.WriteString("CREATE SCHEMA IF NOT EXISTS ") - b.WriteString(pq.QuoteIdentifier(meta.GetExternalName(cr))) + var queries []xsql.Query - if cr.Spec.ForProvider.Role != nil { - b.WriteString(" AUTHORIZATION ") - b.WriteString(pq.QuoteIdentifier(*cr.Spec.ForProvider.Role)) - } + cr.SetConditions(xpv1.Creating()) - return managed.ExternalCreation{}, errors.Wrap(c.db.Exec(ctx, xsql.Query{String: b.String()}), errCreateSchema) + createSchemaQueries(cr.Spec.ForProvider, &queries, meta.GetExternalName(cr)) + + err := c.db.ExecTx(ctx, queries) + return managed.ExternalCreation{}, errors.Wrap(err, errCreateSchema) } func (c *external) Update(ctx context.Context, mg resource.Managed) (managed.ExternalUpdate, error) { //nolint:gocyclo @@ -189,13 +187,10 @@ func (c *external) Update(ctx context.Context, mg resource.Managed) (managed.Ext return managed.ExternalUpdate{}, nil } - var b strings.Builder - b.WriteString("ALTER SCHEMA ") - b.WriteString(pq.QuoteIdentifier(meta.GetExternalName(mg))) - b.WriteString(" OWNER TO ") - b.WriteString(pq.QuoteIdentifier(*cr.Spec.ForProvider.Role)) + var queries []xsql.Query + updateSchemaQueries(cr.Spec.ForProvider, &queries, meta.GetExternalName(cr)) - err := c.db.Exec(ctx, xsql.Query{String: b.String()}) + err := c.db.ExecTx(ctx, queries) return managed.ExternalUpdate{}, errors.Wrap(err, errAlterSchema) } @@ -226,3 +221,46 @@ func lateInit(observed v1alpha1.SchemaParameters, desired *v1alpha1.SchemaParame return li } + +func createSchemaQueries(sp v1alpha1.SchemaParameters, ql *[]xsql.Query, en string) { // nolint: gocyclo + + var b strings.Builder + b.WriteString("CREATE SCHEMA IF NOT EXISTS ") + b.WriteString(pq.QuoteIdentifier(en)) + + if sp.Role != nil { + b.WriteString(" AUTHORIZATION ") + b.WriteString(pq.QuoteIdentifier(*sp.Role)) + b.WriteString(";") + } + + *ql = append(*ql, + xsql.Query{String: b.String()}, + ) + + if sp.RevokePublicOnSchema != nil && *sp.RevokePublicOnSchema { + *ql = append(*ql, + xsql.Query{String: "REVOKE ALL ON SCHEMA PUBLIC FROM PUBLIC;"}, + ) + } + +} + +func updateSchemaQueries(sp v1alpha1.SchemaParameters, ql *[]xsql.Query, en string) { // nolint: gocyclo + + var b strings.Builder + b.WriteString("ALTER SCHEMA ") + b.WriteString(pq.QuoteIdentifier(en)) + b.WriteString(" OWNER TO ") + b.WriteString(pq.QuoteIdentifier(*sp.Role)) + + *ql = append(*ql, + xsql.Query{String: b.String()}, + ) + + if sp.RevokePublicOnSchema != nil && *sp.RevokePublicOnSchema { + *ql = append(*ql, + xsql.Query{String: "REVOKE ALL ON SCHEMA PUBLIC FROM PUBLIC;"}, + ) + } +} diff --git a/pkg/controller/postgresql/schema/reconciler_test.go b/pkg/controller/postgresql/schema/reconciler_test.go index 8423ef4b..d2c493e5 100644 --- a/pkg/controller/postgresql/schema/reconciler_test.go +++ b/pkg/controller/postgresql/schema/reconciler_test.go @@ -371,7 +371,7 @@ func TestCreate(t *testing.T) { reason: "Any errors encountered while creating the schema should be returned", fields: fields{ db: &mockDB{ - MockExec: func(ctx context.Context, q xsql.Query) error { return errBoom }, + MockExecTx: func(ctx context.Context, ql []xsql.Query) error { return errBoom }, }, }, args: args{ @@ -387,7 +387,7 @@ func TestCreate(t *testing.T) { reason: "No error should be returned when we successfully create a extension", fields: fields{ db: &mockDB{ - MockExec: func(ctx context.Context, q xsql.Query) error { return nil }, + MockExecTx: func(ctx context.Context, ql []xsql.Query) error { return nil }, }, }, args: args{ @@ -457,7 +457,7 @@ func TestUpdate(t *testing.T) { reason: "No error should be returned when we successfully update a schema", fields: fields{ db: &mockDB{ - MockExec: func(ctx context.Context, q xsql.Query) error { return nil }, + MockExecTx: func(ctx context.Context, ql []xsql.Query) error { return nil }, }, }, args: args{ From d0c080b28c56990f8966495944370a7e3a36884c Mon Sep 17 00:00:00 2001 From: olikyr Date: Mon, 13 Jan 2025 20:52:48 +0100 Subject: [PATCH 12/24] test(postgresql): implement postgresdb integration tests (#208) Signed-off-by: oliver.zokra --- cluster/local/integration_tests.sh | 23 +++- cluster/local/postgresdb_functions.sh | 167 ++++++++++++++++++++++++++ examples/postgresql/database.yaml | 10 ++ examples/postgresql/grant.yaml | 27 +++++ examples/postgresql/role.yaml | 17 ++- examples/postgresql/schema.yaml | 14 +++ 6 files changed, 254 insertions(+), 4 deletions(-) create mode 100644 cluster/local/postgresdb_functions.sh diff --git a/cluster/local/integration_tests.sh b/cluster/local/integration_tests.sh index fc19b1d5..68892b42 100755 --- a/cluster/local/integration_tests.sh +++ b/cluster/local/integration_tests.sh @@ -62,6 +62,20 @@ if [ "$skipcleanup" != true ]; then trap cleanup EXIT fi +SCRIPT_DIR="$(dirname "$(realpath "$0")")" +# shellcheck source="$SCRIPT_DIR/postgresdb_functions.sh" +source "$SCRIPT_DIR/postgresdb_functions.sh" +if [ $? -ne 0 ]; then + echo "postgresdb_functions.sh failed. Exiting." + exit 1 +fi + +integration_tests_end() { + echo_step "--- CLEAN-UP ---" + cleanup_provider + echo_success " All integration tests succeeded!" +} + setup_cluster() { echo_step "setting up local package cache" @@ -469,7 +483,10 @@ cleanup_provider_config cleanup_mariadb cleanup_tls_certs -echo_step "--- CLEAN-UP ---" -cleanup_provider +echo_step "--- INTEGRATION TESTS FOR MySQL ACCOMPLISHED SUCCESSFULLY ---" + +echo_step "--- TESTING POSTGRESDB ---" +integration_tests_postgres +echo_step "--- INTEGRATION TESTS FOR POSTGRESDB ACCOMPLISHED SUCCESSFULLY ---" -echo_success "Integration tests succeeded!" +integration_tests_end \ No newline at end of file diff --git a/cluster/local/postgresdb_functions.sh b/cluster/local/postgresdb_functions.sh new file mode 100644 index 00000000..978f25ec --- /dev/null +++ b/cluster/local/postgresdb_functions.sh @@ -0,0 +1,167 @@ +#!/usr/bin/env bash +set -e + +setup_postgresdb_no_tls() { + echo_step "Installing PostgresDB Helm chart into default namespace" + postgres_root_pw=$(LC_ALL=C tr -cd "A-Za-z0-9" Date: Tue, 14 Jan 2025 14:00:09 +0100 Subject: [PATCH 13/24] update helm repo before intalling mariadb (#209) Signed-off-by: oliver.zokra --- cluster/local/integration_tests.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cluster/local/integration_tests.sh b/cluster/local/integration_tests.sh index 68892b42..4b0585e7 100755 --- a/cluster/local/integration_tests.sh +++ b/cluster/local/integration_tests.sh @@ -337,6 +337,7 @@ setup_mariadb_no_tls() { --from-literal port="3306" "${HELM}" repo add bitnami https://charts.bitnami.com/bitnami >/dev/null + "${HELM}" repo update "${HELM}" install mariadb bitnami/mariadb \ --version 11.3.0 \ --set auth.rootPassword="${MARIADB_ROOT_PW}" \ @@ -377,6 +378,7 @@ EOF ) "${HELM}" repo add bitnami https://charts.bitnami.com/bitnami >/dev/null + "${HELM}" repo update "${HELM}" install mariadb bitnami/mariadb \ --version 11.3.0 \ --values <(echo "$values") \ From 4cf415ff875ebb66aa4b228f5c639d2b4b6a37d9 Mon Sep 17 00:00:00 2001 From: Jeroen Op 't Eynde Date: Wed, 23 Apr 2025 20:48:40 +0200 Subject: [PATCH 14/24] chore: add chlunde to maintainers list (#225) Signed-off-by: Duologic --- OWNERS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/OWNERS.md b/OWNERS.md index 11ab618c..4e738dba 100644 --- a/OWNERS.md +++ b/OWNERS.md @@ -13,6 +13,7 @@ Please see [GOVERNANCE.md] for governance guidelines and responsibilities. * Nic Cope ([negz](https://github.com/negz)) * Javier Palomo ([jvrplmlmn](https://github.com/jvrplmlmn)) * Iain Lane ([iainlane](https://github.com/iainlane)) +* Carl Henrik Lunde ([chlunde](https://github.com/chlunde)) ## Emeritus maintainers From 8d48ca954a4f7fd22032e97a515ceefd8db6b81f Mon Sep 17 00:00:00 2001 From: Lars Haugan Date: Fri, 2 May 2025 10:44:13 +0200 Subject: [PATCH 15/24] bump github actions upload-action to latest release due to deprecation Signed-off-by: Lars Haugan --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f78a81d6..858cd11c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -306,7 +306,7 @@ jobs: BUILD_ARGS: "--load" - name: Publish Artifacts to GitHub - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: output path: _output/** From cdf9f3d14c2c36bb947586e9b315f079dc2fa31b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=2E=20Fern=C3=A1ndez?= <7312236+fernandezcuesta@users.noreply.github.com> Date: Fri, 2 May 2025 10:22:04 +0000 Subject: [PATCH 16/24] chore: bump golangci version (#216) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: bump golangci Signed-off-by: Jesús Fernández <7312236+fernandezcuesta@users.noreply.github.com> * chore: bump golangci on github actions workflow Signed-off-by: Jesús Fernández <7312236+fernandezcuesta@users.noreply.github.com> * chore: bump golangci up to v2, bump up all action dependencies Signed-off-by: Jesús Fernández <7312236+fernandezcuesta@users.noreply.github.com> * chore: even more actions pinned Signed-off-by: Jesús Fernández <7312236+fernandezcuesta@users.noreply.github.com> --------- Signed-off-by: Jesús Fernández <7312236+fernandezcuesta@users.noreply.github.com> --- .github/workflows/backport.yml | 6 +- .github/workflows/ci.yml | 79 +++-- .github/workflows/codeql.yml | 12 +- .github/workflows/commands.yml | 14 +- .github/workflows/promote.yml | 8 +- .github/workflows/tag.yml | 8 +- .golangci.yml | 320 ++++++++---------- Makefile | 2 + build | 2 +- pkg/controller/mssql/grant/reconciler_test.go | 6 +- pkg/controller/mysql/grant/reconciler_test.go | 6 +- 11 files changed, 222 insertions(+), 241 deletions(-) diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml index 1ee4208e..224b69c6 100644 --- a/.github/workflows/backport.yml +++ b/.github/workflows/backport.yml @@ -18,11 +18,11 @@ jobs: # The main gotcha with this action is that PRs _must_ be labelled before they're # merged to trigger a backport. open-pr: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 if: github.event.pull_request.merged steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 - name: Open Backport PR - uses: korthout/backport-action@v1 + uses: korthout/backport-action@bd68141f079bd036e45ea8149bc9d174d5a04703 # v1 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 858cd11c..7eb4dc48 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,8 +11,8 @@ on: env: # Common versions GO_VERSION: '1.21' - GOLANGCI_VERSION: 'v1.54.0' - DOCKER_BUILDX_VERSION: 'v0.9.1' + GOLANGCI_VERSION: 'v2.1.2' + DOCKER_BUILDX_VERSION: 'v0.23.0' # Common users. We can't run a step 'if secrets.AWS_USR != ""' but we can run # a step 'if env.AWS_USR' != ""', so we copy these to succinctly test whether @@ -23,13 +23,13 @@ env: jobs: detect-noop: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 outputs: noop: ${{ steps.noop.outputs.should_skip }} steps: - name: Detect No-op Changes id: noop - uses: fkirc/skip-duplicate-actions@v5.2.0 + uses: fkirc/skip-duplicate-actions@f75f66ce1886f00957d99748a42c724f4330bdcf # v5.3.1 with: github_token: ${{ secrets.GITHUB_TOKEN }} paths_ignore: '["**.md", "**.png", "**.jpg"]' @@ -38,18 +38,18 @@ jobs: lint: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 needs: detect-noop if: needs.detect-noop.outputs.noop != 'true' steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: submodules: true - name: Setup Go - uses: actions/setup-go@v3 + uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0 with: go-version: ${{ env.GO_VERSION }} @@ -58,14 +58,14 @@ jobs: run: echo "cachedir=$(make go.cachedir)" >> $GITHUB_ENV - name: Cache the Go Build Cache - uses: actions/cache@v3 + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 with: path: ${{ env.cachedir }} key: ${{ runner.os }}-build-lint-${{ hashFiles('**/go.sum') }} restore-keys: ${{ runner.os }}-build-lint- - name: Cache Go Dependencies - uses: actions/cache@v3 + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 with: path: .work/pkg key: ${{ runner.os }}-pkg-${{ hashFiles('**/go.sum') }} @@ -77,24 +77,23 @@ jobs: # We could run 'make lint' but we prefer this action because it leaves # 'annotations' (i.e. it comments on PRs to point out linter violations). - name: Lint - uses: golangci/golangci-lint-action@v3 + uses: golangci/golangci-lint-action@1481404843c368bc19ca9406f87d6e0fc97bdcfd # v7.0.0 with: version: ${{ env.GOLANGCI_VERSION }} - skip-go-installation: true check-diff: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 needs: detect-noop if: needs.detect-noop.outputs.noop != 'true' steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: submodules: true - name: Setup Go - uses: actions/setup-go@v3 + uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0 with: go-version: ${{ env.GO_VERSION }} @@ -103,14 +102,14 @@ jobs: run: echo "cachedir=$(make go.cachedir)" >> $GITHUB_ENV - name: Cache the Go Build Cache - uses: actions/cache@v3 + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 with: path: ${{ env.cachedir }} key: ${{ runner.os }}-build-check-diff-${{ hashFiles('**/go.sum') }} restore-keys: ${{ runner.os }}-build-check-diff- - name: Cache Go Dependencies - uses: actions/cache@v3 + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 with: path: .work/pkg key: ${{ runner.os }}-pkg-${{ hashFiles('**/go.sum') }} @@ -130,13 +129,13 @@ jobs: run: git diff unit-tests: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 needs: detect-noop if: needs.detect-noop.outputs.noop != 'true' steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: submodules: true @@ -144,7 +143,7 @@ jobs: run: git fetch --prune --unshallow - name: Setup Go - uses: actions/setup-go@v3 + uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0 with: go-version: ${{ env.GO_VERSION }} @@ -153,14 +152,14 @@ jobs: run: echo "cachedir=$(make go.cachedir)" >> $GITHUB_ENV - name: Cache the Go Build Cache - uses: actions/cache@v3 + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 with: path: ${{ env.cachedir }} key: ${{ runner.os }}-build-unit-tests-${{ hashFiles('**/go.sum') }} restore-keys: ${{ runner.os }}-build-unit-tests- - name: Cache Go Dependencies - uses: actions/cache@v3 + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 with: path: .work/pkg key: ${{ runner.os }}-pkg-${{ hashFiles('**/go.sum') }} @@ -173,30 +172,30 @@ jobs: run: make -j2 test - name: Publish Unit Test Coverage - uses: codecov/codecov-action@v3 + uses: codecov/codecov-action@ad3126e916f78f00edff4ed0317cf185271ccc2d # v5.4.2 with: flags: unittests - file: _output/tests/linux_amd64/coverage.txt + files: _output/tests/linux_amd64/coverage.txt e2e-tests: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 needs: detect-noop if: needs.detect-noop.outputs.noop != 'true' steps: - name: Setup QEMU - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0 with: platforms: all - name: Setup Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0 with: version: ${{ env.DOCKER_BUILDX_VERSION }} install: true - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: submodules: true @@ -204,7 +203,7 @@ jobs: run: git fetch --prune --unshallow - name: Setup Go - uses: actions/setup-go@v3 + uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0 with: go-version: ${{ env.GO_VERSION }} @@ -213,14 +212,14 @@ jobs: run: echo "cachedir=$(make go.cachedir)" >> $GITHUB_ENV - name: Cache the Go Build Cache - uses: actions/cache@v3 + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 with: path: ${{ env.cachedir }} key: ${{ runner.os }}-build-unit-tests-${{ hashFiles('**/go.sum') }} restore-keys: ${{ runner.os }}-build-unit-tests- - name: Cache Go Dependencies - uses: actions/cache@v3 + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 with: path: .work/pkg key: ${{ runner.os }}-pkg-${{ hashFiles('**/go.sum') }} @@ -240,24 +239,24 @@ jobs: run: make e2e USE_HELM=true publish-artifacts: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 needs: detect-noop if: needs.detect-noop.outputs.noop != 'true' steps: - name: Setup QEMU - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0 with: platforms: all - name: Setup Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3.10.0 with: version: ${{ env.DOCKER_BUILDX_VERSION }} install: true - name: Login to Upbound - uses: docker/login-action@v1 + uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 if: env.XPKG_ACCESS_ID != '' with: registry: xpkg.upbound.io @@ -265,7 +264,7 @@ jobs: password: ${{ secrets.XPKG_TOKEN }} - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: submodules: true @@ -273,7 +272,7 @@ jobs: run: git fetch --prune --unshallow - name: Setup Go - uses: actions/setup-go@v3 + uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0 with: go-version: ${{ env.GO_VERSION }} @@ -282,14 +281,14 @@ jobs: run: echo "cachedir=$(make go.cachedir)" >> $GITHUB_ENV - name: Cache the Go Build Cache - uses: actions/cache@v3 + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 with: path: ${{ env.cachedir }} key: ${{ runner.os }}-build-publish-artifacts-${{ hashFiles('**/go.sum') }} restore-keys: ${{ runner.os }}-build-publish-artifacts- - name: Cache Go Dependencies - uses: actions/cache@v3 + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 with: path: .work/pkg key: ${{ runner.os }}-pkg-${{ hashFiles('**/go.sum') }} @@ -306,7 +305,7 @@ jobs: BUILD_ARGS: "--load" - name: Publish Artifacts to GitHub - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: output path: _output/** @@ -316,7 +315,7 @@ jobs: run: make publish BRANCH_NAME=${GITHUB_REF##*/} - name: Login to Docker - uses: docker/login-action@v1 + uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 if: env.CONTRIB_DOCKER_USR != '' with: username: ${{ secrets.CONTRIB_DOCKER_USR }} diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 6b077c85..e4071a1f 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -9,13 +9,13 @@ on: jobs: detect-noop: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 outputs: noop: ${{ steps.noop.outputs.should_skip }} steps: - name: Detect No-op Changes id: noop - uses: fkirc/skip-duplicate-actions@v5.2.0 + uses: fkirc/skip-duplicate-actions@f75f66ce1886f00957d99748a42c724f4330bdcf # v5.3.1 with: github_token: ${{ secrets.GITHUB_TOKEN }} paths_ignore: '["**.md", "**.png", "**.jpg"]' @@ -23,20 +23,20 @@ jobs: concurrent_skipping: false analyze: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 needs: detect-noop if: needs.detect-noop.outputs.noop != 'true' steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: submodules: true - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@28deaeda66b76a05916b6923827895f2b14ab387 # v3.28.16 with: languages: go - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@28deaeda66b76a05916b6923827895f2b14ab387 # v3.28.16 diff --git a/.github/workflows/commands.yml b/.github/workflows/commands.yml index df101a8e..5de09f44 100644 --- a/.github/workflows/commands.yml +++ b/.github/workflows/commands.yml @@ -4,13 +4,13 @@ on: issue_comment jobs: points: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 if: startsWith(github.event.comment.body, '/points') steps: - name: Extract Command id: command - uses: xt0rted/slash-command-action@v1 + uses: xt0rted/slash-command-action@bf51f8f5f4ea3d58abc7eca58f77104182b23e88 # v2.0.0 with: repo-token: ${{ secrets.GITHUB_TOKEN }} command: points @@ -19,7 +19,7 @@ jobs: allow-edits: "false" permission-level: write - name: Handle Command - uses: actions/github-script@v4 + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 env: POINTS: ${{ steps.command.outputs.command-arguments }} with: @@ -65,12 +65,12 @@ jobs: # NOTE(negz): See also backport.yml, which is the variant that triggers on PR # merge rather than on comment. backport: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 if: github.event.issue.pull_request && startsWith(github.event.comment.body, '/backport') steps: - name: Extract Command id: command - uses: xt0rted/slash-command-action@v1 + uses: xt0rted/slash-command-action@865ee04a1dfc8aa2571513eee8e84b5377153511 # v1 with: repo-token: ${{ secrets.GITHUB_TOKEN }} command: backport @@ -80,7 +80,7 @@ jobs: permission-level: write - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Open Backport PR - uses: korthout/backport-action@v1 + uses: korthout/backport-action@bd68141f079bd036e45ea8149bc9d174d5a04703 # v1 diff --git a/.github/workflows/promote.yml b/.github/workflows/promote.yml index 680c0f9e..eef81b9a 100644 --- a/.github/workflows/promote.yml +++ b/.github/workflows/promote.yml @@ -21,11 +21,11 @@ env: jobs: promote-artifacts: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: submodules: true @@ -33,14 +33,14 @@ jobs: run: git fetch --prune --unshallow - name: Login to Docker - uses: docker/login-action@v1 + uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 if: env.CONTRIB_DOCKER_USR != '' with: username: ${{ secrets.CONTRIB_DOCKER_USR }} password: ${{ secrets.CONTRIB_DOCKER_PSW }} - name: Login to Upbound - uses: docker/login-action@v1 + uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 if: env.XPKG_ACCESS_ID != '' with: registry: xpkg.upbound.io diff --git a/.github/workflows/tag.yml b/.github/workflows/tag.yml index db32dd0f..1424b6fb 100644 --- a/.github/workflows/tag.yml +++ b/.github/workflows/tag.yml @@ -12,15 +12,15 @@ on: jobs: create-tag: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Create Tag - uses: negz/create-tag@v1 + uses: negz/create-tag@39bae1e0932567a58c20dea5a1a0d18358503320 # v1 with: version: ${{ github.event.inputs.version }} message: ${{ github.event.inputs.message }} - token: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file + token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.golangci.yml b/.golangci.yml index 771bc4fa..5b6c12b7 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,185 +1,165 @@ +version: "2" run: - deadline: 2m - - skip-files: - - "zz_generated\\..+\\.go$" - -output: - # colored-line-number|line-number|json|tab|checkstyle|code-climate, default is "colored-line-number" - format: colored-line-number - -linters-settings: - errcheck: - # report about not checking of errors in type assetions: `a := b.(MyStruct)`; - # default is false: such cases aren't reported by default. - check-type-assertions: false - - # report about assignment of errors to blank identifier: `num, _ := strconv.Atoi(numStr)`; - # default is false: such cases aren't reported by default. - check-blank: false - - # [deprecated] comma-separated list of pairs of the form pkg:regex - # the regex is used to ignore names within pkg. (default "fmt:.*"). - # see https://github.com/kisielk/errcheck#the-deprecated-method for details - ignore: fmt:.*,io/ioutil:^Read.* - - govet: - # report about shadowed variables - check-shadowing: false - - golint: - # minimal confidence for issues, default is 0.8 - min-confidence: 0.8 - - gofmt: - # simplify code: gofmt with `-s` option, true by default - simplify: true - - goimports: - # put imports beginning with prefix after 3rd-party packages; - # it's a comma-separated list of prefixes - local-prefixes: github.com/crossplane/provider-sql - - gocyclo: - # minimal code complexity to report, 30 by default (but we recommend 10-20) - min-complexity: 10 - - maligned: - # print struct with more effective memory layout or not, false by default - suggest-new: true - - dupl: - # tokens count to trigger issue, 150 by default - threshold: 100 - - goconst: - # minimal length of string constant, 3 by default - min-len: 3 - # minimal occurrences count to trigger, 3 by default - min-occurrences: 5 - - lll: - # tab width in spaces. Default to 1. - tab-width: 1 - - unused: - # treat code as a program (not a library) and report unused exported identifiers; default is false. - # XXX: if you enable this setting, unused will report a lot of false-positives in text editors: - # if it's called for subdir of a project it can't find funcs usages. All text editor integrations - # with golangci-lint call it on a directory with the changed file. - check-exported: false - - unparam: - # Inspect exported functions, default is false. Set to true if no external program/library imports your code. - # XXX: if you enable this setting, unparam will report a lot of false-positives in text editors: - # if it's called for subdir of a project it can't find external interfaces. All text editor integrations - # with golangci-lint call it on a directory with the changed file. - check-exported: false - - nakedret: - # make an issue if func has more lines of code than this setting and it has naked returns; default is 30 - max-func-lines: 30 - - prealloc: - # XXX: we don't recommend using this linter before doing performance profiling. - # For most programs usage of prealloc will be a premature optimization. - - # Report preallocation suggestions only on simple loops that have no returns/breaks/continues/gotos in them. - # True by default. - simple: true - range-loops: true # Report preallocation suggestions on range loops, true by default - for-loops: false # Report preallocation suggestions on for loops, false by default - - gocritic: - # Enable multiple checks by tags, run `GL_DEBUG=gocritic golangci-lint` run to see all tags and checks. - # Empty list by default. See https://github.com/go-critic/go-critic#usage -> section "Tags". - enabled-tags: - - performance - - settings: # settings passed to gocritic - captLocal: # must be valid enabled check name - paramsOnly: true - rangeValCopy: - sizeThreshold: 32 + timeout: 2m + +formatters: + # Enable specific formatter. + # Default: [] (uses standard Go formatting) + enable: + - gofmt + - goimports + # - gci + # - gofumpt + # - golines + + settings: + gofmt: + # simplify code: gofmt with `-s` option, true by default + simplify: true + + goimports: + # put imports beginning with prefix after 3rd-party packages + local-prefixes: + - github.com/crossplane/provider-sql linters: + default: standard enable: - - megacheck - govet - gocyclo - gocritic - - interfacer + - iface - goconst - - goimports - - gofmt # We enable this as well as goimports for its simplify mode. - prealloc - - golint + - revive - unconvert - misspell - nakedret - - presets: - - bugs - - unused - fast: false - - + settings: + errcheck: + # report about not checking of errors in type assetions: `a := b.(MyStruct)`; + # default is false: such cases aren't reported by default. + check-type-assertions: false + + # report about assignment of errors to blank identifier: `num, _ := strconv.Atoi(numStr)`; + # default is false: such cases aren't reported by default. + check-blank: false + + exclude-functions: + - fmt:.* + - io/ioutil:^Read.* + + govet: + # report about shadowed variables + disable: + - shadow + + revive: + # minimal confidence for issues, default is 0.8 + confidence: 0.8 + + gocyclo: + # minimal code complexity to report, 30 by default (but we recommend 10-20) + min-complexity: 10 + + dupl: + # tokens count to trigger issue, 150 by default + threshold: 100 + + goconst: + # minimal length of string constant, 3 by default + min-len: 3 + # minimal occurrences count to trigger, 3 by default + min-occurrences: 5 + + lll: + # tab width in spaces. Default to 1. + tab-width: 1 + + unused: + exported-fields-are-used: false + + unparam: + # Inspect exported functions, default is false. Set to true if no external program/library imports your code. + # XXX: if you enable this setting, unparam will report a lot of false-positives in text editors: + # if it's called for subdir of a project it can't find external interfaces. All text editor integrations + # with golangci-lint call it on a directory with the changed file. + check-exported: false + + nakedret: + # make an issue if func has more lines of code than this setting and it has naked returns; default is 30 + max-func-lines: 30 + + prealloc: + # XXX: we don't recommend using this linter before doing performance profiling. + # For most programs usage of prealloc will be a premature optimization. + + # Report preallocation suggestions only on simple loops that have no returns/breaks/continues/gotos in them. + # True by default. + simple: true + range-loops: true # Report preallocation suggestions on range loops, true by default + for-loops: false # Report preallocation suggestions on for loops, false by default + + gocritic: + # Enable multiple checks by tags, run `GL_DEBUG=gocritic golangci-lint` run to see all tags and checks. + # Empty list by default. See https://github.com/go-critic/go-critic#usage -> section "Tags". + enabled-tags: + - performance + + settings: # settings passed to gocritic + captLocal: # must be valid enabled check name + paramsOnly: true + rangeValCopy: + sizeThreshold: 32 + exclusions: + rules: + # Exclude some linters from running on tests files. + - path: _test(ing)?\.go + linters: + - gocyclo + - errcheck + - dupl + - gosec + - scopelint + - unparam + + # Ease some gocritic warnings on test files. + - path: _test\.go + text: "(unnamedResult|exitAfterDefer)" + linters: + - gocritic + + # These are performance optimisations rather than style issues per se. + # They warn when function arguments or range values copy a lot of memory + # rather than using a pointer. + - text: "(hugeParam|rangeValCopy):" + linters: + - gocritic + + # This "TestMain should call os.Exit to set exit code" warning is not clever + # enough to notice that we call a helper method that calls os.Exit. + - text: "SA3000:" + linters: + - staticcheck + + - text: "k8s.io/api/core/v1" + linters: + - goimports + + # This is a "potential hardcoded credentials" warning. It's triggered by + # any variable with 'secret' in the same, and thus hits a lot of false + # positives in Kubernetes land where a Secret is an object type. + - text: "G101:" + linters: + - gosec + - gas + + # This is an 'errors unhandled' warning that duplicates errcheck. + - text: "G104:" + linters: + - gosec + - gas issues: - # Excluding configuration per-path and per-linter - exclude-rules: - # Exclude some linters from running on tests files. - - path: _test(ing)?\.go - linters: - - gocyclo - - errcheck - - dupl - - gosec - - scopelint - - unparam - - # Ease some gocritic warnings on test files. - - path: _test\.go - text: "(unnamedResult|exitAfterDefer)" - linters: - - gocritic - - # These are performance optimisations rather than style issues per se. - # They warn when function arguments or range values copy a lot of memory - # rather than using a pointer. - - text: "(hugeParam|rangeValCopy):" - linters: - - gocritic - - # This "TestMain should call os.Exit to set exit code" warning is not clever - # enough to notice that we call a helper method that calls os.Exit. - - text: "SA3000:" - linters: - - staticcheck - - - text: "k8s.io/api/core/v1" - linters: - - goimports - - # This is a "potential hardcoded credentials" warning. It's triggered by - # any variable with 'secret' in the same, and thus hits a lot of false - # positives in Kubernetes land where a Secret is an object type. - - text: "G101:" - linters: - - gosec - - gas - - # This is an 'errors unhandled' warning that duplicates errcheck. - - text: "G104:" - linters: - - gosec - - gas - - # Independently from option `exclude` we use default exclude patterns, - # it can be disabled by this option. To list all - # excluded by default patterns execute `golangci-lint run --help`. - # Default value for this option is true. - exclude-use-default: false - # Show only new issues: if there are unstaged changes or untracked files, # only those changes are analyzed, else only changes in HEAD~ are analyzed. # It's a super-useful option for integration of golangci-lint into existing @@ -189,7 +169,7 @@ issues: new: false # Maximum issues count per one linter. Set to 0 to disable. Default is 50. - max-per-linter: 0 + max-issues-per-linter: 0 # Maximum count of issues with the same text. Set to 0 to disable. Default is 3. max-same-issues: 0 diff --git a/Makefile b/Makefile index ff3a0507..95926214 100644 --- a/Makefile +++ b/Makefile @@ -23,10 +23,12 @@ NPROCS ?= 1 # to half the number of CPU cores. GO_TEST_PARALLEL := $(shell echo $$(( $(NPROCS) / 2 ))) +GOLANGCILINT_VERSION ?= 1.63.4 GO_STATIC_PACKAGES = $(GO_PROJECT)/cmd/provider GO_LDFLAGS += -X $(GO_PROJECT)/pkg/version.Version=$(VERSION) GO_SUBDIRS += cmd pkg apis GO111MODULE = on +GOLANGCILINT_VERSION = 2.1.2 -include build/makelib/golang.mk # ==================================================================================== diff --git a/build b/build index 231258db..92457ef1 160000 --- a/build +++ b/build @@ -1 +1 @@ -Subproject commit 231258db281237379d8ec0c6e4af9d7c1ae5cc4a +Subproject commit 92457ef1c0feb75cd235bdb90244e340d0796b7f diff --git a/pkg/controller/mssql/grant/reconciler_test.go b/pkg/controller/mssql/grant/reconciler_test.go index 65aba6f1..c4b9d079 100644 --- a/pkg/controller/mssql/grant/reconciler_test.go +++ b/pkg/controller/mssql/grant/reconciler_test.go @@ -879,11 +879,11 @@ func Test_diffPermissions(t *testing.T) { } for name, tc := range cases { t.Run(name, func(t *testing.T) { - gotToGrant, gotToRevoke := diffPermissions(tc.args.desired, tc.args.observed) - if diff := cmp.Diff(tc.want.toGrant, gotToGrant, equateSlices()); diff != "" { + gotToGrant, gotToRevoke := diffPermissions(tc.desired, tc.observed) + if diff := cmp.Diff(tc.toGrant, gotToGrant, equateSlices()); diff != "" { t.Errorf("\ndiffPermissions(...): -want toGrant, +got toGrant:\n%s", diff) } - if diff := cmp.Diff(tc.want.toRevoke, gotToRevoke, equateSlices()); diff != "" { + if diff := cmp.Diff(tc.toRevoke, gotToRevoke, equateSlices()); diff != "" { t.Errorf("\ndiffPermissions(...): -want toRevoke, +got toRevoke:\n%s", diff) } }) diff --git a/pkg/controller/mysql/grant/reconciler_test.go b/pkg/controller/mysql/grant/reconciler_test.go index 1f54281f..49b2eaf4 100644 --- a/pkg/controller/mysql/grant/reconciler_test.go +++ b/pkg/controller/mysql/grant/reconciler_test.go @@ -1230,11 +1230,11 @@ func Test_diffPermissions(t *testing.T) { } for name, tc := range cases { t.Run(name, func(t *testing.T) { - gotToGrant, gotToRevoke := diffPermissions(tc.args.desired, tc.args.observed) - if diff := cmp.Diff(tc.want.toGrant, gotToGrant, equateSlices()...); diff != "" { + gotToGrant, gotToRevoke := diffPermissions(tc.desired, tc.observed) + if diff := cmp.Diff(tc.toGrant, gotToGrant, equateSlices()...); diff != "" { t.Errorf("\ndiffPermissions(...): -want toGrant, +got toGrant:\n%s", diff) } - if diff := cmp.Diff(tc.want.toRevoke, gotToRevoke, equateSlices()...); diff != "" { + if diff := cmp.Diff(tc.toRevoke, gotToRevoke, equateSlices()...); diff != "" { t.Errorf("\ndiffPermissions(...): -want toRevoke, +got toRevoke:\n%s", diff) } }) From 141e7c80f6c493849b931113daf5152483fefa1f Mon Sep 17 00:00:00 2001 From: Carl Henrik Lunde Date: Wed, 7 May 2025 06:42:47 +0200 Subject: [PATCH 17/24] chore: Update Go to 1.23.9 (#230) Go 1.23.9 is a security update, and we also need to update Go to get dependabot security updates out (dependabot does not run 'go mod tidy'). Signed-off-by: Carl Henrik Lunde --- .github/workflows/ci.yml | 2 +- go.mod | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7eb4dc48..67f7cb52 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,7 +10,7 @@ on: env: # Common versions - GO_VERSION: '1.21' + GO_VERSION: '1.23' GOLANGCI_VERSION: 'v2.1.2' DOCKER_BUILDX_VERSION: 'v0.23.0' diff --git a/go.mod b/go.mod index 713e48ed..23b5bb7f 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,6 @@ module github.com/crossplane-contrib/provider-sql -go 1.21 - -toolchain go1.21.11 +go 1.23.9 require ( github.com/DATA-DOG/go-sqlmock v1.5.0 From 81159bd3b23c3bc584cae49bbdc42d50966c071c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 7 May 2025 06:53:14 +0200 Subject: [PATCH 18/24] Bump golang.org/x/crypto from 0.21.0 to 0.35.0 (#229) Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.21.0 to 0.35.0. - [Commits](https://github.com/golang/crypto/compare/v0.21.0...v0.35.0) --- updated-dependencies: - dependency-name: golang.org/x/crypto dependency-version: 0.35.0 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 15 ++++++++------- go.sum | 32 ++++++++++++++++---------------- 2 files changed, 24 insertions(+), 23 deletions(-) diff --git a/go.mod b/go.mod index 23b5bb7f..86fce7b2 100644 --- a/go.mod +++ b/go.mod @@ -68,16 +68,17 @@ require ( github.com/xhit/go-str2duration/v2 v2.1.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.26.0 // indirect - golang.org/x/crypto v0.21.0 // indirect + golang.org/x/crypto v0.35.0 // indirect golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 // indirect - golang.org/x/mod v0.14.0 // indirect - golang.org/x/net v0.23.0 // indirect + golang.org/x/mod v0.17.0 // indirect + golang.org/x/net v0.25.0 // indirect golang.org/x/oauth2 v0.15.0 // indirect - golang.org/x/sys v0.18.0 // indirect - golang.org/x/term v0.18.0 // indirect - golang.org/x/text v0.14.0 // indirect + golang.org/x/sync v0.11.0 // indirect + golang.org/x/sys v0.30.0 // indirect + golang.org/x/term v0.29.0 // indirect + golang.org/x/text v0.22.0 // indirect golang.org/x/time v0.5.0 // indirect - golang.org/x/tools v0.17.0 // indirect + golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect google.golang.org/appengine v1.6.8 // indirect google.golang.org/protobuf v1.31.0 // indirect diff --git a/go.sum b/go.sum index cd23c657..cf2b123f 100644 --- a/go.sum +++ b/go.sum @@ -167,31 +167,31 @@ golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= -golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs= +golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ= golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 h1:hNQpMuAJe5CtcUqCXaWga3FHu+kQvCqcsoVaQgSV60o= golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= -golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= -golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/oauth2 v0.15.0 h1:s8pnnxNVzjWyrvYdFUQq5llS1PX2zhPXmccZv99h7uQ= golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= -golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= +golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -201,18 +201,18 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= -golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= +golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU= +golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= +golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -220,8 +220,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc= -golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= From ee8f3ac41e08aa2d61d7419b66e0ee3197d4118c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 7 May 2025 07:02:28 +0200 Subject: [PATCH 19/24] Bump golang.org/x/net from 0.25.0 to 0.38.0 (#231) Bumps [golang.org/x/net](https://github.com/golang/net) from 0.25.0 to 0.38.0. - [Commits](https://github.com/golang/net/compare/v0.25.0...v0.38.0) --- updated-dependencies: - dependency-name: golang.org/x/net dependency-version: 0.38.0 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 12 ++++++------ go.sum | 24 ++++++++++++------------ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/go.mod b/go.mod index 86fce7b2..186a23c7 100644 --- a/go.mod +++ b/go.mod @@ -68,15 +68,15 @@ require ( github.com/xhit/go-str2duration/v2 v2.1.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.26.0 // indirect - golang.org/x/crypto v0.35.0 // indirect + golang.org/x/crypto v0.36.0 // indirect golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 // indirect golang.org/x/mod v0.17.0 // indirect - golang.org/x/net v0.25.0 // indirect + golang.org/x/net v0.38.0 // indirect golang.org/x/oauth2 v0.15.0 // indirect - golang.org/x/sync v0.11.0 // indirect - golang.org/x/sys v0.30.0 // indirect - golang.org/x/term v0.29.0 // indirect - golang.org/x/text v0.22.0 // indirect + golang.org/x/sync v0.12.0 // indirect + golang.org/x/sys v0.31.0 // indirect + golang.org/x/term v0.30.0 // indirect + golang.org/x/text v0.23.0 // indirect golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect diff --git a/go.sum b/go.sum index cf2b123f..d692f19d 100644 --- a/go.sum +++ b/go.sum @@ -167,8 +167,8 @@ golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs= -golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ= +golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= +golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 h1:hNQpMuAJe5CtcUqCXaWga3FHu+kQvCqcsoVaQgSV60o= golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -182,16 +182,16 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= -golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= +golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= +golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= golang.org/x/oauth2 v0.15.0 h1:s8pnnxNVzjWyrvYdFUQq5llS1PX2zhPXmccZv99h7uQ= golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= -golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= +golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -201,18 +201,18 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= -golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= +golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU= -golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s= +golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y= +golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= -golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= +golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= +golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= From e3cb31c36e6486cc8eb49629e042fd8f1622ff1a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 7 May 2025 07:10:41 +0200 Subject: [PATCH 20/24] Bump google.golang.org/protobuf from 1.31.0 to 1.33.0 (#232) Bumps google.golang.org/protobuf from 1.31.0 to 1.33.0. --- updated-dependencies: - dependency-name: google.golang.org/protobuf dependency-version: 1.33.0 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 186a23c7..ed6c2164 100644 --- a/go.mod +++ b/go.mod @@ -81,7 +81,7 @@ require ( golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect google.golang.org/appengine v1.6.8 // indirect - google.golang.org/protobuf v1.31.0 // indirect + google.golang.org/protobuf v1.33.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index d692f19d..b69dfcad 100644 --- a/go.sum +++ b/go.sum @@ -232,8 +232,8 @@ google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAs google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From 598c9cc30eee3212b39f68590d499253e98e8332 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=2E=20Fern=C3=A1ndez?= <7312236+fernandezcuesta@users.noreply.github.com> Date: Thu, 8 May 2025 19:49:55 +0000 Subject: [PATCH 21/24] fix: enable management policies (#215) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: enable management policies Signed-off-by: Jesús Fernández <7312236+fernandezcuesta@users.noreply.github.com> * fix: linter Signed-off-by: Jesús Fernández <7312236+fernandezcuesta@users.noreply.github.com> * chore: offload lint changes to #216 Signed-off-by: Jesús Fernández <7312236+fernandezcuesta@users.noreply.github.com> * chore: revert changes as per peer review Signed-off-by: Jesús Fernández <7312236+fernandezcuesta@users.noreply.github.com> --------- Signed-off-by: Jesús Fernández <7312236+fernandezcuesta@users.noreply.github.com> --- cmd/provider/main.go | 27 +++++++++++++------ go.mod | 4 +-- go.sum | 4 --- pkg/controller/mssql/database/reconciler.go | 15 ++++++++--- pkg/controller/mssql/grant/reconciler.go | 15 ++++++++--- pkg/controller/mssql/user/reconciler.go | 15 ++++++++--- pkg/controller/mysql/database/reconciler.go | 14 +++++++--- pkg/controller/mysql/grant/reconciler.go | 15 ++++++++--- pkg/controller/mysql/user/reconciler.go | 15 ++++++++--- .../postgresql/database/reconciler.go | 15 ++++++++--- .../postgresql/extension/reconciler.go | 15 ++++++++--- pkg/controller/postgresql/grant/reconciler.go | 15 ++++++++--- pkg/controller/postgresql/role/reconciler.go | 15 ++++++++--- .../postgresql/schema/reconciler.go | 15 ++++++++--- 14 files changed, 141 insertions(+), 58 deletions(-) diff --git a/cmd/provider/main.go b/cmd/provider/main.go index c4e98f35..300a4eb6 100644 --- a/cmd/provider/main.go +++ b/cmd/provider/main.go @@ -24,13 +24,15 @@ import ( _ "github.com/go-sql-driver/mysql" _ "github.com/lib/pq" - "gopkg.in/alecthomas/kingpin.v2" + "github.com/alecthomas/kingpin/v2" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/cache" "sigs.k8s.io/controller-runtime/pkg/log/zap" xpcontroller "github.com/crossplane/crossplane-runtime/pkg/controller" + "github.com/crossplane/crossplane-runtime/pkg/feature" "github.com/crossplane/crossplane-runtime/pkg/logging" + "github.com/crossplane/crossplane-runtime/pkg/ratelimiter" "github.com/crossplane-contrib/provider-sql/apis" "github.com/crossplane-contrib/provider-sql/pkg/controller" @@ -38,11 +40,13 @@ import ( func main() { var ( - app = kingpin.New(filepath.Base(os.Args[0]), "SQL support for Crossplane.").DefaultEnvars() - debug = app.Flag("debug", "Run with debug logging.").Short('d').Bool() - pollInterval = app.Flag("poll", "Poll interval controls how often an individual resource should be checked for drift.").Default("10m").Duration() - syncPeriod = app.Flag("sync", "Controller manager sync period such as 300ms, 1.5h, or 2h45m").Short('s').Default("1h").Duration() - leaderElection = app.Flag("leader-election", "Use leader election for the conroller manager.").Short('l').Default("false").Envar("LEADER_ELECTION").Bool() + app = kingpin.New(filepath.Base(os.Args[0]), "SQL support for Crossplane.").DefaultEnvars() + debug = app.Flag("debug", "Run with debug logging.").Short('d').Bool() + pollInterval = app.Flag("poll", "Poll interval controls how often an individual resource should be checked for drift.").Default("10m").Duration() + syncPeriod = app.Flag("sync", "How often all resources will be double-checked for drift from the desired state.").Short('s').Default("1h").Duration() + leaderElection = app.Flag("leader-election", "Use leader election for the controller manager.").Short('l').Default("false").Envar("LEADER_ELECTION").Bool() + maxReconcileRate = app.Flag("max-reconcile-rate", "The global maximum rate per second at which resources may checked for drift from the desired state.").Default("10").Int() + enableManagementPolicies = app.Flag("enable-management-policies", "Enable/disable support for Management Policies.").Default("true").Envar("ENABLE_MANAGEMENT_POLICIES").Bool() ) kingpin.MustParse(app.Parse(os.Args[1:])) @@ -71,8 +75,15 @@ func main() { kingpin.FatalIfError(apis.AddToScheme(mgr.GetScheme()), "Cannot add SQL APIs to scheme") o := xpcontroller.Options{ - Logger: log, - PollInterval: *pollInterval, + Logger: log, + MaxConcurrentReconciles: *maxReconcileRate, + PollInterval: *pollInterval, + GlobalRateLimiter: ratelimiter.NewGlobal(*maxReconcileRate), + Features: &feature.Flags{}, + } + if *enableManagementPolicies { + o.Features.Enable(feature.EnableBetaManagementPolicies) + log.Info("Beta feature enabled", "flag", feature.EnableBetaManagementPolicies) } kingpin.FatalIfError(controller.Setup(mgr, o), "Cannot setup SQL controllers") diff --git a/go.mod b/go.mod index ed6c2164..fa491915 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.23.9 require ( github.com/DATA-DOG/go-sqlmock v1.5.0 + github.com/alecthomas/kingpin/v2 v2.4.0 github.com/crossplane/crossplane-runtime v1.16.0 github.com/crossplane/crossplane-tools v0.0.0-20240522174801-1ad3d4c87f21 github.com/denisenkom/go-mssqldb v0.11.0 @@ -11,7 +12,6 @@ require ( github.com/google/go-cmp v0.6.0 github.com/lib/pq v1.8.0 github.com/pkg/errors v0.9.1 - gopkg.in/alecthomas/kingpin.v2 v2.2.6 k8s.io/api v0.29.1 k8s.io/apimachinery v0.29.1 k8s.io/utils v0.0.0-20230726121419-3b25d923346b @@ -21,8 +21,6 @@ require ( require ( dario.cat/mergo v1.0.0 // indirect - github.com/alecthomas/kingpin/v2 v2.4.0 // indirect - github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/blang/semver/v4 v4.0.0 // indirect diff --git a/go.sum b/go.sum index b69dfcad..e3991144 100644 --- a/go.sum +++ b/go.sum @@ -4,8 +4,6 @@ github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20O github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/alecthomas/kingpin/v2 v2.4.0 h1:f48lwail6p8zpO1bC4TxtqACaGqHYA22qkHjHpqDjYY= github.com/alecthomas/kingpin/v2 v2.4.0/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc= github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -234,8 +232,6 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= -gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= diff --git a/pkg/controller/mssql/database/reconciler.go b/pkg/controller/mssql/database/reconciler.go index f1a2537c..e64c6938 100644 --- a/pkg/controller/mssql/database/reconciler.go +++ b/pkg/controller/mssql/database/reconciler.go @@ -29,6 +29,7 @@ import ( xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" xpcontroller "github.com/crossplane/crossplane-runtime/pkg/controller" "github.com/crossplane/crossplane-runtime/pkg/event" + "github.com/crossplane/crossplane-runtime/pkg/feature" "github.com/crossplane/crossplane-runtime/pkg/meta" "github.com/crossplane/crossplane-runtime/pkg/reconciler/managed" "github.com/crossplane/crossplane-runtime/pkg/resource" @@ -57,13 +58,19 @@ func Setup(mgr ctrl.Manager, o xpcontroller.Options) error { name := managed.ControllerName(v1alpha1.DatabaseGroupKind) t := resource.NewProviderConfigUsageTracker(mgr.GetClient(), &v1alpha1.ProviderConfigUsage{}) - r := managed.NewReconciler(mgr, - resource.ManagedKind(v1alpha1.DatabaseGroupVersionKind), + reconcilerOptions := []managed.ReconcilerOption{ managed.WithExternalConnecter(&connector{kube: mgr.GetClient(), usage: t, newClient: mssql.New}), managed.WithLogger(o.Logger.WithValues("controller", name)), managed.WithPollInterval(o.PollInterval), - managed.WithRecorder(event.NewAPIRecorder(mgr.GetEventRecorderFor(name)))) - + managed.WithRecorder(event.NewAPIRecorder(mgr.GetEventRecorderFor(name))), + } + if o.Features.Enabled(feature.EnableBetaManagementPolicies) { + reconcilerOptions = append(reconcilerOptions, managed.WithManagementPolicies()) + } + r := managed.NewReconciler(mgr, + resource.ManagedKind(v1alpha1.DatabaseGroupVersionKind), + reconcilerOptions..., + ) return ctrl.NewControllerManagedBy(mgr). Named(name). For(&v1alpha1.Database{}). diff --git a/pkg/controller/mssql/grant/reconciler.go b/pkg/controller/mssql/grant/reconciler.go index 7566446d..fb01ade5 100644 --- a/pkg/controller/mssql/grant/reconciler.go +++ b/pkg/controller/mssql/grant/reconciler.go @@ -33,6 +33,7 @@ import ( xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" xpcontroller "github.com/crossplane/crossplane-runtime/pkg/controller" "github.com/crossplane/crossplane-runtime/pkg/event" + "github.com/crossplane/crossplane-runtime/pkg/feature" "github.com/crossplane/crossplane-runtime/pkg/reconciler/managed" "github.com/crossplane/crossplane-runtime/pkg/resource" @@ -60,14 +61,20 @@ func Setup(mgr ctrl.Manager, o xpcontroller.Options) error { name := managed.ControllerName(v1alpha1.GrantGroupKind) t := resource.NewProviderConfigUsageTracker(mgr.GetClient(), &v1alpha1.ProviderConfigUsage{}) - r := managed.NewReconciler(mgr, - resource.ManagedKind(v1alpha1.GrantGroupVersionKind), + reconcilerOptions := []managed.ReconcilerOption{ managed.WithExternalConnecter(&connector{kube: mgr.GetClient(), usage: t, newClient: mssql.New}), managed.WithReferenceResolver(managed.NewAPISimpleReferenceResolver(mgr.GetClient())), managed.WithLogger(o.Logger.WithValues("controller", name)), managed.WithPollInterval(o.PollInterval), - managed.WithRecorder(event.NewAPIRecorder(mgr.GetEventRecorderFor(name)))) - + managed.WithRecorder(event.NewAPIRecorder(mgr.GetEventRecorderFor(name))), + } + if o.Features.Enabled(feature.EnableBetaManagementPolicies) { + reconcilerOptions = append(reconcilerOptions, managed.WithManagementPolicies()) + } + r := managed.NewReconciler(mgr, + resource.ManagedKind(v1alpha1.GrantGroupVersionKind), + reconcilerOptions..., + ) return ctrl.NewControllerManagedBy(mgr). Named(name). For(&v1alpha1.Grant{}). diff --git a/pkg/controller/mssql/user/reconciler.go b/pkg/controller/mssql/user/reconciler.go index 054d3b04..c8cf357f 100644 --- a/pkg/controller/mssql/user/reconciler.go +++ b/pkg/controller/mssql/user/reconciler.go @@ -31,6 +31,7 @@ import ( xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" xpcontroller "github.com/crossplane/crossplane-runtime/pkg/controller" "github.com/crossplane/crossplane-runtime/pkg/event" + "github.com/crossplane/crossplane-runtime/pkg/feature" "github.com/crossplane/crossplane-runtime/pkg/meta" "github.com/crossplane/crossplane-runtime/pkg/password" "github.com/crossplane/crossplane-runtime/pkg/reconciler/managed" @@ -67,13 +68,19 @@ func Setup(mgr ctrl.Manager, o xpcontroller.Options) error { name := managed.ControllerName(v1alpha1.UserGroupKind) t := resource.NewProviderConfigUsageTracker(mgr.GetClient(), &v1alpha1.ProviderConfigUsage{}) - r := managed.NewReconciler(mgr, - resource.ManagedKind(v1alpha1.UserGroupVersionKind), + reconcilerOptions := []managed.ReconcilerOption{ managed.WithExternalConnecter(&connector{kube: mgr.GetClient(), usage: t, newClient: mssql.New}), managed.WithLogger(o.Logger.WithValues("controller", name)), managed.WithPollInterval(o.PollInterval), - managed.WithRecorder(event.NewAPIRecorder(mgr.GetEventRecorderFor(name)))) - + managed.WithRecorder(event.NewAPIRecorder(mgr.GetEventRecorderFor(name))), + } + if o.Features.Enabled(feature.EnableBetaManagementPolicies) { + reconcilerOptions = append(reconcilerOptions, managed.WithManagementPolicies()) + } + r := managed.NewReconciler(mgr, + resource.ManagedKind(v1alpha1.UserGroupVersionKind), + reconcilerOptions..., + ) return ctrl.NewControllerManagedBy(mgr). Named(name). For(&v1alpha1.User{}). diff --git a/pkg/controller/mysql/database/reconciler.go b/pkg/controller/mysql/database/reconciler.go index 1c8c3687..d5d8c932 100644 --- a/pkg/controller/mysql/database/reconciler.go +++ b/pkg/controller/mysql/database/reconciler.go @@ -29,6 +29,7 @@ import ( xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" xpcontroller "github.com/crossplane/crossplane-runtime/pkg/controller" "github.com/crossplane/crossplane-runtime/pkg/event" + "github.com/crossplane/crossplane-runtime/pkg/feature" "github.com/crossplane/crossplane-runtime/pkg/meta" "github.com/crossplane/crossplane-runtime/pkg/reconciler/managed" "github.com/crossplane/crossplane-runtime/pkg/resource" @@ -59,12 +60,19 @@ func Setup(mgr ctrl.Manager, o xpcontroller.Options) error { name := managed.ControllerName(v1alpha1.DatabaseGroupKind) t := resource.NewProviderConfigUsageTracker(mgr.GetClient(), &v1alpha1.ProviderConfigUsage{}) - r := managed.NewReconciler(mgr, - resource.ManagedKind(v1alpha1.DatabaseGroupVersionKind), + reconcilerOptions := []managed.ReconcilerOption{ managed.WithExternalConnecter(&connector{kube: mgr.GetClient(), usage: t, newDB: mysql.New}), managed.WithLogger(o.Logger.WithValues("controller", name)), managed.WithPollInterval(o.PollInterval), - managed.WithRecorder(event.NewAPIRecorder(mgr.GetEventRecorderFor(name)))) + managed.WithRecorder(event.NewAPIRecorder(mgr.GetEventRecorderFor(name))), + } + if o.Features.Enabled(feature.EnableBetaManagementPolicies) { + reconcilerOptions = append(reconcilerOptions, managed.WithManagementPolicies()) + } + r := managed.NewReconciler(mgr, + resource.ManagedKind(v1alpha1.DatabaseGroupVersionKind), + reconcilerOptions..., + ) return ctrl.NewControllerManagedBy(mgr). Named(name). diff --git a/pkg/controller/mysql/grant/reconciler.go b/pkg/controller/mysql/grant/reconciler.go index 7e643cd2..675ab401 100644 --- a/pkg/controller/mysql/grant/reconciler.go +++ b/pkg/controller/mysql/grant/reconciler.go @@ -34,6 +34,7 @@ import ( xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" xpcontroller "github.com/crossplane/crossplane-runtime/pkg/controller" "github.com/crossplane/crossplane-runtime/pkg/event" + "github.com/crossplane/crossplane-runtime/pkg/feature" "github.com/crossplane/crossplane-runtime/pkg/reconciler/managed" "github.com/crossplane/crossplane-runtime/pkg/resource" @@ -69,14 +70,20 @@ func Setup(mgr ctrl.Manager, o xpcontroller.Options) error { name := managed.ControllerName(v1alpha1.GrantGroupKind) t := resource.NewProviderConfigUsageTracker(mgr.GetClient(), &v1alpha1.ProviderConfigUsage{}) - r := managed.NewReconciler(mgr, - resource.ManagedKind(v1alpha1.GrantGroupVersionKind), + reconcilerOptions := []managed.ReconcilerOption{ managed.WithExternalConnecter(&connector{kube: mgr.GetClient(), usage: t, newDB: mysql.New}), managed.WithReferenceResolver(managed.NewAPISimpleReferenceResolver(mgr.GetClient())), managed.WithLogger(o.Logger.WithValues("controller", name)), managed.WithPollInterval(o.PollInterval), - managed.WithRecorder(event.NewAPIRecorder(mgr.GetEventRecorderFor(name)))) - + managed.WithRecorder(event.NewAPIRecorder(mgr.GetEventRecorderFor(name))), + } + if o.Features.Enabled(feature.EnableBetaManagementPolicies) { + reconcilerOptions = append(reconcilerOptions, managed.WithManagementPolicies()) + } + r := managed.NewReconciler(mgr, + resource.ManagedKind(v1alpha1.GrantGroupVersionKind), + reconcilerOptions..., + ) return ctrl.NewControllerManagedBy(mgr). Named(name). For(&v1alpha1.Grant{}). diff --git a/pkg/controller/mysql/user/reconciler.go b/pkg/controller/mysql/user/reconciler.go index 532e63c3..07de47d7 100644 --- a/pkg/controller/mysql/user/reconciler.go +++ b/pkg/controller/mysql/user/reconciler.go @@ -31,6 +31,7 @@ import ( xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" xpcontroller "github.com/crossplane/crossplane-runtime/pkg/controller" "github.com/crossplane/crossplane-runtime/pkg/event" + "github.com/crossplane/crossplane-runtime/pkg/feature" "github.com/crossplane/crossplane-runtime/pkg/meta" "github.com/crossplane/crossplane-runtime/pkg/password" "github.com/crossplane/crossplane-runtime/pkg/reconciler/managed" @@ -65,13 +66,19 @@ func Setup(mgr ctrl.Manager, o xpcontroller.Options) error { name := managed.ControllerName(v1alpha1.UserGroupKind) t := resource.NewProviderConfigUsageTracker(mgr.GetClient(), &v1alpha1.ProviderConfigUsage{}) - r := managed.NewReconciler(mgr, - resource.ManagedKind(v1alpha1.UserGroupVersionKind), + reconcilerOptions := []managed.ReconcilerOption{ managed.WithExternalConnecter(&connector{kube: mgr.GetClient(), usage: t, newDB: mysql.New}), managed.WithLogger(o.Logger.WithValues("controller", name)), managed.WithPollInterval(o.PollInterval), - managed.WithRecorder(event.NewAPIRecorder(mgr.GetEventRecorderFor(name)))) - + managed.WithRecorder(event.NewAPIRecorder(mgr.GetEventRecorderFor(name))), + } + if o.Features.Enabled(feature.EnableBetaManagementPolicies) { + reconcilerOptions = append(reconcilerOptions, managed.WithManagementPolicies()) + } + r := managed.NewReconciler(mgr, + resource.ManagedKind(v1alpha1.UserGroupVersionKind), + reconcilerOptions..., + ) return ctrl.NewControllerManagedBy(mgr). Named(name). For(&v1alpha1.User{}). diff --git a/pkg/controller/postgresql/database/reconciler.go b/pkg/controller/postgresql/database/reconciler.go index c120f50f..9990a5f7 100644 --- a/pkg/controller/postgresql/database/reconciler.go +++ b/pkg/controller/postgresql/database/reconciler.go @@ -34,6 +34,7 @@ import ( xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" xpcontroller "github.com/crossplane/crossplane-runtime/pkg/controller" "github.com/crossplane/crossplane-runtime/pkg/event" + "github.com/crossplane/crossplane-runtime/pkg/feature" "github.com/crossplane/crossplane-runtime/pkg/meta" "github.com/crossplane/crossplane-runtime/pkg/reconciler/managed" "github.com/crossplane/crossplane-runtime/pkg/resource" @@ -67,13 +68,19 @@ func Setup(mgr ctrl.Manager, o xpcontroller.Options) error { name := managed.ControllerName(v1alpha1.DatabaseGroupKind) t := resource.NewProviderConfigUsageTracker(mgr.GetClient(), &v1alpha1.ProviderConfigUsage{}) - r := managed.NewReconciler(mgr, - resource.ManagedKind(v1alpha1.DatabaseGroupVersionKind), + reconcilerOptions := []managed.ReconcilerOption{ managed.WithExternalConnecter(&connector{kube: mgr.GetClient(), usage: t, newDB: postgresql.New}), managed.WithLogger(o.Logger.WithValues("controller", name)), managed.WithPollInterval(o.PollInterval), - managed.WithRecorder(event.NewAPIRecorder(mgr.GetEventRecorderFor(name)))) - + managed.WithRecorder(event.NewAPIRecorder(mgr.GetEventRecorderFor(name))), + } + if o.Features.Enabled(feature.EnableBetaManagementPolicies) { + reconcilerOptions = append(reconcilerOptions, managed.WithManagementPolicies()) + } + r := managed.NewReconciler(mgr, + resource.ManagedKind(v1alpha1.DatabaseGroupVersionKind), + reconcilerOptions..., + ) return ctrl.NewControllerManagedBy(mgr). Named(name). For(&v1alpha1.Database{}). diff --git a/pkg/controller/postgresql/extension/reconciler.go b/pkg/controller/postgresql/extension/reconciler.go index 6d82168d..ac2ae11d 100644 --- a/pkg/controller/postgresql/extension/reconciler.go +++ b/pkg/controller/postgresql/extension/reconciler.go @@ -31,6 +31,7 @@ import ( xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" xpcontroller "github.com/crossplane/crossplane-runtime/pkg/controller" "github.com/crossplane/crossplane-runtime/pkg/event" + "github.com/crossplane/crossplane-runtime/pkg/feature" "github.com/crossplane/crossplane-runtime/pkg/reconciler/managed" "github.com/crossplane/crossplane-runtime/pkg/resource" @@ -59,13 +60,19 @@ func Setup(mgr ctrl.Manager, o xpcontroller.Options) error { name := managed.ControllerName(v1alpha1.ExtensionGroupKind) t := resource.NewProviderConfigUsageTracker(mgr.GetClient(), &v1alpha1.ProviderConfigUsage{}) - r := managed.NewReconciler(mgr, - resource.ManagedKind(v1alpha1.ExtensionGroupVersionKind), + reconcilerOptions := []managed.ReconcilerOption{ managed.WithExternalConnecter(&connector{kube: mgr.GetClient(), usage: t, newDB: postgresql.New}), managed.WithLogger(o.Logger.WithValues("controller", name)), managed.WithPollInterval(o.PollInterval), - managed.WithRecorder(event.NewAPIRecorder(mgr.GetEventRecorderFor(name)))) - + managed.WithRecorder(event.NewAPIRecorder(mgr.GetEventRecorderFor(name))), + } + if o.Features.Enabled(feature.EnableBetaManagementPolicies) { + reconcilerOptions = append(reconcilerOptions, managed.WithManagementPolicies()) + } + r := managed.NewReconciler(mgr, + resource.ManagedKind(v1alpha1.ExtensionGroupVersionKind), + reconcilerOptions..., + ) return ctrl.NewControllerManagedBy(mgr). Named(name). For(&v1alpha1.Extension{}). diff --git a/pkg/controller/postgresql/grant/reconciler.go b/pkg/controller/postgresql/grant/reconciler.go index d73c3943..7a236c09 100644 --- a/pkg/controller/postgresql/grant/reconciler.go +++ b/pkg/controller/postgresql/grant/reconciler.go @@ -32,6 +32,7 @@ import ( xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" xpcontroller "github.com/crossplane/crossplane-runtime/pkg/controller" "github.com/crossplane/crossplane-runtime/pkg/event" + "github.com/crossplane/crossplane-runtime/pkg/feature" "github.com/crossplane/crossplane-runtime/pkg/reconciler/managed" "github.com/crossplane/crossplane-runtime/pkg/resource" @@ -68,13 +69,19 @@ func Setup(mgr ctrl.Manager, o xpcontroller.Options) error { name := managed.ControllerName(v1alpha1.GrantGroupKind) t := resource.NewProviderConfigUsageTracker(mgr.GetClient(), &v1alpha1.ProviderConfigUsage{}) - r := managed.NewReconciler(mgr, - resource.ManagedKind(v1alpha1.GrantGroupVersionKind), + reconcilerOptions := []managed.ReconcilerOption{ managed.WithExternalConnecter(&connector{kube: mgr.GetClient(), usage: t, newDB: postgresql.New}), managed.WithLogger(o.Logger.WithValues("controller", name)), managed.WithPollInterval(o.PollInterval), - managed.WithRecorder(event.NewAPIRecorder(mgr.GetEventRecorderFor(name)))) - + managed.WithRecorder(event.NewAPIRecorder(mgr.GetEventRecorderFor(name))), + } + if o.Features.Enabled(feature.EnableBetaManagementPolicies) { + reconcilerOptions = append(reconcilerOptions, managed.WithManagementPolicies()) + } + r := managed.NewReconciler(mgr, + resource.ManagedKind(v1alpha1.GrantGroupVersionKind), + reconcilerOptions..., + ) return ctrl.NewControllerManagedBy(mgr). Named(name). For(&v1alpha1.Grant{}). diff --git a/pkg/controller/postgresql/role/reconciler.go b/pkg/controller/postgresql/role/reconciler.go index 474c93a8..055e4b77 100644 --- a/pkg/controller/postgresql/role/reconciler.go +++ b/pkg/controller/postgresql/role/reconciler.go @@ -35,6 +35,7 @@ import ( xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" xpcontroller "github.com/crossplane/crossplane-runtime/pkg/controller" "github.com/crossplane/crossplane-runtime/pkg/event" + "github.com/crossplane/crossplane-runtime/pkg/feature" "github.com/crossplane/crossplane-runtime/pkg/meta" "github.com/crossplane/crossplane-runtime/pkg/password" "github.com/crossplane/crossplane-runtime/pkg/reconciler/managed" @@ -69,13 +70,19 @@ func Setup(mgr ctrl.Manager, o xpcontroller.Options) error { name := managed.ControllerName(v1alpha1.RoleGroupKind) t := resource.NewProviderConfigUsageTracker(mgr.GetClient(), &v1alpha1.ProviderConfigUsage{}) - r := managed.NewReconciler(mgr, - resource.ManagedKind(v1alpha1.RoleGroupVersionKind), + reconcilerOptions := []managed.ReconcilerOption{ managed.WithExternalConnecter(&connector{kube: mgr.GetClient(), usage: t, newDB: postgresql.New}), managed.WithLogger(o.Logger.WithValues("controller", name)), managed.WithPollInterval(o.PollInterval), - managed.WithRecorder(event.NewAPIRecorder(mgr.GetEventRecorderFor(name)))) - + managed.WithRecorder(event.NewAPIRecorder(mgr.GetEventRecorderFor(name))), + } + if o.Features.Enabled(feature.EnableBetaManagementPolicies) { + reconcilerOptions = append(reconcilerOptions, managed.WithManagementPolicies()) + } + r := managed.NewReconciler(mgr, + resource.ManagedKind(v1alpha1.RoleGroupVersionKind), + reconcilerOptions..., + ) return ctrl.NewControllerManagedBy(mgr). Named(name). For(&v1alpha1.Role{}). diff --git a/pkg/controller/postgresql/schema/reconciler.go b/pkg/controller/postgresql/schema/reconciler.go index d3d3515e..d60cbe13 100644 --- a/pkg/controller/postgresql/schema/reconciler.go +++ b/pkg/controller/postgresql/schema/reconciler.go @@ -31,6 +31,7 @@ import ( xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" xpcontroller "github.com/crossplane/crossplane-runtime/pkg/controller" "github.com/crossplane/crossplane-runtime/pkg/event" + "github.com/crossplane/crossplane-runtime/pkg/feature" "github.com/crossplane/crossplane-runtime/pkg/meta" "github.com/crossplane/crossplane-runtime/pkg/reconciler/managed" "github.com/crossplane/crossplane-runtime/pkg/resource" @@ -62,13 +63,19 @@ func Setup(mgr ctrl.Manager, o xpcontroller.Options) error { name := managed.ControllerName(v1alpha1.SchemaGroupKind) t := resource.NewProviderConfigUsageTracker(mgr.GetClient(), &v1alpha1.ProviderConfigUsage{}) - r := managed.NewReconciler(mgr, - resource.ManagedKind(v1alpha1.SchemaGroupVersionKind), + reconcilerOptions := []managed.ReconcilerOption{ managed.WithExternalConnecter(&connector{kube: mgr.GetClient(), usage: t, newDB: postgresql.New}), managed.WithLogger(o.Logger.WithValues("controller", name)), managed.WithPollInterval(o.PollInterval), - managed.WithRecorder(event.NewAPIRecorder(mgr.GetEventRecorderFor(name)))) - + managed.WithRecorder(event.NewAPIRecorder(mgr.GetEventRecorderFor(name))), + } + if o.Features.Enabled(feature.EnableBetaManagementPolicies) { + reconcilerOptions = append(reconcilerOptions, managed.WithManagementPolicies()) + } + r := managed.NewReconciler(mgr, + resource.ManagedKind(v1alpha1.SchemaGroupVersionKind), + reconcilerOptions..., + ) return ctrl.NewControllerManagedBy(mgr). Named(name). For(&v1alpha1.Schema{}). From 890b6199bd8a2be6d8deb0d796c963d245cec902 Mon Sep 17 00:00:00 2001 From: Carl Henrik Lunde Date: Mon, 12 May 2025 11:03:16 +0200 Subject: [PATCH 22/24] Move negz to emeritus status (#226) As requested on slack Signed-off-by: Carl Henrik Lunde --- OWNERS.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OWNERS.md b/OWNERS.md index 4e738dba..9668c5f9 100644 --- a/OWNERS.md +++ b/OWNERS.md @@ -10,7 +10,6 @@ Please see [GOVERNANCE.md] for governance guidelines and responsibilities. * Jeroen Op 't Eynde ([Duologic](https://github.com/Duologic)) * James Wilson ([jdotw](https://github.com/jdotw)) -* Nic Cope ([negz](https://github.com/negz)) * Javier Palomo ([jvrplmlmn](https://github.com/jvrplmlmn)) * Iain Lane ([iainlane](https://github.com/iainlane)) * Carl Henrik Lunde ([chlunde](https://github.com/chlunde)) @@ -19,5 +18,6 @@ Please see [GOVERNANCE.md] for governance guidelines and responsibilities. * Ben Agricola ([benagricola](https://github.com/benagricola)) * Simon Ruegg ([srueg](https://github.com/srueg)) +* Nic Cope ([negz](https://github.com/negz)) -[GOVERNANCE.md]: https://github.com/crossplane/crossplane/blob/master/GOVERNANCE.md \ No newline at end of file +[GOVERNANCE.md]: https://github.com/crossplane/crossplane/blob/master/GOVERNANCE.md From 71c4b3a92f26ae3a92ad0ca85fcc6728ef4461af Mon Sep 17 00:00:00 2001 From: Carl Henrik Lunde Date: Mon, 12 May 2025 15:51:23 +0200 Subject: [PATCH 23/24] test: add coverage of managementPolicies to e2e (#233) Signed-off-by: Carl Henrik Lunde --- cluster/local/postgresdb_functions.sh | 42 ++++++++++++++++++++++++--- examples/postgresql/database.yaml | 11 ++++++- 2 files changed, 48 insertions(+), 5 deletions(-) diff --git a/cluster/local/postgresdb_functions.sh b/cluster/local/postgresdb_functions.sh index 978f25ec..4a64c7e2 100644 --- a/cluster/local/postgresdb_functions.sh +++ b/cluster/local/postgresdb_functions.sh @@ -136,13 +136,45 @@ check_schema_privileges(){ echo_step_completed } +setup_observe_only_database(){ + echo_step "create pre-existing database for observe only" + + local datname + datname="$(PGPASSWORD="${postgres_root_pw}" psql -h localhost -p 5432 -U postgres -wtAc "CREATE DATABASE \"db-observe\";")" + + echo_step_completed +} + +check_observe_only_database(){ + echo_step "check if observe only database is preserved after deletion" + + # Delete the database kubernetes object, it should not delete the database + kubectl delete database.postgresql.sql.crossplane.io db-observe + + local datname + datname="$(PGPASSWORD="${postgres_root_pw}" psql -h localhost -p 5432 -U postgres -wtAc "SELECT datname FROM pg_database WHERE datname = 'db-observe';")" + + if [[ "$datname" == "db-observe" ]]; then + echo "Database db-observe is still present" + echo_info "OK" + else + echo "Database db-observe was NOT preserved" + echo_error "Not OK" + fi + + # Clean up + PGPASSWORD="${postgres_root_pw}" psql -h localhost -p 5432 -U postgres -wtAc "DROP DATABASE \"db-observe\";" + + echo_step_completed +} + delete_postgresdb_resources(){ # uninstall echo_step "uninstalling ${PROJECT_NAME}" - "${KUBECTL}" delete -f ${projectdir}/examples/postgresql/grant.yaml - "${KUBECTL}" delete -f ${projectdir}/examples/postgresql/database.yaml - "${KUBECTL}" delete -f ${projectdir}/examples/postgresql/role.yaml - "${KUBECTL}" delete -f ${projectdir}/examples/postgresql/schema.yaml + "${KUBECTL}" delete -f "${projectdir}/examples/postgresql/grant.yaml" + "${KUBECTL}" delete --ignore-not-found=true -f "${projectdir}/examples/postgresql/database.yaml" + "${KUBECTL}" delete -f "${projectdir}/examples/postgresql/role.yaml" + "${KUBECTL}" delete -f "${projectdir}/examples/postgresql/schema.yaml" echo "${PROVIDER_CONFIG_POSTGRES_YAML}" | "${KUBECTL}" delete -f - # ----------- cleaning postgres related resources @@ -160,7 +192,9 @@ delete_postgresdb_resources(){ integration_tests_postgres() { setup_postgresdb_no_tls setup_provider_config_postgres_no_tls + setup_observe_only_database setup_postgresdb_tests + check_observe_only_database check_all_roles_privileges check_schema_privileges delete_postgresdb_resources diff --git a/examples/postgresql/database.yaml b/examples/postgresql/database.yaml index c7710753..58720418 100644 --- a/examples/postgresql/database.yaml +++ b/examples/postgresql/database.yaml @@ -13,4 +13,13 @@ spec: deletionPolicy: Orphan forProvider: allowConnections: true - owner: "ownerrole" \ No newline at end of file + owner: "ownerrole" +--- +apiVersion: postgresql.sql.crossplane.io/v1alpha1 +kind: Database +metadata: + name: db-observe +spec: + managementPolicies: + - Observe + forProvider: {} From c742efe2268c14e866fced80f6a0830fc9ebed34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=2E=20Fern=C3=A1ndez?= <7312236+fernandezcuesta@users.noreply.github.com> Date: Thu, 22 May 2025 12:59:59 +0200 Subject: [PATCH 24/24] chore: remove duplicate entry of golangci version (#236) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: remove duplicate entry of golangci version Signed-off-by: Jesús Fernández <7312236+fernandezcuesta@users.noreply.github.com> * chore: bump up versions for crossplane 1.20 Signed-off-by: Jesús Fernández <7312236+fernandezcuesta@users.noreply.github.com> * chore: restore changes Signed-off-by: Jesús Fernández <7312236+fernandezcuesta@users.noreply.github.com> --------- Signed-off-by: Jesús Fernández <7312236+fernandezcuesta@users.noreply.github.com> --- Makefile | 9 +++++---- cluster/local/integration_tests.sh | 4 ++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 95926214..715600c7 100644 --- a/Makefile +++ b/Makefile @@ -23,18 +23,19 @@ NPROCS ?= 1 # to half the number of CPU cores. GO_TEST_PARALLEL := $(shell echo $$(( $(NPROCS) / 2 ))) -GOLANGCILINT_VERSION ?= 1.63.4 +GOLANGCILINT_VERSION ?= 2.1.2 GO_STATIC_PACKAGES = $(GO_PROJECT)/cmd/provider GO_LDFLAGS += -X $(GO_PROJECT)/pkg/version.Version=$(VERSION) GO_SUBDIRS += cmd pkg apis GO111MODULE = on -GOLANGCILINT_VERSION = 2.1.2 -include build/makelib/golang.mk # ==================================================================================== # Setup Kubernetes tools -KIND_NODE_IMAGE_TAG ?= v1.23.4 -DOCKER_REGISTRY ?= "xpkg.upbound.io" +KIND_NODE_IMAGE_TAG ?= v1.30.13 +KIND_VERSION ?= v0.29.0 +KUBECTL_VERSION ?= v1.30.13 +CROSSPLANE_CLI_VERSION ?= v1.20.0 -include build/makelib/k8s_tools.mk # ==================================================================================== diff --git a/cluster/local/integration_tests.sh b/cluster/local/integration_tests.sh index 4b0585e7..e8669b78 100755 --- a/cluster/local/integration_tests.sh +++ b/cluster/local/integration_tests.sh @@ -102,8 +102,8 @@ EOF echo_step "tag controller image and load it into kind cluster" - docker tag "${CONTROLLER_IMAGE}" "xpkg.upbound.io/${PACKAGE_NAME}" - "${KIND}" load docker-image "xpkg.upbound.io/${PACKAGE_NAME}" --name="${K8S_CLUSTER}" + docker tag "${CONTROLLER_IMAGE}" "xpkg.crossplane.io/${PACKAGE_NAME}" + "${KIND}" load docker-image "xpkg.crossplane.io/${PACKAGE_NAME}" --name="${K8S_CLUSTER}" echo_step "create crossplane-system namespace"