Use cmp.Equal instead of manual Equals methods (#5828)

* Use cmp.Equal instead of manual Equals methods

Equals methods can get out-of-sync with the fields added in structs they
compare. Using `cmp.Equal` handles that, removes a ton of code and makes
it more explicit when specific fields are excluded from comparison.

* Use gogoproto equal plugin for comparing proto values

This will be faster than reflect-based go-cmp.
This commit is contained in:
Andrew Lytvynov
2021-05-06 11:47:31 -07:00
committed by GitHub
parent db6fb57dae
commit ac9ba539ce
25 changed files with 60 additions and 545 deletions
+1 -1
View File
@@ -5,7 +5,7 @@ go 1.15
require (
github.com/gogo/protobuf v1.3.1
github.com/golang/protobuf v1.4.2
github.com/google/go-cmp v0.4.0
github.com/google/go-cmp v0.5.4
github.com/gravitational/trace v1.1.15
github.com/jonboulle/clockwork v0.2.2 // indirect
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
+2 -1
View File
@@ -23,8 +23,9 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/gravitational/trace v1.1.13 h1:4vSuBtVQCbUGj28dm5ke8UPnuejcxeSlz9GEW9X7HIM=
github.com/gravitational/trace v1.1.13/go.mod h1:RvdOUHE4SHqR3oXlFFKnGzms8a5dugHygGw1bqDstYI=
github.com/gravitational/trace v1.1.15 h1:dfaFcARt110nCX6RSvrcRUbvRawEYAasXyCqnhXo0Xg=
-49
View File
@@ -93,8 +93,6 @@ type AccessRequest interface {
// CheckAndSetDefaults validates the access request and
// supplies default values where appropriate.
CheckAndSetDefaults() error
// Equals checks equality between access request values.
Equals(AccessRequest) bool
}
// NewAccessRequest assembled an AccessRequest resource.
@@ -383,30 +381,10 @@ func (r *AccessRequestV3) String() string {
return fmt.Sprintf("AccessRequest(user=%v,roles=%+v)", r.Spec.User, r.Spec.Roles)
}
// Equals compares two AccessRequests
func (r *AccessRequestV3) Equals(other AccessRequest) bool {
o, ok := other.(*AccessRequestV3)
if !ok {
return false
}
if r.GetName() != o.GetName() {
return false
}
return r.Spec.Equals(&o.Spec)
}
func (t AccessReviewThreshold) Equals(other AccessReviewThreshold) bool {
return reflect.DeepEqual(t, other)
}
func (c AccessReviewConditions) IsZero() bool {
return reflect.ValueOf(c).IsZero()
}
func (c AccessRequestConditions) IsZero() bool {
return reflect.ValueOf(c).IsZero()
}
func (s AccessReviewSubmission) Check() error {
if s.RequestID == "" {
return trace.BadParameter("missing request ID")
@@ -544,28 +522,6 @@ func (s RequestState) IsResolved() bool {
return s.IsApproved() || s.IsDenied()
}
// Equals compares two AccessRequestSpecs
func (s *AccessRequestSpecV3) Equals(other *AccessRequestSpecV3) bool {
if s.User != other.User {
return false
}
if len(s.Roles) != len(other.Roles) {
return false
}
for i, role := range s.Roles {
if role != other.Roles[i] {
return false
}
}
if s.Created != other.Created {
return false
}
if s.Expires != other.Expires {
return false
}
return s.State == other.State
}
// key values for map encoding of request filter
const (
keyID = "id"
@@ -620,8 +576,3 @@ func (f *AccessRequestFilter) Match(req AccessRequest) bool {
}
return true
}
// Equals compares two AccessRequestFilters
func (f *AccessRequestFilter) Equals(o AccessRequestFilter) bool {
return f.ID == o.ID && f.User == o.User && f.State == o.State
}
-16
View File
@@ -236,19 +236,3 @@ func (f *PluginDataFilter) Match(data PluginData) bool {
}
return true
}
// Equals compares two PluginDataEntries
func (d *PluginDataEntry) Equals(other *PluginDataEntry) bool {
if other == nil {
return false
}
if len(d.Data) != len(other.Data) {
return false
}
for key, val := range d.Data {
if other.Data[key] != val {
return false
}
}
return true
}
-156
View File
@@ -36,9 +36,6 @@ type Role interface {
Resource
// CheckAndSetDefaults checks and set default values for any missing fields.
CheckAndSetDefaults() error
// Equals returns true if the roles are equal. Roles are equal if options and
// conditions match.
Equals(other Role) bool
// GetOptions gets role options.
GetOptions() RoleOptions
@@ -151,52 +148,6 @@ const (
Deny RoleConditionType = false
)
// Equals returns true if the roles are equal. Roles are equal if options,
// namespaces, logins, labels, and conditions match.
func (r *RoleV3) Equals(other Role) bool {
if !r.GetOptions().Equals(other.GetOptions()) {
return false
}
for _, condition := range []RoleConditionType{Allow, Deny} {
if !utils.StringSlicesEqual(r.GetLogins(condition), other.GetLogins(condition)) {
return false
}
if !utils.StringSlicesEqual(r.GetNamespaces(condition), other.GetNamespaces(condition)) {
return false
}
if !r.GetNodeLabels(condition).Equals(other.GetNodeLabels(condition)) {
return false
}
if !r.GetAppLabels(condition).Equals(other.GetAppLabels(condition)) {
return false
}
if !r.GetDatabaseLabels(condition).Equals(other.GetDatabaseLabels(condition)) {
return false
}
if !utils.StringSlicesEqual(r.GetDatabaseNames(condition), other.GetDatabaseNames(condition)) {
return false
}
if !utils.StringSlicesEqual(r.GetDatabaseUsers(condition), other.GetDatabaseUsers(condition)) {
return false
}
if !RuleSlicesEqual(r.GetRules(condition), other.GetRules(condition)) {
return false
}
if !r.GetClusterLabels(condition).Equals(other.GetClusterLabels(condition)) {
return false
}
if !r.GetKubernetesLabels(condition).Equals(other.GetKubernetesLabels(condition)) {
return false
}
if !r.GetImpersonateConditions(condition).Equals(other.GetImpersonateConditions(condition)) {
return false
}
}
return true
}
// GetVersion returns resource version
func (r *RoleV3) GetVersion() string {
return r.Version
@@ -669,75 +620,11 @@ func (r *RoleV3) String() string {
r.GetName(), r.Spec.Options, r.Spec.Allow, r.Spec.Deny)
}
// Equals checks if all the key/values in the RoleOptions map match.
func (o RoleOptions) Equals(other RoleOptions) bool {
return (o.ForwardAgent.Value() == other.ForwardAgent.Value() &&
o.MaxSessionTTL.Value() == other.MaxSessionTTL.Value() &&
BoolDefaultTrue(o.PortForwarding) == BoolDefaultTrue(other.PortForwarding) &&
o.CertificateFormat == other.CertificateFormat &&
o.ClientIdleTimeout.Value() == other.ClientIdleTimeout.Value() &&
o.DisconnectExpiredCert.Value() == other.DisconnectExpiredCert.Value() &&
utils.StringSlicesEqual(o.BPF, other.BPF))
}
// Equals returns true if the role conditions (logins, namespaces, labels,
// and rules) are equal and false if they are not.
func (r *RoleConditions) Equals(o RoleConditions) bool {
if !utils.StringSlicesEqual(r.Logins, o.Logins) {
return false
}
if !utils.StringSlicesEqual(r.Namespaces, o.Namespaces) {
return false
}
if !r.NodeLabels.Equals(o.NodeLabels) {
return false
}
if !r.AppLabels.Equals(o.AppLabels) {
return false
}
if !r.KubernetesLabels.Equals(o.KubernetesLabels) {
return false
}
if !r.DatabaseLabels.Equals(o.DatabaseLabels) {
return false
}
if !utils.StringSlicesEqual(r.DatabaseNames, o.DatabaseNames) {
return false
}
if !utils.StringSlicesEqual(r.DatabaseUsers, o.DatabaseUsers) {
return false
}
if len(r.Rules) != len(o.Rules) {
return false
}
for i := range r.Rules {
if !r.Rules[i].Equals(o.Rules[i]) {
return false
}
}
return true
}
// IsEmpty returns true if conditions are unspecified
func (i ImpersonateConditions) IsEmpty() bool {
return len(i.Users) == 0 || len(i.Roles) == 0
}
// Equals returns true if the impersonate conditions (logins, roles
// and rules) are equal and false if they are not.
func (i ImpersonateConditions) Equals(o ImpersonateConditions) bool {
if !utils.StringSlicesEqual(i.Users, o.Users) {
return false
}
if !utils.StringSlicesEqual(i.Roles, o.Roles) {
return false
}
if i.Where != o.Where {
return false
}
return true
}
// CheckAndSetDefaults checks and sets default values
func (i ImpersonateConditions) CheckAndSetDefaults() error {
if len(i.Users) != 0 && len(i.Roles) == 0 {
@@ -795,23 +682,6 @@ func (r *Rule) HasVerb(verb string) bool {
return false
}
// Equals returns true if the rule equals to another
func (r *Rule) Equals(other Rule) bool {
if !utils.StringSlicesEqual(r.Resources, other.Resources) {
return false
}
if !utils.StringSlicesEqual(r.Verbs, other.Verbs) {
return false
}
if !utils.StringSlicesEqual(r.Actions, other.Actions) {
return false
}
if r.Where != other.Where {
return false
}
return true
}
// CopyRulesSlice copies input slice of Rules and returns the copy
func CopyRulesSlice(in []Rule) []Rule {
out := make([]Rule, len(in))
@@ -819,19 +689,6 @@ func CopyRulesSlice(in []Rule) []Rule {
return out
}
// RuleSlicesEqual returns true if two rule slices are equal
func RuleSlicesEqual(a, b []Rule) bool {
if len(a) != len(b) {
return false
}
for i := range a {
if !a[i].Equals(b[i]) {
return false
}
}
return true
}
// Labels is a wrapper around map
// that can marshal and unmarshal itself
// from scalar and list values
@@ -897,19 +754,6 @@ func (l Labels) Clone() Labels {
return out
}
// Equals returns true if two label sets are equal
func (l Labels) Equals(o Labels) bool {
if len(l) != len(o) {
return false
}
for key := range l {
if !utils.StringSlicesEqual(l[key], o[key]) {
return false
}
}
return true
}
// NewBool returns Bool struct based on bool value
func NewBool(b bool) Bool {
return Bool(b)
-45
View File
@@ -53,8 +53,6 @@ type SAMLConnector interface {
GetSigningKeyPair() *AsymmetricKeyPair
// GetSigningKeyPair sets signing key pair
SetSigningKeyPair(k *AsymmetricKeyPair)
// Equals returns true if the connectors are identical
Equals(other SAMLConnector) bool
// GetSSO returns SSO service
GetSSO() string
// SetSSO sets SSO service
@@ -219,49 +217,6 @@ func (o *SAMLConnectorV2) SetAssertionConsumerService(v string) {
o.Spec.AssertionConsumerService = v
}
// Equals returns true if the connectors are identical
func (o *SAMLConnectorV2) Equals(other SAMLConnector) bool {
if o.GetName() != other.GetName() {
return false
}
if o.GetCert() != other.GetCert() {
return false
}
if o.GetAudience() != other.GetAudience() {
return false
}
if o.GetEntityDescriptor() != other.GetEntityDescriptor() {
return false
}
if o.Expiry() != other.Expiry() {
return false
}
if o.GetIssuer() != other.GetIssuer() {
return false
}
if (o.GetSigningKeyPair() == nil && other.GetSigningKeyPair() != nil) || (o.GetSigningKeyPair() != nil && other.GetSigningKeyPair() == nil) {
return false
}
if o.GetSigningKeyPair() != nil {
a, b := o.GetSigningKeyPair(), other.GetSigningKeyPair()
if a.Cert != b.Cert || a.PrivateKey != b.PrivateKey {
return false
}
}
mappings := o.GetAttributesToRoles()
otherMappings := other.GetAttributesToRoles()
if len(mappings) != len(otherMappings) {
return false
}
for i := range mappings {
a, b := mappings[i], otherMappings[i]
if a.Name != b.Name || a.Value != b.Value || !utils.StringSlicesEqual(a.Roles, b.Roles) {
return false
}
}
return o.GetSSO() == other.GetSSO()
}
// SetDisplay sets friendly name for this provider.
func (o *SAMLConnectorV2) SetDisplay(display string) {
o.Spec.Display = display
+1 -21
View File
@@ -23,11 +23,8 @@ import (
"strings"
"time"
"github.com/gravitational/teleport/api/utils"
"github.com/gravitational/trace"
"github.com/gogo/protobuf/proto"
"github.com/gravitational/trace"
)
// Server represents a Node, Proxy or Auth server in a Teleport cluster
@@ -354,23 +351,6 @@ type CommandLabel interface {
GetCommand() []string
// Clone returns label copy
Clone() CommandLabel
// Equals returns true if label is equal to the other one
// false otherwise
Equals(CommandLabel) bool
}
// Equals returns true if labels are equal, false otherwise
func (c *CommandLabelV2) Equals(other CommandLabel) bool {
if c.GetPeriod() != other.GetPeriod() {
return false
}
if c.GetResult() != other.GetResult() {
return false
}
if !utils.StringSlicesEqual(c.GetCommand(), other.GetCommand()) {
return false
}
return true
}
// Clone returns non-shallow copy of the label
-5
View File
@@ -581,8 +581,3 @@ func (f *WebSessionFilter) Match(session WebSession) bool {
}
return true
}
// Equals compares two filters.
func (f *WebSessionFilter) Equals(o WebSessionFilter) bool {
return f.User == o.User
}
+3 -25
View File
@@ -20,6 +20,8 @@ import (
"fmt"
"time"
"github.com/google/go-cmp/cmp"
"github.com/gravitational/teleport/api/defaults"
"github.com/gravitational/teleport/api/utils"
@@ -251,7 +253,7 @@ func (c *TrustedClusterV2) CanChangeStateTo(t TrustedCluster) error {
if !utils.StringSlicesEqual(c.GetRoles(), t.GetRoles()) {
return immutableFieldErr("roles")
}
if !c.GetRoleMap().Equals(t.GetRoleMap()) {
if !cmp.Equal(c.GetRoleMap(), t.GetRoleMap()) {
return immutableFieldErr("role_map")
}
@@ -271,33 +273,9 @@ func (c *TrustedClusterV2) String() string {
c.Spec.Enabled, c.Spec.Roles, c.Spec.Token, c.Spec.ProxyAddress, c.Spec.ReverseTunnelAddress)
}
// Equals checks if the two role mappings are equal.
func (r RoleMapping) Equals(o RoleMapping) bool {
if r.Remote != o.Remote {
return false
}
if !utils.StringSlicesEqual(r.Local, r.Local) {
return false
}
return true
}
// RoleMap is a list of mappings
type RoleMap []RoleMapping
// Equals checks if the two role maps are equal.
func (r RoleMap) Equals(o RoleMap) bool {
if len(r) != len(o) {
return false
}
for i := range r {
if !r[i].Equals(o[i]) {
return false
}
}
return true
}
// SortedTrustedCluster sorts clusters by name
type SortedTrustedCluster []TrustedCluster
-5
View File
@@ -308,11 +308,6 @@ func (i *ExternalIdentity) String() string {
return fmt.Sprintf("OIDCIdentity(connectorID=%v, username=%v)", i.ConnectorID, i.Username)
}
// Equals returns true if this identity equals to passed one
func (i *ExternalIdentity) Equals(other *ExternalIdentity) bool {
return i.ConnectorID == other.ConnectorID && i.Username == other.Username
}
// Check returns nil if all parameters are great, err otherwise
func (i *ExternalIdentity) Check() error {
if i.ConnectorID == "" {
+3 -2
View File
@@ -29,6 +29,7 @@ import (
"golang.org/x/crypto/ssh"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/gravitational/teleport"
"github.com/gravitational/teleport/api/constants"
@@ -887,12 +888,12 @@ func (s *AuthSuite) TestUpsertDeleteRoleEventsEmitted(c *C) {
roleRetrieved, err := s.a.GetRole(ctx, "test")
c.Assert(err, IsNil)
c.Assert(roleRetrieved.Equals(roleTest), Equals, true)
c.Assert(cmp.Diff(roleRetrieved, roleTest, cmpopts.IgnoreFields(types.Metadata{}, "ID")), Equals, "")
// test update role
err = s.a.upsertRole(ctx, roleTest)
c.Assert(err, IsNil)
c.Assert(roleRetrieved.Equals(roleTest), Equals, true)
c.Assert(cmp.Diff(roleRetrieved, roleTest, cmpopts.IgnoreFields(types.Metadata{}, "ID")), Equals, "")
c.Assert(s.mockEmitter.LastEvent().GetType(), DeepEquals, events.RoleCreatedEvent)
c.Assert(s.mockEmitter.LastEvent().(*events.RoleCreate).Name, Equals, "test")
s.mockEmitter.Reset()
+3 -1
View File
@@ -24,6 +24,8 @@ import (
"fmt"
"io/ioutil"
"github.com/google/go-cmp/cmp"
"github.com/gravitational/teleport"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/lib/defaults"
@@ -123,7 +125,7 @@ func (a *Server) getSAMLProvider(conn services.SAMLConnector) (*saml2.SAMLServic
defer a.lock.Unlock()
providerPack, ok := a.samlProviders[conn.GetName()]
if ok && providerPack.connector.Equals(conn) {
if ok && cmp.Equal(providerPack.connector, conn) {
return providerPack.provider, nil
}
delete(a.samlProviders, conn.GetName())
+1 -1
View File
@@ -2292,7 +2292,7 @@ func (process *TeleportProcess) setupProxyListeners() (*proxyListeners, error) {
case cfg.Proxy.DisableWebService && cfg.Proxy.DisableReverseTunnel:
process.log.Debugf("Setup Proxy: Reverse tunnel proxy and web proxy are disabled.")
return &listeners, nil
case cfg.Proxy.ReverseTunnelListenAddr.Equals(cfg.Proxy.WebAddr) && !cfg.Proxy.DisableTLS:
case cfg.Proxy.ReverseTunnelListenAddr == cfg.Proxy.WebAddr && !cfg.Proxy.DisableTLS:
process.log.Debugf("Setup Proxy: Reverse tunnel proxy and web proxy listen on the same port, multiplexing is on.")
listener, err := process.importOrCreateListener(listenerProxyTunnelAndWeb, cfg.Proxy.WebAddr.Addr)
if err != nil {
+3 -1
View File
@@ -21,6 +21,8 @@ import (
"fmt"
"sort"
"github.com/google/go-cmp/cmp"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/lib/utils"
"github.com/gravitational/teleport/lib/utils/parse"
@@ -1049,7 +1051,7 @@ func (c *thresholdCollector) pushThreshold(t types.AccessReviewThreshold) (uint3
// don't bother double-storing equivalent thresholds
for i, threshold := range c.Thresholds {
if t.Equals(threshold) {
if cmp.Equal(t, threshold) {
return uint32(i), nil
}
}
+7 -13
View File
@@ -22,10 +22,9 @@ import (
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/lib/fixtures"
"github.com/gravitational/teleport/lib/utils"
"github.com/google/go-cmp/cmp"
"github.com/gravitational/trace"
"github.com/pborman/uuid"
"github.com/stretchr/testify/require"
)
@@ -630,7 +629,7 @@ func TestAccessRequestMarshaling(t *testing.T) {
req2, err := UnmarshalAccessRequest(marshaled)
require.NoError(t, err)
require.True(t, req1.Equals(req2))
require.True(t, cmp.Equal(req1, req2))
}
// TestPluginDataExpectations verifies the correct behavior of the `Expect` mapping.
@@ -810,17 +809,12 @@ func TestRequestFilterConversion(t *testing.T) {
},
}
for _, tc := range testCases {
if m := tc.f.IntoMap(); !utils.StringMapsEqual(m, tc.m) {
t.Errorf("bad map encoding: expected %+v, got %+v", tc.m, m)
}
m := tc.f.IntoMap()
require.Empty(t, cmp.Diff(m, tc.m))
var f AccessRequestFilter
if err := f.FromMap(tc.m); err != nil {
t.Errorf("failed to parse %+v: %s", tc.m, err)
}
if !f.Equals(tc.f) {
t.Errorf("bad map decoding: expected %+v, got %+v", tc.f, f)
}
err := f.FromMap(tc.m)
require.NoError(t, err)
require.Empty(t, cmp.Diff(f, tc.f))
}
badMaps := []map[string]string{
{"food": "carrots"},
-85
View File
@@ -19,7 +19,6 @@ limitations under the License.
package services
import (
"bytes"
"encoding/json"
"fmt"
"time"
@@ -53,37 +52,6 @@ func ValidateLocalAuthSecrets(l *LocalAuthSecrets) error {
return nil
}
// LocalAuthSecretsEquals checks equality (nil safe).
func LocalAuthSecretsEquals(l *LocalAuthSecrets, other *LocalAuthSecrets) bool {
if (l == nil) || (other == nil) {
return l == other
}
if !bytes.Equal(l.PasswordHash, other.PasswordHash) {
return false
}
if len(l.MFA) != len(other.MFA) {
return false
}
mfa := make(map[string]*types.MFADevice, len(l.MFA))
for i, d := range l.MFA {
mfa[d.Id] = l.MFA[i]
}
mfaOther := make(map[string]*types.MFADevice, len(other.MFA))
for i, d := range other.MFA {
mfaOther[d.Id] = other.MFA[i]
}
for id, d := range mfa {
od, ok := mfaOther[id]
if !ok {
return false
}
if !mfaDeviceEquals(d, od) {
return false
}
}
return true
}
// NewTOTPDevice creates a TOTP MFADevice from the given key.
func NewTOTPDevice(name, key string, addedAt time.Time) (*types.MFADevice, error) {
d := types.NewMFADevice(name, uuid.New(), addedAt)
@@ -126,59 +94,6 @@ func validateTOTPDevice(d *types.TOTPDevice) error {
return nil
}
func mfaDeviceEquals(d, other *types.MFADevice) bool {
if (d == nil) || (other == nil) {
return d == other
}
if d.Kind != other.Kind {
return false
}
if d.SubKind != other.SubKind {
return false
}
if d.Version != other.Version {
return false
}
if d.Metadata.Name != other.Metadata.Name {
return false
}
if d.Id != other.Id {
return false
}
if !d.AddedAt.Equal(other.AddedAt) {
return false
}
// Ignore LastUsed, it's a very dynamic field.
if !totpDeviceEquals(d.GetTotp(), other.GetTotp()) {
return false
}
if !u2fDeviceEquals(d.GetU2F(), other.GetU2F()) {
return false
}
return true
}
func totpDeviceEquals(d, other *types.TOTPDevice) bool {
if (d == nil) || (other == nil) {
return d == other
}
return d.Key == other.Key
}
func u2fDeviceEquals(d, other *types.U2FDevice) bool {
if (d == nil) || (other == nil) {
return d == other
}
if !bytes.Equal(d.KeyHandle, other.KeyHandle) {
return false
}
if !bytes.Equal(d.PubKey, other.PubKey) {
return false
}
// Ignore the counter, it's a very dynamic value.
return true
}
// AuthPreferenceSpecSchemaTemplate is JSON schema for AuthPreferenceSpec
const AuthPreferenceSpecSchemaTemplate = `{
"type": "object",
+5 -3
View File
@@ -25,6 +25,8 @@ import (
"golang.org/x/crypto/bcrypt"
"github.com/google/go-cmp/cmp"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/lib/auth/u2f"
"github.com/gravitational/teleport/lib/backend"
@@ -273,7 +275,7 @@ func (s *IdentityService) GetUserByOIDCIdentity(id services.ExternalIdentity) (s
}
for _, u := range users {
for _, uid := range u.GetOIDCIdentities() {
if uid.Equals(&id) {
if cmp.Equal(uid, &id) {
return u, nil
}
}
@@ -290,7 +292,7 @@ func (s *IdentityService) GetUserBySAMLIdentity(id services.ExternalIdentity) (s
}
for _, u := range users {
for _, uid := range u.GetSAMLIdentities() {
if uid.Equals(&id) {
if cmp.Equal(uid, &id) {
return u, nil
}
}
@@ -306,7 +308,7 @@ func (s *IdentityService) GetUserByGithubIdentity(id services.ExternalIdentity)
}
for _, u := range users {
for _, uid := range u.GetGithubIdentities() {
if uid.Equals(&id) {
if cmp.Equal(uid, &id) {
return u, nil
}
}
+4 -2
View File
@@ -24,6 +24,8 @@ import (
"testing"
"time"
"github.com/google/go-cmp/cmp"
"github.com/gravitational/teleport"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/api/types/wrappers"
@@ -440,7 +442,7 @@ func TestRoleParse(t *testing.T) {
}
} else {
require.NoError(t, err)
require.True(t, role.Equals(&tc.role))
require.True(t, cmp.Equal(role, &tc.role))
err := ValidateRole(role)
require.NoError(t, err)
@@ -450,7 +452,7 @@ func TestRoleParse(t *testing.T) {
role2, err := UnmarshalRole(out)
require.NoError(t, err)
require.True(t, role2.Equals(&tc.role))
require.True(t, cmp.Equal(role2, &tc.role))
}
})
}
+10 -72
View File
@@ -39,24 +39,22 @@ const (
Different = iota
)
// Compare compares two provided resources.
func Compare(a, b Resource) int {
// CompareServers compares two provided servers.
func CompareServers(a, b Resource) int {
if serverA, ok := a.(Server); ok {
if serverB, ok := b.(Server); ok {
return CompareServers(serverA, serverB)
return compareServers(serverA, serverB)
}
}
if dbA, ok := a.(types.DatabaseServer); ok {
if dbB, ok := b.(types.DatabaseServer); ok {
return CompareDatabaseServers(dbA, dbB)
return compareDatabaseServers(dbA, dbB)
}
}
return Different
}
// CompareServers returns difference between two server
// objects, Equal (0) if identical, OnlyTimestampsDifferent(1) if only timestamps differ, Different(2) otherwise
func CompareServers(a, b Server) int {
func compareServers(a, b Server) int {
if a.GetKind() != b.GetKind() {
return Different
}
@@ -85,7 +83,7 @@ func CompareServers(a, b Server) int {
if !utils.StringMapsEqual(a.GetLabels(), b.GetLabels()) {
return Different
}
if !CmdLabelMapsEqual(a.GetCmdLabels(), b.GetCmdLabels()) {
if !cmp.Equal(a.GetCmdLabels(), b.GetCmdLabels()) {
return Different
}
if !a.Expiry().Equal(b.Expiry()) {
@@ -95,58 +93,16 @@ func CompareServers(a, b Server) int {
return Different
}
// If this server is proxying applications, compare them to make sure they match.
if a.GetKind() == KindAppServer {
return CompareApps(a.GetApps(), b.GetApps())
if !cmp.Equal(a.GetApps(), b.GetApps()) {
return Different
}
if !cmp.Equal(a.GetKubernetesClusters(), b.GetKubernetesClusters()) {
return Different
}
return Equal
}
// CompareApps compares two slices of apps and returns if they are equal or
// different.
func CompareApps(a []*App, b []*App) int {
if len(a) != len(b) {
return Different
}
for i := range a {
if a[i].Name != b[i].Name {
return Different
}
if a[i].URI != b[i].URI {
return Different
}
if a[i].PublicAddr != b[i].PublicAddr {
return Different
}
if !utils.StringMapsEqual(a[i].StaticLabels, b[i].StaticLabels) {
return Different
}
if !CmdLabelMapsEqual(
V2ToLabels(a[i].DynamicLabels),
V2ToLabels(b[i].DynamicLabels)) {
return Different
}
if (a[i].Rewrite == nil && b[i].Rewrite != nil) ||
(a[i].Rewrite != nil && b[i].Rewrite == nil) {
return Different
}
if a[i].Rewrite != nil && b[i].Rewrite != nil {
if !utils.StringSlicesEqual(a[i].Rewrite.Redirect, b[i].Rewrite.Redirect) {
return Different
}
}
}
return Equal
}
// CompareDatabaseServers returns whether the two provided database servers
// are equal or different.
func CompareDatabaseServers(a, b types.DatabaseServer) int {
func compareDatabaseServers(a, b types.DatabaseServer) int {
if a.GetKind() != b.GetKind() {
return Different
}
@@ -166,7 +122,7 @@ func CompareDatabaseServers(a, b types.DatabaseServer) int {
if !utils.StringMapsEqual(a.GetStaticLabels(), b.GetStaticLabels()) {
return Different
}
if !CmdLabelMapsEqual(a.GetDynamicLabels(), b.GetDynamicLabels()) {
if !cmp.Equal(a.GetDynamicLabels(), b.GetDynamicLabels()) {
return Different
}
if !a.Expiry().Equal(b.Expiry()) {
@@ -181,24 +137,6 @@ func CompareDatabaseServers(a, b types.DatabaseServer) int {
return Equal
}
// CmdLabelMapsEqual compares two maps with command labels,
// returns true if label sets are equal
func CmdLabelMapsEqual(a, b map[string]CommandLabel) bool {
if len(a) != len(b) {
return false
}
for key, val := range a {
val2, ok := b[key]
if !ok {
return false
}
if !val.Equals(val2) {
return false
}
}
return true
}
// CommandLabels is a set of command labels
type CommandLabels map[string]CommandLabel
-1
View File
@@ -318,7 +318,6 @@ var (
NewRole = types.NewRole
NewRule = types.NewRule
CopyRulesSlice = types.CopyRulesSlice
RuleSlicesEqual = types.RuleSlicesEqual
NewBool = types.NewBool
NewBoolOption = types.NewBoolOption
BoolDefaultTrue = types.BoolDefaultTrue
+11 -32
View File
@@ -21,8 +21,12 @@ import (
"fmt"
"time"
"github.com/gravitational/teleport/lib/utils"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/gravitational/trace"
"github.com/gravitational/teleport/api/types"
"github.com/gravitational/teleport/lib/utils"
)
// ValidateUser validates the User and sets default values
@@ -40,37 +44,12 @@ func ValidateUser(u User) error {
// UsersEquals checks if the users are equal
func UsersEquals(u User, other User) bool {
if u.GetName() != other.GetName() {
return false
}
otherIdentities := other.GetOIDCIdentities()
if len(u.GetOIDCIdentities()) != len(otherIdentities) {
return false
}
for i := range u.GetOIDCIdentities() {
if !u.GetOIDCIdentities()[i].Equals(&otherIdentities[i]) {
return false
}
}
otherSAMLIdentities := other.GetSAMLIdentities()
if len(u.GetSAMLIdentities()) != len(otherSAMLIdentities) {
return false
}
for i := range u.GetSAMLIdentities() {
if !u.GetSAMLIdentities()[i].Equals(&otherSAMLIdentities[i]) {
return false
}
}
otherGithubIdentities := other.GetGithubIdentities()
if len(u.GetGithubIdentities()) != len(otherGithubIdentities) {
return false
}
for i := range u.GetGithubIdentities() {
if !u.GetGithubIdentities()[i].Equals(&otherGithubIdentities[i]) {
return false
}
}
return LocalAuthSecretsEquals(u.GetLocalAuth(), other.GetLocalAuth())
return cmp.Equal(u, other,
cmpopts.IgnoreFields(types.Metadata{}, "ID"),
cmpopts.SortSlices(func(a, b *types.MFADevice) bool {
return a.Metadata.Name < b.Metadata.Name
}),
)
}
// LoginAttempt represents successful or unsuccessful attempt for user to login
+2 -2
View File
@@ -334,7 +334,7 @@ func (h *Heartbeat) fetch() error {
h.reset(HeartbeatStateAnnounce)
return nil
}
result := services.Compare(h.current, server)
result := services.CompareServers(h.current, server)
// server update happened, time to announce
if result == services.Different {
h.current = server
@@ -352,7 +352,7 @@ func (h *Heartbeat) fetch() error {
h.setState(HeartbeatStateKeepAlive)
return nil
}
result := services.Compare(h.current, server)
result := services.CompareServers(h.current, server)
// server update happened, move to announce
if result == services.Different {
h.current = server
-5
View File
@@ -65,11 +65,6 @@ func (a *NetAddr) Port(defaultPort int) int {
return porti
}
// Equals returns true if address is equal to other
func (a *NetAddr) Equals(other NetAddr) bool {
return a.Addr == other.Addr && a.AddrNetwork == other.AddrNetwork && a.Path == other.Path
}
// IsLocal returns true if this is a local address
func (a *NetAddr) IsLocal() bool {
host, _, err := net.SplitHostPort(a.Addr)
+1 -1
View File
@@ -116,7 +116,7 @@ func (l *LoadBalancer) RemoveBackend(b NetAddr) error {
defer l.Unlock()
l.currentIndex = -1
for i := range l.backends {
if l.backends[i].Equals(b) {
if l.backends[i] == b {
l.backends = append(l.backends[:i], l.backends[i+1:]...)
l.dropConnections(b)
return nil
+3
View File
@@ -277,8 +277,11 @@ github.com/gravitational/roundtrip
## explicit
github.com/gravitational/teleport/api/client
github.com/gravitational/teleport/api/client/proto
github.com/gravitational/teleport/api/client/webclient
github.com/gravitational/teleport/api/constants
github.com/gravitational/teleport/api/defaults
github.com/gravitational/teleport/api/identityfile
github.com/gravitational/teleport/api/profile
github.com/gravitational/teleport/api/types
github.com/gravitational/teleport/api/types/events
github.com/gravitational/teleport/api/types/wrappers