From 25853ca5694433d1196882aaa49dd171736dbed5 Mon Sep 17 00:00:00 2001 From: Tim Ross Date: Wed, 20 Sep 2023 10:44:56 -0400 Subject: [PATCH 1/3] Set revision on resources retrieved from the backend Adds a new `MarshalOption` that ensures the resource revision is set when unmarshalling a backend item. The new `WithRevision` option was also applied everywhere that the legacy `WithResourceID` was being used. --- lib/services/access_list.go | 6 +++ lib/services/access_request.go | 3 ++ lib/services/app.go | 6 +++ lib/services/audit.go | 3 ++ lib/services/authentication.go | 3 ++ lib/services/authority.go | 3 ++ lib/services/clustername.go | 3 ++ lib/services/connection_diagnostic.go | 4 ++ lib/services/database.go | 3 ++ lib/services/databaseserver.go | 3 ++ lib/services/databaseservice.go | 3 ++ lib/services/desktop.go | 6 +++ lib/services/installer.go | 3 ++ lib/services/integration.go | 3 ++ lib/services/kubernetes.go | 6 +++ lib/services/local/access.go | 8 ++-- lib/services/local/apps.go | 4 +- lib/services/local/configuration.go | 12 ++--- lib/services/local/connection_diagnostic.go | 2 +- lib/services/local/databases.go | 4 +- lib/services/local/desktops.go | 6 +-- lib/services/local/dynamic_access.go | 2 + lib/services/local/events.go | 39 +++++++++++++++- lib/services/local/generic/generic.go | 4 +- lib/services/local/generic/generic_test.go | 3 ++ lib/services/local/kube.go | 4 +- lib/services/local/plugins.go | 6 +-- lib/services/local/presence.go | 51 ++++++++++++++------- lib/services/local/provisioning.go | 3 +- lib/services/local/resource.go | 1 + lib/services/local/restrictions.go | 2 +- lib/services/local/trust.go | 6 +-- lib/services/local/users.go | 4 +- lib/services/lock.go | 3 ++ lib/services/namespace.go | 3 ++ lib/services/networking.go | 3 ++ lib/services/oidc.go | 3 ++ lib/services/okta.go | 6 +++ lib/services/plugin_data.go | 3 ++ lib/services/plugin_static_credentials.go | 3 ++ lib/services/plugins.go | 3 ++ lib/services/provisioning.go | 6 +++ lib/services/remotecluster.go | 3 ++ lib/services/resource.go | 13 +++++- lib/services/restrictions.go | 3 ++ lib/services/role.go | 3 ++ lib/services/saml.go | 3 ++ lib/services/saml_idp_service_provider.go | 3 ++ lib/services/semaphore.go | 3 ++ lib/services/server.go | 3 ++ lib/services/server_info.go | 3 ++ lib/services/services_test.go | 18 ++++---- lib/services/session.go | 3 ++ lib/services/sessionrecording.go | 3 ++ lib/services/statictokens.go | 3 ++ lib/services/trustedcluster.go | 3 ++ lib/services/tunnel.go | 3 ++ lib/services/tunnelconn.go | 3 ++ lib/services/ui_config.go | 3 ++ lib/services/user.go | 3 ++ lib/services/user_login_state.go | 3 ++ lib/services/usergroup.go | 3 ++ 62 files changed, 279 insertions(+), 58 deletions(-) diff --git a/lib/services/access_list.go b/lib/services/access_list.go index e063d42733857..1751d4e095526 100644 --- a/lib/services/access_list.go +++ b/lib/services/access_list.go @@ -96,6 +96,9 @@ func UnmarshalAccessList(data []byte, opts ...MarshalOption) (*accesslist.Access if cfg.ID != 0 { accessList.SetResourceID(cfg.ID) } + if cfg.Revision != "" { + accessList.SetRevision(cfg.Revision) + } if !cfg.Expires.IsZero() { accessList.SetExpiry(cfg.Expires) } @@ -162,6 +165,9 @@ func UnmarshalAccessListMember(data []byte, opts ...MarshalOption) (*accesslist. if cfg.ID != 0 { member.SetResourceID(cfg.ID) } + if cfg.Revision != "" { + member.SetRevision(cfg.Revision) + } if !cfg.Expires.IsZero() { member.SetExpiry(cfg.Expires) } diff --git a/lib/services/access_request.go b/lib/services/access_request.go index 3b9e837c7dded..a04df5d3aa297 100644 --- a/lib/services/access_request.go +++ b/lib/services/access_request.go @@ -1568,6 +1568,9 @@ func UnmarshalAccessRequest(data []byte, opts ...MarshalOption) (types.AccessReq if cfg.ID != 0 { req.SetResourceID(cfg.ID) } + if cfg.Revision != "" { + req.SetRevision(cfg.Revision) + } if !cfg.Expires.IsZero() { req.SetExpiry(cfg.Expires) } diff --git a/lib/services/app.go b/lib/services/app.go index dc7b1a0ef6eb0..6205b7436ead6 100644 --- a/lib/services/app.go +++ b/lib/services/app.go @@ -100,6 +100,9 @@ func UnmarshalApp(data []byte, opts ...MarshalOption) (types.Application, error) if cfg.ID != 0 { app.SetResourceID(cfg.ID) } + if cfg.Revision != "" { + app.SetRevision(cfg.Revision) + } if !cfg.Expires.IsZero() { app.SetExpiry(cfg.Expires) } @@ -157,6 +160,9 @@ func UnmarshalAppServer(data []byte, opts ...MarshalOption) (types.AppServer, er if cfg.ID != 0 { s.SetResourceID(cfg.ID) } + if cfg.Revision != "" { + s.SetRevision(cfg.Revision) + } if !cfg.Expires.IsZero() { s.SetExpiry(cfg.Expires) } diff --git a/lib/services/audit.go b/lib/services/audit.go index 5549b1c82ee6b..f22d479336ec5 100644 --- a/lib/services/audit.go +++ b/lib/services/audit.go @@ -59,6 +59,9 @@ func UnmarshalClusterAuditConfig(bytes []byte, opts ...MarshalOption) (types.Clu if cfg.ID != 0 { auditConfig.SetResourceID(cfg.ID) } + if cfg.Revision != "" { + auditConfig.SetRevision(cfg.Revision) + } if !cfg.Expires.IsZero() { auditConfig.SetExpiry(cfg.Expires) } diff --git a/lib/services/authentication.go b/lib/services/authentication.go index fdb007e6bcea9..0ccabecabf65a 100644 --- a/lib/services/authentication.go +++ b/lib/services/authentication.go @@ -117,6 +117,9 @@ func UnmarshalAuthPreference(bytes []byte, opts ...MarshalOption) (types.AuthPre if cfg.ID != 0 { authPreference.SetResourceID(cfg.ID) } + if cfg.Revision != "" { + authPreference.SetRevision(cfg.Revision) + } if !cfg.Expires.IsZero() { authPreference.SetExpiry(cfg.Expires) } diff --git a/lib/services/authority.go b/lib/services/authority.go index 0167895dbecb5..4d30de788c89e 100644 --- a/lib/services/authority.go +++ b/lib/services/authority.go @@ -473,6 +473,9 @@ func UnmarshalCertAuthority(bytes []byte, opts ...MarshalOption) (types.CertAuth if cfg.ID != 0 { ca.SetResourceID(cfg.ID) } + if cfg.Revision != "" { + ca.SetRevision(cfg.Revision) + } // Correct problems with existing CAs that contain non-UTC times, which // causes panics when doing a gogoproto Clone; should only ever be // possible with LastRotated, but we enforce it on all the times anyway. diff --git a/lib/services/clustername.go b/lib/services/clustername.go index bf773fad1f7f2..a7612afc11d8d 100644 --- a/lib/services/clustername.go +++ b/lib/services/clustername.go @@ -58,6 +58,9 @@ func UnmarshalClusterName(bytes []byte, opts ...MarshalOption) (types.ClusterNam if cfg.ID != 0 { clusterName.SetResourceID(cfg.ID) } + if cfg.Revision != "" { + clusterName.SetRevision(cfg.Revision) + } if !cfg.Expires.IsZero() { clusterName.SetExpiry(cfg.Expires) } diff --git a/lib/services/connection_diagnostic.go b/lib/services/connection_diagnostic.go index a8e15ba4492d8..ed5bcb61ccf50 100644 --- a/lib/services/connection_diagnostic.go +++ b/lib/services/connection_diagnostic.go @@ -106,6 +106,10 @@ func UnmarshalConnectionDiagnostic(data []byte, opts ...MarshalOption) (types.Co s.SetResourceID(cfg.ID) } + if cfg.Revision != "" { + s.SetRevision(cfg.Revision) + } + if !cfg.Expires.IsZero() { s.SetExpiry(cfg.Expires) } diff --git a/lib/services/database.go b/lib/services/database.go index 47bcca47e2c47..587da7e8b7f20 100644 --- a/lib/services/database.go +++ b/lib/services/database.go @@ -130,6 +130,9 @@ func UnmarshalDatabase(data []byte, opts ...MarshalOption) (types.Database, erro if cfg.ID != 0 { database.SetResourceID(cfg.ID) } + if cfg.Revision != "" { + database.SetRevision(cfg.Revision) + } if !cfg.Expires.IsZero() { database.SetExpiry(cfg.Expires) } diff --git a/lib/services/databaseserver.go b/lib/services/databaseserver.go index d39a314bd3dcf..90b7b9d167d21 100644 --- a/lib/services/databaseserver.go +++ b/lib/services/databaseserver.go @@ -74,6 +74,9 @@ func UnmarshalDatabaseServer(data []byte, opts ...MarshalOption) (types.Database if cfg.ID != 0 { s.SetResourceID(cfg.ID) } + if cfg.Revision != "" { + s.SetRevision(cfg.Revision) + } if !cfg.Expires.IsZero() { s.SetExpiry(cfg.Expires) } diff --git a/lib/services/databaseservice.go b/lib/services/databaseservice.go index f81b0809b9940..2237fd1a2769b 100644 --- a/lib/services/databaseservice.go +++ b/lib/services/databaseservice.go @@ -88,6 +88,9 @@ func UnmarshalDatabaseService(data []byte, opts ...MarshalOption) (types.Databas if cfg.ID != 0 { s.SetResourceID(cfg.ID) } + if cfg.Revision != "" { + s.SetRevision(cfg.Revision) + } if !cfg.Expires.IsZero() { s.SetExpiry(cfg.Expires) } diff --git a/lib/services/desktop.go b/lib/services/desktop.go index b4d927412a815..318db3071c63a 100644 --- a/lib/services/desktop.go +++ b/lib/services/desktop.go @@ -93,6 +93,9 @@ func UnmarshalWindowsDesktop(data []byte, opts ...MarshalOption) (types.WindowsD if cfg.ID != 0 { s.SetResourceID(cfg.ID) } + if cfg.Revision != "" { + s.SetRevision(cfg.Revision) + } if !cfg.Expires.IsZero() { s.SetExpiry(cfg.Expires) } @@ -152,6 +155,9 @@ func UnmarshalWindowsDesktopService(data []byte, opts ...MarshalOption) (types.W if cfg.ID != 0 { s.SetResourceID(cfg.ID) } + if cfg.Revision != "" { + s.SetRevision(cfg.Revision) + } if !cfg.Expires.IsZero() { s.SetExpiry(cfg.Expires) } diff --git a/lib/services/installer.go b/lib/services/installer.go index adc165056e872..a6e35e686f0c6 100644 --- a/lib/services/installer.go +++ b/lib/services/installer.go @@ -46,6 +46,9 @@ func UnmarshalInstaller(data []byte, opts ...MarshalOption) (types.Installer, er if cfg.ID != 0 { installer.SetResourceID(cfg.ID) } + if cfg.Revision != "" { + installer.SetRevision(cfg.Revision) + } if !cfg.Expires.IsZero() { installer.SetExpiry(cfg.Expires) } diff --git a/lib/services/integration.go b/lib/services/integration.go index 4e025c7faa683..b9c35f88e09ec 100644 --- a/lib/services/integration.go +++ b/lib/services/integration.go @@ -91,6 +91,9 @@ func UnmarshalIntegration(data []byte, opts ...MarshalOption) (types.Integration if cfg.ID != 0 { ig.SetResourceID(cfg.ID) } + if cfg.Revision != "" { + ig.SetRevision(cfg.Revision) + } if !cfg.Expires.IsZero() { ig.SetExpiry(cfg.Expires) } diff --git a/lib/services/kubernetes.go b/lib/services/kubernetes.go index ae4cce596ac5e..e4198c71e4681 100644 --- a/lib/services/kubernetes.go +++ b/lib/services/kubernetes.go @@ -110,6 +110,9 @@ func UnmarshalKubeServer(data []byte, opts ...MarshalOption) (types.KubeServer, if cfg.ID != 0 { s.SetResourceID(cfg.ID) } + if cfg.Revision != "" { + s.SetRevision(cfg.Revision) + } if !cfg.Expires.IsZero() { s.SetExpiry(cfg.Expires) } @@ -167,6 +170,9 @@ func UnmarshalKubeCluster(data []byte, opts ...MarshalOption) (types.KubeCluster if cfg.ID != 0 { s.SetResourceID(cfg.ID) } + if cfg.Revision != "" { + s.SetRevision(cfg.Revision) + } if !cfg.Expires.IsZero() { s.SetExpiry(cfg.Expires) } diff --git a/lib/services/local/access.go b/lib/services/local/access.go index 8ada6d97fbb97..34cfa8965cfd5 100644 --- a/lib/services/local/access.go +++ b/lib/services/local/access.go @@ -54,7 +54,7 @@ func (s *AccessService) GetRoles(ctx context.Context) ([]types.Role, error) { out := make([]types.Role, 0, len(result.Items)) for _, item := range result.Items { role, err := services.UnmarshalRole(item.Value, - services.WithResourceID(item.ID), services.WithExpires(item.Expires)) + services.WithResourceID(item.ID), services.WithExpires(item.Expires), services.WithRevision(item.Revision)) if err != nil { // Try to get the role name for the error, it allows admins to take action // against the "bad" role. @@ -132,7 +132,7 @@ func (s *AccessService) GetRole(ctx context.Context, name string) (types.Role, e return nil, trace.Wrap(err) } return services.UnmarshalRole(item.Value, - services.WithResourceID(item.ID), services.WithExpires(item.Expires)) + services.WithResourceID(item.ID), services.WithExpires(item.Expires), services.WithRevision(item.Revision)) } // DeleteRole deletes a role from the backend @@ -161,7 +161,7 @@ func (s *AccessService) GetLock(ctx context.Context, name string) (types.Lock, e } return nil, trace.Wrap(err) } - return services.UnmarshalLock(item.Value, services.WithResourceID(item.ID), services.WithExpires(item.Expires)) + return services.UnmarshalLock(item.Value, services.WithResourceID(item.ID), services.WithExpires(item.Expires), services.WithRevision(item.Revision)) } // GetLocks gets all/in-force locks that match at least one of the targets when specified. @@ -174,7 +174,7 @@ func (s *AccessService) GetLocks(ctx context.Context, inForceOnly bool, targets out := []types.Lock{} for _, item := range result.Items { - lock, err := services.UnmarshalLock(item.Value, services.WithResourceID(item.ID), services.WithExpires(item.Expires)) + lock, err := services.UnmarshalLock(item.Value, services.WithResourceID(item.ID), services.WithExpires(item.Expires), services.WithRevision(item.Revision)) if err != nil { return nil, trace.Wrap(err) } diff --git a/lib/services/local/apps.go b/lib/services/local/apps.go index 67c73114c7317..6ff7790475906 100644 --- a/lib/services/local/apps.go +++ b/lib/services/local/apps.go @@ -46,7 +46,7 @@ func (s *AppService) GetApps(ctx context.Context) ([]types.Application, error) { apps := make([]types.Application, len(result.Items)) for i, item := range result.Items { app, err := services.UnmarshalApp(item.Value, - services.WithResourceID(item.ID), services.WithExpires(item.Expires)) + services.WithResourceID(item.ID), services.WithExpires(item.Expires), services.WithRevision(item.Revision)) if err != nil { return nil, trace.Wrap(err) } @@ -65,7 +65,7 @@ func (s *AppService) GetApp(ctx context.Context, name string) (types.Application return nil, trace.Wrap(err) } app, err := services.UnmarshalApp(item.Value, - services.WithResourceID(item.ID), services.WithExpires(item.Expires)) + services.WithResourceID(item.ID), services.WithExpires(item.Expires), services.WithRevision(item.Revision)) if err != nil { return nil, trace.Wrap(err) } diff --git a/lib/services/local/configuration.go b/lib/services/local/configuration.go index 5bc58b2502a19..b8053b22498ff 100644 --- a/lib/services/local/configuration.go +++ b/lib/services/local/configuration.go @@ -68,7 +68,7 @@ func (s *ClusterConfigurationService) GetClusterName(opts ...services.MarshalOpt return nil, trace.Wrap(err) } return services.UnmarshalClusterName(item.Value, - services.AddOptions(opts, services.WithResourceID(item.ID))...) + services.AddOptions(opts, services.WithResourceID(item.ID), services.WithRevision(item.Revision))...) } // DeleteClusterName deletes types.ClusterName from the backend. @@ -133,7 +133,7 @@ func (s *ClusterConfigurationService) GetStaticTokens() (types.StaticTokens, err return nil, trace.Wrap(err) } return services.UnmarshalStaticTokens(item.Value, - services.WithResourceID(item.ID), services.WithExpires(item.Expires)) + services.WithResourceID(item.ID), services.WithExpires(item.Expires), services.WithRevision(item.Revision)) } // SetStaticTokens sets the list of static tokens used to provision nodes. @@ -178,7 +178,7 @@ func (s *ClusterConfigurationService) GetAuthPreference(ctx context.Context) (ty return nil, trace.Wrap(err) } return services.UnmarshalAuthPreference(item.Value, - services.WithResourceID(item.ID), services.WithExpires(item.Expires)) + services.WithResourceID(item.ID), services.WithExpires(item.Expires), services.WithRevision(item.Revision)) } // SetAuthPreference sets the cluster authentication preferences @@ -229,7 +229,7 @@ func (s *ClusterConfigurationService) GetClusterAuditConfig(ctx context.Context, } return nil, trace.Wrap(err) } - return services.UnmarshalClusterAuditConfig(item.Value, append(opts, services.WithResourceID(item.ID), services.WithExpires(item.Expires))...) + return services.UnmarshalClusterAuditConfig(item.Value, append(opts, services.WithResourceID(item.ID), services.WithExpires(item.Expires), services.WithRevision(item.Revision))...) } // SetClusterAuditConfig sets the cluster audit config on the backend. @@ -273,7 +273,7 @@ func (s *ClusterConfigurationService) GetClusterNetworkingConfig(ctx context.Con } return nil, trace.Wrap(err) } - return services.UnmarshalClusterNetworkingConfig(item.Value, append(opts, services.WithResourceID(item.ID), services.WithExpires(item.Expires))...) + return services.UnmarshalClusterNetworkingConfig(item.Value, append(opts, services.WithResourceID(item.ID), services.WithExpires(item.Expires), services.WithRevision(item.Revision))...) } // SetClusterNetworkingConfig sets the cluster networking config @@ -323,7 +323,7 @@ func (s *ClusterConfigurationService) GetSessionRecordingConfig(ctx context.Cont } return nil, trace.Wrap(err) } - return services.UnmarshalSessionRecordingConfig(item.Value, append(opts, services.WithResourceID(item.ID), services.WithExpires(item.Expires))...) + return services.UnmarshalSessionRecordingConfig(item.Value, append(opts, services.WithResourceID(item.ID), services.WithExpires(item.Expires), services.WithRevision(item.Revision))...) } // SetSessionRecordingConfig sets session recording config on the backend. diff --git a/lib/services/local/connection_diagnostic.go b/lib/services/local/connection_diagnostic.go index ad6183eb1d838..03b4cdfd26171 100644 --- a/lib/services/local/connection_diagnostic.go +++ b/lib/services/local/connection_diagnostic.go @@ -135,7 +135,7 @@ func (s *ConnectionDiagnosticService) GetConnectionDiagnostic(ctx context.Contex } connectionDiagnostic, err := services.UnmarshalConnectionDiagnostic(item.Value, - services.WithResourceID(item.ID), services.WithExpires(item.Expires)) + services.WithResourceID(item.ID), services.WithExpires(item.Expires), services.WithRevision(item.Revision)) if err != nil { return nil, trace.Wrap(err) } diff --git a/lib/services/local/databases.go b/lib/services/local/databases.go index b61a2908400c8..0f70ac031a2a5 100644 --- a/lib/services/local/databases.go +++ b/lib/services/local/databases.go @@ -46,7 +46,7 @@ func (s *DatabaseService) GetDatabases(ctx context.Context) ([]types.Database, e databases := make([]types.Database, len(result.Items)) for i, item := range result.Items { database, err := services.UnmarshalDatabase(item.Value, - services.WithResourceID(item.ID), services.WithExpires(item.Expires)) + services.WithResourceID(item.ID), services.WithExpires(item.Expires), services.WithRevision(item.Revision)) if err != nil { return nil, trace.Wrap(err) } @@ -65,7 +65,7 @@ func (s *DatabaseService) GetDatabase(ctx context.Context, name string) (types.D return nil, trace.Wrap(err) } database, err := services.UnmarshalDatabase(item.Value, - services.WithResourceID(item.ID), services.WithExpires(item.Expires)) + services.WithResourceID(item.ID), services.WithExpires(item.Expires), services.WithRevision(item.Revision)) if err != nil { return nil, trace.Wrap(err) } diff --git a/lib/services/local/desktops.go b/lib/services/local/desktops.go index f90a3c6573037..a5a0660602fa9 100644 --- a/lib/services/local/desktops.go +++ b/lib/services/local/desktops.go @@ -47,7 +47,7 @@ func (s *WindowsDesktopService) GetWindowsDesktops(ctx context.Context, filter t var desktops []types.WindowsDesktop for _, item := range result.Items { desktop, err := services.UnmarshalWindowsDesktop(item.Value, - services.WithResourceID(item.ID), services.WithExpires(item.Expires)) + services.WithResourceID(item.ID), services.WithExpires(item.Expires), services.WithRevision(item.Revision)) if err != nil { return nil, trace.Wrap(err) } @@ -184,7 +184,7 @@ func (s *WindowsDesktopService) ListWindowsDesktops(ctx context.Context, req typ } desktop, err := services.UnmarshalWindowsDesktop(item.Value, - services.WithResourceID(item.ID), services.WithExpires(item.Expires)) + services.WithResourceID(item.ID), services.WithExpires(item.Expires), services.WithRevision(item.Revision)) if err != nil { return false, trace.Wrap(err) } @@ -249,7 +249,7 @@ func (s *WindowsDesktopService) ListWindowsDesktopServices(ctx context.Context, } desktop, err := services.UnmarshalWindowsDesktopService(item.Value, - services.WithResourceID(item.ID), services.WithExpires(item.Expires)) + services.WithResourceID(item.ID), services.WithExpires(item.Expires), services.WithRevision(item.Revision)) if err != nil { return false, trace.Wrap(err) } diff --git a/lib/services/local/dynamic_access.go b/lib/services/local/dynamic_access.go index e48e20226427c..6c15bfbe6b20a 100644 --- a/lib/services/local/dynamic_access.go +++ b/lib/services/local/dynamic_access.go @@ -457,6 +457,7 @@ func itemToAccessRequest(item backend.Item, opts ...services.MarshalOption) (typ opts, services.WithResourceID(item.ID), services.WithExpires(item.Expires), + services.WithRevision(item.Revision), ) req, err := services.UnmarshalAccessRequest( item.Value, @@ -491,6 +492,7 @@ func itemToPluginData(item backend.Item) (types.PluginData, error) { item.Value, services.WithResourceID(item.ID), services.WithExpires(item.Expires), + services.WithRevision(item.Revision), ) if err != nil { return nil, trace.Wrap(err) diff --git a/lib/services/local/events.go b/lib/services/local/events.go index 4e8d47c5ffa55..7b45f38254f8d 100644 --- a/lib/services/local/events.go +++ b/lib/services/local/events.go @@ -358,7 +358,7 @@ func (p *certAuthorityParser) parse(event backend.Event) (types.Resource, error) }, nil case types.OpPut: ca, err := services.UnmarshalCertAuthority(event.Item.Value, - services.WithResourceID(event.Item.ID), services.WithExpires(event.Item.Expires)) + services.WithResourceID(event.Item.ID), services.WithExpires(event.Item.Expires), services.WithRevision(event.Item.Revision)) if err != nil { return nil, trace.Wrap(err) } @@ -389,6 +389,7 @@ func (p *provisionTokenParser) parse(event backend.Event) (types.Resource, error token, err := services.UnmarshalProvisionToken(event.Item.Value, services.WithResourceID(event.Item.ID), services.WithExpires(event.Item.Expires), + services.WithRevision(event.Item.Revision), ) if err != nil { return nil, trace.Wrap(err) @@ -422,6 +423,7 @@ func (p *staticTokensParser) parse(event backend.Event) (types.Resource, error) tokens, err := services.UnmarshalStaticTokens(event.Item.Value, services.WithResourceID(event.Item.ID), services.WithExpires(event.Item.Expires), + services.WithRevision(event.Item.Revision), ) if err != nil { return nil, trace.Wrap(err) @@ -456,6 +458,7 @@ func (p *clusterAuditConfigParser) parse(event backend.Event) (types.Resource, e event.Item.Value, services.WithResourceID(event.Item.ID), services.WithExpires(event.Item.Expires), + services.WithRevision(event.Item.Revision), ) if err != nil { return nil, trace.Wrap(err) @@ -490,6 +493,7 @@ func (p *clusterNetworkingConfigParser) parse(event backend.Event) (types.Resour event.Item.Value, services.WithResourceID(event.Item.ID), services.WithExpires(event.Item.Expires), + services.WithRevision(event.Item.Revision), ) if err != nil { return nil, trace.Wrap(err) @@ -524,6 +528,7 @@ func (p *authPreferenceParser) parse(event backend.Event) (types.Resource, error event.Item.Value, services.WithResourceID(event.Item.ID), services.WithExpires(event.Item.Expires), + services.WithRevision(event.Item.Revision), ) if err != nil { return nil, trace.Wrap(err) @@ -558,6 +563,7 @@ func (p *uiConfigParser) parse(event backend.Event) (types.Resource, error) { event.Item.Value, services.WithResourceID(event.Item.ID), services.WithExpires(event.Item.Expires), + services.WithRevision(event.Item.Revision), ) if err != nil { return nil, trace.Wrap(err) @@ -592,6 +598,7 @@ func (p *sessionRecordingConfigParser) parse(event backend.Event) (types.Resourc event.Item.Value, services.WithResourceID(event.Item.ID), services.WithExpires(event.Item.Expires), + services.WithRevision(event.Item.Revision), ) if err != nil { return nil, trace.Wrap(err) @@ -625,6 +632,7 @@ func (p *clusterNameParser) parse(event backend.Event) (types.Resource, error) { clusterName, err := services.UnmarshalClusterName(event.Item.Value, services.WithResourceID(event.Item.ID), services.WithExpires(event.Item.Expires), + services.WithRevision(event.Item.Revision), ) if err != nil { return nil, trace.Wrap(err) @@ -665,6 +673,7 @@ func (p *namespaceParser) parse(event backend.Event) (types.Resource, error) { namespace, err := services.UnmarshalNamespace(event.Item.Value, services.WithResourceID(event.Item.ID), services.WithExpires(event.Item.Expires), + services.WithRevision(event.Item.Revision), ) if err != nil { return nil, trace.Wrap(err) @@ -693,6 +702,7 @@ func (p *roleParser) parse(event backend.Event) (types.Resource, error) { resource, err := services.UnmarshalRole(event.Item.Value, services.WithResourceID(event.Item.ID), services.WithExpires(event.Item.Expires), + services.WithRevision(event.Item.Revision), ) if err != nil { return nil, trace.Wrap(err) @@ -779,6 +789,7 @@ func (p *userParser) parse(event backend.Event) (types.Resource, error) { resource, err := services.UnmarshalUser(event.Item.Value, services.WithResourceID(event.Item.ID), services.WithExpires(event.Item.Expires), + services.WithRevision(event.Item.Revision), ) if err != nil { return nil, trace.Wrap(err) @@ -861,6 +872,7 @@ func (p *tunnelConnectionParser) parse(event backend.Event) (types.Resource, err resource, err := services.UnmarshalTunnelConnection(event.Item.Value, services.WithResourceID(event.Item.ID), services.WithExpires(event.Item.Expires), + services.WithRevision(event.Item.Revision), ) if err != nil { return nil, trace.Wrap(err) @@ -889,6 +901,7 @@ func (p *reverseTunnelParser) parse(event backend.Event) (types.Resource, error) resource, err := services.UnmarshalReverseTunnel(event.Item.Value, services.WithResourceID(event.Item.ID), services.WithExpires(event.Item.Expires), + services.WithRevision(event.Item.Revision), ) if err != nil { return nil, trace.Wrap(err) @@ -993,6 +1006,7 @@ func (p *webSessionParser) parse(event backend.Event) (types.Resource, error) { resource, err := services.UnmarshalWebSession(event.Item.Value, services.WithResourceID(event.Item.ID), services.WithExpires(event.Item.Expires), + services.WithRevision(event.Item.Revision), ) if err != nil { return nil, trace.Wrap(err) @@ -1021,6 +1035,7 @@ func (p *webTokenParser) parse(event backend.Event) (types.Resource, error) { resource, err := services.UnmarshalWebToken(event.Item.Value, services.WithResourceID(event.Item.ID), services.WithExpires(event.Item.Expires), + services.WithRevision(event.Item.Revision), ) if err != nil { return nil, trace.Wrap(err) @@ -1062,6 +1077,7 @@ func (p *kubeServerParser) parse(event backend.Event) (types.Resource, error) { event.Item.Value, services.WithResourceID(event.Item.ID), services.WithExpires(event.Item.Expires), + services.WithRevision(event.Item.Revision), ) default: return nil, trace.BadParameter("event %v is not supported", event.Type) @@ -1099,6 +1115,7 @@ func (p *databaseServerParser) parse(event backend.Event) (types.Resource, error event.Item.Value, services.WithResourceID(event.Item.ID), services.WithExpires(event.Item.Expires), + services.WithRevision(event.Item.Revision), ) default: return nil, trace.BadParameter("event %v is not supported", event.Type) @@ -1124,6 +1141,7 @@ func (p *databaseServiceParser) parse(event backend.Event) (types.Resource, erro event.Item.Value, services.WithResourceID(event.Item.ID), services.WithExpires(event.Item.Expires), + services.WithRevision(event.Item.Revision), ) default: return nil, trace.BadParameter("event %v is not supported", event.Type) @@ -1148,6 +1166,7 @@ func (p *kubeClusterParser) parse(event backend.Event) (types.Resource, error) { return services.UnmarshalKubeCluster(event.Item.Value, services.WithResourceID(event.Item.ID), services.WithExpires(event.Item.Expires), + services.WithRevision(event.Item.Revision), ) default: return nil, trace.BadParameter("event %v is not supported", event.Type) @@ -1172,6 +1191,7 @@ func (p *appParser) parse(event backend.Event) (types.Resource, error) { return services.UnmarshalApp(event.Item.Value, services.WithResourceID(event.Item.ID), services.WithExpires(event.Item.Expires), + services.WithRevision(event.Item.Revision), ) default: return nil, trace.BadParameter("event %v is not supported", event.Type) @@ -1196,6 +1216,7 @@ func (p *databaseParser) parse(event backend.Event) (types.Resource, error) { return services.UnmarshalDatabase(event.Item.Value, services.WithResourceID(event.Item.ID), services.WithExpires(event.Item.Expires), + services.WithRevision(event.Item.Revision), ) default: return nil, trace.BadParameter("event %v is not supported", event.Type) @@ -1211,6 +1232,7 @@ func parseServer(event backend.Event, kind string) (types.Resource, error) { kind, services.WithResourceID(event.Item.ID), services.WithExpires(event.Item.Expires), + services.WithRevision(event.Item.Revision), ) if err != nil { return nil, trace.Wrap(err) @@ -1247,6 +1269,7 @@ func (p *remoteClusterParser) parse(event backend.Event) (types.Resource, error) resource, err := services.UnmarshalRemoteCluster(event.Item.Value, services.WithResourceID(event.Item.ID), services.WithExpires(event.Item.Expires), + services.WithRevision(event.Item.Revision), ) if err != nil { return nil, trace.Wrap(err) @@ -1276,6 +1299,7 @@ func (p *lockParser) parse(event backend.Event) (types.Resource, error) { event.Item.Value, services.WithResourceID(event.Item.ID), services.WithExpires(event.Item.Expires), + services.WithRevision(event.Item.Revision), ) default: return nil, trace.BadParameter("event %v is not supported", event.Type) @@ -1308,6 +1332,7 @@ func (p *networkRestrictionsParser) parse(event backend.Event) (types.Resource, resource, err := services.UnmarshalNetworkRestrictions(event.Item.Value, services.WithResourceID(event.Item.ID), services.WithExpires(event.Item.Expires), + services.WithRevision(event.Item.Revision), ) if err != nil { return nil, trace.Wrap(err) @@ -1337,6 +1362,7 @@ func (p *windowsDesktopServicesParser) parse(event backend.Event) (types.Resourc event.Item.Value, services.WithResourceID(event.Item.ID), services.WithExpires(event.Item.Expires), + services.WithRevision(event.Item.Revision), ) default: return nil, trace.BadParameter("event %v is not supported", event.Type) @@ -1374,6 +1400,7 @@ func (p *windowsDesktopsParser) parse(event backend.Event) (types.Resource, erro event.Item.Value, services.WithResourceID(event.Item.ID), services.WithExpires(event.Item.Expires), + services.WithRevision(event.Item.Revision), ) default: return nil, trace.BadParameter("event %v is not supported", event.Type) @@ -1402,6 +1429,7 @@ func (p *installerParser) parse(event backend.Event) (types.Resource, error) { inst, err := services.UnmarshalInstaller(event.Item.Value, services.WithResourceID(event.Item.ID), services.WithExpires(event.Item.Expires), + services.WithRevision(event.Item.Revision), ) if err != nil { return nil, trace.Wrap(err) @@ -1436,6 +1464,7 @@ func (p *pluginParser) parse(event backend.Event) (types.Resource, error) { plugin, err := services.UnmarshalPlugin(event.Item.Value, services.WithResourceID(event.Item.ID), services.WithExpires(event.Item.Expires), + services.WithRevision(event.Item.Revision), ) if err != nil { return nil, trace.Wrap(err) @@ -1464,6 +1493,7 @@ func (p *samlIDPServiceProviderParser) parse(event backend.Event) (types.Resourc return services.UnmarshalSAMLIdPServiceProvider(event.Item.Value, services.WithResourceID(event.Item.ID), services.WithExpires(event.Item.Expires), + services.WithRevision(event.Item.Revision), ) default: return nil, trace.BadParameter("event %v is not supported", event.Type) @@ -1488,6 +1518,7 @@ func (p *userGroupParser) parse(event backend.Event) (types.Resource, error) { return services.UnmarshalUserGroup(event.Item.Value, services.WithResourceID(event.Item.ID), services.WithExpires(event.Item.Expires), + services.WithRevision(event.Item.Revision), ) default: return nil, trace.BadParameter("event %v is not supported", event.Type) @@ -1512,6 +1543,7 @@ func (p *oktaImportRuleParser) parse(event backend.Event) (types.Resource, error return services.UnmarshalOktaImportRule(event.Item.Value, services.WithResourceID(event.Item.ID), services.WithExpires(event.Item.Expires), + services.WithRevision(event.Item.Revision), ) default: return nil, trace.BadParameter("event %v is not supported", event.Type) @@ -1536,6 +1568,7 @@ func (p *oktaAssignmentParser) parse(event backend.Event) (types.Resource, error return services.UnmarshalOktaAssignment(event.Item.Value, services.WithResourceID(event.Item.ID), services.WithExpires(event.Item.Expires), + services.WithRevision(event.Item.Revision), ) default: return nil, trace.BadParameter("event %v is not supported", event.Type) @@ -1560,6 +1593,7 @@ func (p *integrationParser) parse(event backend.Event) (types.Resource, error) { return services.UnmarshalIntegration(event.Item.Value, services.WithResourceID(event.Item.ID), services.WithExpires(event.Item.Expires), + services.WithRevision(event.Item.Revision), ) default: return nil, trace.BadParameter("event %v is not supported", event.Type) @@ -1619,6 +1653,7 @@ func (p *accessListParser) parse(event backend.Event) (types.Resource, error) { return services.UnmarshalAccessList(event.Item.Value, services.WithResourceID(event.Item.ID), services.WithExpires(event.Item.Expires), + services.WithRevision(event.Item.Revision), ) default: return nil, trace.BadParameter("event %v is not supported", event.Type) @@ -1643,6 +1678,7 @@ func (p *userLoginStateParser) parse(event backend.Event) (types.Resource, error return services.UnmarshalUserLoginState(event.Item.Value, services.WithResourceID(event.Item.ID), services.WithExpires(event.Item.Expires), + services.WithRevision(event.Item.Revision), ) default: return nil, trace.BadParameter("event %v is not supported", event.Type) @@ -1667,6 +1703,7 @@ func (p *accessListMemberParser) parse(event backend.Event) (types.Resource, err return services.UnmarshalAccessListMember(event.Item.Value, services.WithResourceID(event.Item.ID), services.WithExpires(event.Item.Expires), + services.WithRevision(event.Item.Revision), ) default: return nil, trace.BadParameter("event %v is not supported", event.Type) diff --git a/lib/services/local/generic/generic.go b/lib/services/local/generic/generic.go index 2a8eaba6e53c9..29a79190a31f3 100644 --- a/lib/services/local/generic/generic.go +++ b/lib/services/local/generic/generic.go @@ -183,7 +183,7 @@ func (s *Service[T]) GetResource(ctx context.Context, name string) (resource T, return resource, trace.Wrap(err) } resource, err = s.unmarshalFunc(item.Value, - services.WithResourceID(item.ID), services.WithExpires(item.Expires)) + services.WithResourceID(item.ID), services.WithExpires(item.Expires), services.WithRevision(item.Revision)) return resource, trace.Wrap(err) } @@ -257,7 +257,7 @@ func (s *Service[T]) UpdateAndSwapResource(ctx context.Context, name string, mod } resource, err := s.unmarshalFunc(existingItem.Value, - services.WithResourceID(existingItem.ID), services.WithExpires(existingItem.Expires)) + services.WithResourceID(existingItem.ID), services.WithExpires(existingItem.Expires), services.WithRevision(existingItem.Revision)) if err != nil { return trace.Wrap(err) } diff --git a/lib/services/local/generic/generic_test.go b/lib/services/local/generic/generic_test.go index 1e5efa1adc2ec..022a80d6b490b 100644 --- a/lib/services/local/generic/generic_test.go +++ b/lib/services/local/generic/generic_test.go @@ -87,6 +87,9 @@ func unmarshalResource(data []byte, opts ...services.MarshalOption) (*testResour if cfg.ID != 0 { r.SetResourceID(cfg.ID) } + if cfg.Revision != "" { + r.SetRevision(cfg.Revision) + } if !cfg.Expires.IsZero() { r.SetExpiry(cfg.Expires) } diff --git a/lib/services/local/kube.go b/lib/services/local/kube.go index d69d2b2b11a24..349b53ef05660 100644 --- a/lib/services/local/kube.go +++ b/lib/services/local/kube.go @@ -46,7 +46,7 @@ func (s *KubernetesService) GetKubernetesClusters(ctx context.Context) ([]types. kubeClusters := make([]types.KubeCluster, len(result.Items)) for i, item := range result.Items { cluster, err := services.UnmarshalKubeCluster(item.Value, - services.WithResourceID(item.ID), services.WithExpires(item.Expires)) + services.WithResourceID(item.ID), services.WithExpires(item.Expires), services.WithRevision(item.Revision)) if err != nil { return nil, trace.Wrap(err) } @@ -65,7 +65,7 @@ func (s *KubernetesService) GetKubernetesCluster(ctx context.Context, name strin return nil, trace.Wrap(err) } cluster, err := services.UnmarshalKubeCluster(item.Value, - services.WithResourceID(item.ID), services.WithExpires(item.Expires)) + services.WithResourceID(item.ID), services.WithExpires(item.Expires), services.WithRevision(item.Revision)) if err != nil { return nil, trace.Wrap(err) } diff --git a/lib/services/local/plugins.go b/lib/services/local/plugins.go index df44362d81f35..16722fe11e98e 100644 --- a/lib/services/local/plugins.go +++ b/lib/services/local/plugins.go @@ -92,7 +92,7 @@ func (s *PluginsService) GetPlugin(ctx context.Context, name string, withSecrets } plugin, err := services.UnmarshalPlugin(item.Value, - services.WithResourceID(item.ID), services.WithExpires(item.Expires)) + services.WithResourceID(item.ID), services.WithExpires(item.Expires), services.WithRevision(item.Revision)) if err != nil { return nil, trace.Wrap(err) } @@ -139,7 +139,7 @@ func (s *PluginsService) ListPlugins(ctx context.Context, limit int, startKey st plugins := make([]types.Plugin, 0, len(result.Items)) for _, item := range result.Items { - plugin, err := services.UnmarshalPlugin(item.Value, services.WithResourceID(item.ID), services.WithExpires(item.Expires)) + plugin, err := services.UnmarshalPlugin(item.Value, services.WithResourceID(item.ID), services.WithExpires(item.Expires), services.WithRevision(item.Revision)) if err != nil { return nil, "", trace.Wrap(err) } @@ -199,7 +199,7 @@ func (s *PluginsService) updateAndSwap(ctx context.Context, name string, modify } plugin, err := services.UnmarshalPlugin(item.Value, - services.WithResourceID(item.ID), services.WithExpires(item.Expires)) + services.WithResourceID(item.ID), services.WithExpires(item.Expires), services.WithRevision(item.Revision)) if err != nil { return trace.Wrap(err) } diff --git a/lib/services/local/presence.go b/lib/services/local/presence.go index 1b5dc6f27b17b..9b0360a58370d 100644 --- a/lib/services/local/presence.go +++ b/lib/services/local/presence.go @@ -76,7 +76,7 @@ func (s *PresenceService) GetNamespaces() ([]types.Namespace, error) { continue } ns, err := services.UnmarshalNamespace( - item.Value, services.WithResourceID(item.ID), services.WithExpires(item.Expires)) + item.Value, services.WithResourceID(item.ID), services.WithExpires(item.Expires), services.WithRevision(item.Revision)) if err != nil { return nil, trace.Wrap(err) } @@ -122,7 +122,7 @@ func (s *PresenceService) GetNamespace(name string) (*types.Namespace, error) { return nil, trace.Wrap(err) } return services.UnmarshalNamespace( - item.Value, services.WithResourceID(item.ID), services.WithExpires(item.Expires)) + item.Value, services.WithResourceID(item.ID), services.WithExpires(item.Expires), services.WithRevision(item.Revision)) } // DeleteNamespace deletes a namespace with all the keys from the backend @@ -149,6 +149,7 @@ func (s *PresenceService) GetServerInfos(ctx context.Context) stream.Stream[type item.Value, services.WithResourceID(item.ID), services.WithExpires(item.Expires), + services.WithRevision(item.Revision), ) if err != nil { s.log.Warnf("Skipping server info at %s, failed to unmarshal: %v", item.Key, err) @@ -171,7 +172,7 @@ func (s *PresenceService) GetServerInfo(ctx context.Context, name string) (types return nil, trace.Wrap(err) } si, err := services.UnmarshalServerInfo( - item.Value, services.WithResourceID(item.ID), services.WithExpires(item.Expires), + item.Value, services.WithResourceID(item.ID), services.WithExpires(item.Expires), services.WithRevision(item.Revision), ) return si, trace.Wrap(err) } @@ -237,6 +238,7 @@ func (s *PresenceService) getServers(ctx context.Context, kind, prefix string) ( item.Value, kind, services.WithResourceID(item.ID), services.WithExpires(item.Expires), + services.WithRevision(item.Revision), ) if err != nil { return nil, trace.Wrap(err) @@ -291,6 +293,7 @@ func (s *PresenceService) GetNode(ctx context.Context, namespace, name string) ( types.KindNode, services.WithResourceID(item.ID), services.WithExpires(item.Expires), + services.WithRevision(item.Revision), ) } @@ -315,6 +318,7 @@ func (s *PresenceService) GetNodes(ctx context.Context, namespace string) ([]typ []services.MarshalOption{ services.WithResourceID(item.ID), services.WithExpires(item.Expires), + services.WithRevision(item.Revision), }..., ) if err != nil { @@ -436,7 +440,7 @@ func (s *PresenceService) GetReverseTunnel(name string, opts ...services.Marshal return nil, trace.Wrap(err) } return services.UnmarshalReverseTunnel(item.Value, - services.AddOptions(opts, services.WithResourceID(item.ID), services.WithExpires(item.Expires))...) + services.AddOptions(opts, services.WithResourceID(item.ID), services.WithExpires(item.Expires), services.WithRevision(item.Revision))...) } // GetReverseTunnels returns a list of registered servers @@ -452,7 +456,7 @@ func (s *PresenceService) GetReverseTunnels(ctx context.Context, opts ...service } for i, item := range result.Items { tunnel, err := services.UnmarshalReverseTunnel( - item.Value, services.AddOptions(opts, services.WithResourceID(item.ID), services.WithExpires(item.Expires))...) + item.Value, services.AddOptions(opts, services.WithResourceID(item.ID), services.WithExpires(item.Expires), services.WithRevision(item.Revision))...) if err != nil { return nil, trace.Wrap(err) } @@ -499,7 +503,7 @@ func (s *PresenceService) GetTrustedCluster(ctx context.Context, name string) (t if err != nil { return nil, trace.Wrap(err) } - return services.UnmarshalTrustedCluster(item.Value, services.WithResourceID(item.ID), services.WithExpires(item.Expires)) + return services.UnmarshalTrustedCluster(item.Value, services.WithResourceID(item.ID), services.WithExpires(item.Expires), services.WithRevision(item.Revision)) } // GetTrustedClusters returns all TrustedClusters in the backend. @@ -512,7 +516,7 @@ func (s *PresenceService) GetTrustedClusters(ctx context.Context) ([]types.Trust out := make([]types.TrustedCluster, len(result.Items)) for i, item := range result.Items { tc, err := services.UnmarshalTrustedCluster(item.Value, - services.WithResourceID(item.ID), services.WithExpires(item.Expires)) + services.WithResourceID(item.ID), services.WithExpires(item.Expires), services.WithRevision(item.Revision)) if err != nil { return nil, trace.Wrap(err) } @@ -569,7 +573,7 @@ func (s *PresenceService) GetTunnelConnection(clusterName, connectionName string return nil, trace.Wrap(err) } conn, err := services.UnmarshalTunnelConnection(item.Value, - services.AddOptions(opts, services.WithResourceID(item.ID), services.WithExpires(item.Expires))...) + services.AddOptions(opts, services.WithResourceID(item.ID), services.WithExpires(item.Expires), services.WithRevision(item.Revision))...) if err != nil { return nil, trace.Wrap(err) } @@ -589,7 +593,7 @@ func (s *PresenceService) GetTunnelConnections(clusterName string, opts ...servi conns := make([]types.TunnelConnection, len(result.Items)) for i, item := range result.Items { conn, err := services.UnmarshalTunnelConnection(item.Value, - services.AddOptions(opts, services.WithResourceID(item.ID), services.WithExpires(item.Expires))...) + services.AddOptions(opts, services.WithResourceID(item.ID), services.WithExpires(item.Expires), services.WithRevision(item.Revision))...) if err != nil { return nil, trace.Wrap(err) } @@ -612,7 +616,8 @@ func (s *PresenceService) GetAllTunnelConnections(opts ...services.MarshalOption conn, err := services.UnmarshalTunnelConnection(item.Value, services.AddOptions(opts, services.WithResourceID(item.ID), - services.WithExpires(item.Expires))...) + services.WithExpires(item.Expires), + services.WithRevision(item.Revision))...) if err != nil { return nil, trace.Wrap(err) } @@ -714,7 +719,7 @@ func (s *PresenceService) GetRemoteClusters(opts ...services.MarshalOption) ([]t clusters := make([]types.RemoteCluster, len(result.Items)) for i, item := range result.Items { cluster, err := services.UnmarshalRemoteCluster(item.Value, - services.AddOptions(opts, services.WithResourceID(item.ID), services.WithExpires(item.Expires))...) + services.AddOptions(opts, services.WithResourceID(item.ID), services.WithExpires(item.Expires), services.WithRevision(item.Revision))...) if err != nil { return nil, trace.Wrap(err) } @@ -736,7 +741,7 @@ func (s *PresenceService) getRemoteCluster(ctx context.Context, clusterName stri return nil, nil, trace.Wrap(err) } rc, err := services.UnmarshalRemoteCluster(item.Value, - services.WithResourceID(item.ID), services.WithExpires(item.Expires)) + services.WithResourceID(item.ID), services.WithExpires(item.Expires), services.WithRevision(item.Revision)) if err != nil { return nil, nil, trace.Wrap(err) } @@ -1145,7 +1150,8 @@ func (s *PresenceService) getKubernetesServers(ctx context.Context) ([]types.Kub server, err := services.UnmarshalKubeServer( item.Value, services.WithResourceID(item.ID), - services.WithExpires(item.Expires)) + services.WithExpires(item.Expires), + services.WithRevision(item.Revision)) if err != nil { return nil, trace.Wrap(err) } @@ -1170,7 +1176,8 @@ func (s *PresenceService) GetDatabaseServers(ctx context.Context, namespace stri item.Value, services.AddOptions(opts, services.WithResourceID(item.ID), - services.WithExpires(item.Expires))...) + services.WithExpires(item.Expires), + services.WithRevision(item.Revision))...) if err != nil { return nil, trace.Wrap(err) } @@ -1263,7 +1270,8 @@ func (s *PresenceService) getApplicationServers(ctx context.Context, namespace s server, err := services.UnmarshalAppServer( item.Value, services.WithResourceID(item.ID), - services.WithExpires(item.Expires)) + services.WithExpires(item.Expires), + services.WithRevision(item.Revision)) if err != nil { return nil, trace.Wrap(err) } @@ -1371,6 +1379,7 @@ func (s *PresenceService) GetWindowsDesktopServices(ctx context.Context) ([]type item.Value, services.WithResourceID(item.ID), services.WithExpires(item.Expires), + services.WithRevision(item.Revision), ) if err != nil { return nil, trace.Wrap(err) @@ -1389,6 +1398,7 @@ func (s *PresenceService) GetWindowsDesktopService(ctx context.Context, name str result.Value, services.WithResourceID(result.ID), services.WithExpires(result.Expires), + services.WithRevision(result.Revision), ) if err != nil { return nil, trace.Wrap(err) @@ -1480,7 +1490,8 @@ func (s *PresenceService) GetUserGroups(ctx context.Context, opts ...services.Ma item.Value, services.AddOptions(opts, services.WithResourceID(item.ID), - services.WithExpires(item.Expires))...) + services.WithExpires(item.Expires), + services.WithRevision(item.Revision))...) if err != nil { return nil, trace.Wrap(err) } @@ -1807,6 +1818,7 @@ func backendItemToDatabaseServer(item backend.Item) (types.ResourceWithLabels, e item.Value, services.WithResourceID(item.ID), services.WithExpires(item.Expires), + services.WithRevision(item.Revision), ) } @@ -1817,6 +1829,7 @@ func backendItemToDatabaseService(item backend.Item) (types.ResourceWithLabels, item.Value, services.WithResourceID(item.ID), services.WithExpires(item.Expires), + services.WithRevision(item.Revision), ) } @@ -1827,6 +1840,8 @@ func backendItemToApplicationServer(item backend.Item) (types.ResourceWithLabels item.Value, services.WithResourceID(item.ID), services.WithExpires(item.Expires), + services.WithRevision(item.Revision), + services.WithRevision(item.Revision), ) } @@ -1837,6 +1852,7 @@ func backendItemToKubernetesServer(item backend.Item) (types.ResourceWithLabels, item.Value, services.WithResourceID(item.ID), services.WithExpires(item.Expires), + services.WithRevision(item.Revision), ) } @@ -1849,6 +1865,7 @@ func backendItemToServer(kind string) backendItemToResourceFunc { item.Value, kind, services.WithResourceID(item.ID), services.WithExpires(item.Expires), + services.WithRevision(item.Revision), ) } } @@ -1860,6 +1877,7 @@ func backendItemToWindowsDesktopService(item backend.Item) (types.ResourceWithLa item.Value, services.WithResourceID(item.ID), services.WithExpires(item.Expires), + services.WithRevision(item.Revision), ) } @@ -1870,6 +1888,7 @@ func backendItemToUserGroup(item backend.Item) (types.ResourceWithLabels, error) item.Value, services.WithResourceID(item.ID), services.WithExpires(item.Expires), + services.WithRevision(item.Revision), ) } diff --git a/lib/services/local/provisioning.go b/lib/services/local/provisioning.go index 5f0fe8696412d..891297e1922b5 100644 --- a/lib/services/local/provisioning.go +++ b/lib/services/local/provisioning.go @@ -100,7 +100,7 @@ func (s *ProvisioningService) GetToken(ctx context.Context, token string) (types return nil, trace.Wrap(err) } - return services.UnmarshalProvisionToken(item.Value, services.WithResourceID(item.ID), services.WithExpires(item.Expires)) + return services.UnmarshalProvisionToken(item.Value, services.WithResourceID(item.ID), services.WithExpires(item.Expires), services.WithRevision(item.Revision)) } // DeleteToken deletes a token by ID @@ -128,6 +128,7 @@ func (s *ProvisioningService) GetTokens(ctx context.Context) ([]types.ProvisionT item.Value, services.WithResourceID(item.ID), services.WithExpires(item.Expires), + services.WithRevision(item.Revision), ) if err != nil { return nil, trace.Wrap(err) diff --git a/lib/services/local/resource.go b/lib/services/local/resource.go index 717f5b186b91d..c38d17b207579 100644 --- a/lib/services/local/resource.go +++ b/lib/services/local/resource.go @@ -141,6 +141,7 @@ func itemToUser(item backend.Item) (types.User, error) { item.Value, services.WithResourceID(item.ID), services.WithExpires(item.Expires), + services.WithRevision(item.Revision), ) if err != nil { return nil, trace.Wrap(err) diff --git a/lib/services/local/restrictions.go b/lib/services/local/restrictions.go index 28ec416964039..f5145036794c9 100644 --- a/lib/services/local/restrictions.go +++ b/lib/services/local/restrictions.go @@ -66,7 +66,7 @@ func (s *RestrictionsService) GetNetworkRestrictions(ctx context.Context) (types return nil, trace.Wrap(err) } return services.UnmarshalNetworkRestrictions(item.Value, - services.WithResourceID(item.ID), services.WithExpires(item.Expires)) + services.WithResourceID(item.ID), services.WithExpires(item.Expires), services.WithRevision(item.Revision)) } // SetNetworkRestrictions upserts NetworkRestrictions diff --git a/lib/services/local/trust.go b/lib/services/local/trust.go index 03a69038557b4..46a916e6b1494 100644 --- a/lib/services/local/trust.go +++ b/lib/services/local/trust.go @@ -177,7 +177,7 @@ func (s *CA) ActivateCertAuthority(id types.CertAuthID) error { } certAuthority, err := services.UnmarshalCertAuthority( - item.Value, services.WithResourceID(item.ID), services.WithExpires(item.Expires)) + item.Value, services.WithResourceID(item.ID), services.WithExpires(item.Expires), services.WithRevision(item.Revision)) if err != nil { return trace.Wrap(err) } @@ -240,7 +240,7 @@ func (s *CA) GetCertAuthority(ctx context.Context, id types.CertAuthID, loadSign if err != nil { return nil, trace.Wrap(err) } - ca, err := services.UnmarshalCertAuthority(item.Value, services.WithResourceID(item.ID), services.WithExpires(item.Expires)) + ca, err := services.UnmarshalCertAuthority(item.Value, services.WithResourceID(item.ID), services.WithExpires(item.Expires), services.WithRevision(item.Revision)) if err != nil { return nil, trace.Wrap(err) } @@ -275,7 +275,7 @@ func (s *CA) GetCertAuthorities(ctx context.Context, caType types.CertAuthType, // Marshal values into a []types.CertAuthority slice. cas := make([]types.CertAuthority, len(result.Items)) for i, item := range result.Items { - ca, err := services.UnmarshalCertAuthority(item.Value, services.WithResourceID(item.ID), services.WithExpires(item.Expires)) + ca, err := services.UnmarshalCertAuthority(item.Value, services.WithResourceID(item.ID), services.WithExpires(item.Expires), services.WithRevision(item.Revision)) if err != nil { return nil, trace.Wrap(err) } diff --git a/lib/services/local/users.go b/lib/services/local/users.go index febea1f0de3c9..a9bbbb4df73c1 100644 --- a/lib/services/local/users.go +++ b/lib/services/local/users.go @@ -89,7 +89,7 @@ func (s *IdentityService) GetUsers(withSecrets bool) ([]types.User, error) { continue } u, err := services.UnmarshalUser( - item.Value, services.WithResourceID(item.ID), services.WithExpires(item.Expires)) + item.Value, services.WithResourceID(item.ID), services.WithExpires(item.Expires), services.WithRevision(item.Revision)) if err != nil { return nil, trace.Wrap(err) } @@ -334,7 +334,7 @@ func (s *IdentityService) getUser(ctx context.Context, user string, withSecrets } u, err := services.UnmarshalUser( - item.Value, services.WithResourceID(item.ID), services.WithExpires(item.Expires)) + item.Value, services.WithResourceID(item.ID), services.WithExpires(item.Expires), services.WithRevision(item.Revision)) if err != nil { return nil, nil, trace.Wrap(err) } diff --git a/lib/services/lock.go b/lib/services/lock.go index cb29bab641c5f..5ca133694045d 100644 --- a/lib/services/lock.go +++ b/lib/services/lock.go @@ -96,6 +96,9 @@ func UnmarshalLock(bytes []byte, opts ...MarshalOption) (types.Lock, error) { if cfg.ID != 0 { lock.SetResourceID(cfg.ID) } + if cfg.Revision != "" { + lock.SetRevision(cfg.Revision) + } if !cfg.Expires.IsZero() { lock.SetExpiry(cfg.Expires) } diff --git a/lib/services/namespace.go b/lib/services/namespace.go index d0a3d581ed1e0..6f05a0762136a 100644 --- a/lib/services/namespace.go +++ b/lib/services/namespace.go @@ -68,6 +68,9 @@ func UnmarshalNamespace(data []byte, opts ...MarshalOption) (*types.Namespace, e if cfg.ID != 0 { namespace.Metadata.ID = cfg.ID } + if cfg.Revision != "" { + namespace.SetRevision(cfg.Revision) + } if !cfg.Expires.IsZero() { namespace.Metadata.Expires = &cfg.Expires } diff --git a/lib/services/networking.go b/lib/services/networking.go index fbb93710f55f9..becee01f216c8 100644 --- a/lib/services/networking.go +++ b/lib/services/networking.go @@ -48,6 +48,9 @@ func UnmarshalClusterNetworkingConfig(bytes []byte, opts ...MarshalOption) (type if cfg.ID != 0 { netConfig.SetResourceID(cfg.ID) } + if cfg.Revision != "" { + netConfig.SetRevision(cfg.Revision) + } if !cfg.Expires.IsZero() { netConfig.SetExpiry(cfg.Expires) } diff --git a/lib/services/oidc.go b/lib/services/oidc.go index 5df318160878d..19bf932e7dc77 100644 --- a/lib/services/oidc.go +++ b/lib/services/oidc.go @@ -123,6 +123,9 @@ func UnmarshalOIDCConnector(bytes []byte, opts ...MarshalOption) (types.OIDCConn if cfg.ID != 0 { c.SetResourceID(cfg.ID) } + if cfg.Revision != "" { + c.SetRevision(cfg.Revision) + } if !cfg.Expires.IsZero() { c.SetExpiry(cfg.Expires) } diff --git a/lib/services/okta.go b/lib/services/okta.go index 287d98ebe89a8..0ed3488bf137a 100644 --- a/lib/services/okta.go +++ b/lib/services/okta.go @@ -127,6 +127,9 @@ func UnmarshalOktaImportRule(data []byte, opts ...MarshalOption) (types.OktaImpo if cfg.ID != 0 { i.SetResourceID(cfg.ID) } + if cfg.Revision != "" { + i.SetRevision(cfg.Revision) + } if !cfg.Expires.IsZero() { i.SetExpiry(cfg.Expires) } @@ -184,6 +187,9 @@ func UnmarshalOktaAssignment(data []byte, opts ...MarshalOption) (types.OktaAssi if cfg.ID != 0 { a.SetResourceID(cfg.ID) } + if cfg.Revision != "" { + a.SetRevision(cfg.Revision) + } if !cfg.Expires.IsZero() { a.SetExpiry(cfg.Expires) } diff --git a/lib/services/plugin_data.go b/lib/services/plugin_data.go index 95f6913bd366c..70e6bf2149897 100644 --- a/lib/services/plugin_data.go +++ b/lib/services/plugin_data.go @@ -65,6 +65,9 @@ func UnmarshalPluginData(raw []byte, opts ...MarshalOption) (types.PluginData, e if cfg.ID != 0 { data.SetResourceID(cfg.ID) } + if cfg.Revision != "" { + data.SetRevision(cfg.Revision) + } if !cfg.Expires.IsZero() { data.SetExpiry(cfg.Expires) } diff --git a/lib/services/plugin_static_credentials.go b/lib/services/plugin_static_credentials.go index 6e94e730e7e31..72400f6004a90 100644 --- a/lib/services/plugin_static_credentials.go +++ b/lib/services/plugin_static_credentials.go @@ -92,6 +92,9 @@ func UnmarshalPluginStaticCredentials(data []byte, opts ...MarshalOption) (types if cfg.ID != 0 { pluginStaticCredentials.SetResourceID(cfg.ID) } + if cfg.Revision != "" { + pluginStaticCredentials.SetRevision(cfg.Revision) + } if !cfg.Expires.IsZero() { pluginStaticCredentials.SetExpiry(cfg.Expires) } diff --git a/lib/services/plugins.go b/lib/services/plugins.go index 96a8febe89f59..f74e46fbaf770 100644 --- a/lib/services/plugins.go +++ b/lib/services/plugins.go @@ -92,6 +92,9 @@ func UnmarshalPlugin(data []byte, opts ...MarshalOption) (types.Plugin, error) { if cfg.ID != 0 { plugin.SetResourceID(cfg.ID) } + if cfg.Revision != "" { + plugin.SetRevision(cfg.Revision) + } if !cfg.Expires.IsZero() { plugin.SetExpiry(cfg.Expires) } diff --git a/lib/services/provisioning.go b/lib/services/provisioning.go index f6bb1938bac4d..6a554d2057f5d 100644 --- a/lib/services/provisioning.go +++ b/lib/services/provisioning.go @@ -86,6 +86,9 @@ func UnmarshalProvisionToken(data []byte, opts ...MarshalOption) (types.Provisio if cfg.ID != 0 { v2.SetResourceID(cfg.ID) } + if cfg.Revision != "" { + v2.SetRevision(cfg.Revision) + } return v2, nil case types.V2: var p types.ProvisionTokenV2 @@ -98,6 +101,9 @@ func UnmarshalProvisionToken(data []byte, opts ...MarshalOption) (types.Provisio if cfg.ID != 0 { p.SetResourceID(cfg.ID) } + if cfg.Revision != "" { + p.SetRevision(cfg.Revision) + } return &p, nil } return nil, trace.BadParameter("server resource version %v is not supported", h.Version) diff --git a/lib/services/remotecluster.go b/lib/services/remotecluster.go index a463aea5cd3c1..fcd9c8171998a 100644 --- a/lib/services/remotecluster.go +++ b/lib/services/remotecluster.go @@ -48,6 +48,9 @@ func UnmarshalRemoteCluster(bytes []byte, opts ...MarshalOption) (types.RemoteCl if cfg.ID != 0 { cluster.SetResourceID(cfg.ID) } + if cfg.Revision != "" { + cluster.SetRevision(cfg.Revision) + } if !cfg.Expires.IsZero() { cluster.SetExpiry(cfg.Expires) } diff --git a/lib/services/resource.go b/lib/services/resource.go index 9782d42f1876d..46c9a0cc902cf 100644 --- a/lib/services/resource.go +++ b/lib/services/resource.go @@ -30,12 +30,15 @@ import ( // MarshalConfig specifies marshaling options type MarshalConfig struct { - // Version specifies particular version we should marshal resources with + // Version specifies a particular version we should marshal resources with Version string // ID is a record ID to assign ID int64 + // Revision of the resource to assign. + Revision string + // PreserveResourceID preserves resource IDs in resource // specs when marshaling PreserveResourceID bool @@ -81,6 +84,14 @@ func WithResourceID(id int64) MarshalOption { } } +// WithRevision assigns Revision to the resource +func WithRevision(rev string) MarshalOption { + return func(c *MarshalConfig) error { + c.Revision = rev + return nil + } +} + // WithExpires assigns expiry value func WithExpires(expires time.Time) MarshalOption { return func(c *MarshalConfig) error { diff --git a/lib/services/restrictions.go b/lib/services/restrictions.go index fced07890e0ff..5024b4f8c556e 100644 --- a/lib/services/restrictions.go +++ b/lib/services/restrictions.go @@ -67,6 +67,9 @@ func UnmarshalNetworkRestrictions(bytes []byte, opts ...MarshalOption) (types.Ne if cfg.ID != 0 { nr.SetResourceID(cfg.ID) } + if cfg.Revision != "" { + nr.SetRevision(cfg.Revision) + } if !cfg.Expires.IsZero() { nr.SetExpiry(cfg.Expires) } diff --git a/lib/services/role.go b/lib/services/role.go index 0cf266441ffb0..9f5370bb84141 100644 --- a/lib/services/role.go +++ b/lib/services/role.go @@ -3134,6 +3134,9 @@ func UnmarshalRole(bytes []byte, opts ...MarshalOption) (types.Role, error) { if cfg.ID != 0 { role.SetResourceID(cfg.ID) } + if cfg.Revision != "" { + role.SetRevision(cfg.Revision) + } if !cfg.Expires.IsZero() { role.SetExpiry(cfg.Expires) } diff --git a/lib/services/saml.go b/lib/services/saml.go index b0121584228f3..b756795516bc4 100644 --- a/lib/services/saml.go +++ b/lib/services/saml.go @@ -299,6 +299,9 @@ func UnmarshalSAMLConnector(bytes []byte, opts ...MarshalOption) (types.SAMLConn if cfg.ID != 0 { c.SetResourceID(cfg.ID) } + if cfg.Revision != "" { + c.SetRevision(cfg.Revision) + } if !cfg.Expires.IsZero() { c.SetExpiry(cfg.Expires) } diff --git a/lib/services/saml_idp_service_provider.go b/lib/services/saml_idp_service_provider.go index edb05544c2186..ad146a1d7538a 100644 --- a/lib/services/saml_idp_service_provider.go +++ b/lib/services/saml_idp_service_provider.go @@ -95,6 +95,9 @@ func UnmarshalSAMLIdPServiceProvider(data []byte, opts ...MarshalOption) (types. if cfg.ID != 0 { s.SetResourceID(cfg.ID) } + if cfg.Revision != "" { + s.SetRevision(cfg.Revision) + } if !cfg.Expires.IsZero() { s.SetExpiry(cfg.Expires) } diff --git a/lib/services/semaphore.go b/lib/services/semaphore.go index 78df632e1888b..837bbf00c1b68 100644 --- a/lib/services/semaphore.go +++ b/lib/services/semaphore.go @@ -301,6 +301,9 @@ func UnmarshalSemaphore(bytes []byte, opts ...MarshalOption) (types.Semaphore, e if cfg.ID != 0 { semaphore.SetResourceID(cfg.ID) } + if cfg.Revision != "" { + semaphore.SetRevision(cfg.Revision) + } if !cfg.Expires.IsZero() { semaphore.SetExpiry(cfg.Expires) } diff --git a/lib/services/server.go b/lib/services/server.go index 87bf4cdaa4c29..cb8564a585baf 100644 --- a/lib/services/server.go +++ b/lib/services/server.go @@ -363,6 +363,9 @@ func UnmarshalServer(bytes []byte, kind string, opts ...MarshalOption) (types.Se if cfg.ID != 0 { s.SetResourceID(cfg.ID) } + if cfg.Revision != "" { + s.SetRevision(cfg.Revision) + } if !cfg.Expires.IsZero() { s.SetExpiry(cfg.Expires) } diff --git a/lib/services/server_info.go b/lib/services/server_info.go index 6a7b895f52ebe..1462fdc406f3d 100644 --- a/lib/services/server_info.go +++ b/lib/services/server_info.go @@ -45,6 +45,9 @@ func UnmarshalServerInfo(bytes []byte, opts ...MarshalOption) (types.ServerInfo, if cfg.ID != 0 { si.SetResourceID(cfg.ID) } + if cfg.Revision != "" { + si.SetRevision(cfg.Revision) + } if !cfg.Expires.IsZero() { si.SetExpiry(cfg.Expires) } diff --git a/lib/services/services_test.go b/lib/services/services_test.go index e8af818905b84..edefd14546276 100644 --- a/lib/services/services_test.go +++ b/lib/services/services_test.go @@ -43,22 +43,24 @@ func TestOptions(t *testing.T) { require.Len(t, out, 0) // make sure original option list is not affected - in := []MarshalOption{} - out = AddOptions(in, WithResourceID(1)) - require.Len(t, out, 1) + var in []MarshalOption + out = AddOptions(in, WithResourceID(1), WithRevision("abc")) + require.Len(t, out, 2) require.Len(t, in, 0) cfg, err := CollectOptions(out) require.NoError(t, err) - require.Equal(t, cfg.ID, int64(1)) + require.Equal(t, int64(1), cfg.ID) + require.Equal(t, "abc", cfg.Revision) // Add a couple of other parameters - out = AddOptions(in, WithResourceID(2), WithVersion(types.V2)) - require.Len(t, out, 2) + out = AddOptions(in, WithResourceID(2), WithVersion(types.V2), WithRevision("xyz")) + require.Len(t, out, 3) require.Len(t, in, 0) cfg, err = CollectOptions(out) require.NoError(t, err) - require.Equal(t, cfg.ID, int64(2)) - require.Equal(t, cfg.Version, types.V2) + require.Equal(t, int64(2), cfg.ID) + require.Equal(t, types.V2, cfg.Version) + require.Equal(t, "xyz", cfg.Revision) } // TestCommandLabels tests command labels diff --git a/lib/services/session.go b/lib/services/session.go index 9404219da0b55..3643038a18906 100644 --- a/lib/services/session.go +++ b/lib/services/session.go @@ -53,6 +53,9 @@ func UnmarshalWebSession(bytes []byte, opts ...MarshalOption) (types.WebSession, if cfg.ID != 0 { ws.SetResourceID(cfg.ID) } + if cfg.Revision != "" { + ws.SetRevision(cfg.Revision) + } if !cfg.Expires.IsZero() { ws.SetExpiry(cfg.Expires) } diff --git a/lib/services/sessionrecording.go b/lib/services/sessionrecording.go index 28eb4186ffcdb..d3348fb924660 100644 --- a/lib/services/sessionrecording.go +++ b/lib/services/sessionrecording.go @@ -57,6 +57,9 @@ func UnmarshalSessionRecordingConfig(bytes []byte, opts ...MarshalOption) (types if cfg.ID != 0 { recConfig.SetResourceID(cfg.ID) } + if cfg.Revision != "" { + recConfig.SetRevision(cfg.Revision) + } if !cfg.Expires.IsZero() { recConfig.SetExpiry(cfg.Expires) } diff --git a/lib/services/statictokens.go b/lib/services/statictokens.go index 9cbc6990193c3..16d1a25b72985 100644 --- a/lib/services/statictokens.go +++ b/lib/services/statictokens.go @@ -46,6 +46,9 @@ func UnmarshalStaticTokens(bytes []byte, opts ...MarshalOption) (types.StaticTok if cfg.ID != 0 { staticTokens.SetResourceID(cfg.ID) } + if cfg.Revision != "" { + staticTokens.SetRevision(cfg.Revision) + } if !cfg.Expires.IsZero() { staticTokens.SetExpiry(cfg.Expires) } diff --git a/lib/services/trustedcluster.go b/lib/services/trustedcluster.go index 811311eb5c825..de1585b6820c9 100644 --- a/lib/services/trustedcluster.go +++ b/lib/services/trustedcluster.go @@ -161,6 +161,9 @@ func UnmarshalTrustedCluster(bytes []byte, opts ...MarshalOption) (types.Trusted if cfg.ID != 0 { trustedCluster.SetResourceID(cfg.ID) } + if cfg.Revision != "" { + trustedCluster.SetRevision(cfg.Revision) + } if !cfg.Expires.IsZero() { trustedCluster.SetExpiry(cfg.Expires) } diff --git a/lib/services/tunnel.go b/lib/services/tunnel.go index d423f90acfd93..42d58854c1791 100644 --- a/lib/services/tunnel.go +++ b/lib/services/tunnel.go @@ -65,6 +65,9 @@ func UnmarshalReverseTunnel(bytes []byte, opts ...MarshalOption) (types.ReverseT if cfg.ID != 0 { r.SetResourceID(cfg.ID) } + if cfg.Revision != "" { + r.SetRevision(cfg.Revision) + } if !cfg.Expires.IsZero() { r.SetExpiry(cfg.Expires) } diff --git a/lib/services/tunnelconn.go b/lib/services/tunnelconn.go index ee90ca49635e1..0a636b35a6b12 100644 --- a/lib/services/tunnelconn.go +++ b/lib/services/tunnelconn.go @@ -82,6 +82,9 @@ func UnmarshalTunnelConnection(data []byte, opts ...MarshalOption) (types.Tunnel if cfg.ID != 0 { r.SetResourceID(cfg.ID) } + if cfg.Revision != "" { + r.SetRevision(cfg.Revision) + } if !cfg.Expires.IsZero() { r.SetExpiry(cfg.Expires) } diff --git a/lib/services/ui_config.go b/lib/services/ui_config.go index a2add1de21836..cc5d717167e2e 100644 --- a/lib/services/ui_config.go +++ b/lib/services/ui_config.go @@ -45,6 +45,9 @@ func UnmarshalUIConfig(data []byte, opts ...MarshalOption) (types.UIConfig, erro if cfg.ID != 0 { uiconfig.SetResourceID(cfg.ID) } + if cfg.Revision != "" { + uiconfig.SetRevision(cfg.Revision) + } if !cfg.Expires.IsZero() { uiconfig.SetExpiry(cfg.Expires) } diff --git a/lib/services/user.go b/lib/services/user.go index 315fdff63261d..f54205687919d 100644 --- a/lib/services/user.go +++ b/lib/services/user.go @@ -105,6 +105,9 @@ func UnmarshalUser(bytes []byte, opts ...MarshalOption) (types.User, error) { if cfg.ID != 0 { u.SetResourceID(cfg.ID) } + if cfg.Revision != "" { + u.SetRevision(cfg.Revision) + } if !cfg.Expires.IsZero() { u.SetExpiry(cfg.Expires) } diff --git a/lib/services/user_login_state.go b/lib/services/user_login_state.go index bbf99f157fec4..782b100835bf2 100644 --- a/lib/services/user_login_state.go +++ b/lib/services/user_login_state.go @@ -84,6 +84,9 @@ func UnmarshalUserLoginState(data []byte, opts ...MarshalOption) (*userloginstat if cfg.ID != 0 { uls.SetResourceID(cfg.ID) } + if cfg.Revision != "" { + uls.SetRevision(cfg.Revision) + } if !cfg.Expires.IsZero() { uls.SetExpiry(cfg.Expires) } diff --git a/lib/services/usergroup.go b/lib/services/usergroup.go index 20d82c5ebcf86..536787ea63e67 100644 --- a/lib/services/usergroup.go +++ b/lib/services/usergroup.go @@ -90,6 +90,9 @@ func UnmarshalUserGroup(data []byte, opts ...MarshalOption) (types.UserGroup, er if cfg.ID != 0 { g.SetResourceID(cfg.ID) } + if cfg.Revision != "" { + g.SetRevision(cfg.Revision) + } if !cfg.Expires.IsZero() { g.SetExpiry(cfg.Expires) } From 40ccc6359ee9b06f3375cf4e906bdfbf9525c37e Mon Sep 17 00:00:00 2001 From: Tim Ross Date: Wed, 20 Sep 2023 10:57:18 -0400 Subject: [PATCH 2/3] Prevent storing resource revision in the backend item value The revision follows the same semantics as the resource id for marshalling. This prevents both items from showing up in the value of the backend item, which can prevent compare and swap operations from completing succesfully. Each backend is responsible for persisting the revision in some manner. The existing PreserveResourceID was reused to prevent having to make multiple copies of a resource when clearing the id and revision. The marshal option will be updated in a follow up when the resource id is removed. --- lib/services/access_list.go | 2 ++ lib/services/access_request.go | 1 + lib/services/app.go | 2 ++ lib/services/audit.go | 1 + lib/services/authority.go | 1 + lib/services/clustername.go | 1 + lib/services/connection_diagnostic.go | 1 + lib/services/database.go | 1 + lib/services/databaseserver.go | 1 + lib/services/databaseservice.go | 1 + lib/services/desktop.go | 2 ++ lib/services/github.go | 1 + lib/services/installer.go | 1 + lib/services/integration.go | 1 + lib/services/kubernetes.go | 2 ++ lib/services/license.go | 1 + lib/services/lock.go | 1 + lib/services/namespace.go | 1 + lib/services/networking.go | 1 + lib/services/oidc.go | 1 + lib/services/okta.go | 2 ++ lib/services/plugin_static_credentials.go | 1 + lib/services/plugins.go | 1 + lib/services/provisioning.go | 1 + lib/services/remotecluster.go | 1 + lib/services/restrictions.go | 1 + lib/services/role.go | 1 + lib/services/saml.go | 1 + lib/services/saml_idp_service_provider.go | 1 + lib/services/semaphore.go | 1 + lib/services/server.go | 1 + lib/services/server_info.go | 1 + lib/services/session.go | 2 ++ lib/services/sessionrecording.go | 1 + lib/services/statictokens.go | 1 + lib/services/trustedcluster.go | 1 + lib/services/tunnel.go | 1 + lib/services/tunnelconn.go | 1 + lib/services/ui_config.go | 1 + lib/services/user.go | 1 + lib/services/usergroup.go | 1 + 41 files changed, 47 insertions(+) diff --git a/lib/services/access_list.go b/lib/services/access_list.go index 1751d4e095526..3642364cd79f5 100644 --- a/lib/services/access_list.go +++ b/lib/services/access_list.go @@ -72,6 +72,7 @@ func MarshalAccessList(accessList *accesslist.AccessList, opts ...MarshalOption) if !cfg.PreserveResourceID { copy := *accessList copy.SetResourceID(0) + copy.SetRevision("") accessList = © } return utils.FastMarshal(accessList) @@ -141,6 +142,7 @@ func MarshalAccessListMember(member *accesslist.AccessListMember, opts ...Marsha if !cfg.PreserveResourceID { copy := *member copy.SetResourceID(0) + copy.SetRevision("") member = © } return utils.FastMarshal(member) diff --git a/lib/services/access_request.go b/lib/services/access_request.go index a04df5d3aa297..dc1404768bc94 100644 --- a/lib/services/access_request.go +++ b/lib/services/access_request.go @@ -1595,6 +1595,7 @@ func MarshalAccessRequest(accessRequest types.AccessRequest, opts ...MarshalOpti // to prevent unexpected data races copy := *accessRequest copy.SetResourceID(0) + copy.SetRevision("") accessRequest = © } return utils.FastMarshal(accessRequest) diff --git a/lib/services/app.go b/lib/services/app.go index 6205b7436ead6..27b21a2fdd19f 100644 --- a/lib/services/app.go +++ b/lib/services/app.go @@ -67,6 +67,7 @@ func MarshalApp(app types.Application, opts ...MarshalOption) ([]byte, error) { if !cfg.PreserveResourceID { copy := *app copy.SetResourceID(0) + copy.SetRevision("") app = © } return utils.FastMarshal(app) @@ -127,6 +128,7 @@ func MarshalAppServer(appServer types.AppServer, opts ...MarshalOption) ([]byte, if !cfg.PreserveResourceID { copy := *appServer copy.SetResourceID(0) + copy.SetRevision("") appServer = © } return utils.FastMarshal(appServer) diff --git a/lib/services/audit.go b/lib/services/audit.go index f22d479336ec5..e84afea75eeec 100644 --- a/lib/services/audit.go +++ b/lib/services/audit.go @@ -86,6 +86,7 @@ func MarshalClusterAuditConfig(auditConfig types.ClusterAuditConfig, opts ...Mar // to prevent unexpected data races copy := *auditConfig copy.SetResourceID(0) + copy.SetRevision("") auditConfig = © } return utils.FastMarshal(auditConfig) diff --git a/lib/services/authority.go b/lib/services/authority.go index 4d30de788c89e..3bc699cac847a 100644 --- a/lib/services/authority.go +++ b/lib/services/authority.go @@ -512,6 +512,7 @@ func MarshalCertAuthority(certAuthority types.CertAuthority, opts ...MarshalOpti // to prevent unexpected data races copy := *certAuthority copy.SetResourceID(0) + copy.SetRevision("") certAuthority = © } return utils.FastMarshal(certAuthority) diff --git a/lib/services/clustername.go b/lib/services/clustername.go index a7612afc11d8d..2dbda8ad5d0d7 100644 --- a/lib/services/clustername.go +++ b/lib/services/clustername.go @@ -86,6 +86,7 @@ func MarshalClusterName(clusterName types.ClusterName, opts ...MarshalOption) ([ // to prevent unexpected data races copy := *clusterName copy.SetResourceID(0) + copy.SetRevision("") clusterName = © } return utils.FastMarshal(clusterName) diff --git a/lib/services/connection_diagnostic.go b/lib/services/connection_diagnostic.go index ed5bcb61ccf50..6b185818a91df 100644 --- a/lib/services/connection_diagnostic.go +++ b/lib/services/connection_diagnostic.go @@ -66,6 +66,7 @@ func MarshalConnectionDiagnostic(s types.ConnectionDiagnostic, opts ...MarshalOp // to prevent unexpected data races copy := *s copy.SetResourceID(0) + copy.SetRevision("") s = © } diff --git a/lib/services/database.go b/lib/services/database.go index 587da7e8b7f20..8ba97583e507d 100644 --- a/lib/services/database.go +++ b/lib/services/database.go @@ -97,6 +97,7 @@ func MarshalDatabase(database types.Database, opts ...MarshalOption) ([]byte, er // to prevent unexpected data races copy := *database copy.SetResourceID(0) + copy.SetRevision("") database = © } return utils.FastMarshal(database) diff --git a/lib/services/databaseserver.go b/lib/services/databaseserver.go index 90b7b9d167d21..2a4fe31dceaa5 100644 --- a/lib/services/databaseserver.go +++ b/lib/services/databaseserver.go @@ -41,6 +41,7 @@ func MarshalDatabaseServer(databaseServer types.DatabaseServer, opts ...MarshalO // to prevent unexpected data races copy := *databaseServer copy.SetResourceID(0) + copy.SetRevision("") databaseServer = © } return utils.FastMarshal(databaseServer) diff --git a/lib/services/databaseservice.go b/lib/services/databaseservice.go index 2237fd1a2769b..f6e37ca1abef1 100644 --- a/lib/services/databaseservice.go +++ b/lib/services/databaseservice.go @@ -55,6 +55,7 @@ func MarshalDatabaseService(databaseService types.DatabaseService, opts ...Marsh // to prevent unexpected data races copy := *databaseService copy.SetResourceID(0) + copy.SetRevision("") databaseService = © } return utils.FastMarshal(databaseService) diff --git a/lib/services/desktop.go b/lib/services/desktop.go index 318db3071c63a..8f289ad12195f 100644 --- a/lib/services/desktop.go +++ b/lib/services/desktop.go @@ -60,6 +60,7 @@ func MarshalWindowsDesktop(s types.WindowsDesktop, opts ...MarshalOption) ([]byt // to prevent unexpected data races copy := *s copy.SetResourceID(0) + copy.SetRevision("") s = © } return utils.FastMarshal(s) @@ -122,6 +123,7 @@ func MarshalWindowsDesktopService(s types.WindowsDesktopService, opts ...Marshal // to prevent unexpected data races copy := *s copy.SetResourceID(0) + copy.SetRevision("") s = © } return utils.FastMarshal(s) diff --git a/lib/services/github.go b/lib/services/github.go index 8cacbea854737..c05b37f1db9fa 100644 --- a/lib/services/github.go +++ b/lib/services/github.go @@ -167,6 +167,7 @@ func marshalGithubConnector(githubConnector types.GithubConnector, opts ...Marsh // to prevent unexpected data races copy := *githubConnector copy.SetResourceID(0) + copy.SetRevision("") githubConnector = © } return utils.FastMarshal(githubConnector) diff --git a/lib/services/installer.go b/lib/services/installer.go index a6e35e686f0c6..24492972ca9ea 100644 --- a/lib/services/installer.go +++ b/lib/services/installer.go @@ -71,6 +71,7 @@ func MarshalInstaller(installer types.Installer, opts ...MarshalOption) ([]byte, // to prevent unexpected data races copy := *installer copy.SetResourceID(0) + copy.SetRevision("") installer = © } return utils.FastMarshal(installer) diff --git a/lib/services/integration.go b/lib/services/integration.go index b9c35f88e09ec..f65ae7e510a06 100644 --- a/lib/services/integration.go +++ b/lib/services/integration.go @@ -62,6 +62,7 @@ func MarshalIntegration(ig types.Integration, opts ...MarshalOption) ([]byte, er if !cfg.PreserveResourceID { copy := *g copy.SetResourceID(0) + copy.SetRevision("") g = © } return utils.FastMarshal(g) diff --git a/lib/services/kubernetes.go b/lib/services/kubernetes.go index e4198c71e4681..cff01d058c5d3 100644 --- a/lib/services/kubernetes.go +++ b/lib/services/kubernetes.go @@ -77,6 +77,7 @@ func MarshalKubeServer(kubeServer types.KubeServer, opts ...MarshalOption) ([]by if !cfg.PreserveResourceID { copy := *server copy.SetResourceID(0) + copy.SetRevision("") server = © } return utils.FastMarshal(server) @@ -137,6 +138,7 @@ func MarshalKubeCluster(kubeCluster types.KubeCluster, opts ...MarshalOption) ([ if !cfg.PreserveResourceID { copy := *cluster copy.SetResourceID(0) + copy.SetRevision("") cluster = © } return utils.FastMarshal(cluster) diff --git a/lib/services/license.go b/lib/services/license.go index e8a84228fa222..f1195a8ddd438 100644 --- a/lib/services/license.go +++ b/lib/services/license.go @@ -64,6 +64,7 @@ func MarshalLicense(license types.License, opts ...MarshalOption) ([]byte, error // to prevent unexpected data races copy := *license copy.SetResourceID(0) + copy.SetRevision("") license = © } return utils.FastMarshal(license) diff --git a/lib/services/lock.go b/lib/services/lock.go index 5ca133694045d..10273502d8b22 100644 --- a/lib/services/lock.go +++ b/lib/services/lock.go @@ -126,6 +126,7 @@ func MarshalLock(lock types.Lock, opts ...MarshalOption) ([]byte, error) { // to prevent unexpected data races copy := *lock copy.SetResourceID(0) + copy.SetRevision("") lock = © } return utils.FastMarshal(lock) diff --git a/lib/services/namespace.go b/lib/services/namespace.go index 6f05a0762136a..9cf88a73a5d7a 100644 --- a/lib/services/namespace.go +++ b/lib/services/namespace.go @@ -38,6 +38,7 @@ func MarshalNamespace(resource types.Namespace, opts ...MarshalOption) ([]byte, // to prevent unexpected data races copy := resource copy.SetResourceID(0) + copy.SetRevision("") resource = copy } return utils.FastMarshal(resource) diff --git a/lib/services/networking.go b/lib/services/networking.go index becee01f216c8..25af65331e8da 100644 --- a/lib/services/networking.go +++ b/lib/services/networking.go @@ -75,6 +75,7 @@ func MarshalClusterNetworkingConfig(netConfig types.ClusterNetworkingConfig, opt // to prevent unexpected data races copy := *netConfig copy.SetResourceID(0) + copy.SetRevision("") netConfig = © } return utils.FastMarshal(netConfig) diff --git a/lib/services/oidc.go b/lib/services/oidc.go index 19bf932e7dc77..062537c25ac96 100644 --- a/lib/services/oidc.go +++ b/lib/services/oidc.go @@ -153,6 +153,7 @@ func MarshalOIDCConnector(oidcConnector types.OIDCConnector, opts ...MarshalOpti // to prevent unexpected data races copy := *oidcConnector copy.SetResourceID(0) + copy.SetRevision("") oidcConnector = © } return utils.FastMarshal(oidcConnector) diff --git a/lib/services/okta.go b/lib/services/okta.go index 0ed3488bf137a..9ebbcbe37ad9c 100644 --- a/lib/services/okta.go +++ b/lib/services/okta.go @@ -94,6 +94,7 @@ func MarshalOktaImportRule(importRule types.OktaImportRule, opts ...MarshalOptio if !cfg.PreserveResourceID { copy := *i copy.SetResourceID(0) + copy.SetRevision("") i = © } return utils.FastMarshal(i) @@ -154,6 +155,7 @@ func MarshalOktaAssignment(assignment types.OktaAssignment, opts ...MarshalOptio if !cfg.PreserveResourceID { copy := *a copy.SetResourceID(0) + copy.SetRevision("") a = © } return utils.FastMarshal(a) diff --git a/lib/services/plugin_static_credentials.go b/lib/services/plugin_static_credentials.go index 72400f6004a90..35b6843f50a4b 100644 --- a/lib/services/plugin_static_credentials.go +++ b/lib/services/plugin_static_credentials.go @@ -55,6 +55,7 @@ func MarshalPluginStaticCredentials(pluginStaticCredentials types.PluginStaticCr if !cfg.PreserveResourceID { copy := *pluginStaticCredentials copy.SetResourceID(0) + copy.SetRevision("") pluginStaticCredentials = © } data, err := protojson.Marshal(protoadapt.MessageV2Of(pluginStaticCredentials)) diff --git a/lib/services/plugins.go b/lib/services/plugins.go index f74e46fbaf770..f4216c76cfeed 100644 --- a/lib/services/plugins.go +++ b/lib/services/plugins.go @@ -54,6 +54,7 @@ func MarshalPlugin(plugin types.Plugin, opts ...MarshalOption) ([]byte, error) { if !cfg.PreserveResourceID { copy := *plugin copy.SetResourceID(0) + copy.SetRevision("") plugin = © } var buf bytes.Buffer diff --git a/lib/services/provisioning.go b/lib/services/provisioning.go index 6a554d2057f5d..6a6247a0a3223 100644 --- a/lib/services/provisioning.go +++ b/lib/services/provisioning.go @@ -127,6 +127,7 @@ func MarshalProvisionToken(provisionToken types.ProvisionToken, opts ...MarshalO // to prevent unexpected data races copy := *provisionToken copy.SetResourceID(0) + copy.SetRevision("") provisionToken = © } if cfg.GetVersion() == types.V1 { diff --git a/lib/services/remotecluster.go b/lib/services/remotecluster.go index fcd9c8171998a..4d7aef5571f99 100644 --- a/lib/services/remotecluster.go +++ b/lib/services/remotecluster.go @@ -76,6 +76,7 @@ func MarshalRemoteCluster(remoteCluster types.RemoteCluster, opts ...MarshalOpti // to prevent unexpected data races copy := *remoteCluster copy.SetResourceID(0) + copy.SetRevision("") remoteCluster = © } return utils.FastMarshal(remoteCluster) diff --git a/lib/services/restrictions.go b/lib/services/restrictions.go index 5024b4f8c556e..2435e0fdc2467 100644 --- a/lib/services/restrictions.go +++ b/lib/services/restrictions.go @@ -96,6 +96,7 @@ func MarshalNetworkRestrictions(restrictions types.NetworkRestrictions, opts ... // to prevent unexpected data races copy := *restrictions copy.SetResourceID(0) + copy.SetRevision("") restrictions = © } return utils.FastMarshal(restrictions) diff --git a/lib/services/role.go b/lib/services/role.go index 9f5370bb84141..754ba22ebefdc 100644 --- a/lib/services/role.go +++ b/lib/services/role.go @@ -3164,6 +3164,7 @@ func MarshalRole(role types.Role, opts ...MarshalOption) ([]byte, error) { // to prevent unexpected data races copy := *role copy.SetResourceID(0) + copy.SetRevision("") role = © } return utils.FastMarshal(role) diff --git a/lib/services/saml.go b/lib/services/saml.go index b756795516bc4..9d8132287781a 100644 --- a/lib/services/saml.go +++ b/lib/services/saml.go @@ -330,6 +330,7 @@ func MarshalSAMLConnector(samlConnector types.SAMLConnector, opts ...MarshalOpti // to prevent unexpected data races copy := *samlConnector copy.SetResourceID(0) + copy.SetRevision("") samlConnector = © } return utils.FastMarshal(samlConnector) diff --git a/lib/services/saml_idp_service_provider.go b/lib/services/saml_idp_service_provider.go index ad146a1d7538a..8f0bd379b8c35 100644 --- a/lib/services/saml_idp_service_provider.go +++ b/lib/services/saml_idp_service_provider.go @@ -62,6 +62,7 @@ func MarshalSAMLIdPServiceProvider(serviceProvider types.SAMLIdPServiceProvider, if !cfg.PreserveResourceID { copy := *sp copy.SetResourceID(0) + copy.SetRevision("") sp = © } return utils.FastMarshal(sp) diff --git a/lib/services/semaphore.go b/lib/services/semaphore.go index 837bbf00c1b68..653225518a0d6 100644 --- a/lib/services/semaphore.go +++ b/lib/services/semaphore.go @@ -328,6 +328,7 @@ func MarshalSemaphore(semaphore types.Semaphore, opts ...MarshalOption) ([]byte, // to prevent unexpected data races copy := *semaphore copy.SetResourceID(0) + copy.SetRevision("") semaphore = © } return utils.FastMarshal(semaphore) diff --git a/lib/services/server.go b/lib/services/server.go index cb8564a585baf..b02b8291aacb5 100644 --- a/lib/services/server.go +++ b/lib/services/server.go @@ -397,6 +397,7 @@ func MarshalServer(server types.Server, opts ...MarshalOption) ([]byte, error) { // to prevent unexpected data races copy := *server copy.SetResourceID(0) + copy.SetRevision("") server = © } return utils.FastMarshal(server) diff --git a/lib/services/server_info.go b/lib/services/server_info.go index 1462fdc406f3d..13e0859b3ea65 100644 --- a/lib/services/server_info.go +++ b/lib/services/server_info.go @@ -76,6 +76,7 @@ func MarshalServerInfo(si types.ServerInfo, opts ...MarshalOption) ([]byte, erro // to prevent unexpected data races copy := *si copy.SetResourceID(0) + copy.SetRevision("") si = © } bytes, err := utils.FastMarshal(si) diff --git a/lib/services/session.go b/lib/services/session.go index 3643038a18906..aedb735526a01 100644 --- a/lib/services/session.go +++ b/lib/services/session.go @@ -83,6 +83,7 @@ func MarshalWebSession(webSession types.WebSession, opts ...MarshalOption) ([]by // to prevent unexpected data races copy := *webSession copy.SetResourceID(0) + copy.SetRevision("") webSession = © } return utils.FastMarshal(webSession) @@ -109,6 +110,7 @@ func MarshalWebToken(webToken types.WebToken, opts ...MarshalOption) ([]byte, er // to prevent unexpected data races copy := *webToken copy.SetResourceID(0) + copy.SetRevision("") webToken = © } return utils.FastMarshal(webToken) diff --git a/lib/services/sessionrecording.go b/lib/services/sessionrecording.go index d3348fb924660..0d5b0a91caa2a 100644 --- a/lib/services/sessionrecording.go +++ b/lib/services/sessionrecording.go @@ -87,6 +87,7 @@ func MarshalSessionRecordingConfig(recConfig types.SessionRecordingConfig, opts // to prevent unexpected data races copy := *recConfig copy.SetResourceID(0) + copy.SetRevision("") recConfig = © } return utils.FastMarshal(recConfig) diff --git a/lib/services/statictokens.go b/lib/services/statictokens.go index 16d1a25b72985..bfaa6a407f66e 100644 --- a/lib/services/statictokens.go +++ b/lib/services/statictokens.go @@ -73,6 +73,7 @@ func MarshalStaticTokens(staticToken types.StaticTokens, opts ...MarshalOption) // to prevent unexpected data races copy := *staticToken copy.SetResourceID(0) + copy.SetRevision("") staticToken = © } return utils.FastMarshal(staticToken) diff --git a/lib/services/trustedcluster.go b/lib/services/trustedcluster.go index de1585b6820c9..fbbe2aa569d18 100644 --- a/lib/services/trustedcluster.go +++ b/lib/services/trustedcluster.go @@ -192,6 +192,7 @@ func MarshalTrustedCluster(trustedCluster types.TrustedCluster, opts ...MarshalO // to prevent unexpected data races copy := *trustedCluster copy.SetResourceID(0) + copy.SetRevision("") trustedCluster = © } return utils.FastMarshal(trustedCluster) diff --git a/lib/services/tunnel.go b/lib/services/tunnel.go index 42d58854c1791..5ac6c1ef5fdf9 100644 --- a/lib/services/tunnel.go +++ b/lib/services/tunnel.go @@ -94,6 +94,7 @@ func MarshalReverseTunnel(reverseTunnel types.ReverseTunnel, opts ...MarshalOpti // to prevent unexpected data races copy := *reverseTunnel copy.SetResourceID(0) + copy.SetRevision("") reverseTunnel = © } return utils.FastMarshal(reverseTunnel) diff --git a/lib/services/tunnelconn.go b/lib/services/tunnelconn.go index 0a636b35a6b12..e59be870d8910 100644 --- a/lib/services/tunnelconn.go +++ b/lib/services/tunnelconn.go @@ -111,6 +111,7 @@ func MarshalTunnelConnection(tunnelConnection types.TunnelConnection, opts ...Ma // to prevent unexpected data races copy := *tunnelConnection copy.SetResourceID(0) + copy.SetRevision("") tunnelConnection = © } return utils.FastMarshal(tunnelConnection) diff --git a/lib/services/ui_config.go b/lib/services/ui_config.go index cc5d717167e2e..2f5afa78725c7 100644 --- a/lib/services/ui_config.go +++ b/lib/services/ui_config.go @@ -70,6 +70,7 @@ func MarshalUIConfig(uiconfig types.UIConfig, opts ...MarshalOption) ([]byte, er // to prevent unexpected data races copy := *uiconfig copy.SetResourceID(0) + copy.SetRevision("") uiconfig = © } return utils.FastMarshal(uiconfig) diff --git a/lib/services/user.go b/lib/services/user.go index f54205687919d..5df4c52fac536 100644 --- a/lib/services/user.go +++ b/lib/services/user.go @@ -135,6 +135,7 @@ func MarshalUser(user types.User, opts ...MarshalOption) ([]byte, error) { // to prevent unexpected data races copy := *user copy.SetResourceID(0) + copy.SetRevision("") user = © } return utils.FastMarshal(user) diff --git a/lib/services/usergroup.go b/lib/services/usergroup.go index 536787ea63e67..5a3a32c7322cc 100644 --- a/lib/services/usergroup.go +++ b/lib/services/usergroup.go @@ -57,6 +57,7 @@ func MarshalUserGroup(group types.UserGroup, opts ...MarshalOption) ([]byte, err if !cfg.PreserveResourceID { copy := *g copy.SetResourceID(0) + copy.SetRevision("") g = © } return utils.FastMarshal(g) From 542ea2c83352000d5e93e1a231620b15e77fdf0a Mon Sep 17 00:00:00 2001 From: Tim Ross Date: Wed, 20 Sep 2023 12:38:46 -0400 Subject: [PATCH 3/3] Ignore revision in resource comparisons --- lib/auth/apiserver_test.go | 2 +- lib/auth/auth_with_roles_test.go | 34 ++++++----- lib/auth/grpcserver_test.go | 54 ++++++++-------- lib/auth/init_test.go | 2 +- lib/auth/okta/service_test.go | 14 ++--- lib/auth/tls_test.go | 15 +++-- lib/auth/trust/trustv1/service_test.go | 6 +- lib/auth/trustedcluster_test.go | 15 ++--- lib/auth/userloginstate/service_test.go | 2 +- lib/authz/permissions_test.go | 2 +- lib/cache/cache_test.go | 44 +++++-------- lib/kube/proxy/watcher_test.go | 16 ++--- lib/services/authority.go | 2 +- lib/services/compare.go | 2 +- lib/services/local/access_list_test.go | 6 +- lib/services/local/access_test.go | 12 ++-- lib/services/local/apps_test.go | 8 +-- lib/services/local/databases_test.go | 8 +-- lib/services/local/desktops_test.go | 2 +- lib/services/local/generic/generic_test.go | 20 +++--- lib/services/local/kube_test.go | 8 +-- lib/services/local/okta_test.go | 30 ++++----- .../local/plugin_static_credentials_test.go | 8 +-- lib/services/local/plugins_test.go | 12 ++-- lib/services/local/presence_test.go | 21 +++---- lib/services/local/resource_test.go | 6 +- .../local/saml_idp_service_provider_test.go | 10 +-- lib/services/local/user_login_state_test.go | 2 +- lib/services/local/usergroup_test.go | 10 +-- lib/services/local/users_test.go | 5 +- lib/services/suite/suite.go | 61 +++++++------------ lib/services/unified_resource_test.go | 6 +- lib/services/user.go | 2 +- lib/services/watcher_test.go | 10 +-- lib/srv/app/server_test.go | 2 +- lib/srv/app/watcher_test.go | 16 ++--- lib/srv/db/watcher_test.go | 2 +- lib/srv/discovery/discovery_test.go | 2 +- tool/tctl/common/resource_command_test.go | 10 +-- 39 files changed, 232 insertions(+), 257 deletions(-) diff --git a/lib/auth/apiserver_test.go b/lib/auth/apiserver_test.go index 6a89bcf783db4..85a50df1d7eea 100644 --- a/lib/auth/apiserver_test.go +++ b/lib/auth/apiserver_test.go @@ -135,7 +135,7 @@ func TestUpsertServer(t *testing.T) { addServers(s.GetAuthServers()) addServers(s.GetNodes(ctx, apidefaults.Namespace)) addServers(s.GetProxies()) - require.Empty(t, cmp.Diff(allServers, []types.Server{tt.wantServer}, cmpopts.IgnoreFields(types.Metadata{}, "ID"))) + require.Empty(t, cmp.Diff(allServers, []types.Server{tt.wantServer}, cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) }) } } diff --git a/lib/auth/auth_with_roles_test.go b/lib/auth/auth_with_roles_test.go index 4c812d35797e3..0039db02d2871 100644 --- a/lib/auth/auth_with_roles_test.go +++ b/lib/auth/auth_with_roles_test.go @@ -37,6 +37,7 @@ import ( "github.com/pquerna/otp/totp" "github.com/sirupsen/logrus" "github.com/stretchr/testify/require" + "golang.org/x/exp/slices" "github.com/gravitational/teleport" "github.com/gravitational/teleport/api" @@ -1782,33 +1783,33 @@ func TestDatabasesCRUDRBAC(t *testing.T) { db, err := devClt.GetDatabase(ctx, devDatabase.GetName()) require.NoError(t, err) require.Empty(t, cmp.Diff(devDatabase, db, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Admin can get both databases. db, err = adminClt.GetDatabase(ctx, adminDatabase.GetName()) require.NoError(t, err) require.Empty(t, cmp.Diff(adminDatabase, db, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) db, err = adminClt.GetDatabase(ctx, devDatabase.GetName()) require.NoError(t, err) require.Empty(t, cmp.Diff(devDatabase, db, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // When listing databases, dev should only see one. dbs, err := devClt.GetDatabases(ctx) require.NoError(t, err) require.Empty(t, cmp.Diff([]types.Database{devDatabase}, dbs, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Admin should see both. dbs, err = adminClt.GetDatabases(ctx) require.NoError(t, err) require.Empty(t, cmp.Diff([]types.Database{adminDatabase, devDatabase}, dbs, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Dev shouldn't be able to delete dev database... @@ -1902,7 +1903,7 @@ func mustGetDatabases(t *testing.T, client *Client, wantDatabases []types.Databa require.NoError(t, err) require.Empty(t, cmp.Diff(wantDatabases, actualDatabases, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), cmpopts.EquateEmpty(), )) } @@ -1957,7 +1958,7 @@ func TestKubernetesClusterCRUD_DiscoveryService(t *testing.T) { t.Run("Read", func(t *testing.T) { clusters, err := discoveryClt.GetKubernetesClusters(ctx) require.NoError(t, err) - require.Empty(t, cmp.Diff([]types.KubeCluster{eksCluster}, clusters)) + require.Empty(t, cmp.Diff([]types.KubeCluster{eksCluster}, clusters, cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) }) t.Run("Update", func(t *testing.T) { require.NoError(t, discoveryClt.UpdateKubernetesCluster(ctx, eksCluster)) @@ -2480,33 +2481,33 @@ func TestApps(t *testing.T) { app, err := devClt.GetApp(ctx, devApp.GetName()) require.NoError(t, err) require.Empty(t, cmp.Diff(devApp, app, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Admin can get both apps. app, err = adminClt.GetApp(ctx, adminApp.GetName()) require.NoError(t, err) require.Empty(t, cmp.Diff(adminApp, app, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) app, err = adminClt.GetApp(ctx, devApp.GetName()) require.NoError(t, err) require.Empty(t, cmp.Diff(devApp, app, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // When listing apps, dev should only see one. apps, err := devClt.GetApps(ctx) require.NoError(t, err) require.Empty(t, cmp.Diff([]types.Application{devApp}, apps, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Admin should see both. apps, err = adminClt.GetApps(ctx) require.NoError(t, err) require.Empty(t, cmp.Diff([]types.Application{adminApp, devApp}, apps, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Dev shouldn't be able to delete dev app... @@ -2531,7 +2532,7 @@ func TestApps(t *testing.T) { apps, err = adminClt.GetApps(ctx) require.NoError(t, err) require.Empty(t, cmp.Diff([]types.Application{adminApp}, apps, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Admin should be able to delete all. @@ -3609,7 +3610,10 @@ func TestListResources_KindUserGroup(t *testing.T) { userGroups, err := types.ResourcesWithLabels(res.Resources).AsUserGroups() require.NoError(t, err) - require.ElementsMatch(t, []types.UserGroup{testUg1, testUg2, testUg3}, userGroups) + slices.SortFunc(userGroups, func(a, b types.UserGroup) int { + return strings.Compare(a.GetName(), b.GetName()) + }) + require.Empty(t, cmp.Diff([]types.UserGroup{testUg2, testUg3, testUg1}, userGroups, cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) }) t.Run("start keys", func(t *testing.T) { @@ -6378,7 +6382,7 @@ func TestCreateAccessRequest(t *testing.T) { // We have to ignore the name here, as it's auto-generated by the underlying access request // logic. require.Empty(t, cmp.Diff(test.expected, accessRequests[0], - cmpopts.IgnoreFields(types.Metadata{}, "Name", "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "Name", "ID", "Revision"), cmpopts.IgnoreFields(types.AccessRequestSpecV3{}), )) }) diff --git a/lib/auth/grpcserver_test.go b/lib/auth/grpcserver_test.go index 462822c73f08c..b9d70a3d4af60 100644 --- a/lib/auth/grpcserver_test.go +++ b/lib/auth/grpcserver_test.go @@ -2454,7 +2454,7 @@ func TestNodesCRUD(t *testing.T) { require.NoError(t, err) require.Len(t, nodes, 2) require.Empty(t, cmp.Diff([]types.Server{node1, node2}, nodes, - cmpopts.IgnoreFields(types.Metadata{}, "ID"))) + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) // GetNodes should not fail if namespace is empty _, err = clt.GetNodes(ctx, "") @@ -2466,7 +2466,7 @@ func TestNodesCRUD(t *testing.T) { node, err := clt.GetNode(ctx, apidefaults.Namespace, "node1") require.NoError(t, err) require.Empty(t, cmp.Diff(node1, node, - cmpopts.IgnoreFields(types.Metadata{}, "ID"))) + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) // GetNode should fail if node name isn't provided _, err = clt.GetNode(ctx, apidefaults.Namespace, "") @@ -2565,7 +2565,7 @@ func TestLocksCRUD(t *testing.T) { require.NoError(t, err) require.Len(t, locks, 2) require.Empty(t, cmp.Diff([]types.Lock{lock1, lock2}, locks, - cmpopts.IgnoreFields(types.Metadata{}, "ID"))) + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) }) t.Run("GetLocks with targets", func(t *testing.T) { t.Parallel() @@ -2574,7 +2574,7 @@ func TestLocksCRUD(t *testing.T) { require.NoError(t, err) require.Len(t, locks, 2) require.Empty(t, cmp.Diff([]types.Lock{lock1, lock2}, locks, - cmpopts.IgnoreFields(types.Metadata{}, "ID"))) + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) // Match only one of the locks. roleTarget := types.LockTarget{Role: "role-A"} @@ -2582,7 +2582,7 @@ func TestLocksCRUD(t *testing.T) { require.NoError(t, err) require.Len(t, locks, 1) require.Empty(t, cmp.Diff([]types.Lock{lock1}, locks, - cmpopts.IgnoreFields(types.Metadata{}, "ID"))) + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) // Match none of the locks. locks, err = clt.GetLocks(ctx, false, roleTarget) @@ -2595,7 +2595,7 @@ func TestLocksCRUD(t *testing.T) { lock, err := clt.GetLock(ctx, lock1.GetName()) require.NoError(t, err) require.Empty(t, cmp.Diff(lock1, lock, - cmpopts.IgnoreFields(types.Metadata{}, "ID"))) + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) // Attempt to get a nonexistent lock. _, err = clt.GetLock(ctx, "lock3") @@ -2675,7 +2675,7 @@ func TestApplicationServersCRUD(t *testing.T) { out, err = clt.GetApplicationServers(ctx, apidefaults.Namespace) require.NoError(t, err) require.Empty(t, cmp.Diff([]types.AppServer{server1, server2, server3}, out, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Update an app server. @@ -2685,7 +2685,7 @@ func TestApplicationServersCRUD(t *testing.T) { out, err = clt.GetApplicationServers(ctx, apidefaults.Namespace) require.NoError(t, err) require.Empty(t, cmp.Diff([]types.AppServer{server1, server2, server3}, out, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Delete an app server. @@ -2694,7 +2694,7 @@ func TestApplicationServersCRUD(t *testing.T) { out, err = clt.GetApplicationServers(ctx, apidefaults.Namespace) require.NoError(t, err) require.Empty(t, cmp.Diff([]types.AppServer{server2, server3}, out, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Delete all app servers. @@ -2745,14 +2745,14 @@ func TestAppsCRUD(t *testing.T) { out, err = clt.GetApps(ctx) require.NoError(t, err) require.Empty(t, cmp.Diff([]types.Application{app1, app2}, out, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Fetch a specific app. app, err := clt.GetApp(ctx, app2.GetName()) require.NoError(t, err) require.Empty(t, cmp.Diff(app2, app, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Try to fetch an app that doesn't exist. @@ -2770,7 +2770,7 @@ func TestAppsCRUD(t *testing.T) { app, err = clt.GetApp(ctx, app1.GetName()) require.NoError(t, err) require.Empty(t, cmp.Diff(app1, app, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Delete an app. @@ -2779,7 +2779,7 @@ func TestAppsCRUD(t *testing.T) { out, err = clt.GetApps(ctx) require.NoError(t, err) require.Empty(t, cmp.Diff([]types.Application{app2}, out, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Try to delete an app that doesn't exist. @@ -2826,7 +2826,7 @@ func TestAppServersCRUD(t *testing.T) { appServer := resources.Resources[0].(types.AppServer) require.Empty(t, cmp.Diff(appServer, appServer1, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) require.NoError(t, clt.DeleteApplicationServer(ctx, apidefaults.Namespace, "hostID", appServer1.GetName())) @@ -2879,7 +2879,7 @@ func TestAppServersCRUD(t *testing.T) { app2.SetOrigin(types.OriginOkta) appServer = resources.Resources[0].(types.AppServer) require.Empty(t, cmp.Diff(appServer, appServer2, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) require.NoError(t, clt.DeleteApplicationServer(ctx, apidefaults.Namespace, "hostID", appServer2.GetName())) @@ -2934,14 +2934,14 @@ func TestDatabasesCRUD(t *testing.T) { out, err = clt.GetDatabases(ctx) require.NoError(t, err) require.Empty(t, cmp.Diff([]types.Database{db1, db2}, out, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Fetch a specific database. db, err := clt.GetDatabase(ctx, db2.GetName()) require.NoError(t, err) require.Empty(t, cmp.Diff(db2, db, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Try to fetch a database that doesn't exist. @@ -2959,7 +2959,7 @@ func TestDatabasesCRUD(t *testing.T) { db, err = clt.GetDatabase(ctx, db1.GetName()) require.NoError(t, err) require.Empty(t, cmp.Diff(db1, db, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Delete a database. @@ -2968,7 +2968,7 @@ func TestDatabasesCRUD(t *testing.T) { out, err = clt.GetDatabases(ctx) require.NoError(t, err) require.Empty(t, cmp.Diff([]types.Database{db2}, out, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Try to delete a database that doesn't exist. @@ -3050,7 +3050,7 @@ func TestDatabaseServicesCRUD(t *testing.T) { out, err = types.ResourcesWithLabels(listServicesResp.Resources).AsDatabaseServices() require.NoError(t, err) require.Empty(t, cmp.Diff([]types.DatabaseService{db1, db2}, out, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Update a DatabaseService. @@ -3072,7 +3072,7 @@ func TestDatabaseServicesCRUD(t *testing.T) { out, err = types.ResourcesWithLabels(listServicesResp.Resources).AsDatabaseServices() require.NoError(t, err) require.Empty(t, cmp.Diff([]types.DatabaseService{db1, db2}, out, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Delete a DatabaseService. @@ -3088,7 +3088,7 @@ func TestDatabaseServicesCRUD(t *testing.T) { out, err = types.ResourcesWithLabels(listServicesResp.Resources).AsDatabaseServices() require.NoError(t, err) require.Empty(t, cmp.Diff([]types.DatabaseService{db2}, out, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Try to delete a DatabaseService that doesn't exist. @@ -3151,7 +3151,7 @@ func TestServerInfoCRUD(t *testing.T) { } requireResourcesEqual := func(t *testing.T, expected, actual interface{}) { - require.Empty(t, cmp.Diff(expected, actual, cmpopts.IgnoreFields(types.Metadata{}, "ID"))) + require.Empty(t, cmp.Diff(expected, actual, cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) } t.Run("ServerInfoGetters", func(t *testing.T) { @@ -3253,7 +3253,7 @@ func TestSAMLIdPServiceProvidersCRUD(t *testing.T) { require.NoError(t, err) require.Empty(t, nextKey) require.Empty(t, cmp.Diff([]types.SAMLIdPServiceProvider{sp1, sp2}, listResp, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Update a service provider. @@ -3266,7 +3266,7 @@ func TestSAMLIdPServiceProvidersCRUD(t *testing.T) { require.NoError(t, err) require.Empty(t, nextKey) require.Empty(t, cmp.Diff([]types.SAMLIdPServiceProvider{sp1, sp2}, listResp, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Delete a service provider. @@ -3276,7 +3276,7 @@ func TestSAMLIdPServiceProvidersCRUD(t *testing.T) { require.NoError(t, err) require.Empty(t, nextKey) require.Empty(t, cmp.Diff([]types.SAMLIdPServiceProvider{sp2}, listResp, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Try to delete a service provider that doesn't exist. @@ -4174,7 +4174,7 @@ func TestRoleVersions(t *testing.T) { return } require.Empty(t, cmp.Diff(tc.expectedRole, gotRole, - cmpopts.IgnoreFields(types.RoleV6{}, "Metadata.ID", "Metadata.Labels"))) + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision", "Labels"))) // The downgraded label value won't match exactly because it // includes the client version, so just check it's not empty // and ignore it in the role diff. diff --git a/lib/auth/init_test.go b/lib/auth/init_test.go index d6a7f32cf24e7..4119d020ce5d4 100644 --- a/lib/auth/init_test.go +++ b/lib/auth/init_test.go @@ -1339,7 +1339,7 @@ func resourceFromYAML(t *testing.T, value string) types.Resource { func resourceDiff(res1, res2 types.Resource) string { return cmp.Diff(res1, res2, - cmpopts.IgnoreFields(types.Metadata{}, "ID", "Namespace"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision", "Namespace"), cmpopts.EquateEmpty()) } diff --git a/lib/auth/okta/service_test.go b/lib/auth/okta/service_test.go index ad1aba003453d..65c0871336ad9 100644 --- a/lib/auth/okta/service_test.go +++ b/lib/auth/okta/service_test.go @@ -61,7 +61,7 @@ func TestOktaImportRules(t *testing.T) { require.NoError(t, err) require.Empty(t, listResp.NextPageToken) require.Empty(t, cmp.Diff([]*types.OktaImportRuleV1{r1, r2, r3}, listResp.ImportRules, - cmpopts.IgnoreFields(types.Metadata{}, "ID"))) + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) r1.SetExpiry(time.Now().Add(30 * time.Minute)) updateResp, err := svc.UpdateOktaImportRule(ctx, &oktapb.UpdateOktaImportRuleRequest{ImportRule: r1}) @@ -71,7 +71,7 @@ func TestOktaImportRules(t *testing.T) { r, err := svc.GetOktaImportRule(ctx, &oktapb.GetOktaImportRuleRequest{Name: r1.GetName()}) require.NoError(t, err) require.Empty(t, cmp.Diff(r1, r, - cmpopts.IgnoreFields(types.Metadata{}, "ID"))) + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) _, err = svc.DeleteOktaImportRule(ctx, &oktapb.DeleteOktaImportRuleRequest{Name: r1.GetName()}) require.NoError(t, err) @@ -80,7 +80,7 @@ func TestOktaImportRules(t *testing.T) { require.NoError(t, err) require.Empty(t, listResp.NextPageToken) require.Empty(t, cmp.Diff([]*types.OktaImportRuleV1{r2, r3}, listResp.ImportRules, - cmpopts.IgnoreFields(types.Metadata{}, "ID"))) + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) _, err = svc.DeleteAllOktaImportRules(ctx, &oktapb.DeleteAllOktaImportRulesRequest{}) require.NoError(t, err) @@ -119,7 +119,7 @@ func TestOktaAssignments(t *testing.T) { require.NoError(t, err) require.Empty(t, listResp.NextPageToken) require.Empty(t, cmp.Diff([]*types.OktaAssignmentV1{a1, a2, a3}, listResp.Assignments, - cmpopts.IgnoreFields(types.Metadata{}, "ID"))) + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) a1.SetExpiry(time.Now().Add(30 * time.Minute)) updateResp, err := svc.UpdateOktaAssignment(ctx, &oktapb.UpdateOktaAssignmentRequest{Assignment: a1}) @@ -129,7 +129,7 @@ func TestOktaAssignments(t *testing.T) { a, err := svc.GetOktaAssignment(ctx, &oktapb.GetOktaAssignmentRequest{Name: a1.GetName()}) require.NoError(t, err) require.Empty(t, cmp.Diff(a1, a, - cmpopts.IgnoreFields(types.Metadata{}, "ID"))) + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) _, err = svc.UpdateOktaAssignmentStatus(ctx, &oktapb.UpdateOktaAssignmentStatusRequest{Name: a1.GetName(), Status: types.OktaAssignmentSpecV1_PROCESSING}) @@ -140,7 +140,7 @@ func TestOktaAssignments(t *testing.T) { require.NoError(t, err) a1.SetLastTransition(a.GetLastTransition()) require.Empty(t, cmp.Diff(a1, a, - cmpopts.IgnoreFields(types.Metadata{}, "ID"))) + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) _, err = svc.DeleteOktaAssignment(ctx, &oktapb.DeleteOktaAssignmentRequest{Name: a1.GetName()}) require.NoError(t, err) @@ -149,7 +149,7 @@ func TestOktaAssignments(t *testing.T) { require.NoError(t, err) require.Empty(t, listResp.NextPageToken) require.Empty(t, cmp.Diff([]*types.OktaAssignmentV1{a2, a3}, listResp.Assignments, - cmpopts.IgnoreFields(types.Metadata{}, "ID"))) + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) _, err = svc.DeleteAllOktaAssignments(ctx, &oktapb.DeleteAllOktaAssignmentsRequest{}) require.NoError(t, err) diff --git a/lib/auth/tls_test.go b/lib/auth/tls_test.go index 27da4add7a509..c1f3a1fdfe227 100644 --- a/lib/auth/tls_test.go +++ b/lib/auth/tls_test.go @@ -1118,7 +1118,7 @@ func TestGetCurrentUser(t *testing.T) { currentUser, err := client1.GetCurrentUser(ctx) require.NoError(t, err) - require.Equal(t, &types.UserV2{ + require.Empty(t, cmp.Diff(&types.UserV2{ Kind: "user", SubKind: "", Version: "v2", @@ -1128,12 +1128,11 @@ func TestGetCurrentUser(t *testing.T) { Description: "", Labels: nil, Expires: nil, - ID: currentUser.GetMetadata().ID, }, Spec: types.UserSpecV2{ Roles: []string{"user:user1"}, }, - }, currentUser) + }, currentUser, cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) } func TestGetCurrentUserRoles(t *testing.T) { @@ -1148,7 +1147,7 @@ func TestGetCurrentUserRoles(t *testing.T) { roles, err := client1.GetCurrentUserRoles(ctx) require.NoError(t, err) - require.Empty(t, cmp.Diff(roles, []types.Role{user1Role}, cmpopts.IgnoreFields(types.Metadata{}, "ID"))) + require.Empty(t, cmp.Diff(roles, []types.Role{user1Role}, cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) } func TestAuthPreferenceSettings(t *testing.T) { @@ -4089,7 +4088,7 @@ func TestGRPCServer_CreateTokenV2(t *testing.T) { require.Empty(t, cmp.Diff( tt.token, token, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) } }) @@ -4256,7 +4255,7 @@ func TestGRPCServer_UpsertTokenV2(t *testing.T) { require.Empty(t, cmp.Diff( tt.token, token, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) } }) @@ -4346,7 +4345,7 @@ func TestGRPCServer_GetTokens(t *testing.T) { require.Empty(t, cmp.Diff( expectTokens, tokens, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) } else { require.Empty(t, tokens) @@ -4416,7 +4415,7 @@ func TestGRPCServer_GetToken(t *testing.T) { require.Empty(t, cmp.Diff( token, pt, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) } else { require.Nil(t, token) diff --git a/lib/auth/trust/trustv1/service_test.go b/lib/auth/trust/trustv1/service_test.go index 702374f7fff34..18c274c9f3797 100644 --- a/lib/auth/trust/trustv1/service_test.go +++ b/lib/auth/trust/trustv1/service_test.go @@ -451,6 +451,7 @@ func TestGetCertAuthority(t *testing.T) { assertion: func(t *testing.T, authority types.CertAuthority, err error) { require.NoError(t, err) require.Empty(t, cmp.Diff(authority, ca, + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), cmpopts.IgnoreFields(types.SSHKeyPair{}, "PrivateKey"), cmpopts.IgnoreFields(types.TLSKeyPair{}, "Key"), cmpopts.IgnoreFields(types.JWTKeyPair{}, "PrivateKey"), @@ -470,7 +471,7 @@ func TestGetCertAuthority(t *testing.T) { }, assertion: func(t *testing.T, authority types.CertAuthority, err error) { require.NoError(t, err) - require.Empty(t, cmp.Diff(authority, ca)) + require.Empty(t, cmp.Diff(authority, ca, cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) }, }, } @@ -542,6 +543,7 @@ func TestGetCertAuthorities(t *testing.T) { assertion: func(t *testing.T, resp *trustpb.GetCertAuthoritiesResponse, err error) { require.NoError(t, err) require.Empty(t, cmp.Diff(expectedCAs, resp.CertAuthoritiesV2, + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), cmpopts.IgnoreFields(types.SSHKeyPair{}, "PrivateKey"), cmpopts.IgnoreFields(types.TLSKeyPair{}, "Key"), cmpopts.IgnoreFields(types.JWTKeyPair{}, "PrivateKey"), @@ -563,7 +565,7 @@ func TestGetCertAuthorities(t *testing.T) { }, assertion: func(t *testing.T, resp *trustpb.GetCertAuthoritiesResponse, err error) { require.NoError(t, err) - require.Empty(t, cmp.Diff(expectedCAs, resp.CertAuthoritiesV2)) + require.Empty(t, cmp.Diff(expectedCAs, resp.CertAuthoritiesV2, cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) }, }, } diff --git a/lib/auth/trustedcluster_test.go b/lib/auth/trustedcluster_test.go index e6bc49a459db1..8eddfaab017cb 100644 --- a/lib/auth/trustedcluster_test.go +++ b/lib/auth/trustedcluster_test.go @@ -22,6 +22,7 @@ import ( "time" "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" "github.com/gravitational/trace" "github.com/stretchr/testify/require" @@ -53,9 +54,8 @@ func TestRemoteClusterStatus(t *testing.T) { // Initially, no tunnels exist and status should be "offline". wantRC.SetConnectionStatus(teleport.RemoteClusterStatusOffline) gotRC, err := a.GetRemoteCluster(rc.GetName()) - gotRC.SetResourceID(0) require.NoError(t, err) - require.Empty(t, cmp.Diff(rc, gotRC)) + require.Empty(t, cmp.Diff(rc, gotRC, cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) // Create several tunnel connections. lastHeartbeat := a.clock.Now().UTC() @@ -86,8 +86,7 @@ func TestRemoteClusterStatus(t *testing.T) { wantRC.SetLastHeartbeat(tc2.GetLastHeartbeat()) gotRC, err = a.GetRemoteCluster(rc.GetName()) require.NoError(t, err) - gotRC.SetResourceID(0) - require.Empty(t, cmp.Diff(rc, gotRC)) + require.Empty(t, cmp.Diff(rc, gotRC, cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) // Delete the latest connection. require.NoError(t, a.DeleteTunnelConnection(tc2.GetClusterName(), tc2.GetName())) @@ -99,9 +98,8 @@ func TestRemoteClusterStatus(t *testing.T) { // heartbeat. wantRC.SetConnectionStatus(teleport.RemoteClusterStatusOnline) gotRC, err = a.GetRemoteCluster(rc.GetName()) - gotRC.SetResourceID(0) require.NoError(t, err) - require.Empty(t, cmp.Diff(rc, gotRC)) + require.Empty(t, cmp.Diff(rc, gotRC, cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) // Delete the remaining connection require.NoError(t, a.DeleteTunnelConnection(tc1.GetClusterName(), tc1.GetName())) @@ -112,9 +110,8 @@ func TestRemoteClusterStatus(t *testing.T) { // The last_heartbeat should remain the same. wantRC.SetConnectionStatus(teleport.RemoteClusterStatusOffline) gotRC, err = a.GetRemoteCluster(rc.GetName()) - gotRC.SetResourceID(0) require.NoError(t, err) - require.Empty(t, cmp.Diff(rc, gotRC)) + require.Empty(t, cmp.Diff(rc, gotRC, cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) } func TestRefreshRemoteClusters(t *testing.T) { @@ -191,7 +188,7 @@ func TestRefreshRemoteClusters(t *testing.T) { var updated int for _, cluster := range clusters { old := allClusters[cluster.GetName()] - if cmp.Diff(old, cluster) != "" { + if cmp.Diff(old, cluster, cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision")) != "" { updated++ } } diff --git a/lib/auth/userloginstate/service_test.go b/lib/auth/userloginstate/service_test.go index 208c7b4923c5c..31059314198b1 100644 --- a/lib/auth/userloginstate/service_test.go +++ b/lib/auth/userloginstate/service_test.go @@ -45,7 +45,7 @@ const ( var ( // cmpOpts are general cmpOpts for all comparisons across the service tests. cmpOpts = []cmp.Option{ - cmpopts.IgnoreFields(header.Metadata{}, "ID"), + cmpopts.IgnoreFields(header.Metadata{}, "ID", "Revision"), cmpopts.SortSlices(func(a, b *userloginstate.UserLoginState) bool { return a.GetName() < b.GetName() }), diff --git a/lib/authz/permissions_test.go b/lib/authz/permissions_test.go index 71eaf2ba8453b..a562f7d5fdf24 100644 --- a/lib/authz/permissions_test.go +++ b/lib/authz/permissions_test.go @@ -910,6 +910,6 @@ func createUserAndRole(client *testClient, username string, allowedLogins []stri func resourceDiff(res1, res2 types.Resource) string { return cmp.Diff(res1, res2, - cmpopts.IgnoreFields(types.Metadata{}, "ID", "Namespace"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision", "Namespace"), cmpopts.EquateEmpty()) } diff --git a/lib/cache/cache_test.go b/lib/cache/cache_test.go index 44fb7e917b2a7..12262e7be8b0f 100644 --- a/lib/cache/cache_test.go +++ b/lib/cache/cache_test.go @@ -336,8 +336,7 @@ func TestCA(t *testing.T) { out, err := p.cache.GetCertAuthority(ctx, ca.GetID(), true) require.NoError(t, err) - ca.SetResourceID(out.GetResourceID()) - require.Empty(t, cmp.Diff(ca, out)) + require.Empty(t, cmp.Diff(ca, out, cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) err = p.trustS.DeleteCertAuthority(ctx, ca.GetID()) require.NoError(t, err) @@ -1048,7 +1047,6 @@ func initStrategy(t *testing.T) { normalizeCA := func(ca types.CertAuthority) types.CertAuthority { ca = ca.Clone() - ca.SetResourceID(0) ca.SetExpiry(time.Time{}) types.RemoveCASecrets(ca) return ca @@ -1057,7 +1055,7 @@ func initStrategy(t *testing.T) { out, err := p.cache.GetCertAuthority(ctx, ca.GetID(), false) require.NoError(t, err) - require.Empty(t, cmp.Diff(normalizeCA(ca), normalizeCA(out))) + require.Empty(t, cmp.Diff(normalizeCA(ca), normalizeCA(out), cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) // fail again, make sure last recent data is still served // on errors @@ -1072,7 +1070,7 @@ func initStrategy(t *testing.T) { out2, err := p.cache.GetCertAuthority(ctx, ca.GetID(), false) require.NoError(t, err) require.Equal(t, out.GetResourceID(), out2.GetResourceID()) - require.Empty(t, cmp.Diff(normalizeCA(ca), normalizeCA(out))) + require.Empty(t, cmp.Diff(normalizeCA(ca), normalizeCA(out), cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) // add modification and expect the resource to recover ca.SetRoleMap(types.RoleMap{types.RoleMapping{Remote: "test", Local: []string{"local-test"}}}) @@ -1089,7 +1087,7 @@ func initStrategy(t *testing.T) { // new value is available now out, err = p.cache.GetCertAuthority(ctx, ca.GetID(), false) require.NoError(t, err) - require.Empty(t, cmp.Diff(normalizeCA(ca), normalizeCA(out))) + require.Empty(t, cmp.Diff(normalizeCA(ca), normalizeCA(out), cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) } // TestRecovery tests error recovery scenario @@ -1132,9 +1130,8 @@ func TestRecovery(t *testing.T) { out, err := p.cache.GetCertAuthority(context.Background(), ca2.GetID(), false) require.NoError(t, err) - ca2.SetResourceID(out.GetResourceID()) types.RemoveCASecrets(ca2) - require.Empty(t, cmp.Diff(ca2, out)) + require.Empty(t, cmp.Diff(ca2, out, cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) } // TestTokens tests static and dynamic tokens @@ -1168,8 +1165,7 @@ func TestTokens(t *testing.T) { out, err := p.cache.GetStaticTokens() require.NoError(t, err) - staticTokens.SetResourceID(out.GetResourceID()) - require.Empty(t, cmp.Diff(staticTokens, out)) + require.Empty(t, cmp.Diff(staticTokens, out, cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) expires := time.Now().Add(10 * time.Hour).Truncate(time.Second).UTC() token, err := types.NewProvisionToken("token", types.SystemRoles{types.RoleAuth, types.RoleNode}, expires) @@ -1187,8 +1183,7 @@ func TestTokens(t *testing.T) { tout, err := p.cache.GetToken(ctx, token.GetName()) require.NoError(t, err) - token.SetResourceID(tout.GetResourceID()) - require.Empty(t, cmp.Diff(token, tout)) + require.Empty(t, cmp.Diff(token, tout, cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) err = p.provisionerS.DeleteToken(ctx, token.GetName()) require.NoError(t, err) @@ -1230,8 +1225,7 @@ func TestAuthPreference(t *testing.T) { outAuthPref, err := p.cache.GetAuthPreference(ctx) require.NoError(t, err) - authPref.SetResourceID(outAuthPref.GetResourceID()) - require.Empty(t, cmp.Diff(outAuthPref, authPref)) + require.Empty(t, cmp.Diff(outAuthPref, authPref, cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) } func TestClusterNetworkingConfig(t *testing.T) { @@ -1260,8 +1254,7 @@ func TestClusterNetworkingConfig(t *testing.T) { outNetConfig, err := p.cache.GetClusterNetworkingConfig(ctx) require.NoError(t, err) - netConfig.SetResourceID(outNetConfig.GetResourceID()) - require.Empty(t, cmp.Diff(outNetConfig, netConfig)) + require.Empty(t, cmp.Diff(outNetConfig, netConfig, cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) } func TestSessionRecordingConfig(t *testing.T) { @@ -1290,8 +1283,7 @@ func TestSessionRecordingConfig(t *testing.T) { outRecConfig, err := p.cache.GetSessionRecordingConfig(ctx) require.NoError(t, err) - recConfig.SetResourceID(outRecConfig.GetResourceID()) - require.Empty(t, cmp.Diff(outRecConfig, recConfig)) + require.Empty(t, cmp.Diff(outRecConfig, recConfig, cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) } func TestClusterAuditConfig(t *testing.T) { @@ -1319,8 +1311,7 @@ func TestClusterAuditConfig(t *testing.T) { outAuditConfig, err := p.cache.GetClusterAuditConfig(ctx) require.NoError(t, err) - auditConfig.SetResourceID(outAuditConfig.GetResourceID()) - require.Empty(t, cmp.Diff(outAuditConfig, auditConfig)) + require.Empty(t, cmp.Diff(outAuditConfig, auditConfig, cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) } func TestClusterName(t *testing.T) { @@ -1347,8 +1338,7 @@ func TestClusterName(t *testing.T) { outName, err := p.cache.GetClusterName() require.NoError(t, err) - clusterName.SetResourceID(outName.GetResourceID()) - require.Empty(t, cmp.Diff(outName, clusterName)) + require.Empty(t, cmp.Diff(outName, clusterName, cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) } // TestNamespaces tests caching of namespaces @@ -1376,8 +1366,7 @@ func TestNamespaces(t *testing.T) { out, err := p.cache.GetNamespace(ns.GetName()) require.NoError(t, err) - ns.SetResourceID(out.GetResourceID()) - require.Empty(t, cmp.Diff(ns, out)) + require.Empty(t, cmp.Diff(ns, out, cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) // update namespace metadata ns.Metadata.Labels = map[string]string{"a": "b"} @@ -1397,8 +1386,7 @@ func TestNamespaces(t *testing.T) { out, err = p.cache.GetNamespace(ns.GetName()) require.NoError(t, err) - ns.SetResourceID(out.GetResourceID()) - require.Empty(t, cmp.Diff(ns, out)) + require.Empty(t, cmp.Diff(ns, out, cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) err = p.presenceS.DeleteNamespace(ns.GetName()) require.NoError(t, err) @@ -2204,8 +2192,8 @@ func testResources[T types.Resource](t *testing.T, p *testPack, funcs testFuncs[ require.NoError(t, err) cmpOpts := []cmp.Option{ - cmpopts.IgnoreFields(types.Metadata{}, "ID"), - cmpopts.IgnoreFields(header.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), + cmpopts.IgnoreFields(header.Metadata{}, "ID", "Revision"), } // Check that the resource is now in the backend. diff --git a/lib/kube/proxy/watcher_test.go b/lib/kube/proxy/watcher_test.go index ef8f10738abd1..49e52fba753cb 100644 --- a/lib/kube/proxy/watcher_test.go +++ b/lib/kube/proxy/watcher_test.go @@ -70,7 +70,7 @@ func TestWatcher(t *testing.T) { case a := <-reconcileCh: sort.Sort(a) require.Empty(t, cmp.Diff(types.KubeClusters{kube0}, a, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) case <-time.After(time.Second): t.Fatal("Didn't receive reconcile event after 1s.") @@ -87,7 +87,7 @@ func TestWatcher(t *testing.T) { case a := <-reconcileCh: sort.Sort(a) require.Empty(t, cmp.Diff(types.KubeClusters{kube0, kube1}, a, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) case <-time.After(time.Second): t.Fatal("Didn't receive reconcile event after 1s.") @@ -104,7 +104,7 @@ func TestWatcher(t *testing.T) { case a := <-reconcileCh: sort.Sort(a) require.Empty(t, cmp.Diff(types.KubeClusters{kube0, kube1}, a, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) case <-time.After(time.Second): t.Fatal("Didn't receive reconcile event after 1s.") @@ -121,7 +121,7 @@ func TestWatcher(t *testing.T) { case a := <-reconcileCh: sort.Sort(a) require.Empty(t, cmp.Diff(types.KubeClusters{kube0, kube1}, a, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) case <-time.After(time.Second): t.Fatal("Didn't receive reconcile event after 1s.") @@ -137,7 +137,7 @@ func TestWatcher(t *testing.T) { case a := <-reconcileCh: sort.Sort(a) require.Empty(t, cmp.Diff(types.KubeClusters{kube0, kube1, kube2}, a, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) case <-time.After(time.Second): t.Fatal("Didn't receive reconcile event after 1s.") @@ -154,7 +154,7 @@ func TestWatcher(t *testing.T) { case a := <-reconcileCh: sort.Sort(a) require.Empty(t, cmp.Diff(types.KubeClusters{kube0, kube1, kube2}, a, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // make sure credentials were updated as well. require.Equal(t, strings.TrimPrefix(kubeMock.URL, "https://"), testCtx.KubeServer.fwd.clusterDetails["kube2"].kubeCreds.getTargetAddr()) @@ -172,7 +172,7 @@ func TestWatcher(t *testing.T) { case a := <-reconcileCh: sort.Sort(a) require.Empty(t, cmp.Diff(types.KubeClusters{kube0, kube2}, a, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) case <-time.After(time.Second): t.Fatal("Didn't receive reconcile event after 1s.") @@ -186,7 +186,7 @@ func TestWatcher(t *testing.T) { select { case a := <-reconcileCh: require.Empty(t, cmp.Diff(types.KubeClusters{kube0}, a, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) case <-time.After(time.Second): t.Fatal("Didn't receive reconcile event after 1s.") diff --git a/lib/services/authority.go b/lib/services/authority.go index 3bc699cac847a..a99de420e03d3 100644 --- a/lib/services/authority.go +++ b/lib/services/authority.go @@ -47,7 +47,7 @@ import ( func CertAuthoritiesEquivalent(lhs, rhs types.CertAuthority) bool { return cmp.Equal(lhs, rhs, ignoreProtoXXXFields(), - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), // Optimize types.CAKeySet comparison. cmp.Comparer(func(a, b types.CAKeySet) bool { // Note that Clone drops XXX_ fields. And it's benchmarked that cloning diff --git a/lib/services/compare.go b/lib/services/compare.go index e26020c00509e..54d1e1073db81 100644 --- a/lib/services/compare.go +++ b/lib/services/compare.go @@ -29,7 +29,7 @@ import ( func CompareResources(resA, resB types.Resource) int { equal := cmp.Equal(resA, resB, ignoreProtoXXXFields(), - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), cmpopts.IgnoreFields(types.DatabaseV3{}, "Status"), cmpopts.EquateEmpty(), ) diff --git a/lib/services/local/access_list_test.go b/lib/services/local/access_list_test.go index ff39a128bf5c8..210ce5ab8d926 100644 --- a/lib/services/local/access_list_test.go +++ b/lib/services/local/access_list_test.go @@ -57,7 +57,7 @@ func TestAccessListCRUD(t *testing.T) { require.Empty(t, out) cmpOpts := []cmp.Option{ - cmpopts.IgnoreFields(header.Metadata{}, "ID"), + cmpopts.IgnoreFields(header.Metadata{}, "ID", "Revision"), } // Create both access lists. @@ -143,7 +143,7 @@ func TestAccessListUpsertWithMembers(t *testing.T) { accessList1 := newAccessList(t, "accessList1") cmpOpts := []cmp.Option{ - cmpopts.IgnoreFields(header.Metadata{}, "ID"), + cmpopts.IgnoreFields(header.Metadata{}, "ID", "Revision"), } t.Run("create access list", func(t *testing.T) { @@ -220,7 +220,7 @@ func TestAccessListMembersCRUD(t *testing.T) { accessList2 := newAccessList(t, "accessList2") cmpOpts := []cmp.Option{ - cmpopts.IgnoreFields(header.Metadata{}, "ID"), + cmpopts.IgnoreFields(header.Metadata{}, "ID", "Revision"), } // Create both access lists. diff --git a/lib/services/local/access_test.go b/lib/services/local/access_test.go index 5d3d61770a5cb..2aff948de1687 100644 --- a/lib/services/local/access_test.go +++ b/lib/services/local/access_test.go @@ -78,7 +78,7 @@ func TestLockCRUD(t *testing.T) { require.NoError(t, err) require.Len(t, locks, 2) require.Empty(t, cmp.Diff([]types.Lock{lock1, lock2}, locks, - cmpopts.IgnoreFields(types.Metadata{}, "ID"))) + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) } }) t.Run("GetLocks with targets", func(t *testing.T) { @@ -88,7 +88,7 @@ func TestLockCRUD(t *testing.T) { require.NoError(t, err) require.Len(t, locks, 2) require.Empty(t, cmp.Diff([]types.Lock{lock1, lock2}, locks, - cmpopts.IgnoreFields(types.Metadata{}, "ID"))) + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) // Match only one of the locks. roleTarget := types.LockTarget{Role: "role-A"} @@ -96,7 +96,7 @@ func TestLockCRUD(t *testing.T) { require.NoError(t, err) require.Len(t, locks, 1) require.Empty(t, cmp.Diff([]types.Lock{lock1}, locks, - cmpopts.IgnoreFields(types.Metadata{}, "ID"))) + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) // Match none of the locks. locks, err = access.GetLocks(ctx, false, roleTarget) @@ -109,7 +109,7 @@ func TestLockCRUD(t *testing.T) { lock, err := access.GetLock(ctx, lock1.GetName()) require.NoError(t, err) require.Empty(t, cmp.Diff(lock1, lock, - cmpopts.IgnoreFields(types.Metadata{}, "ID"))) + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) // Attempt to get a nonexistent lock. _, err = access.GetLock(ctx, "lock3") @@ -166,7 +166,7 @@ func TestLockCRUD(t *testing.T) { require.NoError(t, err) require.Len(t, locks, 2) require.Empty(t, cmp.Diff(newRemoteLocks, locks, - cmpopts.IgnoreFields(types.Metadata{}, "ID"))) + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) for _, lock := range locks { require.True(t, strings.HasPrefix(lock.GetName(), clusterName+"/")) } @@ -181,7 +181,7 @@ func TestLockCRUD(t *testing.T) { require.NoError(t, err) require.Len(t, locks, 1) require.Empty(t, cmp.Diff(newRemoteLocks, locks, - cmpopts.IgnoreFields(types.Metadata{}, "ID"))) + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) _, err = access.GetLock(ctx, lock2.GetName()) require.Error(t, err) require.True(t, trace.IsNotFound(err)) diff --git a/lib/services/local/apps_test.go b/lib/services/local/apps_test.go index d059c59925f99..d41ea527208c8 100644 --- a/lib/services/local/apps_test.go +++ b/lib/services/local/apps_test.go @@ -71,14 +71,14 @@ func TestAppsCRUD(t *testing.T) { out, err = service.GetApps(ctx) require.NoError(t, err) require.Empty(t, cmp.Diff([]types.Application{app1, app2}, out, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Fetch a specific application. app, err := service.GetApp(ctx, app2.GetName()) require.NoError(t, err) require.Empty(t, cmp.Diff(app2, app, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Try to fetch an application that doesn't exist. @@ -96,7 +96,7 @@ func TestAppsCRUD(t *testing.T) { app, err = service.GetApp(ctx, app1.GetName()) require.NoError(t, err) require.Empty(t, cmp.Diff(app1, app, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Delete an application. @@ -105,7 +105,7 @@ func TestAppsCRUD(t *testing.T) { out, err = service.GetApps(ctx) require.NoError(t, err) require.Empty(t, cmp.Diff([]types.Application{app2}, out, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Try to delete an application that doesn't exist. diff --git a/lib/services/local/databases_test.go b/lib/services/local/databases_test.go index 1607532241e90..0ac705109deea 100644 --- a/lib/services/local/databases_test.go +++ b/lib/services/local/databases_test.go @@ -84,14 +84,14 @@ func TestDatabasesCRUD(t *testing.T) { out, err = service.GetDatabases(ctx) require.NoError(t, err) require.Empty(t, cmp.Diff([]types.Database{dbBadURI, db1, db2}, out, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Fetch a specific database. db, err := service.GetDatabase(ctx, db2.GetName()) require.NoError(t, err) require.Empty(t, cmp.Diff(db2, db, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Try to fetch a database that doesn't exist. @@ -109,7 +109,7 @@ func TestDatabasesCRUD(t *testing.T) { db, err = service.GetDatabase(ctx, db1.GetName()) require.NoError(t, err) require.Empty(t, cmp.Diff(db1, db, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Delete a database. @@ -118,7 +118,7 @@ func TestDatabasesCRUD(t *testing.T) { out, err = service.GetDatabases(ctx) require.NoError(t, err) require.Empty(t, cmp.Diff([]types.Database{dbBadURI, db2}, out, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Try to delete a database that doesn't exist. diff --git a/lib/services/local/desktops_test.go b/lib/services/local/desktops_test.go index dbd3fc7ef0b4b..3a13df56659f1 100644 --- a/lib/services/local/desktops_test.go +++ b/lib/services/local/desktops_test.go @@ -76,7 +76,7 @@ func TestListWindowsDesktops(t *testing.T) { require.NoError(t, err) require.Empty(t, out.NextKey) require.Empty(t, cmp.Diff([]types.WindowsDesktop{d1, d2, d3}, out.Desktops, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Test pagination. diff --git a/lib/services/local/generic/generic_test.go b/lib/services/local/generic/generic_test.go index 022a80d6b490b..b5d03f2919cb8 100644 --- a/lib/services/local/generic/generic_test.go +++ b/lib/services/local/generic/generic_test.go @@ -137,7 +137,7 @@ func TestGenericCRUD(t *testing.T) { require.NoError(t, err) require.Empty(t, nextToken) require.Empty(t, cmp.Diff([]*testResource{r1, r2}, out, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Fetch a paginated list of resources. @@ -156,21 +156,21 @@ func TestGenericCRUD(t *testing.T) { require.Equal(t, 2, numPages) require.Empty(t, cmp.Diff([]*testResource{r1, r2}, paginatedOut, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Fetch a list of all resources allResources, err := service.GetResources(ctx) require.NoError(t, err) require.Empty(t, cmp.Diff(paginatedOut, allResources, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Fetch a specific service provider. r, err := service.GetResource(ctx, r2.GetName()) require.NoError(t, err) require.Empty(t, cmp.Diff(r2, r, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Try to fetch a resource that doesn't exist. @@ -188,7 +188,7 @@ func TestGenericCRUD(t *testing.T) { r, err = service.GetResource(ctx, r1.GetName()) require.NoError(t, err) require.Empty(t, cmp.Diff(r1, r, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Update a resource that doesn't exist. @@ -203,7 +203,7 @@ func TestGenericCRUD(t *testing.T) { require.NoError(t, err) require.Empty(t, nextToken) require.Empty(t, cmp.Diff([]*testResource{r2}, out, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Upsert a resource (create). @@ -213,7 +213,7 @@ func TestGenericCRUD(t *testing.T) { require.NoError(t, err) require.Empty(t, nextToken) require.Empty(t, cmp.Diff([]*testResource{r1, r2}, out, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Upsert a resource (update). @@ -224,7 +224,7 @@ func TestGenericCRUD(t *testing.T) { require.NoError(t, err) require.Empty(t, nextToken) require.Empty(t, cmp.Diff([]*testResource{r1, r2}, out, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Update and swap a value @@ -237,7 +237,7 @@ func TestGenericCRUD(t *testing.T) { require.NoError(t, err) require.Empty(t, nextToken) require.Empty(t, cmp.Diff([]*testResource{r1, r2}, out, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Try to delete a resource that doesn't exist. @@ -252,7 +252,7 @@ func TestGenericCRUD(t *testing.T) { r, err = unmarshalResource(item.Value) require.NoError(t, err) require.Empty(t, cmp.Diff(r1, r, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) return nil diff --git a/lib/services/local/kube_test.go b/lib/services/local/kube_test.go index 25a9b6b90019a..8346ce856291d 100644 --- a/lib/services/local/kube_test.go +++ b/lib/services/local/kube_test.go @@ -67,14 +67,14 @@ func TestKubernetesCRUD(t *testing.T) { out, err = service.GetKubernetesClusters(ctx) require.NoError(t, err) require.Empty(t, cmp.Diff([]types.KubeCluster{kubeCluster1, kubeCluster2}, out, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Fetch a specific Kubernetes. cluster, err := service.GetKubernetesCluster(ctx, kubeCluster2.GetName()) require.NoError(t, err) require.Empty(t, cmp.Diff(kubeCluster2, cluster, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Try to fetch a Kubernetes that doesn't exist. @@ -92,7 +92,7 @@ func TestKubernetesCRUD(t *testing.T) { cluster, err = service.GetKubernetesCluster(ctx, kubeCluster1.GetName()) require.NoError(t, err) require.Empty(t, cmp.Diff(kubeCluster1, cluster, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Delete a Kubernetes. @@ -101,7 +101,7 @@ func TestKubernetesCRUD(t *testing.T) { out, err = service.GetKubernetesClusters(ctx) require.NoError(t, err) require.Empty(t, cmp.Diff([]types.KubeCluster{kubeCluster2}, out, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Try to delete a Kubernetes that doesn't exist. diff --git a/lib/services/local/okta_test.go b/lib/services/local/okta_test.go index 0feccbfda2648..cb7f4aadb5cfd 100644 --- a/lib/services/local/okta_test.go +++ b/lib/services/local/okta_test.go @@ -118,13 +118,13 @@ func TestOktaImportRuleCRUD(t *testing.T) { importRule, err := service.CreateOktaImportRule(ctx, importRule1) require.NoError(t, err) require.Empty(t, cmp.Diff(importRule1, importRule, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) importRule, err = service.CreateOktaImportRule(ctx, importRule2) require.NoError(t, err) require.Empty(t, cmp.Diff(importRule2, importRule, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Fetch all import rules. @@ -132,7 +132,7 @@ func TestOktaImportRuleCRUD(t *testing.T) { require.NoError(t, err) require.Empty(t, nextToken) require.Empty(t, cmp.Diff([]types.OktaImportRule{importRule1, importRule2}, out, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Fetch a paginated list of import rules @@ -149,14 +149,14 @@ func TestOktaImportRuleCRUD(t *testing.T) { require.Len(t, paginatedOut, 2) require.Empty(t, cmp.Diff([]types.OktaImportRule{importRule1, importRule2}, paginatedOut, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Fetch a specific import rule. importRule, err = service.GetOktaImportRule(ctx, importRule2.GetName()) require.NoError(t, err) require.Empty(t, cmp.Diff(importRule2, importRule, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Try to fetch an import rule that doesn't exist. @@ -174,7 +174,7 @@ func TestOktaImportRuleCRUD(t *testing.T) { importRule, err = service.GetOktaImportRule(ctx, importRule1.GetName()) require.NoError(t, err) require.Empty(t, cmp.Diff(importRule1, importRule, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Delete an import rule @@ -184,7 +184,7 @@ func TestOktaImportRuleCRUD(t *testing.T) { require.NoError(t, err) require.Empty(t, nextToken) require.Empty(t, cmp.Diff([]types.OktaImportRule{importRule2}, out, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Try to delete an import rule that doesn't exist. @@ -330,13 +330,13 @@ func TestOktaAssignmentCRUD(t *testing.T) { assignment, err := service.CreateOktaAssignment(ctx, assignment1) require.NoError(t, err) require.Empty(t, cmp.Diff(assignment1, assignment, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) assignment, err = service.CreateOktaAssignment(ctx, assignment2) require.NoError(t, err) require.Empty(t, cmp.Diff(assignment2, assignment, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Fetch all assignments. @@ -344,7 +344,7 @@ func TestOktaAssignmentCRUD(t *testing.T) { require.NoError(t, err) require.Empty(t, nextToken) require.Empty(t, cmp.Diff([]types.OktaAssignment{assignment1, assignment2}, out, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Fetch a paginated list of assignments @@ -363,14 +363,14 @@ func TestOktaAssignmentCRUD(t *testing.T) { require.Equal(t, 2, numPages) require.Empty(t, cmp.Diff([]types.OktaAssignment{assignment1, assignment2}, paginatedOut, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Fetch a specific assignment. assignment, err = service.GetOktaAssignment(ctx, assignment2.GetName()) require.NoError(t, err) require.Empty(t, cmp.Diff(assignment2, assignment, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Try to fetch an assignment that doesn't exist. @@ -392,7 +392,7 @@ func TestOktaAssignmentCRUD(t *testing.T) { assignment, err = service.GetOktaAssignment(ctx, assignment1.GetName()) require.NoError(t, err) require.Empty(t, cmp.Diff(assignment1, assignment, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Fail to update the status for an assignment due to a bad transition. @@ -410,7 +410,7 @@ func TestOktaAssignmentCRUD(t *testing.T) { assignment, err = service.GetOktaAssignment(ctx, assignment1.GetName()) require.NoError(t, err) require.Empty(t, cmp.Diff(assignment1, assignment, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Delete an assignment @@ -420,7 +420,7 @@ func TestOktaAssignmentCRUD(t *testing.T) { require.NoError(t, err) require.Empty(t, nextToken) require.Empty(t, cmp.Diff([]types.OktaAssignment{assignment2}, out, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Try to delete an assignment that doesn't exist. diff --git a/lib/services/local/plugin_static_credentials_test.go b/lib/services/local/plugin_static_credentials_test.go index 12d80ad6e6476..c6250022060b2 100644 --- a/lib/services/local/plugin_static_credentials_test.go +++ b/lib/services/local/plugin_static_credentials_test.go @@ -83,7 +83,7 @@ func TestPluginStaticCredentialsCRUD(t *testing.T) { cred, err := service.GetPluginStaticCredentials(ctx, cred1.GetName()) require.NoError(t, err) require.Empty(t, cmp.Diff(cred1, cred, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Try to fetch a static credential that doesn't exist. @@ -101,7 +101,7 @@ func TestPluginStaticCredentialsCRUD(t *testing.T) { }) require.NoError(t, err) require.Empty(t, cmp.Diff([]types.PluginStaticCredentials{cred1}, creds, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) creds, err = service.GetPluginStaticCredentialsByLabels(ctx, map[string]string{ @@ -109,7 +109,7 @@ func TestPluginStaticCredentialsCRUD(t *testing.T) { }) require.NoError(t, err) require.Empty(t, cmp.Diff([]types.PluginStaticCredentials{cred1, cred2}, creds, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) creds, err = service.GetPluginStaticCredentialsByLabels(ctx, map[string]string{ @@ -118,7 +118,7 @@ func TestPluginStaticCredentialsCRUD(t *testing.T) { }) require.NoError(t, err) require.Empty(t, cmp.Diff([]types.PluginStaticCredentials{cred2}, creds, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Delete a static credential. diff --git a/lib/services/local/plugins_test.go b/lib/services/local/plugins_test.go index 88d7ffc321d1c..f34fb67966879 100644 --- a/lib/services/local/plugins_test.go +++ b/lib/services/local/plugins_test.go @@ -76,14 +76,14 @@ func TestPluginsCRUD(t *testing.T) { out, err = service.GetPlugins(ctx, true) require.NoError(t, err) require.Empty(t, cmp.Diff([]types.Plugin{plugin1, plugin2}, out, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Fetch a specific plugin. cluster, err := service.GetPlugin(ctx, plugin2.GetName(), true) require.NoError(t, err) require.Empty(t, cmp.Diff(plugin2, cluster, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Try to fetch a plugin that doesn't exist. @@ -104,7 +104,7 @@ func TestPluginsCRUD(t *testing.T) { require.NoError(t, err) // Fields other than Status should remain unchanged require.Empty(t, cmp.Diff(plugin1, cluster, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), cmpopts.IgnoreFields(types.PluginV1{}, "Status"), )) require.Empty(t, cmp.Diff(status, cluster.GetStatus())) @@ -124,7 +124,7 @@ func TestPluginsCRUD(t *testing.T) { out, err = service.GetPlugins(ctx, true) require.NoError(t, err) require.Empty(t, cmp.Diff([]types.Plugin{plugin2}, out, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Try to delete a plugin that doesn't exist. @@ -192,7 +192,7 @@ func TestListPlugins(t *testing.T) { fetchedPlugins = append(fetchedPlugins, page3...) require.Empty(t, cmp.Diff(insertedPlugins, fetchedPlugins, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) }) @@ -202,7 +202,7 @@ func TestListPlugins(t *testing.T) { require.Empty(t, nextKey) require.Empty(t, cmp.Diff(insertedPlugins, fetchedPlugins, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) }) } diff --git a/lib/services/local/presence_test.go b/lib/services/local/presence_test.go index a0a495e65fe9d..40a09b801997c 100644 --- a/lib/services/local/presence_test.go +++ b/lib/services/local/presence_test.go @@ -252,7 +252,7 @@ func TestApplicationServersCRUD(t *testing.T) { servers := types.AppServers(out) require.NoError(t, servers.SortByCustom(types.SortBy{Field: types.ResourceMetadataName})) require.Empty(t, cmp.Diff([]types.AppServer{serverA, serverB}, out, - cmpopts.IgnoreFields(types.Metadata{}, "ID"))) + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) // Delete an app server. err = presence.DeleteApplicationServer(ctx, serverA.GetNamespace(), serverA.GetHostID(), serverA.GetName()) @@ -262,7 +262,7 @@ func TestApplicationServersCRUD(t *testing.T) { out, err = presence.GetApplicationServers(ctx, apidefaults.Namespace) require.NoError(t, err) require.Empty(t, cmp.Diff([]types.AppServer{serverB}, out, - cmpopts.IgnoreFields(types.Metadata{}, "ID"))) + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) // Upsert server with TTL. serverA.SetExpiry(clock.Now().UTC().Add(time.Hour)) @@ -337,8 +337,7 @@ func TestDatabaseServersCRUD(t *testing.T) { // Check again, expect a single server to be found. out, err = presence.GetDatabaseServers(ctx, server.GetNamespace()) require.NoError(t, err) - server.SetResourceID(out[0].GetResourceID()) - require.EqualValues(t, []types.DatabaseServer{server}, out) + require.Empty(t, cmp.Diff([]types.DatabaseServer{server}, out, cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) // Make sure can't delete with empty namespace or host ID or name. err = presence.DeleteDatabaseServer(ctx, server.GetNamespace(), server.GetHostID(), "") @@ -424,7 +423,7 @@ func TestNodeCRUD(t *testing.T) { require.NoError(t, err) require.EqualValues(t, len(nodes), 2) require.Empty(t, cmp.Diff([]types.Server{node1, node2}, nodes, - cmpopts.IgnoreFields(types.Metadata{}, "ID"))) + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) // GetNodes should fail if namespace isn't provided _, err = presence.GetNodes(ctx, "") @@ -436,7 +435,7 @@ func TestNodeCRUD(t *testing.T) { node, err := presence.GetNode(ctx, apidefaults.Namespace, "node1") require.NoError(t, err) require.Empty(t, cmp.Diff(node1, node, - cmpopts.IgnoreFields(types.Metadata{}, "ID"))) + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) // GetNode should fail if node name isn't provided _, err = presence.GetNode(ctx, apidefaults.Namespace, "") @@ -1374,15 +1373,15 @@ func TestServerInfoCRUD(t *testing.T) { out, err = stream.Collect(presence.GetServerInfos(ctx)) require.NoError(t, err) require.Empty(t, cmp.Diff([]types.ServerInfo{serverInfoA, serverInfoB}, out, - cmpopts.IgnoreFields(types.Metadata{}, "ID"))) + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) outInfo, err := presence.GetServerInfo(ctx, serverInfoA.GetName()) require.NoError(t, err) - require.Empty(t, cmp.Diff(serverInfoA, outInfo, cmpopts.IgnoreFields(types.Metadata{}, "ID"))) + require.Empty(t, cmp.Diff(serverInfoA, outInfo, cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) outInfo, err = presence.GetServerInfo(ctx, serverInfoB.GetName()) require.NoError(t, err) - require.Empty(t, cmp.Diff(serverInfoB, outInfo, cmpopts.IgnoreFields(types.Metadata{}, "ID"))) + require.Empty(t, cmp.Diff(serverInfoB, outInfo, cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) _, err = presence.GetServerInfo(ctx, "nonexistant") require.True(t, trace.IsNotFound(err)) @@ -1392,7 +1391,7 @@ func TestServerInfoCRUD(t *testing.T) { out, err = stream.Collect(presence.GetServerInfos(ctx)) require.NoError(t, err) require.Empty(t, cmp.Diff([]types.ServerInfo{serverInfoB}, out, - cmpopts.IgnoreFields(types.Metadata{}, "ID"))) + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) // Update server info. serverInfoB.SetStaticLabels(map[string]string{ @@ -1403,7 +1402,7 @@ func TestServerInfoCRUD(t *testing.T) { out, err = stream.Collect(presence.GetServerInfos(ctx)) require.NoError(t, err) require.Empty(t, cmp.Diff([]types.ServerInfo{serverInfoB}, out, - cmpopts.IgnoreFields(types.Metadata{}, "ID"))) + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) // Delete all server infos. require.NoError(t, presence.DeleteAllServerInfos(ctx)) diff --git a/lib/services/local/resource_test.go b/lib/services/local/resource_test.go index d907f48c35aa6..d3fc1608cf953 100644 --- a/lib/services/local/resource_test.go +++ b/lib/services/local/resource_test.go @@ -23,10 +23,10 @@ import ( "time" "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" "github.com/jonboulle/clockwork" "github.com/stretchr/testify/require" "golang.org/x/crypto/bcrypt" - "google.golang.org/protobuf/testing/protocmp" apidefaults "github.com/gravitational/teleport/api/defaults" "github.com/gravitational/teleport/api/types" @@ -50,7 +50,7 @@ func TestCreateResourcesProvisionToken(t *testing.T) { s := NewProvisioningService(tt.bk) fetchedToken, err := s.GetToken(ctx, "foo") require.NoError(t, err) - require.Empty(t, cmp.Diff(token, fetchedToken)) + require.Empty(t, cmp.Diff(token, fetchedToken, cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) } func TestUserResource(t *testing.T) { @@ -248,5 +248,5 @@ func TestBootstrapLock(t *testing.T) { l, err := tt.suite.Access.GetLock(ctx, "test") require.NoError(t, err) - require.Empty(t, cmp.Diff(nl, l, protocmp.Transform())) + require.Empty(t, cmp.Diff(nl, l, cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) } diff --git a/lib/services/local/saml_idp_service_provider_test.go b/lib/services/local/saml_idp_service_provider_test.go index 4a90318e8bd77..29dab40861792 100644 --- a/lib/services/local/saml_idp_service_provider_test.go +++ b/lib/services/local/saml_idp_service_provider_test.go @@ -122,7 +122,7 @@ func TestSAMLIdPServiceProviderCRUD(t *testing.T) { require.NoError(t, err) require.Empty(t, nextToken) require.Empty(t, cmp.Diff([]types.SAMLIdPServiceProvider{sp1, sp2}, out, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Fetch a paginated list of service providers @@ -141,14 +141,14 @@ func TestSAMLIdPServiceProviderCRUD(t *testing.T) { require.Equal(t, 2, numPages) require.Empty(t, cmp.Diff([]types.SAMLIdPServiceProvider{sp1, sp2}, paginatedOut, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Fetch a specific service provider. sp, err := service.GetSAMLIdPServiceProvider(ctx, sp2.GetName()) require.NoError(t, err) require.Empty(t, cmp.Diff(sp2, sp, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Try to fetch a service provider that doesn't exist. @@ -167,7 +167,7 @@ func TestSAMLIdPServiceProviderCRUD(t *testing.T) { sp, err = service.GetSAMLIdPServiceProvider(ctx, sp1.GetName()) require.NoError(t, err) require.Empty(t, cmp.Diff(sp1, sp, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Update a service provider to an existing entity ID. @@ -193,7 +193,7 @@ func TestSAMLIdPServiceProviderCRUD(t *testing.T) { require.NoError(t, err) require.Empty(t, nextToken) require.Empty(t, cmp.Diff([]types.SAMLIdPServiceProvider{sp2}, out, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Try to delete a service provider that doesn't exist. diff --git a/lib/services/local/user_login_state_test.go b/lib/services/local/user_login_state_test.go index 9d3887b9a8fbc..f8ff64c89e8f8 100644 --- a/lib/services/local/user_login_state_test.go +++ b/lib/services/local/user_login_state_test.go @@ -50,7 +50,7 @@ func TestUserLoginStateCRUD(t *testing.T) { state2 := newUserLoginState(t, "state2") cmpOpts := []cmp.Option{ - cmpopts.IgnoreFields(header.Metadata{}, "ID"), + cmpopts.IgnoreFields(header.Metadata{}, "ID", "Revision"), } // Neither state should exist. diff --git a/lib/services/local/usergroup_test.go b/lib/services/local/usergroup_test.go index f3f26a5c244fa..b6f9a7c9d49a3 100644 --- a/lib/services/local/usergroup_test.go +++ b/lib/services/local/usergroup_test.go @@ -72,7 +72,7 @@ func TestUserGroupCRUD(t *testing.T) { require.NoError(t, err) require.Empty(t, nextToken) require.Empty(t, cmp.Diff([]types.UserGroup{g1, g2}, out, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Fetch a paginated list of user groups. @@ -91,14 +91,14 @@ func TestUserGroupCRUD(t *testing.T) { require.Equal(t, 2, numPages) require.Empty(t, cmp.Diff([]types.UserGroup{g1, g2}, paginatedOut, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Fetch a specific user group. sp, err := service.GetUserGroup(ctx, g2.GetName()) require.NoError(t, err) require.Empty(t, cmp.Diff(g2, sp, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Try to fetch a user group that doesn't exist. @@ -116,7 +116,7 @@ func TestUserGroupCRUD(t *testing.T) { sp, err = service.GetUserGroup(ctx, g1.GetName()) require.NoError(t, err) require.Empty(t, cmp.Diff(g1, sp, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Delete a user group. @@ -126,7 +126,7 @@ func TestUserGroupCRUD(t *testing.T) { require.NoError(t, err) require.Empty(t, nextToken) require.Empty(t, cmp.Diff([]types.UserGroup{g2}, out, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) // Try to delete a user group that doesn't exist. diff --git a/lib/services/local/users_test.go b/lib/services/local/users_test.go index 4b75581b8ef30..d201265a5fbbe 100644 --- a/lib/services/local/users_test.go +++ b/lib/services/local/users_test.go @@ -28,6 +28,7 @@ import ( "github.com/go-webauthn/webauthn/protocol" "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" "github.com/google/uuid" "github.com/gravitational/trace" "github.com/jonboulle/clockwork" @@ -1074,14 +1075,14 @@ func TestIdentityService_UpdateAndSwapUser(t *testing.T) { } // Assert update response. - if diff := cmp.Diff(want, updated); diff != "" { + if diff := cmp.Diff(want, updated, cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision")); diff != "" { t.Errorf("UpdateAndSwapUser return mismatch (-want +got)\n%s", diff) } // Assert stored. stored, err := identity.GetUser(test.user, test.withSecrets) require.NoError(t, err, "GetUser failed") - if diff := cmp.Diff(want, stored); diff != "" { + if diff := cmp.Diff(want, stored, cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision")); diff != "" { t.Errorf("UpdateAndSwapUser storage mismatch (-want +got)\n%s", diff) } }) diff --git a/lib/services/suite/suite.go b/lib/services/suite/suite.go index 392cc85ce6c2f..2638030c55431 100644 --- a/lib/services/suite/suite.go +++ b/lib/services/suite/suite.go @@ -309,23 +309,22 @@ func (s *ServicesTestSuite) CertAuthCRUD(t *testing.T) { out, err := s.CAS.GetCertAuthority(ctx, ca.GetID(), true) require.NoError(t, err) - ca.SetResourceID(out.GetResourceID()) - require.Equal(t, out, ca) + require.Empty(t, cmp.Diff(out, ca, cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) cas, err := s.CAS.GetCertAuthorities(ctx, types.UserCA, false) require.NoError(t, err) ca2 := ca.Clone().(*types.CertAuthorityV2) ca2.Spec.ActiveKeys.SSH[0].PrivateKey = nil ca2.Spec.ActiveKeys.TLS[0].Key = nil - require.Equal(t, cas[0], ca2) + require.Empty(t, cmp.Diff(cas[0], ca2, cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) cas, err = s.CAS.GetCertAuthorities(ctx, types.UserCA, true) require.NoError(t, err) - require.Equal(t, cas[0], ca) + require.Empty(t, cmp.Diff(cas[0], ca, cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) cas, err = s.CAS.GetCertAuthorities(ctx, types.UserCA, true) require.NoError(t, err) - require.Equal(t, cas[0], ca) + require.Empty(t, cmp.Diff(cas[0], ca, cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) err = s.CAS.DeleteCertAuthority(ctx, *ca.ID()) require.NoError(t, err) @@ -349,8 +348,7 @@ func (s *ServicesTestSuite) CertAuthCRUD(t *testing.T) { out, err = s.CAS.GetCertAuthority(ctx, ca.GetID(), true) require.NoError(t, err) - newCA.SetResourceID(out.GetResourceID()) - require.Empty(t, cmp.Diff(&newCA, out, cmpopts.EquateApproxTime(time.Second))) + require.Empty(t, cmp.Diff(&newCA, out, cmpopts.EquateApproxTime(time.Second), cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) } // NewServer creates a new server resource @@ -382,14 +380,12 @@ func (s *ServicesTestSuite) ServerCRUD(t *testing.T) { node, err := s.PresenceS.GetNode(ctx, srv.Metadata.Namespace, srv.GetName()) require.NoError(t, err) - srv.SetResourceID(node.GetResourceID()) - require.Empty(t, cmp.Diff(node, srv)) + require.Empty(t, cmp.Diff(node, srv, cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) out, err = s.PresenceS.GetNodes(ctx, srv.Metadata.Namespace) require.NoError(t, err) require.Len(t, out, 1) - srv.SetResourceID(out[0].GetResourceID()) - require.Empty(t, cmp.Diff(out, []types.Server{srv})) + require.Empty(t, cmp.Diff(out, []types.Server{srv}, cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) err = s.PresenceS.DeleteNode(ctx, srv.Metadata.Namespace, srv.GetName()) require.NoError(t, err) @@ -409,8 +405,7 @@ func (s *ServicesTestSuite) ServerCRUD(t *testing.T) { out, err = s.PresenceS.GetProxies() require.NoError(t, err) require.Len(t, out, 1) - proxy.SetResourceID(out[0].GetResourceID()) - require.Empty(t, cmp.Diff(out, []types.Server{proxy})) + require.Empty(t, cmp.Diff(out, []types.Server{proxy}, cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) err = s.PresenceS.DeleteProxy(ctx, proxy.GetName()) require.NoError(t, err) @@ -430,8 +425,7 @@ func (s *ServicesTestSuite) ServerCRUD(t *testing.T) { out, err = s.PresenceS.GetAuthServers() require.NoError(t, err) require.Len(t, out, 1) - auth.SetResourceID(out[0].GetResourceID()) - require.Empty(t, cmp.Diff(out, []types.Server{auth})) + require.Empty(t, cmp.Diff(out, []types.Server{auth}, cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) } // AppServerCRUD tests CRUD functionality for services.Server. @@ -465,8 +459,7 @@ func (s *ServicesTestSuite) AppServerCRUD(t *testing.T) { out, err = s.PresenceS.GetApplicationServers(ctx, server.GetNamespace()) require.NoError(t, err) require.Len(t, out, 1) - server.SetResourceID(out[0].GetResourceID()) - require.Empty(t, cmp.Diff([]types.AppServer{server}, out)) + require.Empty(t, cmp.Diff([]types.AppServer{server}, out, cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) // Remove the application. err = s.PresenceS.DeleteApplicationServer(ctx, server.Metadata.Namespace, server.GetHostID(), server.GetName()) @@ -504,8 +497,7 @@ func (s *ServicesTestSuite) ReverseTunnelsCRUD(t *testing.T) { out, err = s.PresenceS.GetReverseTunnels(context.Background()) require.NoError(t, err) require.Len(t, out, 1) - tunnel.SetResourceID(out[0].GetResourceID()) - require.Empty(t, cmp.Diff(out, []types.ReverseTunnel{tunnel})) + require.Empty(t, cmp.Diff(out, []types.ReverseTunnel{tunnel}, cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) err = s.PresenceS.DeleteReverseTunnel(tunnel.Spec.ClusterName) require.NoError(t, err) @@ -699,16 +691,14 @@ func (s *ServicesTestSuite) RolesCRUD(t *testing.T) { require.NoError(t, err) rout, err := s.Access.GetRole(ctx, role.Metadata.Name) require.NoError(t, err) - role.SetResourceID(rout.GetResourceID()) - require.Empty(t, cmp.Diff(rout, &role)) + require.Empty(t, cmp.Diff(rout, &role, cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) role.Spec.Allow.Logins = []string{"bob"} err = s.Access.UpsertRole(ctx, &role) require.NoError(t, err) rout, err = s.Access.GetRole(ctx, role.Metadata.Name) require.NoError(t, err) - role.SetResourceID(rout.GetResourceID()) - require.Empty(t, cmp.Diff(rout, &role)) + require.Empty(t, cmp.Diff(rout, &role, cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) err = s.Access.DeleteRole(ctx, role.Metadata.Name) require.NoError(t, err) @@ -820,13 +810,12 @@ func (s *ServicesTestSuite) TunnelConnectionsCRUD(t *testing.T) { out, err = s.PresenceS.GetTunnelConnections(clusterName) require.NoError(t, err) require.Equal(t, len(out), 1) - conn.SetResourceID(out[0].GetResourceID()) - require.Empty(t, cmp.Diff(out[0], conn)) + require.Empty(t, cmp.Diff(out[0], conn, cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) out, err = s.PresenceS.GetAllTunnelConnections() require.NoError(t, err) require.Equal(t, len(out), 1) - require.Empty(t, cmp.Diff(out[0], conn)) + require.Empty(t, cmp.Diff(out[0], conn, cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) dt = dt.Add(time.Hour) conn.SetLastHeartbeat(dt) @@ -837,8 +826,7 @@ func (s *ServicesTestSuite) TunnelConnectionsCRUD(t *testing.T) { out, err = s.PresenceS.GetTunnelConnections(clusterName) require.NoError(t, err) require.Equal(t, len(out), 1) - conn.SetResourceID(out[0].GetResourceID()) - require.Empty(t, cmp.Diff(out[0], conn)) + require.Empty(t, cmp.Diff(out[0], conn, cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) err = s.PresenceS.DeleteAllTunnelConnections() require.NoError(t, err) @@ -857,8 +845,7 @@ func (s *ServicesTestSuite) TunnelConnectionsCRUD(t *testing.T) { out, err = s.PresenceS.GetTunnelConnections(clusterName) require.NoError(t, err) require.Equal(t, len(out), 1) - conn.SetResourceID(out[0].GetResourceID()) - require.Empty(t, cmp.Diff(out[0], conn)) + require.Empty(t, cmp.Diff(out[0], conn, cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) err = s.PresenceS.DeleteTunnelConnection(clusterName, conn.GetName()) require.NoError(t, err) @@ -945,8 +932,7 @@ func (s *ServicesTestSuite) RemoteClustersCRUD(t *testing.T) { out, err = s.PresenceS.GetRemoteClusters() require.NoError(t, err) require.Equal(t, len(out), 1) - rc.SetResourceID(out[0].GetResourceID()) - require.Empty(t, cmp.Diff(out[0], rc)) + require.Empty(t, cmp.Diff(out[0], rc, cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) err = s.PresenceS.DeleteAllRemoteClusters() require.NoError(t, err) @@ -962,7 +948,7 @@ func (s *ServicesTestSuite) RemoteClustersCRUD(t *testing.T) { out, err = s.PresenceS.GetRemoteClusters() require.NoError(t, err) require.Equal(t, len(out), 1) - require.Empty(t, cmp.Diff(out[0], rc)) + require.Empty(t, cmp.Diff(out[0], rc, cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) err = s.PresenceS.DeleteRemoteCluster(ctx, clusterName) require.NoError(t, err) @@ -1027,8 +1013,7 @@ func (s *ServicesTestSuite) StaticTokens(t *testing.T) { out, err := s.ConfigS.GetStaticTokens() require.NoError(t, err) - staticTokens.SetResourceID(out.GetResourceID()) - require.Empty(t, cmp.Diff(staticTokens, out)) + require.Empty(t, cmp.Diff(staticTokens, out, cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) err = s.ConfigS.DeleteStaticTokens() require.NoError(t, err) @@ -1074,8 +1059,7 @@ func (s *ServicesTestSuite) ClusterName(t *testing.T, opts ...Option) { gotName, err := s.ConfigS.GetClusterName() require.NoError(t, err) - clusterName.SetResourceID(gotName.GetResourceID()) - require.Empty(t, cmp.Diff(clusterName, gotName)) + require.Empty(t, cmp.Diff(clusterName, gotName, cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) err = s.ConfigS.DeleteClusterName() require.NoError(t, err) @@ -1088,8 +1072,7 @@ func (s *ServicesTestSuite) ClusterName(t *testing.T, opts ...Option) { gotName, err = s.ConfigS.GetClusterName() require.NoError(t, err) - clusterName.SetResourceID(gotName.GetResourceID()) - require.Empty(t, cmp.Diff(clusterName, gotName)) + require.Empty(t, cmp.Diff(clusterName, gotName, cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"))) } // ClusterNetworkingConfig tests cluster networking configuration. diff --git a/lib/services/unified_resource_test.go b/lib/services/unified_resource_test.go index 796dc095db746..d60bf34df4cbd 100644 --- a/lib/services/unified_resource_test.go +++ b/lib/services/unified_resource_test.go @@ -196,7 +196,8 @@ func TestUnifiedResourceWatcher(t *testing.T) { expectedRes, res, cmpopts.EquateEmpty(), - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), + cmpopts.IgnoreFields(header.Metadata{}, "ID", "Revision"), // Ignore order. cmpopts.SortSlices(func(a, b types.ResourceWithLabels) bool { return a.GetName() < b.GetName() }), )) @@ -223,7 +224,8 @@ func TestUnifiedResourceWatcher(t *testing.T) { expectedRes, res, cmpopts.EquateEmpty(), - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), + cmpopts.IgnoreFields(header.Metadata{}, "ID", "Revision"), // Ignore order. cmpopts.SortSlices(func(a, b types.ResourceWithLabels) bool { return a.GetName() < b.GetName() }), )) diff --git a/lib/services/user.go b/lib/services/user.go index 5df4c52fac536..6c91294978d29 100644 --- a/lib/services/user.go +++ b/lib/services/user.go @@ -56,7 +56,7 @@ func ValidateUserRoles(ctx context.Context, u types.User, roleGetter RoleGetter) func UsersEquals(u types.User, other types.User) bool { return cmp.Equal(u, other, ignoreProtoXXXFields(), - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), cmpopts.SortSlices(func(a, b *types.MFADevice) bool { return a.Metadata.Name < b.Metadata.Name }), diff --git a/lib/services/watcher_test.go b/lib/services/watcher_test.go index 9c6a0d4a34c47..41d6edff9452e 100644 --- a/lib/services/watcher_test.go +++ b/lib/services/watcher_test.go @@ -523,7 +523,7 @@ func expectLockInForce(t *testing.T, expectedLock types.Lock, err error) { func resourceDiff(res1, res2 types.Resource) string { return cmp.Diff(res1, res2, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), cmpopts.EquateEmpty()) } @@ -1276,7 +1276,7 @@ func TestOktaAssignmentWatcher(t *testing.T) { require.Empty(t, cmp.Diff(expected, changeset, - cmpopts.IgnoreFields(types.Metadata{}, "ID")), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision")), "should be no differences in the changeset after adding the first assignment") case <-w.Done(): t.Fatal("Watcher has unexpectedly exited.") @@ -1300,7 +1300,7 @@ func TestOktaAssignmentWatcher(t *testing.T) { cmp.Diff( expected, changeset, - cmpopts.IgnoreFields(types.Metadata{}, "ID")), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision")), "should be no difference in the changeset after adding the second assignment") case <-w.Done(): t.Fatal("Watcher has unexpectedly exited.") @@ -1324,7 +1324,7 @@ func TestOktaAssignmentWatcher(t *testing.T) { cmp.Diff( expected, changeset, - cmpopts.IgnoreFields(types.Metadata{}, "ID")), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision")), "should be no difference in the changeset after update") case <-w.Done(): t.Fatal("Watcher has unexpectedly exited.") @@ -1346,7 +1346,7 @@ func TestOktaAssignmentWatcher(t *testing.T) { cmp.Diff( expected, changeset, - cmpopts.IgnoreFields(types.Metadata{}, "ID")), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision")), "should be no difference in the changeset after deleting the first assignment") case <-w.Done(): t.Fatal("Watcher has unexpectedly exited.") diff --git a/lib/srv/app/server_test.go b/lib/srv/app/server_test.go index 73d37d391edb1..664fa977cc017 100644 --- a/lib/srv/app/server_test.go +++ b/lib/srv/app/server_test.go @@ -415,7 +415,7 @@ func TestStart(t *testing.T) { sort.Sort(types.AppServers(servers)) require.Empty(t, cmp.Diff([]types.AppServer{serverAWS, serverFoo}, servers, - cmpopts.IgnoreFields(types.Metadata{}, "ID", "Expires"))) + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision", "Expires"))) // Check the expiry time is correct. for _, server := range servers { diff --git a/lib/srv/app/watcher_test.go b/lib/srv/app/watcher_test.go index a1b4e7f2278ef..cf9ae7eab3f1c 100644 --- a/lib/srv/app/watcher_test.go +++ b/lib/srv/app/watcher_test.go @@ -62,7 +62,7 @@ func TestWatcher(t *testing.T) { case a := <-reconcileCh: sort.Sort(a) require.Empty(t, cmp.Diff(types.Apps{app0}, a, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) case <-time.After(time.Second): t.Fatal("Didn't receive reconcile event after 1s.") @@ -79,7 +79,7 @@ func TestWatcher(t *testing.T) { case a := <-reconcileCh: sort.Sort(a) require.Empty(t, cmp.Diff(types.Apps{app0, app1}, a, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) case <-time.After(time.Second): t.Fatal("Didn't receive reconcile event after 1s.") @@ -96,7 +96,7 @@ func TestWatcher(t *testing.T) { case a := <-reconcileCh: sort.Sort(a) require.Empty(t, cmp.Diff(types.Apps{app0, app1}, a, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) case <-time.After(time.Second): t.Fatal("Didn't receive reconcile event after 1s.") @@ -113,7 +113,7 @@ func TestWatcher(t *testing.T) { case a := <-reconcileCh: sort.Sort(a) require.Empty(t, cmp.Diff(types.Apps{app0, app1}, a, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) case <-time.After(time.Second): t.Fatal("Didn't receive reconcile event after 1s.") @@ -129,7 +129,7 @@ func TestWatcher(t *testing.T) { case a := <-reconcileCh: sort.Sort(a) require.Empty(t, cmp.Diff(types.Apps{app0, app1, app2}, a, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) case <-time.After(time.Second): t.Fatal("Didn't receive reconcile event after 1s.") @@ -145,7 +145,7 @@ func TestWatcher(t *testing.T) { case a := <-reconcileCh: sort.Sort(a) require.Empty(t, cmp.Diff(types.Apps{app0, app1, app2}, a, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) case <-time.After(time.Second): t.Fatal("Didn't receive reconcile event after 1s.") @@ -161,7 +161,7 @@ func TestWatcher(t *testing.T) { case a := <-reconcileCh: sort.Sort(a) require.Empty(t, cmp.Diff(types.Apps{app0, app2}, a, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) case <-time.After(time.Second): t.Fatal("Didn't receive reconcile event after 1s.") @@ -175,7 +175,7 @@ func TestWatcher(t *testing.T) { select { case a := <-reconcileCh: require.Empty(t, cmp.Diff(types.Apps{app0}, a, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), )) case <-time.After(time.Second): t.Fatal("Didn't receive reconcile event after 1s.") diff --git a/lib/srv/db/watcher_test.go b/lib/srv/db/watcher_test.go index 1c14f0ae5dc2d..339ab4b853d29 100644 --- a/lib/srv/db/watcher_test.go +++ b/lib/srv/db/watcher_test.go @@ -341,7 +341,7 @@ func assertReconciledResource(t *testing.T, ch chan types.Databases, databases t sort.Sort(d) require.Equal(t, len(d), len(databases)) require.Empty(t, cmp.Diff(databases, d, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), cmpopts.IgnoreFields(types.DatabaseStatusV3{}, "CACert"), )) case <-time.After(time.Second): diff --git a/lib/srv/discovery/discovery_test.go b/lib/srv/discovery/discovery_test.go index c45c32973e51f..a6ff0eabadaa6 100644 --- a/lib/srv/discovery/discovery_test.go +++ b/lib/srv/discovery/discovery_test.go @@ -1483,7 +1483,7 @@ func TestDiscoveryDatabase(t *testing.T) { actualDatabases, err := tlsServer.Auth().GetDatabases(ctx) require.NoError(t, err) require.Empty(t, cmp.Diff(tc.expectDatabases, actualDatabases, - cmpopts.IgnoreFields(types.Metadata{}, "ID"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision"), cmpopts.IgnoreFields(types.DatabaseStatusV3{}, "CACert"), )) case <-time.After(time.Second): diff --git a/tool/tctl/common/resource_command_test.go b/tool/tctl/common/resource_command_test.go index 2412ada58eb6b..a8615272db0e4 100644 --- a/tool/tctl/common/resource_command_test.go +++ b/tool/tctl/common/resource_command_test.go @@ -913,7 +913,7 @@ func (test *dynamicResourceTest[T]) run(t *testing.T) { resources = mustDecodeJSON[[]T](t, buf) require.Len(t, resources, 3) require.Empty(t, cmp.Diff([]T{test.fooResource, test.fooBar1Resource, test.fooBar2Resource}, resources, - cmpopts.IgnoreFields(types.Metadata{}, "ID", "Namespace"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision", "Namespace"), )) // Fetch specific resource. @@ -923,7 +923,7 @@ func (test *dynamicResourceTest[T]) run(t *testing.T) { resources = mustDecodeJSON[[]T](t, buf) require.Len(t, resources, 1) require.Empty(t, cmp.Diff([]T{test.fooResource}, resources, - cmpopts.IgnoreFields(types.Metadata{}, "ID", "Namespace"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision", "Namespace"), )) // Remove a resource. @@ -936,7 +936,7 @@ func (test *dynamicResourceTest[T]) run(t *testing.T) { resources = mustDecodeJSON[[]T](t, buf) require.Len(t, resources, 2) require.Empty(t, cmp.Diff([]T{test.fooBar1Resource, test.fooBar2Resource}, resources, - cmpopts.IgnoreFields(types.Metadata{}, "ID", "Namespace"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision", "Namespace"), )) if !test.runDiscoveredNameChecks { @@ -950,7 +950,7 @@ func (test *dynamicResourceTest[T]) run(t *testing.T) { resources = mustDecodeJSON[[]T](t, buf) require.Len(t, resources, 2) require.Empty(t, cmp.Diff([]T{test.fooBar1Resource, test.fooBar2Resource}, resources, - cmpopts.IgnoreFields(types.Metadata{}, "ID", "Namespace"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision", "Namespace"), )) // Removing multiple resources ("foo-bar-1" and "foo-bar-2") by discovered name is an error. @@ -967,7 +967,7 @@ func (test *dynamicResourceTest[T]) run(t *testing.T) { resources = mustDecodeJSON[[]T](t, buf) require.Len(t, resources, 1) require.Empty(t, cmp.Diff([]T{test.fooBar1Resource}, resources, - cmpopts.IgnoreFields(types.Metadata{}, "ID", "Namespace"), + cmpopts.IgnoreFields(types.Metadata{}, "ID", "Revision", "Namespace"), )) }