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

     1  /*
     2  Copyright 2022 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  	"sort"
    22  	"time"
    23  
    24  	"github.com/gravitational/trace"
    25  
    26  	"github.com/gravitational/teleport/api"
    27  	"github.com/gravitational/teleport/api/types/compare"
    28  	"github.com/gravitational/teleport/api/utils"
    29  )
    30  
    31  var _ compare.IsEqual[KubeServer] = (*KubernetesServerV3)(nil)
    32  
    33  // KubeServer represents a single Kubernetes server.
    34  type KubeServer interface {
    35  	// ResourceWithLabels provides common resource methods.
    36  	ResourceWithLabels
    37  	// GetNamespace returns server namespace.
    38  	GetNamespace() string
    39  	// GetTeleportVersion returns the teleport version the server is running on.
    40  	GetTeleportVersion() string
    41  	// GetHostname returns the server hostname.
    42  	GetHostname() string
    43  	// GetHostID returns ID of the host the server is running on.
    44  	GetHostID() string
    45  	// GetRotation gets the state of certificate authority rotation.
    46  	GetRotation() Rotation
    47  	// SetRotation sets the state of certificate authority rotation.
    48  	SetRotation(Rotation)
    49  	// String returns string representation of the server.
    50  	String() string
    51  	// Copy returns a copy of this kube server object.
    52  	Copy() KubeServer
    53  	// CloneResource returns a copy of the KubeServer as a ResourceWithLabels
    54  	CloneResource() ResourceWithLabels
    55  	// GetCluster returns the Kubernetes Cluster this kube server proxies.
    56  	GetCluster() KubeCluster
    57  	// SetCluster sets the kube cluster this kube server server proxies.
    58  	SetCluster(KubeCluster) error
    59  	// ProxiedService provides common methods for a proxied service.
    60  	ProxiedService
    61  }
    62  
    63  // NewKubernetesServerV3 creates a new kube server instance.
    64  func NewKubernetesServerV3(meta Metadata, spec KubernetesServerSpecV3) (*KubernetesServerV3, error) {
    65  	s := &KubernetesServerV3{
    66  		Metadata: meta,
    67  		Spec:     spec,
    68  	}
    69  	if err := s.CheckAndSetDefaults(); err != nil {
    70  		return nil, trace.Wrap(err)
    71  	}
    72  	return s, nil
    73  }
    74  
    75  // NewKubernetesServerV3FromCluster creates a new kubernetes server from the provided clusters.
    76  func NewKubernetesServerV3FromCluster(cluster *KubernetesClusterV3, hostname, hostID string) (*KubernetesServerV3, error) {
    77  	return NewKubernetesServerV3(Metadata{
    78  		Name: cluster.GetName(),
    79  	}, KubernetesServerSpecV3{
    80  		Hostname: hostname,
    81  		HostID:   hostID,
    82  		Cluster:  cluster,
    83  	})
    84  }
    85  
    86  // GetVersion returns the kubernetes server resource version.
    87  func (s *KubernetesServerV3) GetVersion() string {
    88  	return s.Version
    89  }
    90  
    91  // GetTeleportVersion returns the Teleport version the server is running.
    92  func (s *KubernetesServerV3) GetTeleportVersion() string {
    93  	return s.Spec.Version
    94  }
    95  
    96  // GetHostname returns the kubernetes server hostname.
    97  func (s *KubernetesServerV3) GetHostname() string {
    98  	return s.Spec.Hostname
    99  }
   100  
   101  // GetHostID returns ID of the host the server is running on.
   102  func (s *KubernetesServerV3) GetHostID() string {
   103  	return s.Spec.HostID
   104  }
   105  
   106  // GetKind returns the resource kind.
   107  func (s *KubernetesServerV3) GetKind() string {
   108  	return s.Kind
   109  }
   110  
   111  // GetSubKind returns the resource subkind.
   112  func (s *KubernetesServerV3) GetSubKind() string {
   113  	return s.SubKind
   114  }
   115  
   116  // SetSubKind sets the resource subkind.
   117  func (s *KubernetesServerV3) SetSubKind(sk string) {
   118  	s.SubKind = sk
   119  }
   120  
   121  // GetResourceID returns the resource ID.
   122  func (s *KubernetesServerV3) GetResourceID() int64 {
   123  	return s.Metadata.ID
   124  }
   125  
   126  // SetResourceID sets the resource ID.
   127  func (s *KubernetesServerV3) SetResourceID(id int64) {
   128  	s.Metadata.ID = id
   129  }
   130  
   131  // GetRevision returns the revision
   132  func (s *KubernetesServerV3) GetRevision() string {
   133  	return s.Metadata.GetRevision()
   134  }
   135  
   136  // SetRevision sets the revision
   137  func (s *KubernetesServerV3) SetRevision(rev string) {
   138  	s.Metadata.SetRevision(rev)
   139  }
   140  
   141  // GetMetadata returns the resource metadata.
   142  func (s *KubernetesServerV3) GetMetadata() Metadata {
   143  	return s.Metadata
   144  }
   145  
   146  // GetNamespace returns the resource namespace.
   147  func (s *KubernetesServerV3) GetNamespace() string {
   148  	return s.Metadata.Namespace
   149  }
   150  
   151  // SetExpiry sets the resource expiry time.
   152  func (s *KubernetesServerV3) SetExpiry(expiry time.Time) {
   153  	s.Metadata.SetExpiry(expiry)
   154  }
   155  
   156  // Expiry returns the resource expiry time.
   157  func (s *KubernetesServerV3) Expiry() time.Time {
   158  	return s.Metadata.Expiry()
   159  }
   160  
   161  // GetName returns the resource name.
   162  func (s *KubernetesServerV3) GetName() string {
   163  	return s.Metadata.Name
   164  }
   165  
   166  // SetName sets the resource name.
   167  func (s *KubernetesServerV3) SetName(name string) {
   168  	s.Metadata.Name = name
   169  }
   170  
   171  // GetRotation returns the server CA rotation state.
   172  func (s *KubernetesServerV3) GetRotation() Rotation {
   173  	return s.Spec.Rotation
   174  }
   175  
   176  // SetRotation sets the server CA rotation state.
   177  func (s *KubernetesServerV3) SetRotation(r Rotation) {
   178  	s.Spec.Rotation = r
   179  }
   180  
   181  // GetCluster returns the cluster this kube server proxies.
   182  func (s *KubernetesServerV3) GetCluster() KubeCluster {
   183  	if s.Spec.Cluster == nil {
   184  		return nil
   185  	}
   186  	return s.Spec.Cluster
   187  }
   188  
   189  // SetCluster sets the cluster this kube server proxies.
   190  func (s *KubernetesServerV3) SetCluster(cluster KubeCluster) error {
   191  	clusterV3, ok := cluster.(*KubernetesClusterV3)
   192  	if !ok {
   193  		return trace.BadParameter("expected *KubernetesClusterV3, got %T", cluster)
   194  	}
   195  	s.Spec.Cluster = clusterV3
   196  	return nil
   197  }
   198  
   199  // String returns the server string representation.
   200  func (s *KubernetesServerV3) String() string {
   201  	return fmt.Sprintf("KubeServer(Name=%v, Version=%v, Hostname=%v, HostID=%v, Cluster=%v)",
   202  		s.GetName(), s.GetTeleportVersion(), s.GetHostname(), s.GetHostID(), s.GetCluster())
   203  }
   204  
   205  // setStaticFields sets static resource header and metadata fields.
   206  func (s *KubernetesServerV3) setStaticFields() {
   207  	s.Kind = KindKubeServer
   208  	s.Version = V3
   209  }
   210  
   211  // CheckAndSetDefaults checks and sets default values for any missing fields.
   212  func (s *KubernetesServerV3) CheckAndSetDefaults() error {
   213  	s.setStaticFields()
   214  	if err := s.Metadata.CheckAndSetDefaults(); err != nil {
   215  		return trace.Wrap(err)
   216  	}
   217  	if s.Spec.HostID == "" {
   218  		return trace.BadParameter("missing kube server HostID")
   219  	}
   220  	if s.Spec.Version == "" {
   221  		s.Spec.Version = api.Version
   222  	}
   223  	if s.Spec.Cluster == nil {
   224  		return trace.BadParameter("missing kube server Cluster")
   225  	}
   226  
   227  	if err := s.Spec.Cluster.CheckAndSetDefaults(); err != nil {
   228  		return trace.Wrap(err)
   229  	}
   230  
   231  	return nil
   232  }
   233  
   234  // Origin returns the origin value of the resource.
   235  func (s *KubernetesServerV3) Origin() string {
   236  	return s.Metadata.Origin()
   237  }
   238  
   239  // SetOrigin sets the origin value of the resource.
   240  func (s *KubernetesServerV3) SetOrigin(origin string) {
   241  	s.Metadata.SetOrigin(origin)
   242  }
   243  
   244  // GetProxyIDs returns a list of proxy ids this server is connected to.
   245  func (s *KubernetesServerV3) GetProxyIDs() []string {
   246  	return s.Spec.ProxyIDs
   247  }
   248  
   249  // SetProxyID sets the proxy ids this server is connected to.
   250  func (s *KubernetesServerV3) SetProxyIDs(proxyIDs []string) {
   251  	s.Spec.ProxyIDs = proxyIDs
   252  }
   253  
   254  // GetLabel retrieves the label with the provided key. If not found
   255  // value will be empty and ok will be false.
   256  func (s *KubernetesServerV3) GetLabel(key string) (value string, ok bool) {
   257  	if s.Spec.Cluster != nil {
   258  		if v, ok := s.Spec.Cluster.GetLabel(key); ok {
   259  			return v, ok
   260  		}
   261  	}
   262  
   263  	v, ok := s.Metadata.Labels[key]
   264  	return v, ok
   265  }
   266  
   267  // GetAllLabels returns all resource's labels. Considering:
   268  // * Static labels from `Metadata.Labels` and `Spec.Cluster`.
   269  // * Dynamic labels from `Spec.Cluster.Spec`.
   270  func (s *KubernetesServerV3) GetAllLabels() map[string]string {
   271  	staticLabels := make(map[string]string)
   272  	for name, value := range s.Metadata.Labels {
   273  		staticLabels[name] = value
   274  	}
   275  
   276  	var dynamicLabels map[string]CommandLabelV2
   277  	if s.Spec.Cluster != nil {
   278  		for name, value := range s.Spec.Cluster.Metadata.Labels {
   279  			staticLabels[name] = value
   280  		}
   281  
   282  		dynamicLabels = s.Spec.Cluster.Spec.DynamicLabels
   283  	}
   284  
   285  	return CombineLabels(staticLabels, dynamicLabels)
   286  }
   287  
   288  // GetStaticLabels returns the kube server static labels.
   289  func (s *KubernetesServerV3) GetStaticLabels() map[string]string {
   290  	return s.Metadata.Labels
   291  }
   292  
   293  // SetStaticLabels sets the kube server static labels.
   294  func (s *KubernetesServerV3) SetStaticLabels(sl map[string]string) {
   295  	s.Metadata.Labels = sl
   296  }
   297  
   298  // Copy returns a copy of this kube server object.
   299  func (s *KubernetesServerV3) Copy() KubeServer {
   300  	return utils.CloneProtoMsg(s)
   301  }
   302  
   303  // CloneResource returns a copy of this kube server object.
   304  func (s *KubernetesServerV3) CloneResource() ResourceWithLabels {
   305  	return s.Copy()
   306  }
   307  
   308  // MatchSearch goes through select field values and tries to
   309  // match against the list of search values.
   310  func (s *KubernetesServerV3) MatchSearch(values []string) bool {
   311  	return MatchSearch(nil, values, nil)
   312  }
   313  
   314  // IsEqual determines if two kube server resources are equivalent to one another.
   315  func (k *KubernetesServerV3) IsEqual(i KubeServer) bool {
   316  	if other, ok := i.(*KubernetesServerV3); ok {
   317  		return deriveTeleportEqualKubernetesServerV3(k, other)
   318  	}
   319  	return false
   320  }
   321  
   322  // KubeServers represents a list of kube servers.
   323  type KubeServers []KubeServer
   324  
   325  // Len returns the slice length.
   326  func (s KubeServers) Len() int { return len(s) }
   327  
   328  // Less compares kube servers by name and host ID.
   329  func (s KubeServers) Less(i, j int) bool {
   330  	switch {
   331  	case s[i].GetName() < s[j].GetName():
   332  		return true
   333  	case s[i].GetName() > s[j].GetName():
   334  		return false
   335  	default:
   336  		return s[i].GetHostID() < s[j].GetHostID()
   337  	}
   338  }
   339  
   340  // Swap swaps two kube servers.
   341  func (s KubeServers) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
   342  
   343  // ToMap returns these kubernetes clusters as a map keyed by cluster name.
   344  func (s KubeServers) ToMap() map[string]KubeServer {
   345  	m := make(map[string]KubeServer, len(s))
   346  	for _, kubeServer := range s {
   347  		m[kubeServer.GetName()] = kubeServer
   348  	}
   349  	return m
   350  }
   351  
   352  // SortByCustom custom sorts by given sort criteria.
   353  func (s KubeServers) SortByCustom(sortBy SortBy) error {
   354  	if sortBy.Field == "" {
   355  		return nil
   356  	}
   357  
   358  	// We assume sorting by type KubeServer, we are really
   359  	// wanting to sort its contained resource Cluster.
   360  	isDesc := sortBy.IsDesc
   361  	switch sortBy.Field {
   362  	case ResourceMetadataName:
   363  		sort.SliceStable(s, func(i, j int) bool {
   364  			return stringCompare(s[i].GetCluster().GetName(), s[j].GetCluster().GetName(), isDesc)
   365  		})
   366  	case ResourceSpecDescription:
   367  		sort.SliceStable(s, func(i, j int) bool {
   368  			return stringCompare(s[i].GetCluster().GetDescription(), s[j].GetCluster().GetDescription(), isDesc)
   369  		})
   370  	default:
   371  		return trace.NotImplemented("sorting by field %q for resource %q is not supported", sortBy.Field, KindKubeServer)
   372  	}
   373  
   374  	return nil
   375  }
   376  
   377  // AsResources returns kube servers as type resources with labels.
   378  func (s KubeServers) AsResources() []ResourceWithLabels {
   379  	resources := make([]ResourceWithLabels, len(s))
   380  	for i, server := range s {
   381  		resources[i] = ResourceWithLabels(server)
   382  	}
   383  	return resources
   384  }
   385  
   386  // GetFieldVals returns list of select field values.
   387  func (s KubeServers) GetFieldVals(field string) ([]string, error) {
   388  	vals := make([]string, 0, len(s))
   389  	switch field {
   390  	case ResourceMetadataName:
   391  		for _, server := range s {
   392  			vals = append(vals, server.GetCluster().GetName())
   393  		}
   394  	case ResourceSpecDescription:
   395  		for _, server := range s {
   396  			vals = append(vals, server.GetCluster().GetDescription())
   397  		}
   398  	default:
   399  		return nil, trace.NotImplemented("getting field %q for resource %q is not supported", field, KindKubeServer)
   400  	}
   401  
   402  	return vals, nil
   403  }