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

     1  /*
     2  Copyright 2020 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 types
    18  
    19  import (
    20  	"fmt"
    21  	"net"
    22  	"sort"
    23  	"strings"
    24  	"time"
    25  
    26  	"github.com/google/uuid"
    27  	"github.com/gravitational/trace"
    28  
    29  	"github.com/gravitational/teleport/api/utils"
    30  	"github.com/gravitational/teleport/api/utils/aws"
    31  )
    32  
    33  // Server represents a Node, Proxy or Auth server in a Teleport cluster
    34  type Server interface {
    35  	// ResourceWithLabels provides common resource headers
    36  	ResourceWithLabels
    37  	// GetTeleportVersion returns the teleport version the server is running on
    38  	GetTeleportVersion() string
    39  	// GetAddr return server address
    40  	GetAddr() string
    41  	// GetHostname returns server hostname
    42  	GetHostname() string
    43  	// GetNamespace returns server namespace
    44  	GetNamespace() string
    45  	// GetLabels returns server's static label key pairs
    46  	GetLabels() map[string]string
    47  	// GetCmdLabels gets command labels
    48  	GetCmdLabels() map[string]CommandLabel
    49  	// SetCmdLabels sets command labels.
    50  	SetCmdLabels(cmdLabels map[string]CommandLabel)
    51  	// GetPublicAddr returns a public address where this server can be reached.
    52  	GetPublicAddr() string
    53  	// GetPublicAddrs returns a list of public addresses where this server can be reached.
    54  	GetPublicAddrs() []string
    55  	// GetRotation gets the state of certificate authority rotation.
    56  	GetRotation() Rotation
    57  	// SetRotation sets the state of certificate authority rotation.
    58  	SetRotation(Rotation)
    59  	// GetUseTunnel gets if a reverse tunnel should be used to connect to this node.
    60  	GetUseTunnel() bool
    61  	// SetUseTunnel sets if a reverse tunnel should be used to connect to this node.
    62  	SetUseTunnel(bool)
    63  	// String returns string representation of the server
    64  	String() string
    65  	// SetAddr sets server address
    66  	SetAddr(addr string)
    67  	// SetPublicAddrs sets the public addresses where this server can be reached.
    68  	SetPublicAddrs([]string)
    69  	// SetNamespace sets server namespace
    70  	SetNamespace(namespace string)
    71  	// GetPeerAddr returns the peer address of the server.
    72  	GetPeerAddr() string
    73  	// SetPeerAddr sets the peer address of the server.
    74  	SetPeerAddr(string)
    75  	// ProxiedService provides common methods for a proxied service.
    76  	ProxiedService
    77  
    78  	// DeepCopy creates a clone of this server value
    79  	DeepCopy() Server
    80  
    81  	// CloneResource is used to return a clone of the Server and match the CloneAny interface
    82  	// This is helpful when interfacing with multiple types at the same time in unified resources
    83  	CloneResource() ResourceWithLabels
    84  
    85  	// GetCloudMetadata gets the cloud metadata for the server.
    86  	GetCloudMetadata() *CloudMetadata
    87  	// GetAWSInfo returns the AWSInfo for the server.
    88  	GetAWSInfo() *AWSInfo
    89  	// SetCloudMetadata sets the server's cloud metadata.
    90  	SetCloudMetadata(meta *CloudMetadata)
    91  
    92  	// IsOpenSSHNode returns whether the connection to this Server must use OpenSSH.
    93  	// This returns true for SubKindOpenSSHNode and SubKindOpenSSHEICENode.
    94  	IsOpenSSHNode() bool
    95  
    96  	// IsEICE returns whether the Node is an EICE instance.
    97  	// Must be `openssh-ec2-ice` subkind and have the AccountID and InstanceID information (AWS Metadata or Labels).
    98  	IsEICE() bool
    99  
   100  	// GetAWSInstanceID returns the AWS Instance ID if this node comes from an EC2 instance.
   101  	GetAWSInstanceID() string
   102  	// GetAWSAccountID returns the AWS Account ID if this node comes from an EC2 instance.
   103  	GetAWSAccountID() string
   104  }
   105  
   106  // NewServer creates an instance of Server.
   107  func NewServer(name, kind string, spec ServerSpecV2) (Server, error) {
   108  	return NewServerWithLabels(name, kind, spec, map[string]string{})
   109  }
   110  
   111  // NewServerWithLabels is a convenience method to create
   112  // ServerV2 with a specific map of labels.
   113  func NewServerWithLabels(name, kind string, spec ServerSpecV2, labels map[string]string) (Server, error) {
   114  	server := &ServerV2{
   115  		Kind: kind,
   116  		Metadata: Metadata{
   117  			Name:   name,
   118  			Labels: labels,
   119  		},
   120  		Spec: spec,
   121  	}
   122  	if err := server.CheckAndSetDefaults(); err != nil {
   123  		return nil, trace.Wrap(err)
   124  	}
   125  	return server, nil
   126  }
   127  
   128  // NewNode is a convenience method to create a Server of Kind Node.
   129  func NewNode(name, subKind string, spec ServerSpecV2, labels map[string]string) (Server, error) {
   130  	server := &ServerV2{
   131  		Kind:    KindNode,
   132  		SubKind: subKind,
   133  		Metadata: Metadata{
   134  			Name:   name,
   135  			Labels: labels,
   136  		},
   137  		Spec: spec,
   138  	}
   139  	if err := server.CheckAndSetDefaults(); err != nil {
   140  		return nil, trace.Wrap(err)
   141  	}
   142  	return server, nil
   143  }
   144  
   145  // NewNode is a convenience method to create an EICE Node.
   146  func NewEICENode(spec ServerSpecV2, labels map[string]string) (Server, error) {
   147  	server := &ServerV2{
   148  		Kind:    KindNode,
   149  		SubKind: SubKindOpenSSHEICENode,
   150  		Metadata: Metadata{
   151  			Labels: labels,
   152  		},
   153  		Spec: spec,
   154  	}
   155  	if err := server.CheckAndSetDefaults(); err != nil {
   156  		return nil, trace.Wrap(err)
   157  	}
   158  	return server, nil
   159  }
   160  
   161  // GetVersion returns resource version
   162  func (s *ServerV2) GetVersion() string {
   163  	return s.Version
   164  }
   165  
   166  // GetTeleportVersion returns the teleport version the server is running on
   167  func (s *ServerV2) GetTeleportVersion() string {
   168  	return s.Spec.Version
   169  }
   170  
   171  // GetKind returns resource kind
   172  func (s *ServerV2) GetKind() string {
   173  	return s.Kind
   174  }
   175  
   176  // GetSubKind returns resource sub kind
   177  func (s *ServerV2) GetSubKind() string {
   178  	// if the server is a node subkind isn't set, this is a teleport node.
   179  	if s.Kind == KindNode && s.SubKind == "" {
   180  		return SubKindTeleportNode
   181  	}
   182  
   183  	return s.SubKind
   184  }
   185  
   186  // SetSubKind sets resource subkind
   187  func (s *ServerV2) SetSubKind(sk string) {
   188  	s.SubKind = sk
   189  }
   190  
   191  // GetResourceID returns resource ID
   192  func (s *ServerV2) GetResourceID() int64 {
   193  	return s.Metadata.ID
   194  }
   195  
   196  // SetResourceID sets resource ID
   197  func (s *ServerV2) SetResourceID(id int64) {
   198  	s.Metadata.ID = id
   199  }
   200  
   201  // GetRevision returns the revision
   202  func (s *ServerV2) GetRevision() string {
   203  	return s.Metadata.GetRevision()
   204  }
   205  
   206  // SetRevision sets the revision
   207  func (s *ServerV2) SetRevision(rev string) {
   208  	s.Metadata.SetRevision(rev)
   209  }
   210  
   211  // GetMetadata returns metadata
   212  func (s *ServerV2) GetMetadata() Metadata {
   213  	return s.Metadata
   214  }
   215  
   216  // SetNamespace sets server namespace
   217  func (s *ServerV2) SetNamespace(namespace string) {
   218  	s.Metadata.Namespace = namespace
   219  }
   220  
   221  // SetAddr sets server address
   222  func (s *ServerV2) SetAddr(addr string) {
   223  	s.Spec.Addr = addr
   224  }
   225  
   226  // SetExpiry sets expiry time for the object
   227  func (s *ServerV2) SetExpiry(expires time.Time) {
   228  	s.Metadata.SetExpiry(expires)
   229  }
   230  
   231  // Expiry returns object expiry setting
   232  func (s *ServerV2) Expiry() time.Time {
   233  	return s.Metadata.Expiry()
   234  }
   235  
   236  // SetPublicAddrs sets the public proxy addresses where this server can be reached.
   237  func (s *ServerV2) SetPublicAddrs(addrs []string) {
   238  	s.Spec.PublicAddrs = addrs
   239  }
   240  
   241  // GetName returns server name
   242  func (s *ServerV2) GetName() string {
   243  	return s.Metadata.Name
   244  }
   245  
   246  // SetName sets the name of the TrustedCluster.
   247  func (s *ServerV2) SetName(e string) {
   248  	s.Metadata.Name = e
   249  }
   250  
   251  // GetAddr return server address
   252  func (s *ServerV2) GetAddr() string {
   253  	return s.Spec.Addr
   254  }
   255  
   256  // GetPublicAddr returns a public address where this server can be reached.
   257  func (s *ServerV2) GetPublicAddr() string {
   258  	addrs := s.GetPublicAddrs()
   259  	if len(addrs) != 0 {
   260  		return addrs[0]
   261  	}
   262  	return ""
   263  }
   264  
   265  // GetPublicAddrs returns a list of public addresses where this server can be reached.
   266  func (s *ServerV2) GetPublicAddrs() []string {
   267  	return s.Spec.PublicAddrs
   268  }
   269  
   270  // GetRotation gets the state of certificate authority rotation.
   271  func (s *ServerV2) GetRotation() Rotation {
   272  	return s.Spec.Rotation
   273  }
   274  
   275  // SetRotation sets the state of certificate authority rotation.
   276  func (s *ServerV2) SetRotation(r Rotation) {
   277  	s.Spec.Rotation = r
   278  }
   279  
   280  // GetUseTunnel gets if a reverse tunnel should be used to connect to this node.
   281  func (s *ServerV2) GetUseTunnel() bool {
   282  	return s.Spec.UseTunnel
   283  }
   284  
   285  // SetUseTunnel sets if a reverse tunnel should be used to connect to this node.
   286  func (s *ServerV2) SetUseTunnel(useTunnel bool) {
   287  	s.Spec.UseTunnel = useTunnel
   288  }
   289  
   290  // GetHostname returns server hostname
   291  func (s *ServerV2) GetHostname() string {
   292  	return s.Spec.Hostname
   293  }
   294  
   295  // GetLabel retrieves the label with the provided key. If not found
   296  // value will be empty and ok will be false.
   297  func (s *ServerV2) GetLabel(key string) (value string, ok bool) {
   298  	if cmd, ok := s.Spec.CmdLabels[key]; ok {
   299  		return cmd.Result, ok
   300  	}
   301  
   302  	v, ok := s.Metadata.Labels[key]
   303  	return v, ok
   304  }
   305  
   306  // GetLabels returns server's static label key pairs.
   307  // GetLabels and GetStaticLabels are the same, and that is intentional. GetLabels
   308  // exists to preserve backwards compatibility, while GetStaticLabels exists to
   309  // implement ResourcesWithLabels.
   310  func (s *ServerV2) GetLabels() map[string]string {
   311  	return s.Metadata.Labels
   312  }
   313  
   314  // GetStaticLabels returns the server static labels.
   315  // GetLabels and GetStaticLabels are the same, and that is intentional. GetLabels
   316  // exists to preserve backwards compatibility, while GetStaticLabels exists to
   317  // implement ResourcesWithLabels.
   318  func (s *ServerV2) GetStaticLabels() map[string]string {
   319  	return s.Metadata.Labels
   320  }
   321  
   322  // SetStaticLabels sets the server static labels.
   323  func (s *ServerV2) SetStaticLabels(sl map[string]string) {
   324  	s.Metadata.Labels = sl
   325  }
   326  
   327  // GetCmdLabels returns command labels
   328  func (s *ServerV2) GetCmdLabels() map[string]CommandLabel {
   329  	if s.Spec.CmdLabels == nil {
   330  		return nil
   331  	}
   332  	return V2ToLabels(s.Spec.CmdLabels)
   333  }
   334  
   335  // Origin returns the origin value of the resource.
   336  func (s *ServerV2) Origin() string {
   337  	return s.Metadata.Origin()
   338  }
   339  
   340  // SetOrigin sets the origin value of the resource.
   341  func (s *ServerV2) SetOrigin(origin string) {
   342  	s.Metadata.SetOrigin(origin)
   343  }
   344  
   345  // SetCmdLabels sets dynamic labels.
   346  func (s *ServerV2) SetCmdLabels(cmdLabels map[string]CommandLabel) {
   347  	s.Spec.CmdLabels = LabelsToV2(cmdLabels)
   348  }
   349  
   350  func (s *ServerV2) String() string {
   351  	return fmt.Sprintf("Server(name=%v, namespace=%v, addr=%v, labels=%v)", s.Metadata.Name, s.Metadata.Namespace, s.Spec.Addr, s.Metadata.Labels)
   352  }
   353  
   354  // GetNamespace returns server namespace
   355  func (s *ServerV2) GetNamespace() string {
   356  	return ProcessNamespace(s.Metadata.Namespace)
   357  }
   358  
   359  // GetProxyID returns the proxy id this server is connected to.
   360  func (s *ServerV2) GetProxyIDs() []string {
   361  	return s.Spec.ProxyIDs
   362  }
   363  
   364  // SetProxyID sets the proxy ids this server is connected to.
   365  func (s *ServerV2) SetProxyIDs(proxyIDs []string) {
   366  	s.Spec.ProxyIDs = proxyIDs
   367  }
   368  
   369  // GetAllLabels returns the full key:value map of both static labels and
   370  // "command labels"
   371  func (s *ServerV2) GetAllLabels() map[string]string {
   372  	// server labels (static and dynamic)
   373  	labels := CombineLabels(s.Metadata.Labels, s.Spec.CmdLabels)
   374  	return labels
   375  }
   376  
   377  // CombineLabels combines the passed in static and dynamic labels.
   378  func CombineLabels(static map[string]string, dynamic map[string]CommandLabelV2) map[string]string {
   379  	if len(dynamic) == 0 {
   380  		return static
   381  	}
   382  
   383  	lmap := make(map[string]string, len(static)+len(dynamic))
   384  	for key, value := range static {
   385  		lmap[key] = value
   386  	}
   387  	for key, cmd := range dynamic {
   388  		lmap[key] = cmd.Result
   389  	}
   390  	return lmap
   391  }
   392  
   393  // GetPeerAddr returns the peer address of the server.
   394  func (s *ServerV2) GetPeerAddr() string {
   395  	return s.Spec.PeerAddr
   396  }
   397  
   398  // SetPeerAddr sets the peer address of the server.
   399  func (s *ServerV2) SetPeerAddr(addr string) {
   400  	s.Spec.PeerAddr = addr
   401  }
   402  
   403  // setStaticFields sets static resource header and metadata fields.
   404  func (s *ServerV2) setStaticFields() {
   405  	s.Version = V2
   406  }
   407  
   408  // IsOpenSSHNode returns whether the connection to this Server must use OpenSSH.
   409  // This returns true for SubKindOpenSSHNode and SubKindOpenSSHEICENode.
   410  func (s *ServerV2) IsOpenSSHNode() bool {
   411  	return IsOpenSSHNodeSubKind(s.SubKind)
   412  }
   413  
   414  // IsOpenSSHNodeSubKind returns whether the Node SubKind is from a server which accepts connections over the
   415  // OpenSSH daemon (instead of a Teleport Node).
   416  func IsOpenSSHNodeSubKind(subkind string) bool {
   417  	return subkind == SubKindOpenSSHNode || subkind == SubKindOpenSSHEICENode
   418  }
   419  
   420  // GetAWSAccountID returns the AWS Account ID if this node comes from an EC2 instance.
   421  func (s *ServerV2) GetAWSAccountID() string {
   422  	awsAccountID, _ := s.GetLabel(AWSAccountIDLabel)
   423  
   424  	awsMetadata := s.GetAWSInfo()
   425  	if awsMetadata != nil && awsMetadata.AccountID != "" {
   426  		awsAccountID = awsMetadata.AccountID
   427  	}
   428  	return awsAccountID
   429  }
   430  
   431  // GetAWSInstanceID returns the AWS Instance ID if this node comes from an EC2 instance.
   432  func (s *ServerV2) GetAWSInstanceID() string {
   433  	awsInstanceID, _ := s.GetLabel(AWSInstanceIDLabel)
   434  
   435  	awsMetadata := s.GetAWSInfo()
   436  	if awsMetadata != nil && awsMetadata.InstanceID != "" {
   437  		awsInstanceID = awsMetadata.InstanceID
   438  	}
   439  	return awsInstanceID
   440  }
   441  
   442  // IsEICE returns whether the Node is an EICE instance.
   443  // Must be `openssh-ec2-ice` subkind and have the AccountID and InstanceID information (AWS Metadata or Labels).
   444  func (s *ServerV2) IsEICE() bool {
   445  	if s.SubKind != SubKindOpenSSHEICENode {
   446  		return false
   447  	}
   448  
   449  	return s.GetAWSAccountID() != "" && s.GetAWSInstanceID() != ""
   450  }
   451  
   452  // openSSHNodeCheckAndSetDefaults are common validations for OpenSSH nodes.
   453  // They include SubKindOpenSSHNode and SubKindOpenSSHEICENode.
   454  func (s *ServerV2) openSSHNodeCheckAndSetDefaults() error {
   455  	if s.Spec.Addr == "" {
   456  		return trace.BadParameter("addr must be set when server SubKind is %q", s.GetSubKind())
   457  	}
   458  	if len(s.GetPublicAddrs()) != 0 {
   459  		return trace.BadParameter("publicAddrs must not be set when server SubKind is %q", s.GetSubKind())
   460  	}
   461  	if s.Spec.Hostname == "" {
   462  		return trace.BadParameter("hostname must be set when server SubKind is %q", s.GetSubKind())
   463  	}
   464  
   465  	_, _, err := net.SplitHostPort(s.Spec.Addr)
   466  	if err != nil {
   467  		return trace.BadParameter("invalid Addr %q: %v", s.Spec.Addr, err)
   468  	}
   469  	return nil
   470  }
   471  
   472  // openSSHEC2InstanceConnectEndpointNodeCheckAndSetDefaults are validations for SubKindOpenSSHEICENode.
   473  func (s *ServerV2) openSSHEC2InstanceConnectEndpointNodeCheckAndSetDefaults() error {
   474  	if err := s.openSSHNodeCheckAndSetDefaults(); err != nil {
   475  		return trace.Wrap(err)
   476  	}
   477  
   478  	// AWS fields are required for SubKindOpenSSHEICENode.
   479  	switch {
   480  	case s.Spec.CloudMetadata == nil || s.Spec.CloudMetadata.AWS == nil:
   481  		return trace.BadParameter("missing AWS CloudMetadata (required for %q SubKind)", s.SubKind)
   482  
   483  	case s.Spec.CloudMetadata.AWS.AccountID == "":
   484  		return trace.BadParameter("missing AWS Account ID (required for %q SubKind)", s.SubKind)
   485  
   486  	case s.Spec.CloudMetadata.AWS.Region == "":
   487  		return trace.BadParameter("missing AWS Region (required for %q SubKind)", s.SubKind)
   488  
   489  	case s.Spec.CloudMetadata.AWS.Integration == "":
   490  		return trace.BadParameter("missing AWS OIDC Integration (required for %q SubKind)", s.SubKind)
   491  
   492  	case s.Spec.CloudMetadata.AWS.InstanceID == "":
   493  		return trace.BadParameter("missing AWS InstanceID (required for %q SubKind)", s.SubKind)
   494  
   495  	case s.Spec.CloudMetadata.AWS.VPCID == "":
   496  		return trace.BadParameter("missing AWS VPC ID (required for %q SubKind)", s.SubKind)
   497  
   498  	case s.Spec.CloudMetadata.AWS.SubnetID == "":
   499  		return trace.BadParameter("missing AWS Subnet ID (required for %q SubKind)", s.SubKind)
   500  	}
   501  
   502  	return nil
   503  }
   504  
   505  // serverNameForEICE returns the deterministic Server's name for an EICE instance.
   506  // This name must comply with the expected format for EC2 Nodes as defined here: api/utils/aws.IsEC2NodeID
   507  // Returns an error if AccountID or InstanceID is not present.
   508  func serverNameForEICE(s *ServerV2) (string, error) {
   509  	awsAccountID := s.GetAWSAccountID()
   510  	awsInstanceID := s.GetAWSInstanceID()
   511  
   512  	if awsAccountID != "" && awsInstanceID != "" {
   513  		eiceNodeName := fmt.Sprintf("%s-%s", awsAccountID, awsInstanceID)
   514  		if !aws.IsEC2NodeID(eiceNodeName) {
   515  			return "", trace.BadParameter("invalid account %q or instance id %q", awsAccountID, awsInstanceID)
   516  		}
   517  		return eiceNodeName, nil
   518  	}
   519  
   520  	return "", trace.BadParameter("missing account id or instance id in %s node", SubKindOpenSSHEICENode)
   521  }
   522  
   523  // CheckAndSetDefaults checks and set default values for any missing fields.
   524  func (s *ServerV2) CheckAndSetDefaults() error {
   525  	// TODO(awly): default s.Metadata.Expiry if not set (use
   526  	// defaults.ServerAnnounceTTL).
   527  	s.setStaticFields()
   528  
   529  	if s.Metadata.Name == "" {
   530  		switch s.SubKind {
   531  		case SubKindOpenSSHEICENode:
   532  			// For EICE nodes, use a deterministic name.
   533  			eiceNodeName, err := serverNameForEICE(s)
   534  			if err != nil {
   535  				return trace.Wrap(err)
   536  			}
   537  			s.Metadata.Name = eiceNodeName
   538  		case SubKindOpenSSHNode:
   539  			// if the server is a registered OpenSSH node, allow the name to be
   540  			// randomly generated
   541  			s.Metadata.Name = uuid.NewString()
   542  		}
   543  	}
   544  
   545  	if err := s.Metadata.CheckAndSetDefaults(); err != nil {
   546  		return trace.Wrap(err)
   547  	}
   548  
   549  	if s.Kind == "" {
   550  		return trace.BadParameter("server Kind is empty")
   551  	}
   552  	if s.Kind != KindNode && s.SubKind != "" {
   553  		return trace.BadParameter(`server SubKind must only be set when Kind is "node"`)
   554  	}
   555  
   556  	switch s.SubKind {
   557  	case "", SubKindTeleportNode:
   558  		// allow but do nothing
   559  	case SubKindOpenSSHNode:
   560  		if err := s.openSSHNodeCheckAndSetDefaults(); err != nil {
   561  			return trace.Wrap(err)
   562  		}
   563  
   564  	case SubKindOpenSSHEICENode:
   565  		if err := s.openSSHEC2InstanceConnectEndpointNodeCheckAndSetDefaults(); err != nil {
   566  			return trace.Wrap(err)
   567  		}
   568  
   569  	default:
   570  		return trace.BadParameter("invalid SubKind %q", s.SubKind)
   571  	}
   572  
   573  	for key := range s.Spec.CmdLabels {
   574  		if !IsValidLabelKey(key) {
   575  			return trace.BadParameter("invalid label key: %q", key)
   576  		}
   577  	}
   578  
   579  	return nil
   580  }
   581  
   582  // MatchSearch goes through select field values and tries to
   583  // match against the list of search values.
   584  func (s *ServerV2) MatchSearch(values []string) bool {
   585  	if s.GetKind() != KindNode {
   586  		return false
   587  	}
   588  
   589  	var custom func(val string) bool
   590  	if s.GetUseTunnel() {
   591  		custom = func(val string) bool {
   592  			return strings.EqualFold(val, "tunnel")
   593  		}
   594  	}
   595  
   596  	fieldVals := make([]string, 0, (len(s.Metadata.Labels)*2)+(len(s.Spec.CmdLabels)*2)+len(s.Spec.PublicAddrs)+3)
   597  
   598  	labels := CombineLabels(s.Metadata.Labels, s.Spec.CmdLabels)
   599  	for key, value := range labels {
   600  		fieldVals = append(fieldVals, key, value)
   601  	}
   602  
   603  	fieldVals = append(fieldVals, s.Metadata.Name, s.Spec.Hostname, s.Spec.Addr)
   604  	fieldVals = append(fieldVals, s.Spec.PublicAddrs...)
   605  
   606  	return MatchSearch(fieldVals, values, custom)
   607  }
   608  
   609  // DeepCopy creates a clone of this server value
   610  func (s *ServerV2) DeepCopy() Server {
   611  	return utils.CloneProtoMsg(s)
   612  }
   613  
   614  // CloneResource creates a clone of this server value
   615  func (s *ServerV2) CloneResource() ResourceWithLabels {
   616  	return s.DeepCopy()
   617  }
   618  
   619  // GetCloudMetadata gets the cloud metadata for the server.
   620  func (s *ServerV2) GetCloudMetadata() *CloudMetadata {
   621  	return s.Spec.CloudMetadata
   622  }
   623  
   624  // GetAWSInfo gets the AWS Cloud metadata for the server.
   625  func (s *ServerV2) GetAWSInfo() *AWSInfo {
   626  	if s.Spec.CloudMetadata == nil {
   627  		return nil
   628  	}
   629  
   630  	return s.Spec.CloudMetadata.AWS
   631  }
   632  
   633  // SetCloudMetadata sets the server's cloud metadata.
   634  func (s *ServerV2) SetCloudMetadata(meta *CloudMetadata) {
   635  	s.Spec.CloudMetadata = meta
   636  }
   637  
   638  // CommandLabel is a label that has a value as a result of the
   639  // output generated by running command, e.g. hostname
   640  type CommandLabel interface {
   641  	// GetPeriod returns label period
   642  	GetPeriod() time.Duration
   643  	// SetPeriod sets label period
   644  	SetPeriod(time.Duration)
   645  	// GetResult returns label result
   646  	GetResult() string
   647  	// SetResult sets label result
   648  	SetResult(string)
   649  	// GetCommand returns to execute and set as a label result
   650  	GetCommand() []string
   651  	// Clone returns label copy
   652  	Clone() CommandLabel
   653  }
   654  
   655  // Clone returns non-shallow copy of the label
   656  func (c *CommandLabelV2) Clone() CommandLabel {
   657  	command := make([]string, len(c.Command))
   658  	copy(command, c.Command)
   659  	return &CommandLabelV2{
   660  		Command: command,
   661  		Period:  c.Period,
   662  		Result:  c.Result,
   663  	}
   664  }
   665  
   666  // SetResult sets label result
   667  func (c *CommandLabelV2) SetResult(r string) {
   668  	c.Result = r
   669  }
   670  
   671  // SetPeriod sets label period
   672  func (c *CommandLabelV2) SetPeriod(p time.Duration) {
   673  	c.Period = Duration(p)
   674  }
   675  
   676  // GetPeriod returns label period
   677  func (c *CommandLabelV2) GetPeriod() time.Duration {
   678  	return c.Period.Duration()
   679  }
   680  
   681  // GetResult returns label result
   682  func (c *CommandLabelV2) GetResult() string {
   683  	return c.Result
   684  }
   685  
   686  // GetCommand returns to execute and set as a label result
   687  func (c *CommandLabelV2) GetCommand() []string {
   688  	return c.Command
   689  }
   690  
   691  // V2ToLabels converts concrete type to command label interface.
   692  func V2ToLabels(l map[string]CommandLabelV2) map[string]CommandLabel {
   693  	out := make(map[string]CommandLabel, len(l))
   694  	for key := range l {
   695  		val := l[key]
   696  		out[key] = &val
   697  	}
   698  	return out
   699  }
   700  
   701  // LabelsToV2 converts labels from interface to V2 spec
   702  func LabelsToV2(labels map[string]CommandLabel) map[string]CommandLabelV2 {
   703  	out := make(map[string]CommandLabelV2, len(labels))
   704  	for key, val := range labels {
   705  		out[key] = CommandLabelV2{
   706  			Period:  NewDuration(val.GetPeriod()),
   707  			Result:  val.GetResult(),
   708  			Command: val.GetCommand(),
   709  		}
   710  	}
   711  	return out
   712  }
   713  
   714  // Servers represents a list of servers.
   715  type Servers []Server
   716  
   717  // Len returns the slice length.
   718  func (s Servers) Len() int { return len(s) }
   719  
   720  // Less compares servers by name.
   721  func (s Servers) Less(i, j int) bool {
   722  	return s[i].GetName() < s[j].GetName()
   723  }
   724  
   725  // Swap swaps two servers.
   726  func (s Servers) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
   727  
   728  // SortByCustom custom sorts by given sort criteria.
   729  func (s Servers) SortByCustom(sortBy SortBy) error {
   730  	if sortBy.Field == "" {
   731  		return nil
   732  	}
   733  
   734  	isDesc := sortBy.IsDesc
   735  	switch sortBy.Field {
   736  	case ResourceMetadataName:
   737  		sort.SliceStable(s, func(i, j int) bool {
   738  			return stringCompare(s[i].GetName(), s[j].GetName(), isDesc)
   739  		})
   740  	case ResourceSpecHostname:
   741  		sort.SliceStable(s, func(i, j int) bool {
   742  			return stringCompare(s[i].GetHostname(), s[j].GetHostname(), isDesc)
   743  		})
   744  	case ResourceSpecAddr:
   745  		sort.SliceStable(s, func(i, j int) bool {
   746  			return stringCompare(s[i].GetAddr(), s[j].GetAddr(), isDesc)
   747  		})
   748  	default:
   749  		return trace.NotImplemented("sorting by field %q for resource %q is not supported", sortBy.Field, KindNode)
   750  	}
   751  
   752  	return nil
   753  }
   754  
   755  // AsResources returns as type resources with labels.
   756  func (s Servers) AsResources() []ResourceWithLabels {
   757  	resources := make([]ResourceWithLabels, 0, len(s))
   758  	for _, server := range s {
   759  		resources = append(resources, ResourceWithLabels(server))
   760  	}
   761  	return resources
   762  }
   763  
   764  // GetFieldVals returns list of select field values.
   765  func (s Servers) GetFieldVals(field string) ([]string, error) {
   766  	vals := make([]string, 0, len(s))
   767  	switch field {
   768  	case ResourceMetadataName:
   769  		for _, server := range s {
   770  			vals = append(vals, server.GetName())
   771  		}
   772  	case ResourceSpecHostname:
   773  		for _, server := range s {
   774  			vals = append(vals, server.GetHostname())
   775  		}
   776  	case ResourceSpecAddr:
   777  		for _, server := range s {
   778  			vals = append(vals, server.GetAddr())
   779  		}
   780  	default:
   781  		return nil, trace.NotImplemented("getting field %q for resource %q is not supported", field, KindNode)
   782  	}
   783  
   784  	return vals, nil
   785  }