dubbo.apache.org/dubbo-go/v3@v3.1.1/remoting/xds/mapping/handler.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  package mapping
    19  
    20  import (
    21  	"encoding/json"
    22  	"fmt"
    23  	"io"
    24  	"net/http"
    25  	"os"
    26  	"sync"
    27  	"time"
    28  
    29  	"github.com/dubbogo/gost/log/logger"
    30  
    31  	structpb "github.com/golang/protobuf/ptypes/struct"
    32  
    33  	"dubbo.apache.org/dubbo-go/v3/remoting/xds/common"
    34  	"dubbo.apache.org/dubbo-go/v3/xds/client"
    35  	perrors "github.com/pkg/errors"
    36  )
    37  
    38  const (
    39  	authorizationHeader = "Authorization"
    40  	istiodTokenPrefix   = "Bearer "
    41  )
    42  
    43  type InterfaceMapHandlerImpl struct {
    44  	hostAddr common.HostAddr
    45  
    46  	istioDebugAddr common.HostAddr
    47  
    48  	xdsClient client.XDSClient
    49  
    50  	istioTokenPath string
    51  
    52  	/*
    53  		interfaceAppNameMap store map of serviceUniqueKey -> hostAddr
    54  	*/
    55  	interfaceAppNameMap     map[string]string
    56  	interfaceAppNameMapLock sync.RWMutex
    57  
    58  	/*
    59  		interfaceNameHostAddrMap cache the dubbo interface unique key -> hostName
    60  		the data is read from istiod:8080/debug/adsz, connection metadata["LABELS"]["DUBBO_GO"]
    61  	*/
    62  	interfaceNameHostAddrMap     map[string]string
    63  	interfaceNameHostAddrMapLock sync.RWMutex
    64  	localDebugMode               bool
    65  }
    66  
    67  func (i *InterfaceMapHandlerImpl) UnRegister(serviceUniqueKey string) error {
    68  	i.interfaceAppNameMapLock.Lock()
    69  	delete(i.interfaceAppNameMap, serviceUniqueKey)
    70  	i.interfaceAppNameMapLock.Unlock()
    71  	return i.xdsClient.SetMetadata(i.interfaceAppNameMap2DubboGoMetadata())
    72  }
    73  
    74  func (i *InterfaceMapHandlerImpl) Register(serviceUniqueKey string) error {
    75  	i.interfaceAppNameMapLock.Lock()
    76  	i.interfaceAppNameMap[serviceUniqueKey] = i.hostAddr.String()
    77  	i.interfaceAppNameMapLock.Unlock()
    78  	return i.xdsClient.SetMetadata(i.interfaceAppNameMap2DubboGoMetadata())
    79  }
    80  
    81  func (i *InterfaceMapHandlerImpl) GetDubboGoMetadata() (map[string]string, error) {
    82  	return i.getServiceUniqueKeyHostAddrMapFromPilot()
    83  }
    84  
    85  func (i *InterfaceMapHandlerImpl) GetHostAddrMap(serviceUniqueKey string) (string, error) {
    86  	i.interfaceNameHostAddrMapLock.RLock()
    87  	if hostAddr, ok := i.interfaceNameHostAddrMap[serviceUniqueKey]; ok {
    88  		i.interfaceNameHostAddrMapLock.RUnlock()
    89  		return hostAddr, nil
    90  	}
    91  	i.interfaceNameHostAddrMapLock.RUnlock()
    92  
    93  	retryCount := 0
    94  	maxRetries := 30
    95  	for {
    96  		if interfaceHostAddrMap, err := i.getServiceUniqueKeyHostAddrMapFromPilot(); err != nil {
    97  			return "", err
    98  		} else {
    99  			i.interfaceNameHostAddrMapLock.Lock()
   100  			i.interfaceNameHostAddrMap = interfaceHostAddrMap
   101  			i.interfaceNameHostAddrMapLock.Unlock()
   102  			hostName, ok := interfaceHostAddrMap[serviceUniqueKey]
   103  			if !ok {
   104  				logger.Infof("[XDS Wrapped Client] Try getting interface %s 's host from istio %s:8080\n", serviceUniqueKey, i.istioDebugAddr)
   105  				time.Sleep(time.Millisecond * 100)
   106  				retryCount++
   107  				if retryCount > maxRetries {
   108  					err := perrors.Errorf("[XDS Wrapped Client] Try getting interface %s 's host from istio %s:8080 failed. Please check if provider's service resource is deployed correctly.\n", serviceUniqueKey, i.istioDebugAddr)
   109  					logger.Error(err)
   110  					return "", err
   111  				}
   112  				continue
   113  			}
   114  			return hostName, nil
   115  		}
   116  	}
   117  }
   118  
   119  // getServiceUniqueKeyHostAddrMapFromPilot get map of service key like 'provider::api.Greeter' to host addr like
   120  // 'dubbo-go-app.default.svc.cluster.local:20000'
   121  func (i *InterfaceMapHandlerImpl) getServiceUniqueKeyHostAddrMapFromPilot() (map[string]string, error) {
   122  	req, _ := http.NewRequest(http.MethodGet, fmt.Sprintf("http://%s/debug/adsz", i.istioDebugAddr.String()), nil)
   123  	if !i.localDebugMode {
   124  		token, err := os.ReadFile(i.istioTokenPath)
   125  		if err != nil {
   126  			return nil, err
   127  		}
   128  		req.Header.Add(authorizationHeader, istiodTokenPrefix+string(token))
   129  	}
   130  	rsp, err := http.DefaultClient.Do(req)
   131  	if err != nil {
   132  		logger.Infof("[XDS Wrapped Client] Try getting interface host map from istio IP %s with error %s\n",
   133  			i.istioDebugAddr, err)
   134  		return nil, err
   135  	}
   136  
   137  	data, err := io.ReadAll(rsp.Body)
   138  	if err != nil {
   139  		return nil, err
   140  	}
   141  	adszRsp := &ADSZResponse{}
   142  	if err := json.Unmarshal(data, adszRsp); err != nil {
   143  		return nil, err
   144  	}
   145  	return adszRsp.GetMap(), nil
   146  }
   147  
   148  func (i *InterfaceMapHandlerImpl) interfaceAppNameMap2DubboGoMetadata() *structpb.Struct {
   149  	i.interfaceAppNameMapLock.RLock()
   150  	defer i.interfaceAppNameMapLock.RUnlock()
   151  	data, _ := json.Marshal(i.interfaceAppNameMap)
   152  	return GetDubboGoMetadata(string(data))
   153  }
   154  
   155  func NewInterfaceMapHandlerImpl(xdsClient client.XDSClient, istioTokenPath string, istioDebugAddr, hostAddr common.HostAddr, localDebugMode bool) InterfaceMapHandler {
   156  	return &InterfaceMapHandlerImpl{
   157  		xdsClient:                xdsClient,
   158  		interfaceAppNameMap:      map[string]string{},
   159  		interfaceNameHostAddrMap: map[string]string{},
   160  		istioDebugAddr:           istioDebugAddr,
   161  		hostAddr:                 hostAddr,
   162  		istioTokenPath:           istioTokenPath,
   163  		localDebugMode:           localDebugMode,
   164  	}
   165  }
   166  
   167  type InterfaceMapHandler interface {
   168  	Register(string) error
   169  	UnRegister(string) error
   170  	GetHostAddrMap(string) (string, error)
   171  	GetDubboGoMetadata() (map[string]string, error)
   172  }