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 }