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

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