github.com/oam-dev/cluster-gateway@v1.9.0/pkg/apis/cluster/v1alpha1/transport.go (about)

     1  package v1alpha1
     2  
     3  import (
     4  	"context"
     5  	"net"
     6  	"net/http"
     7  	"net/url"
     8  	"strconv"
     9  	"time"
    10  
    11  	"github.com/pkg/errors"
    12  	"google.golang.org/grpc"
    13  	grpccredentials "google.golang.org/grpc/credentials"
    14  	"google.golang.org/grpc/keepalive"
    15  	k8snet "k8s.io/apimachinery/pkg/util/net"
    16  	restclient "k8s.io/client-go/rest"
    17  	konnectivity "sigs.k8s.io/apiserver-network-proxy/konnectivity-client/pkg/client"
    18  	"sigs.k8s.io/apiserver-network-proxy/pkg/util"
    19  
    20  	"github.com/oam-dev/cluster-gateway/pkg/config"
    21  )
    22  
    23  var DialerGetter = func(ctx context.Context) (k8snet.DialFunc, error) {
    24  	tlsCfg, err := util.GetClientTLSConfig(
    25  		config.ClusterProxyCAFile,
    26  		config.ClusterProxyCertFile,
    27  		config.ClusterProxyKeyFile,
    28  		config.ClusterProxyHost,
    29  		nil)
    30  	if err != nil {
    31  		return nil, err
    32  	}
    33  	dialerTunnel, err := konnectivity.CreateSingleUseGrpcTunnel(
    34  		ctx,
    35  		net.JoinHostPort(config.ClusterProxyHost, strconv.Itoa(config.ClusterProxyPort)),
    36  		grpc.WithTransportCredentials(grpccredentials.NewTLS(tlsCfg)),
    37  		grpc.WithKeepaliveParams(keepalive.ClientParameters{
    38  			Time: time.Second * 5,
    39  		}),
    40  	)
    41  	if err != nil {
    42  		return nil, err
    43  	}
    44  	return dialerTunnel.DialContext, nil
    45  }
    46  
    47  func NewConfigFromCluster(ctx context.Context, c *ClusterGateway) (*restclient.Config, error) {
    48  	cfg := &restclient.Config{
    49  		Timeout: time.Second * 40,
    50  	}
    51  	// setting up endpoint
    52  	switch c.Spec.Access.Endpoint.Type {
    53  	case ClusterEndpointTypeConst:
    54  		cfg.Host = c.Spec.Access.Endpoint.Const.Address
    55  		cfg.CAData = c.Spec.Access.Endpoint.Const.CABundle
    56  		if c.Spec.Access.Endpoint.Const.Insecure != nil && *c.Spec.Access.Endpoint.Const.Insecure {
    57  			cfg.TLSClientConfig = restclient.TLSClientConfig{Insecure: true}
    58  		}
    59  		u, err := url.Parse(c.Spec.Access.Endpoint.Const.Address)
    60  		if err != nil {
    61  			return nil, err
    62  		}
    63  
    64  		const missingPort = "missing port in address"
    65  		host, _, err := net.SplitHostPort(u.Host)
    66  		if err != nil {
    67  			addrErr, ok := err.(*net.AddrError)
    68  			if !ok {
    69  				return nil, err
    70  			}
    71  			if addrErr.Err != missingPort {
    72  				return nil, err
    73  			}
    74  			host = u.Host
    75  		}
    76  		cfg.ServerName = host // apiserver may listen on SNI cert
    77  
    78  		if c.Spec.Access.Endpoint.Const.ProxyURL != nil {
    79  			_url, _err := url.Parse(*c.Spec.Access.Endpoint.Const.ProxyURL)
    80  			if _err != nil {
    81  				return nil, _err
    82  			}
    83  			cfg.Proxy = http.ProxyURL(_url)
    84  		}
    85  	case ClusterEndpointTypeClusterProxy:
    86  		cfg.Host = c.Name // the same as the cluster name
    87  		cfg.Insecure = true
    88  		cfg.CAData = nil
    89  		dail, err := DialerGetter(ctx)
    90  		if err != nil {
    91  			return nil, err
    92  		}
    93  		cfg.Dial = dail
    94  	}
    95  	// setting up credentials
    96  	switch c.Spec.Access.Credential.Type {
    97  	case CredentialTypeDynamic:
    98  		if token := c.Spec.Access.Credential.ServiceAccountToken; token != "" {
    99  			cfg.BearerToken = token
   100  		}
   101  
   102  		if c.Spec.Access.Credential.X509 != nil && len(c.Spec.Access.Credential.X509.Certificate) > 0 && len(c.Spec.Access.Credential.X509.PrivateKey) > 0 {
   103  			cfg.CertData = c.Spec.Access.Credential.X509.Certificate
   104  			cfg.KeyData = c.Spec.Access.Credential.X509.PrivateKey
   105  		}
   106  
   107  	case CredentialTypeServiceAccountToken:
   108  		cfg.BearerToken = c.Spec.Access.Credential.ServiceAccountToken
   109  
   110  	case CredentialTypeX509Certificate:
   111  		cfg.CertData = c.Spec.Access.Credential.X509.Certificate
   112  		cfg.KeyData = c.Spec.Access.Credential.X509.PrivateKey
   113  	}
   114  	return cfg, nil
   115  }
   116  
   117  func GetEndpointURL(c *ClusterGateway) (*url.URL, error) {
   118  	switch c.Spec.Access.Endpoint.Type {
   119  	case ClusterEndpointTypeConst:
   120  		urlAddr, err := url.Parse(c.Spec.Access.Endpoint.Const.Address)
   121  		if err != nil {
   122  			return nil, errors.Wrapf(err, "failed parsing url from cluster %s invalid value %s",
   123  				c.Name, c.Spec.Access.Endpoint.Const.Address)
   124  		}
   125  		return urlAddr, nil
   126  	case ClusterEndpointTypeClusterProxy:
   127  		return &url.URL{
   128  			Scheme: "https",
   129  			Host:   c.Name,
   130  		}, nil
   131  	default:
   132  		return nil, errors.New("unsupported cluster gateway endpoint type")
   133  	}
   134  }