github.com/gravitational/teleport/api@v0.0.0-20240507183017-3110591cbafc/types/discoveryconfig/discoveryconfig.go (about)

     1  /*
     2  Copyright 2023 Gravitational, Inc.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package discoveryconfig
    18  
    19  import (
    20  	"time"
    21  
    22  	"github.com/gravitational/trace"
    23  
    24  	"github.com/gravitational/teleport/api/types"
    25  	"github.com/gravitational/teleport/api/types/compare"
    26  	"github.com/gravitational/teleport/api/types/header"
    27  	"github.com/gravitational/teleport/api/types/header/convert/legacy"
    28  	"github.com/gravitational/teleport/api/utils"
    29  )
    30  
    31  var _ compare.IsEqual[*DiscoveryConfig] = (*DiscoveryConfig)(nil)
    32  
    33  // DiscoveryConfig describes extra discovery matchers that are added to DiscoveryServices that share the same Discovery Group.
    34  type DiscoveryConfig struct {
    35  	// ResourceHeader is the common resource header for all resources.
    36  	header.ResourceHeader
    37  
    38  	// Spec is the specification for the discovery config.
    39  	Spec Spec `json:"spec" yaml:"spec"`
    40  
    41  	// Status is the status for the discovery config.
    42  	Status Status `json:"status" yaml:"status"`
    43  }
    44  
    45  // Spec is the specification for a discovery config.
    46  type Spec struct {
    47  	// DiscoveryGroup is the Discovery Group for the current DiscoveryConfig.
    48  	// DiscoveryServices should include all the matchers if the DiscoveryGroup matches with their own group.
    49  	DiscoveryGroup string `json:"discovery_group" yaml:"discovery_group"`
    50  
    51  	// AWS is a list of matchers for the supported resources in AWS.
    52  	AWS []types.AWSMatcher `json:"aws,omitempty" yaml:"aws"`
    53  	// Azure is a list of matchers for the supported resources in Azure.
    54  	Azure []types.AzureMatcher `json:"azure,omitempty" yaml:"azure"`
    55  	// GCP is a list of matchers for the supported resources in GCP.
    56  	GCP []types.GCPMatcher `json:"gcp,omitempty" yaml:"gcp"`
    57  	// Kube is a list of matchers for the supported resources in Kubernetes.
    58  	Kube []types.KubernetesMatcher `json:"kube,omitempty" yaml:"kube"`
    59  	// AccessGraph is the configuration for the Access Graph Cloud sync.
    60  	AccessGraph *types.AccessGraphSync `json:"access_graph,omitempty" yaml:"access_graph"`
    61  }
    62  
    63  // Equal checks if the discovery config is equal to another.
    64  // Deprecated: use IsEqual.
    65  func (m *DiscoveryConfig) Equal(n *DiscoveryConfig) bool {
    66  	return m.IsEqual(n)
    67  }
    68  
    69  // IsEqual checks if the discovery config is equal to another.
    70  func (m *DiscoveryConfig) IsEqual(n *DiscoveryConfig) bool {
    71  	return deriveTeleportEqualDiscoveryConfig(m, n)
    72  }
    73  
    74  // Status holds dynamic information about the discovery configuration
    75  // running status such as errors, state and count of the resources.
    76  type Status struct {
    77  	// State is the current state of the discovery config.
    78  	State string `json:"state" yaml:"state"`
    79  	// ErrorMessage holds the error message when state is DISCOVERY_CONFIG_STATE_ERROR.
    80  	ErrorMessage *string `json:"error_message,omitempty" yaml:"error_message,omitempty"`
    81  	// DiscoveredResources holds the count of the discovered resources in the previous iteration.
    82  	DiscoveredResources uint64 `json:"discovered_resources" yaml:"discovered_resources"`
    83  	// LastSyncTime is the timestamp when the Discovery Config was last sync.
    84  	LastSyncTime time.Time `json:"last_sync_time,omitempty" yaml:"last_sync_time,omitempty"`
    85  }
    86  
    87  // NewDiscoveryConfig will create a new discovery config.
    88  func NewDiscoveryConfig(metadata header.Metadata, spec Spec) (*DiscoveryConfig, error) {
    89  	discoveryConfig := &DiscoveryConfig{
    90  		ResourceHeader: header.ResourceHeaderFromMetadata(metadata),
    91  		Spec:           spec,
    92  	}
    93  
    94  	if err := discoveryConfig.CheckAndSetDefaults(); err != nil {
    95  		return nil, trace.Wrap(err)
    96  	}
    97  
    98  	return discoveryConfig, nil
    99  }
   100  
   101  // CheckAndSetDefaults validates fields and populates empty fields with default values.
   102  func (a *DiscoveryConfig) CheckAndSetDefaults() error {
   103  	a.SetKind(types.KindDiscoveryConfig)
   104  	a.SetVersion(types.V1)
   105  
   106  	if err := a.ResourceHeader.CheckAndSetDefaults(); err != nil {
   107  		return trace.Wrap(err)
   108  	}
   109  
   110  	if a.Spec.DiscoveryGroup == "" {
   111  		return trace.BadParameter("discovery config group required")
   112  	}
   113  
   114  	if a.Spec.AWS == nil {
   115  		a.Spec.AWS = make([]types.AWSMatcher, 0)
   116  	}
   117  	for i := range a.Spec.AWS {
   118  		if err := a.Spec.AWS[i].CheckAndSetDefaults(); err != nil {
   119  			return trace.Wrap(err)
   120  		}
   121  	}
   122  
   123  	if a.Spec.Azure == nil {
   124  		a.Spec.Azure = make([]types.AzureMatcher, 0)
   125  	}
   126  	for i := range a.Spec.Azure {
   127  		if err := a.Spec.Azure[i].CheckAndSetDefaults(); err != nil {
   128  			return trace.Wrap(err)
   129  		}
   130  	}
   131  
   132  	if a.Spec.GCP == nil {
   133  		a.Spec.GCP = make([]types.GCPMatcher, 0)
   134  	}
   135  	for i := range a.Spec.GCP {
   136  		if err := a.Spec.GCP[i].CheckAndSetDefaults(); err != nil {
   137  			return trace.Wrap(err)
   138  		}
   139  	}
   140  
   141  	if a.Spec.Kube == nil {
   142  		a.Spec.Kube = make([]types.KubernetesMatcher, 0)
   143  	}
   144  	for i := range a.Spec.Kube {
   145  		if err := a.Spec.Kube[i].CheckAndSetDefaults(); err != nil {
   146  			return trace.Wrap(err)
   147  		}
   148  	}
   149  
   150  	if a.Spec.AccessGraph != nil {
   151  		if err := a.Spec.AccessGraph.CheckAndSetDefaults(); err != nil {
   152  			return trace.Wrap(err)
   153  		}
   154  	}
   155  
   156  	return nil
   157  }
   158  
   159  // GetDiscoveryGroup returns the DiscoveryGroup from the discovery config.
   160  func (a *DiscoveryConfig) GetDiscoveryGroup() string {
   161  	return a.Spec.DiscoveryGroup
   162  }
   163  
   164  // GetMetadata returns metadata. This is specifically for conforming to the Resource interface,
   165  // and should be removed when possible.
   166  func (a *DiscoveryConfig) GetMetadata() types.Metadata {
   167  	return legacy.FromHeaderMetadata(a.Metadata)
   168  }
   169  
   170  // MatchSearch goes through select field values of a resource
   171  // and tries to match against the list of search values.
   172  func (a *DiscoveryConfig) MatchSearch(values []string) bool {
   173  	fieldVals := append(utils.MapToStrings(a.GetAllLabels()), a.GetName(), a.GetDiscoveryGroup())
   174  	return types.MatchSearch(fieldVals, values, nil)
   175  }
   176  
   177  // CloneResource returns a copy of the resource as types.ResourceWithLabels.
   178  func (a *DiscoveryConfig) CloneResource() types.ResourceWithLabels {
   179  	var copy *DiscoveryConfig
   180  	utils.StrictObjectToStruct(a, &copy)
   181  	return copy
   182  }