github.com/polarismesh/polaris@v1.17.8/apiserver/eurekaserver/model.go (about)

     1  /**
     2   * Tencent is pleased to support the open source community by making Polaris available.
     3   *
     4   * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
     5   *
     6   * Licensed under the BSD 3-Clause License (the "License");
     7   * you may not use this file except in compliance with the License.
     8   * You may obtain a copy of the License at
     9   *
    10   * https://opensource.org/licenses/BSD-3-Clause
    11   *
    12   * Unless required by applicable law or agreed to in writing, software distributed
    13   * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
    14   * CONDITIONS OF ANY KIND, either express or implied. See the License for the
    15   * specific language governing permissions and limitations under the License.
    16   */
    17  
    18  package eurekaserver
    19  
    20  import (
    21  	"encoding/json"
    22  	"encoding/xml"
    23  	"fmt"
    24  	"reflect"
    25  	"strconv"
    26  	"strings"
    27  
    28  	apiservice "github.com/polarismesh/specification/source/go/api/v1/service_manage"
    29  )
    30  
    31  // PortWrapper 端口包装类
    32  type PortWrapper struct {
    33  	Port interface{} `json:"$" xml:",chardata"`
    34  
    35  	RealPort int `json:"-" xml:"-"`
    36  
    37  	Enabled interface{} `json:"@enabled" xml:"enabled,attr"`
    38  
    39  	RealEnable bool `json:"-" xml:"-"`
    40  }
    41  
    42  // UnmarshalXML PortWrapper xml 反序列化
    43  func (p *PortWrapper) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
    44  	var err error
    45  	port := struct {
    46  		Port    string `xml:",chardata"`
    47  		Enabled string `xml:"enabled,attr"`
    48  	}{}
    49  	if err = d.DecodeElement(&port, &start); err != nil {
    50  		return err
    51  	}
    52  
    53  	p.RealPort, err = strconv.Atoi(port.Port)
    54  	if err != nil {
    55  		return err
    56  	}
    57  	p.Port = port.Port
    58  	p.RealEnable, err = strconv.ParseBool(port.Enabled)
    59  	if err != nil {
    60  		return err
    61  	}
    62  	p.Enabled = port.Enabled
    63  	return nil
    64  }
    65  
    66  func convertIntValue(value interface{}) (int, error) {
    67  	if jsonNumber, ok := value.(json.Number); ok {
    68  		realPort, err := jsonNumber.Int64()
    69  		if err != nil {
    70  			return 0, err
    71  		}
    72  		return int(realPort), nil
    73  	}
    74  	if floatValue, ok := value.(float64); ok {
    75  		return int(floatValue), nil
    76  	}
    77  	if strValue, ok := value.(string); ok {
    78  		return strconv.Atoi(strValue)
    79  	}
    80  	return 0, fmt.Errorf("unknow type of port value, type is %v", reflect.TypeOf(value))
    81  }
    82  
    83  func (p *PortWrapper) convertPortValue() error {
    84  	var err error
    85  	p.RealPort, err = convertIntValue(p.Port)
    86  	return err
    87  }
    88  
    89  func (p *PortWrapper) convertEnableValue() error {
    90  	if jsonEnableStr, ok := p.Enabled.(string); ok {
    91  		enableValue, err := strconv.ParseBool(jsonEnableStr)
    92  		if err != nil {
    93  			return err
    94  		}
    95  		p.RealEnable = enableValue
    96  		return nil
    97  	}
    98  	if jsonEnableValue, ok := p.Enabled.(bool); ok {
    99  		p.RealEnable = jsonEnableValue
   100  		return nil
   101  	}
   102  	return fmt.Errorf("unknow type of enable value, type is %v", reflect.TypeOf(p.Enabled))
   103  }
   104  
   105  // DataCenterInfo 数据中心信息
   106  type DataCenterInfo struct {
   107  	Clazz string `json:"@class" xml:"class,attr"`
   108  
   109  	Name string `json:"name" xml:"name"`
   110  }
   111  
   112  // LeaseInfo 租约信息
   113  type LeaseInfo struct {
   114  
   115  	// Client settings
   116  	RenewalIntervalInSecs int `json:"renewalIntervalInSecs" xml:"renewalIntervalInSecs"`
   117  
   118  	DurationInSecs int `json:"durationInSecs" xml:"durationInSecs"`
   119  
   120  	// Server populated
   121  	RegistrationTimestamp int `json:"registrationTimestamp" xml:"registrationTimestamp"`
   122  
   123  	LastRenewalTimestamp int `json:"lastRenewalTimestamp" xml:"lastRenewalTimestamp"`
   124  
   125  	EvictionTimestamp int `json:"evictionTimestamp" xml:"evictionTimestamp"`
   126  
   127  	ServiceUpTimestamp int `json:"serviceUpTimestamp" xml:"serviceUpTimestamp"`
   128  }
   129  
   130  // RegistrationRequest 实例注册请求
   131  type RegistrationRequest struct {
   132  	Instance *InstanceInfo `json:"instance"`
   133  }
   134  
   135  // ApplicationsResponse 服务拉取应答
   136  type ApplicationsResponse struct {
   137  	Applications *Applications `json:"applications"`
   138  }
   139  
   140  // ApplicationResponse 单个服务拉取响应
   141  type ApplicationResponse struct {
   142  	Application *Application `json:"application"`
   143  }
   144  
   145  // InstanceResponse 单个服务实例拉取响应
   146  type InstanceResponse struct {
   147  	InstanceInfo *InstanceInfo `json:"instance" xml:"instance"`
   148  }
   149  
   150  // Metadata 元数据信息,xml 格式无法直接反序列化成 map[string]string 类型。这里通过 []byte 类型的 Raw 接收,并反序列化到 Meta 中。
   151  // 反序列化后,polaris 在业务中只使用 Meta 字段。
   152  type Metadata struct {
   153  	Raw []byte `xml:",innerxml" json:"-"`
   154  
   155  	Attributes StringMap
   156  
   157  	Meta StringMap
   158  }
   159  
   160  // UnmarshalJSON Metadata json 反序列化方法
   161  func (i *Metadata) UnmarshalJSON(b []byte) error {
   162  	i.Raw = b
   163  
   164  	err := json.Unmarshal(b, &i.Meta)
   165  	if err != nil {
   166  		return err
   167  	}
   168  
   169  	return nil
   170  }
   171  
   172  // UnmarshalXML Metadata xml 反序列化方法
   173  func (i *Metadata) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
   174  	i.Meta = make(map[string]interface{})
   175  	values, err := xmlToMapParser(start.Name.Local, start.Attr, d, true)
   176  	if err != nil {
   177  		return err
   178  	}
   179  	var subValues map[string]interface{}
   180  	if len(values) > 0 {
   181  		subValuesRaw := values[start.Name.Local]
   182  		subValues, _ = subValuesRaw.(map[string]interface{})
   183  	}
   184  	if len(subValues) > 0 {
   185  		for k, v := range subValues {
   186  			i.Meta[k] = v
   187  		}
   188  	}
   189  	return nil
   190  }
   191  
   192  // MarshalJSON Metadata json 序列化方法
   193  func (i *Metadata) MarshalJSON() ([]byte, error) {
   194  	if i.Meta != nil {
   195  		return json.Marshal(i.Meta)
   196  	}
   197  
   198  	if i.Raw == nil {
   199  		i.Raw = []byte("{}")
   200  	}
   201  
   202  	return i.Raw, nil
   203  }
   204  
   205  func startLocalName(local string) xml.StartElement {
   206  	return xml.StartElement{Name: xml.Name{Space: "", Local: local}}
   207  }
   208  
   209  func startLocalAttribute(attrName string, attrValue string) xml.Attr {
   210  	return xml.Attr{Name: xml.Name{Space: "", Local: attrName}, Value: attrValue}
   211  }
   212  
   213  // MarshalXML Metadata xml 序列化方法
   214  func (i *Metadata) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
   215  	tokens := []xml.Token{start}
   216  	if i.Meta != nil {
   217  		for key, value := range i.Meta {
   218  			strValue := ObjectToString(value)
   219  			if strings.HasPrefix(key, attributeNotion) {
   220  				start.Attr = append(start.Attr, startLocalAttribute(key[1:], strValue))
   221  				continue
   222  			}
   223  			// 兼容,后续去掉
   224  			if strings.HasPrefix(key, attributeNotionCross) {
   225  				start.Attr = append(start.Attr, startLocalAttribute(key[1:], strValue))
   226  				continue
   227  			}
   228  			t := startLocalName(key)
   229  			tokens = append(tokens, t, xml.CharData(strValue), xml.EndElement{Name: t.Name})
   230  		}
   231  	}
   232  	tokens = append(tokens, xml.EndElement{Name: start.Name})
   233  	if len(start.Attr) > 0 {
   234  		tokens[0] = start
   235  	}
   236  	for _, t := range tokens {
   237  		err := e.EncodeToken(t)
   238  		if err != nil {
   239  			return err
   240  		}
   241  	}
   242  
   243  	// flush to ensure tokens are written
   244  	return e.Flush()
   245  }
   246  
   247  // InstanceInfo 实例信息
   248  type InstanceInfo struct {
   249  	XMLName struct{} `json:"-" xml:"instance"`
   250  
   251  	InstanceId string `json:"instanceId" xml:"instanceId"`
   252  
   253  	AppName string `json:"app" xml:"app"`
   254  
   255  	AppGroupName string `json:"appGroupName" xml:"appGroupName,omitempty"`
   256  
   257  	IpAddr string `json:"ipAddr" xml:"ipAddr"`
   258  
   259  	Sid string `json:"sid" xml:"sid,omitempty"`
   260  
   261  	Port *PortWrapper `json:"port" xml:"port,omitempty"`
   262  
   263  	SecurePort *PortWrapper `json:"securePort" xml:"securePort,omitempty"`
   264  
   265  	HomePageUrl string `json:"homePageUrl" xml:"homePageUrl,omitempty"`
   266  
   267  	StatusPageUrl string `json:"statusPageUrl" xml:"statusPageUrl,omitempty"`
   268  
   269  	HealthCheckUrl string `json:"healthCheckUrl" xml:"healthCheckUrl,omitempty"`
   270  
   271  	SecureHealthCheckUrl string `json:"secureHealthCheckUrl" xml:"secureHealthCheckUrl,omitempty"`
   272  
   273  	VipAddress string `json:"vipAddress" xml:"vipAddress,omitempty"`
   274  
   275  	SecureVipAddress string `json:"secureVipAddress" xml:"secureVipAddress,omitempty"`
   276  
   277  	CountryId interface{} `json:"countryId" xml:"countryId,omitempty"`
   278  
   279  	DataCenterInfo *DataCenterInfo `json:"dataCenterInfo" xml:"dataCenterInfo"`
   280  
   281  	HostName string `json:"hostName" xml:"hostName,omitempty"`
   282  
   283  	Status string `json:"status" xml:"status"`
   284  
   285  	OverriddenStatus string `json:"overriddenStatus" xml:"overriddenStatus,omitempty"`
   286  
   287  	LeaseInfo *LeaseInfo `json:"leaseInfo" xml:"leaseInfo,omitempty"`
   288  
   289  	IsCoordinatingDiscoveryServer interface{} `json:"isCoordinatingDiscoveryServer" xml:"isCoordinatingDiscoveryServer,omitempty"`
   290  
   291  	Metadata *Metadata `json:"metadata" xml:"metadata"`
   292  
   293  	LastUpdatedTimestamp interface{} `json:"lastUpdatedTimestamp" xml:"lastUpdatedTimestamp,omitempty"`
   294  
   295  	LastDirtyTimestamp interface{} `json:"lastDirtyTimestamp" xml:"lastDirtyTimestamp,omitempty"`
   296  
   297  	ActionType string `json:"actionType" xml:"actionType"`
   298  
   299  	// 实际的北极星实例模型
   300  	RealInstance *apiservice.Instance `json:"-" xml:"-"`
   301  }
   302  
   303  // Clone 对实例进行拷贝
   304  func (i *InstanceInfo) Clone(actionType string) *InstanceInfo {
   305  	return &InstanceInfo{
   306  		InstanceId:                    i.InstanceId,
   307  		AppName:                       i.AppName,
   308  		AppGroupName:                  i.AppGroupName,
   309  		IpAddr:                        i.IpAddr,
   310  		Sid:                           i.Sid,
   311  		Port:                          i.Port,
   312  		SecurePort:                    i.SecurePort,
   313  		HomePageUrl:                   i.HomePageUrl,
   314  		StatusPageUrl:                 i.StatusPageUrl,
   315  		HealthCheckUrl:                i.HealthCheckUrl,
   316  		SecureHealthCheckUrl:          i.SecureHealthCheckUrl,
   317  		VipAddress:                    i.VipAddress,
   318  		SecureVipAddress:              i.SecureVipAddress,
   319  		CountryId:                     i.CountryId,
   320  		DataCenterInfo:                i.DataCenterInfo,
   321  		HostName:                      i.HostName,
   322  		Status:                        i.Status,
   323  		OverriddenStatus:              i.OverriddenStatus,
   324  		LeaseInfo:                     i.LeaseInfo,
   325  		IsCoordinatingDiscoveryServer: i.IsCoordinatingDiscoveryServer,
   326  		Metadata:                      i.Metadata,
   327  		LastUpdatedTimestamp:          i.LastUpdatedTimestamp,
   328  		LastDirtyTimestamp:            i.LastDirtyTimestamp,
   329  		ActionType:                    actionType,
   330  	}
   331  }
   332  
   333  // Equals 判断实例是否发生变更
   334  func (i *InstanceInfo) Equals(another *InstanceInfo) bool {
   335  	return i.RealInstance.GetRevision().GetValue() == another.RealInstance.GetRevision().GetValue()
   336  }
   337  
   338  // Application 服务数据
   339  type Application struct {
   340  	XMLName struct{} `json:"-" xml:"application"`
   341  
   342  	Name string `json:"name" xml:"name"`
   343  
   344  	Instance []*InstanceInfo `json:"instance" xml:"instance"`
   345  
   346  	InstanceMap map[string]*InstanceInfo `json:"-" xml:"-"`
   347  
   348  	Revision string `json:"-" xml:"-"`
   349  
   350  	StatusCounts map[string]int `json:"-" xml:"-"`
   351  }
   352  
   353  // GetInstance 获取eureka实例
   354  func (a *Application) GetInstance(instId string) *InstanceInfo {
   355  	if len(a.InstanceMap) > 0 {
   356  		return a.InstanceMap[instId]
   357  	}
   358  	return nil
   359  }
   360  
   361  // Applications 服务列表
   362  type Applications struct {
   363  	XMLName struct{} `json:"-" xml:"applications"`
   364  
   365  	VersionsDelta string `json:"versions__delta" xml:"versions__delta"`
   366  
   367  	AppsHashCode string `json:"apps__hashcode" xml:"apps__hashcode"`
   368  
   369  	Application []*Application `json:"application" xml:"application"`
   370  
   371  	ApplicationMap map[string]*Application `json:"-" xml:"-"`
   372  }
   373  
   374  // GetApplication 获取eureka应用
   375  func (a *Applications) GetApplication(appId string) *Application {
   376  	if len(a.ApplicationMap) > 0 {
   377  		return a.ApplicationMap[appId]
   378  	}
   379  	return nil
   380  }
   381  
   382  // GetInstance get instance by instanceId
   383  func (a *Applications) GetInstance(instId string) *InstanceInfo {
   384  	if len(a.Application) == 0 {
   385  		return nil
   386  	}
   387  	for _, app := range a.Application {
   388  		inst, ok := app.InstanceMap[instId]
   389  		if ok {
   390  			return inst
   391  		}
   392  	}
   393  	return nil
   394  }
   395  
   396  // StringMap is a map[string]string.
   397  type StringMap map[string]interface{}
   398  
   399  // ReplicationInstance request for instance replicate
   400  type ReplicationInstance struct {
   401  	AppName            string        `json:"appName"`
   402  	Id                 string        `json:"id"`
   403  	LastDirtyTimestamp int64         `json:"lastDirtyTimestamp"`
   404  	OverriddenStatus   string        `json:"overriddenStatus"`
   405  	Status             string        `json:"status"`
   406  	InstanceInfo       *InstanceInfo `json:"instanceInfo"`
   407  	Action             string        `json:"action"`
   408  }
   409  
   410  // ReplicationList instances list to replicate
   411  type ReplicationList struct {
   412  	ReplicationList []*ReplicationInstance `json:"replicationList"`
   413  }
   414  
   415  // ReplicationInstanceResponse response for instance replicate process
   416  type ReplicationInstanceResponse struct {
   417  	StatusCode     int           `json:"statusCode"`
   418  	ResponseEntity *InstanceInfo `json:"responseEntity"`
   419  }
   420  
   421  // ReplicationListResponse list for replicate instance response
   422  type ReplicationListResponse struct {
   423  	ResponseList []*ReplicationInstanceResponse `json:"responseList"`
   424  }