github.com/gravitational/teleport/api@v0.0.0-20240507183017-3110591cbafc/types/tunnel_strategy.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  	"encoding/json"
    21  
    22  	"github.com/gravitational/trace"
    23  
    24  	"github.com/gravitational/teleport/api/utils"
    25  )
    26  
    27  const (
    28  	tunnelStrategyTypeParam     = "type"
    29  	defaultAgentConnectionCount = 1
    30  )
    31  
    32  // DefaultAgentMeshTunnelStrategy sets default values for a agent mesh
    33  // tunnel strategy.
    34  func DefaultAgentMeshTunnelStrategy() *AgentMeshTunnelStrategy {
    35  	return &AgentMeshTunnelStrategy{}
    36  }
    37  
    38  // DefaultProxyPeeringTunnelStrategy sets default values for a proxy peering
    39  // tunnel strategy.
    40  func DefaultProxyPeeringTunnelStrategy() *ProxyPeeringTunnelStrategy {
    41  	return &ProxyPeeringTunnelStrategy{
    42  		AgentConnectionCount: defaultAgentConnectionCount,
    43  	}
    44  }
    45  
    46  // DefaultTunnelStrategy is the default tunnel strategy used when one is not
    47  // specified.
    48  func DefaultTunnelStrategy() TunnelStrategy {
    49  	return &TunnelStrategyV1_AgentMesh{
    50  		AgentMesh: DefaultAgentMeshTunnelStrategy(),
    51  	}
    52  }
    53  
    54  // TunnelStrategy defines methods to be implemented by any TunnelStrategy.
    55  type TunnelStrategy interface {
    56  	isTunnelStrategyV1_Strategy
    57  	CheckAndSetDefaults() error
    58  }
    59  
    60  // tunnelStrategyConfig represents a unparsed tunnel strategy configuration.
    61  type tunnelStrategyConfig struct {
    62  	Type   TunnelStrategyType     `yaml:"type"`
    63  	Params map[string]interface{} `yaml:",inline"`
    64  }
    65  
    66  // newTunnelStrategyConfig creates a new tunnelStrategyConfig instance.
    67  func newTunnelStrategyConfig() *tunnelStrategyConfig {
    68  	return &tunnelStrategyConfig{}
    69  }
    70  
    71  // setFromMap sets a TunnelStrategyConfig from a map.
    72  func (c *tunnelStrategyConfig) setFromMap(m map[string]interface{}) error {
    73  	rawStrategy, ok := m[tunnelStrategyTypeParam]
    74  	if !ok {
    75  		return trace.BadParameter("missing type parameter")
    76  	}
    77  
    78  	// The map representation of TunnelStrategyType is expected to be a string.
    79  	strategyType, ok := rawStrategy.(string)
    80  	if !ok {
    81  		return trace.BadParameter("invalid type parameter")
    82  	}
    83  	c.Type = TunnelStrategyType(strategyType)
    84  
    85  	c.Params = make(map[string]interface{}, len(m)-1)
    86  	for k, v := range m {
    87  		if k == tunnelStrategyTypeParam {
    88  			continue
    89  		}
    90  		c.Params[k] = v
    91  	}
    92  	return nil
    93  }
    94  
    95  // getMapCopy returns a TunnelStrategyConfig as a map.
    96  func (c *tunnelStrategyConfig) getMapCopy() map[string]interface{} {
    97  	mCopy := make(map[string]interface{}, len(c.Params)+1)
    98  	for k, v := range c.Params {
    99  		mCopy[k] = v
   100  	}
   101  
   102  	// The map representation of TunnelStrategyType is expected to be a string.
   103  	mCopy[tunnelStrategyTypeParam] = string(c.Type)
   104  	return mCopy
   105  }
   106  
   107  // MarshalYAML converts a TunnelStrategyV1 to yaml.
   108  func (s *TunnelStrategyV1) MarshalYAML() (interface{}, error) {
   109  	var config *tunnelStrategyConfig
   110  	err := s.marshal(func(c *tunnelStrategyConfig) error {
   111  		config = c
   112  		return nil
   113  	})
   114  	if err != nil {
   115  		return nil, trace.Wrap(err)
   116  	}
   117  	return config.getMapCopy(), nil
   118  }
   119  
   120  // UnmarshalYAML converts yaml to a TunnelStrategyV1 using a strict policy to
   121  // disallow unknown fields.
   122  func (s *TunnelStrategyV1) UnmarshalYAML(unmarshal func(interface{}) error) error {
   123  	err := s.unmarshal(utils.StrictObjectToStruct, func(c *tunnelStrategyConfig) error {
   124  		return trace.Wrap(unmarshal(c))
   125  	})
   126  	return trace.Wrap(err)
   127  }
   128  
   129  // MarshalJSON converts a TunnelStrategyV1 to json.
   130  func (s *TunnelStrategyV1) MarshalJSON() ([]byte, error) {
   131  	var data []byte
   132  	err := s.marshal(func(c *tunnelStrategyConfig) error {
   133  		var err error
   134  		data, err = json.Marshal(c.getMapCopy())
   135  		return trace.Wrap(err)
   136  	})
   137  	if err != nil {
   138  		return nil, trace.Wrap(err)
   139  	}
   140  	return data, nil
   141  }
   142  
   143  // UnmarshalJSON converts json to a TunnelStrategyV1. Unknown fields are allowed
   144  // to prevent rollbacks causing issues decoding this data from the backend.
   145  func (s *TunnelStrategyV1) UnmarshalJSON(data []byte) error {
   146  	err := s.unmarshal(utils.ObjectToStruct, func(c *tunnelStrategyConfig) error {
   147  		params := make(map[string]interface{})
   148  		err := json.Unmarshal(data, &params)
   149  		if err != nil {
   150  			return trace.Wrap(err)
   151  		}
   152  		return trace.Wrap(c.setFromMap(params))
   153  	})
   154  	return trace.Wrap(err)
   155  }
   156  
   157  // marshal converts a TunnelStrategyV1 to a TunnelStrategyConfig before calling
   158  // the given marshal function.
   159  func (s *TunnelStrategyV1) marshal(marshal func(*tunnelStrategyConfig) error) error {
   160  	config := newTunnelStrategyConfig()
   161  	switch strategy := s.Strategy.(type) {
   162  	case *TunnelStrategyV1_AgentMesh:
   163  		config.Type = AgentMesh
   164  		err := utils.ObjectToStruct(strategy.AgentMesh, &config.Params)
   165  		if err != nil {
   166  			return trace.Wrap(err)
   167  		}
   168  	case *TunnelStrategyV1_ProxyPeering:
   169  		config.Type = ProxyPeering
   170  		err := utils.ObjectToStruct(strategy.ProxyPeering, &config.Params)
   171  		if err != nil {
   172  			return trace.Wrap(err)
   173  		}
   174  	default:
   175  		return trace.BadParameter("unknown tunnel strategy: \"%s\"", config.Type)
   176  	}
   177  
   178  	return trace.Wrap(marshal(config))
   179  }
   180  
   181  // objectToStructFunc is a function that converts one struct to another.
   182  type objectToStructFunc func(interface{}, interface{}) error
   183  
   184  func (s *TunnelStrategyV1) unmarshal(ots objectToStructFunc, unmarshal func(*tunnelStrategyConfig) error) error {
   185  	config := newTunnelStrategyConfig()
   186  	err := unmarshal(config)
   187  	if err != nil {
   188  		return trace.Wrap(err)
   189  	}
   190  
   191  	switch config.Type {
   192  	case AgentMesh:
   193  		strategy := &TunnelStrategyV1_AgentMesh{
   194  			AgentMesh: &AgentMeshTunnelStrategy{},
   195  		}
   196  
   197  		err = ots(&config.Params, strategy.AgentMesh)
   198  		if err != nil {
   199  			return trace.Wrap(err)
   200  		}
   201  		s.Strategy = strategy
   202  	case ProxyPeering:
   203  		strategy := &TunnelStrategyV1_ProxyPeering{
   204  			ProxyPeering: &ProxyPeeringTunnelStrategy{},
   205  		}
   206  
   207  		err = ots(&config.Params, strategy.ProxyPeering)
   208  		if err != nil {
   209  			return trace.Wrap(err)
   210  		}
   211  		s.Strategy = strategy
   212  	default:
   213  		return trace.BadParameter("unknown tunnel strategy: \"%s\"", config.Type)
   214  	}
   215  
   216  	return nil
   217  }
   218  
   219  // CheckAndSetDefaults validates and sets default values for a tunnel strategy.
   220  func (s *TunnelStrategyV1) CheckAndSetDefaults() error {
   221  	if s.Strategy == nil {
   222  		s.Strategy = DefaultTunnelStrategy()
   223  	}
   224  
   225  	switch strategy := s.Strategy.(type) {
   226  	case TunnelStrategy:
   227  		err := strategy.CheckAndSetDefaults()
   228  		if err != nil {
   229  			return trace.Wrap(err)
   230  		}
   231  	default:
   232  		return trace.BadParameter("unknown tunnel strategy: %T", strategy)
   233  	}
   234  
   235  	return nil
   236  }
   237  
   238  // CheckAndSetDefaults validates an agent mesh tunnel strategy.
   239  func (s *TunnelStrategyV1_AgentMesh) CheckAndSetDefaults() error {
   240  	if s.AgentMesh == nil {
   241  		s.AgentMesh = DefaultAgentMeshTunnelStrategy()
   242  	}
   243  
   244  	return nil
   245  }
   246  
   247  // CheckAndSetDefaults validates a proxy peering tunnel strategy.
   248  func (s *TunnelStrategyV1_ProxyPeering) CheckAndSetDefaults() error {
   249  	if s.ProxyPeering == nil {
   250  		s.ProxyPeering = DefaultProxyPeeringTunnelStrategy()
   251  	}
   252  	if s.ProxyPeering.AgentConnectionCount == 0 {
   253  		s.ProxyPeering.AgentConnectionCount = defaultAgentConnectionCount
   254  	}
   255  
   256  	return nil
   257  }