dubbo.apache.org/dubbo-go/v3@v3.1.1/xds/client/client.go (about)

     1  /*
     2   * Licensed to the Apache Software Foundation (ASF) under one or more
     3   * contributor license agreements.  See the NOTICE file distributed with
     4   * this work for additional information regarding copyright ownership.
     5   * The ASF licenses this file to You under the Apache License, Version 2.0
     6   * (the "License"); you may not use this file except in compliance with
     7   * the License.  You may obtain a copy of the License at
     8   *
     9   *     http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17  
    18  /*
    19   *
    20   * Copyright 2019 gRPC authors.
    21   *
    22   */
    23  
    24  // package client implements a full fledged gRPC client for the xDS API used
    25  // by the xds resolver and balancer implementations.
    26  package client
    27  
    28  import (
    29  	"fmt"
    30  	"sync"
    31  	"time"
    32  )
    33  
    34  import (
    35  	dubbogoLogger "github.com/dubbogo/gost/log/logger"
    36  
    37  	_struct "github.com/golang/protobuf/ptypes/struct"
    38  )
    39  
    40  import (
    41  	"dubbo.apache.org/dubbo-go/v3/xds/client/bootstrap"
    42  	"dubbo.apache.org/dubbo-go/v3/xds/client/resource"
    43  	"dubbo.apache.org/dubbo-go/v3/xds/utils/grpcsync"
    44  	cache "dubbo.apache.org/dubbo-go/v3/xds/utils/xds_cache"
    45  )
    46  
    47  // clientImpl is the real implementation of the xds client. The exported Client
    48  // is a wrapper of this struct with a ref count.
    49  //
    50  // Implements UpdateHandler interface.
    51  // TODO(easwars): Make a wrapper struct which implements this interface in the
    52  // style of ccBalancerWrapper so that the Client type does not implement these
    53  // exported methods.
    54  type clientImpl struct {
    55  	done                  *grpcsync.Event
    56  	config                *bootstrap.Config
    57  	refreshMetadataCancel func()
    58  
    59  	// authorityMu protects the authority fields. It's necessary because an
    60  	// authority is created when it's used.
    61  	authorityMu sync.Mutex
    62  	// authorities is a map from ServerConfig to authority. So that
    63  	// different authorities sharing the same ServerConfig can share the
    64  	// authority.
    65  	//
    66  	// The key is **ServerConfig.String()**, not the authority name.
    67  	//
    68  	// An authority is either in authorities, or idleAuthorities,
    69  	// never both.
    70  	authorities map[string]*authority
    71  	// idleAuthorities keeps the authorities that are not used (the last
    72  	// watch on it was canceled). They are kept in the cache and will be deleted
    73  	// after a timeout. The key is ServerConfig.String().
    74  	//
    75  	// An authority is either in authorities, or idleAuthorities,
    76  	// never both.
    77  	idleAuthorities *cache.TimeoutCache
    78  
    79  	logger             dubbogoLogger.Logger
    80  	watchExpiryTimeout time.Duration
    81  }
    82  
    83  // newWithConfig returns a new xdsClient with the given config.
    84  func newWithConfig(config *bootstrap.Config, watchExpiryTimeout time.Duration, idleAuthorityDeleteTimeout time.Duration) (_ *clientImpl, retErr error) {
    85  	c := &clientImpl{
    86  		done:               grpcsync.NewEvent(),
    87  		config:             config,
    88  		watchExpiryTimeout: watchExpiryTimeout,
    89  
    90  		authorities:     make(map[string]*authority),
    91  		idleAuthorities: cache.NewTimeoutCache(idleAuthorityDeleteTimeout),
    92  	}
    93  
    94  	defer func() {
    95  		if retErr != nil {
    96  			c.Close()
    97  		}
    98  	}()
    99  
   100  	c.logger = dubbogoLogger.GetLogger()
   101  	c.logger.Infof("Created ClientConn to xDS management server: %s", config.XDSServer)
   102  
   103  	c.logger.Infof("Created")
   104  	return c, nil
   105  }
   106  
   107  func (c *clientImpl) SetMetadata(m *_struct.Struct) error {
   108  	a, _, err := c.findAuthority(resource.ParseName(""))
   109  	if err != nil {
   110  		return err
   111  	}
   112  	if err := a.SetMetadata(m); err != nil {
   113  		return err
   114  	}
   115  	a.watchEndpoints("", func(update resource.EndpointsUpdate, err error) {})
   116  	return nil
   117  }
   118  
   119  // BootstrapConfig returns the configuration read from the bootstrap file.
   120  // Callers must treat the return value as read-only.
   121  func (c *clientRefCounted) BootstrapConfig() *bootstrap.Config {
   122  	return c.config
   123  }
   124  
   125  // Close closes the gRPC connection to the management server.
   126  func (c *clientImpl) Close() {
   127  	if c.done.HasFired() {
   128  		return
   129  	}
   130  	c.done.Fire()
   131  	// TODO: Should we invoke the registered callbacks here with an error that
   132  	// the client is closed?
   133  
   134  	// Note that Close needs to check for nils even if some of them are always
   135  	// set in the constructor. This is because the constructor defers Close() in
   136  	// error cases, and the fields might not be set when the error happens.
   137  
   138  	c.authorityMu.Lock()
   139  	for _, a := range c.authorities {
   140  		a.close()
   141  	}
   142  	c.idleAuthorities.Clear(true)
   143  	c.authorityMu.Unlock()
   144  
   145  	c.logger.Infof("Shutdown")
   146  }
   147  
   148  func (c *clientImpl) filterChainUpdateValidator(fc *resource.FilterChain) error {
   149  	if fc == nil {
   150  		return nil
   151  	}
   152  	return c.securityConfigUpdateValidator(fc.SecurityCfg)
   153  }
   154  
   155  func (c *clientImpl) securityConfigUpdateValidator(sc *resource.SecurityConfig) error {
   156  	if sc == nil {
   157  		return nil
   158  	}
   159  	if sc.IdentityInstanceName != "" {
   160  		if _, ok := c.config.CertProviderConfigs[sc.IdentityInstanceName]; !ok {
   161  			return fmt.Errorf("identitiy certificate provider instance name %q missing in bootstrap configuration", sc.IdentityInstanceName)
   162  		}
   163  	}
   164  	if sc.RootInstanceName != "" {
   165  		if _, ok := c.config.CertProviderConfigs[sc.RootInstanceName]; !ok {
   166  			return fmt.Errorf("root certificate provider instance name %q missing in bootstrap configuration", sc.RootInstanceName)
   167  		}
   168  	}
   169  	return nil
   170  }
   171  
   172  func (c *clientImpl) updateValidator(u interface{}) error {
   173  	switch update := u.(type) {
   174  	case resource.ListenerUpdate:
   175  		if update.InboundListenerCfg == nil || update.InboundListenerCfg.FilterChains == nil {
   176  			return nil
   177  		}
   178  		return update.InboundListenerCfg.FilterChains.Validate(c.filterChainUpdateValidator)
   179  	case resource.ClusterUpdate:
   180  		return c.securityConfigUpdateValidator(update.SecurityCfg)
   181  	default:
   182  		// We currently invoke this update validation function only for LDS and
   183  		// CDS updates. In the future, if we wish to invoke it for other xDS
   184  		// updates, corresponding plumbing needs to be added to those unmarshal
   185  		// functions.
   186  	}
   187  	return nil
   188  }